The Turmeric reader converts source text into a form tree before the compiler sees it. This guide documents every construct the reader understands, organised by category.
Comments are consumed by the reader and produce no form.
;Ignores everything from ; to the end of the line.
(println "hello") ; this is ignored
#| ... |#Ignores a delimited region of text. Block comments nest.
#|
This whole region is ignored.
(println "never runs")
#| nested block comments work too |#
|#
(println "ok")
#; (planned)Reads one complete datum and discards it. The surrounding code sees nothing.
Unlike #| |#, #; understands structure -- it always discards exactly one
form, no matter how many lines it spans.
(println #;99 "ok") ; => ok
(println #;"ignored" "ok") ; => ok
(println #;(this is discarded) "ok") ; => ok
(println (+ 1 #;999 2)) ; => 3
Datum comments compose: #;#;1 2 3 discards 2 (the result that inner #;1
would have produced) and leaves 3.
(println #;#;1 2 3) ; => 3
#; at end of file, or immediately before a closing delimiter, is an error.
Decimal, hexadecimal (0x/0X), and binary (0b/0B) are supported.
An optional type suffix pins the width.
42
-7
0xff
0b1010
255u8
1000i32
| Suffix | Type |
|---|---|
i8 |
signed 8-bit |
i16 |
signed 16-bit |
i32 |
signed 32-bit |
i64 |
signed 64-bit |
u8 |
unsigned 8-bit |
u16 |
unsigned 16-bit |
u32 |
unsigned 32-bit |
u64 |
unsigned 64-bit |
A . or exponent (e/E) makes a literal a float. The suffix f32 or f64
pins the width; unsuffixed floats are f64.
3.14
1.0e10
2.5f32
1f64
"..."Double-quoted UTF-8 text. Standard C escape sequences apply (\n, \t, \\,
\", etc.).
"hello, world"
"line one\nline two"
:A colon followed immediately by a name produces a keyword (an interned compile-time constant).
:ok
:error
:tur
Any name that starts with a letter or one of + - * / = < > ! ? _ $ & . ^ |
or a UTF-8 code-point in the symbol-start set (includes λ, ∀, ∃).
foo
my-var
+
->
|>
λ
(...)An ordered sequence of forms. The primary syntactic unit in Turmeric.
(println "hello")
(+ 1 2 3)
(defn square [x :int] :int (* x x))
[...]A vector literal.
[1 2 3]
[:a :b :c]
#{...}A map (hash-array-mapped trie) literal. Key-value pairs are written interleaved.
#{:name "Alice" :age 30}
#s(...)A set literal.
#s(1 2 3)
#s(:red :green :blue)
{ var : T | pred }A refinement type annotation. Introduces a binding var of type T with
predicate pred.
{ x : :int | (> x 0) }
Each of these reads one following datum and rewrites it into a longer form.
'exprExpands to (quote expr). Prevents evaluation.
'foo ; => (quote foo)
'(1 2 3) ; => (quote (1 2 3))
`exprExpands to (quasiquote expr). Like quote, but ~ and ~@ splice in values.
`(1 2 3) ; => (quasiquote (1 2 3))
`(1 ~x 3) ; unquotes x
`(1 ~@xs 3) ; splices list xs
~exprValid only inside a quasiquote. Expands to (unquote expr).
`(a ~b c) ; b is evaluated and inserted
~@exprValid only inside a quasiquote. Expands to (unquote-splicing expr). The
value must be a list; its elements are spliced into the surrounding list.
(let [xs '(2 3)]
`(1 ~@xs 4)) ; => (1 2 3 4)
@exprExpands to (deref expr).
@my-ref ; => (deref my-ref)
@{...}A @ immediately followed by { reads a brace-delimited effect-row map
rather than a deref.
@{IO}
@{IO Exn}
&exprExpands to (& expr). A bare & followed by whitespace or a close delimiter
is left as the symbol & (preserving the explicit (& x) call form).
&x ; => (& x)
(& x) ; identical -- explicit form still works
&mut exprExpands to (&mut expr).
&mut x ; => (&mut x)
Forms beginning with # followed by a specific character.
#[...]Attaches a compile-time attribute to the next definition.
#[no-unwind]
(defn risky [] :int ...)
#?(...)Selects a branch based on the current reader target. Use :tur for compiled
output and :turi for the interpreter.
(println #?(:tur "compiled" :turi "interpreted"))
```c ... ```A triple-backtick block embeds raw C code inside a defn body. The closing
``` must be on the same line as its enclosing ).
(defn file-size [f] :int
```c
FILE* file = (FILE*)f;
return (int)ftell(file);
```)
The following forms are active when sweet-expression mode is enabled
(#lang sweet-exp or the --sweet flag).
f(...)A symbol (or atom) followed immediately by ( (no space) is read as a
function call.
square(9) ; => (square 9)
{a op b}Braces in sweet-exp mode treat the middle element as an infix operator.
{1 + 2} ; => (+ 1 2)
{x > 0} ; => (> x 0)