Getting Started with Parsley
This tutorial walks you through Parsley's core concepts with hands-on examples. By the end, you'll be able to write variables, functions, loops, and HTML templates โ everything you need to start building with Basil.
Prerequisites: You need
pars(the Parsley CLI) installed. Runparsto start an interactive session, orpars myfile.parsto run a script.
Your First Program
Create a file called hello.pars:
let name = "world"
"Hello, " + name + "!"
Run it:
$ pars hello.pars
Hello, world!
let creates a variable. The + operator concatenates strings. Parsley outputs the result of the last expression โ no print() needed.
Variables and Expressions
Parsley has two ways to declare variables:
letโ immutable (cannot be reassigned)varโ mutable (can be reassigned)
let name = "Alice" // immutable
var count = 0 // mutable
count = count + 1 // OK โ var allows this
// name = "Bob" // Error โ let doesn't allow reassignment
Parsley has numbers, strings, booleans, and null:
let age = 30
let price = 9.99
let active = true
let missing = null
Arithmetic works as you'd expect:
let x = 10
let y = 3
x + y // 13
x * y // 30
x / y // 3.333...
x % y // 1 (remainder)
See: Variables & Binding ยท Types ยท Operators
Strings
Strings can be written with double quotes, single quotes, or backticks:
let s1 = "double quoted"
let s2 = `backtick โ {1 + 1} interpolation`
let s3 = 'single quoted โ @{1 + 1} interpolation'
Backtick strings use {expr} for interpolation. Single-quoted strings use @{expr}:
let user = "Alice"
`Welcome, {user}!` // Welcome, Alice!
Having three types of interpolation will make sense, when you start making real-world scripts, especially for the web.
Strings have many useful methods:
"hello".toUpper() // HELLO
" hi ".trim() // hi
"hello world".split(" ") // ["hello", "world"]
"banana".includes("nan") // true
See: Strings
Arrays
Arrays are ordered collections. Create them with square brackets:
let fruits = ["apple", "banana", "cherry"]
fruits[0] // apple
fruits[-1] // cherry (last element)
fruits.length() // 3
Use .map() to transform and .filter() to select:
let nums = [1, 2, 3, 4, 5]
nums.map(fn(n) { n * 2 }) // [2, 4, 6, 8, 10]
nums.filter(fn(n) { n > 3 }) // [4, 5]
Concatenate arrays with ++:
[1, 2] ++ [3, 4] // [1, 2, 3, 4]
See: Arrays
Dictionaries
Dictionaries are key-value pairs โ Parsley's equivalent of objects or maps:
let person = {name: "Alice", age: 30, city: "London"}
person.name // Alice
person.age // 30
Merge dictionaries with ++:
let defaults = {theme: "light", lang: "en"}
let prefs = {theme: "dark"}
defaults ++ prefs // {theme: "dark", lang: "en"}
Destructure to extract values:
let {name, age} = {name: "Bob", age: 25, role: "admin"}
name // Bob
age // 25
See: Dictionaries
Functions
Functions are created with fn. The last expression is the return value:
let double = fn(x) { x * 2 }
double(5) // 10
let add = fn(a, b) { a + b }
add(3, 4) // 7
Use dictionary destructuring with ?? for optional parameters:
let greet = fn({name, greeting}) {
let g = greeting ?? "Hello"
`{g}, {name}!`
}
greet({name: "Alice"}) // Hello, Alice!
greet({name: "Bob", greeting: "Hey"}) // Hey, Bob!
Functions are values โ you can pass them to other functions:
let apply = fn(f, x) { f(x) }
apply(double, 21) // 42
See: Functions
Control Flow
if is an Expression
if returns a value, so you can use it inline:
let age = 20
let status = if (age >= 18) "adult" else "minor"
status // adult
Or with blocks:
if (age >= 18) {
"Welcome!"
} else {
"Too young"
}
for Returns an Array
for loops are expressions that return arrays โ like map in other languages:
let nums = [1, 2, 3, 4, 5]
let squares = for (n in nums) { n * n }
squares // [1, 4, 9, 16, 25]
Filter by returning values only from an if:
let evens = for (n in nums) {
if (n % 2 == 0) { n }
}
evens // [2, 4]
Iterate over dictionaries:
let scores = {alice: 95, bob: 87}
for (name, score in scores) {
`{name}: {score}`
}
// ["alice: 95", "bob: 87"]
See: Control Flow
CSV to Table in One Line
Parsley makes data processing simple. Parse a CSV string, and you get a table with typed columns. Chain .toBox() to see it formatted:
let csv = "name,age,role\nAlice,30,Engineer\nBob,25,Designer\nCarol,35,Manager"
csv.parseCSV().toBox()
Result:
โโโโโโโโโฌโโโโโโฌโโโโโโโโโโโ
โ name โ age โ role โ
โโโโโโโโโผโโโโโโผโโโโโโโโโโโค
โ Alice โ 30 โ Engineer โ
โ Bob โ 25 โ Designer โ
โ Carol โ 35 โ Manager โ
โโโโโโโโโดโโโโโโดโโโโโโโโโโโ
Tables support SQL-like operations, so you can filter, sort, and aggregate before displaying:
csv.parseCSV()
.where(fn(row) { row.age >= 30 })
.orderBy("name")
.toBox()
โโโโโโโโโฌโโโโโโฌโโโโโโโโโโโ
โ name โ age โ role โ
โโโโโโโโโผโโโโโโผโโโโโโโโโโโค
โ Alice โ 30 โ Engineer โ
โ Carol โ 35 โ Manager โ
โโโโโโโโโดโโโโโโดโโโโโโโโโโโ
See: Data Formats ยท Tables
Building HTML with Tags
Parsley has first-class HTML tag syntax. Tags are values, not strings:
<h1>"Hello!"</h1> // <h1>Hello!</h1>
Important: Text content inside tags must be quoted. Tag attributes don't need quotes for simple values.
Embed expressions directly inside tags:
let user = "Alice"
<p>"Welcome, " user "!"</p>
Result: <p>Welcome, Alice!</p>
Use for to generate lists:
let items = ["Apples", "Bananas", "Cherries"]
<ul>
for (item in items) {
<li>item</li>
}
</ul>
Result: <ul><li>Apples</li><li>Bananas</li><li>Cherries</li></ul>
Singleton tags MUST be self-closing: Write
<br/>,<hr/>,<img src="photo.jpg"/>โ never<br>or<img>.
See: Tags
Components
Components are functions that return tags. Use them like custom HTML elements:
let Card = fn({title, body}) {
<div class=card>
<h2>title</h2>
<p>body</p>
</div>
}
<Card title="Hello" body="Welcome to Parsley!"/>
Result: <div class=card><h2>Hello</h2><p>Welcome to Parsley!</p></div>
Components compose naturally:
let Page = fn({title, contents}) {
<html>
<head><title>title</title></head>
<body>contents</body>
</html>
}
<Page title="Home">
<h1>"Welcome!"</h1>
<p>"This is my page."</p>
</Page>
A Simple Web Page Handler
In Basil, each route is a .pars file that exports a handler. Here's a complete example:
// components/Layout.pars
export Layout = fn({title, contents}) {
<html>
<head>
<title>title</title>
<link rel="stylesheet" href="/style.css"/>
</head>
<body>
<nav><a href="/">"Home"</a></nav>
<main>contents</main>
</body>
</html>
}
// routes/index.pars
let {Layout} = import @./components/Layout.pars
let items = ["Learn Parsley", "Build with Basil", "Ship it!"]
<Layout title="My App">
<h1>"My To-Do List"</h1>
<ul>
for (item in items) {
<li>item</li>
}
</ul>
</Layout>
The handler returns HTML automatically โ Basil detects the leading < tag and sets the content type.
Error Handling
try wraps a function call and returns {result, error} โ there are no catch blocks:
let risky = fn() { fail("oops") }
let {result, error} = try risky()
if (error) {
"Failed: " + error
} else {
"Got: " + result
}
Use check as a guard โ it's like an assertion that returns early:
let process = fn(input) {
check input != null else "No input"
check input.length() > 0 else "Empty input"
`Processing: {input}`
}
Note:
log()is Parsley's debug output function โ use it when you need to inspect values mid-execution (inside loops, conditionals, or complex expressions). For normal output, just let the expression be the result.
See: Error Handling
Where to Go Next
You now know the fundamentals. Here are paths forward depending on what you're building:
| Goal | Read |
|---|---|
| Learn all the built-in types | Types, then the Built-in Types section |
| Build web pages | Tags โ Modules โ Strings |
| Work with databases | Database โ Query DSL โ Schemas |
| Build REST APIs | @basil/api โ HTTP & Networking โ Session Management |
| Process files and data | File I/O โ Data Formats โ Arrays |
| Explore the full manual | Manual Index |
Key Differences from Other Languages
If you're coming from JavaScript, Python, or similar languages, watch out for these:
| Concept | Parsley | Other languages |
|---|---|---|
| Variables | let (immutable), var (mutable) |
const/let in JS, let/var in Swift |
| Output | Last expression is the result | print(), console.log() |
| Debug output | log() (for debugging only) |
Same as output in most languages |
| Comments | // only |
# in Python |
| String interpolation | `Hello {name}` |
${} in JS, f"" in Python |
| For loops | Return arrays (like map) |
Statements (no return value) |
| If/else | Expression (returns a value) | Statement in most languages |
| Tags | First-class syntax: <p>"hi"</p> |
Strings: "<p>hi</p>" |
| Self-closing tags | Required: <br/> |
Optional in HTML5 |
| Paths | Literals: @./file.txt |
Strings: "./file.txt" |
See: Parsley Cheatsheet