Cirru Syntax Essentials
1. Indentation = Nesting
Cirru uses 2-space indentation to represent nested structures:
defn add (a b)
&+ a b
Equivalent JSON:
["defn", "add", ["a", "b"], ["&+", "a", "b"]]
2. The $ Operator (Single-Child Expand)
$ creates a single nested expression on the same line:
; Without $: explicit nesting
let
x 1
println x
; With $: inline nesting
let (x 1)
println x
; Multiple $ chain right-to-left
println $ str $ &+ 1 2
; Equivalent to: (println (str (&+ 1 2)))
Rule: a $ b c → ["a", ["b", "c"]]
3. The | Prefix (String Literals)
| marks a string literal:
println |hello
println |hello-world
println "|hello world with spaces"
|hello→"hello"(string, not symbol)- Without
|:hellois a symbol/identifier - For strings with spaces:
"|hello world"
4. The , Operator (Expression Terminator)
, forces the end of current expression, starting a new sibling:
; Without comma - ambiguous
if true 1 2
; With comma - clear structure
if true
, 1
, 2
Useful in cond, case, let bindings:
cond
&< x 0
, |negative ; comma separates condition from result
(&= x 0) |zero
true |positive
5. Quasiquote, Unquote, Unquote-Splicing
For macros:
quasiquoteor backtick: template~(unquote): insert evaluated value~@(unquote-splicing): splice list contents
defmacro when-not (cond & body)
quasiquote $ if (not ~cond)
do ~@body
JSON equivalent:
[
"defmacro",
"when-not",
["cond", "&", "body"],
["quasiquote", ["if", ["not", "~cond"], ["do", "~@body"]]]
]
6. Common Patterns
Function Definition
defn function-name (arg1 arg2)
body-expression
Let Binding
let
x 1
y $ &+ x 2
&* x y
Conditional
if condition
then-branch
else-branch
Multi-branch Cond
cond
(test1) result1
(test2) result2
true default-result
JSON Format Rules
When using -j or --json-input:
- Everything is arrays or strings:
["defn", "name", ["args"], ["body"]] - Numbers as strings:
["&+", "1", "2"]not["&+", 1, 2] - Preserve prefixes:
"|string","~var","~@list" - No objects: JSON
{}cannot be converted to Cirru
Common Mistakes
| ❌ Wrong | ✅ Correct | Reason |
|---|---|---|
println hello | println \|hello | Missing \| for string |
$ a b c at line start | a b c | A line is an expression, no need of $ for extra nesting |
a$b | a $ b | Missing space around $ |
["&+", 1, 2] | ["&+", "1", "2"] | Numbers in syntax tree must be strings in JSON |
| Tabs for indent | 2 spaces | Cirru requires spaces |