Special forms & declarations #
Core syntactic forms built into the Tangu compiler and evaluator.
def #
(def name value)
Declares a top-level or hoisted binding (function, struct, trait, or constant). Stack attributes like #pub, #inline, and #test on lines above (def ...).
(def add (Func [a b] (+ a b)))
let #
(let pattern value)
Binds a local immutable variable (or rebindable #var / mutable #mut binding) sequentially within the current lexical scope. Supports array [a b] and map {:x} destructuring.
(let [first ...rest] [10 20 30])
Func #
(Func params body...)
Constructs a first-class lexical closure. Parameter forms: () for zero args, x for single arg, or [a b ...rest] for multiple/typed/destructured args.
(let double (Func x (* x 2)))
Struct #
(Struct #Type #{constraints}? field (#Type field default) ...)
Defines a nominal product type with typed fields, optional default values, and declarative validation constraints.
(def Point (Struct #Int x #Int y))
Trait #
(Trait #(Func [This ...] Ret) (method (Func [this ...])) ...)
Defines a polymorphic trait interface that can be implemented for structs or built-in types via impl.
(def Printable (Trait #(Func This String) (format (Func this))))
impl #
(impl Trait-Name Target-Type (let method (Func [self ...] ...)))
Implements a Trait for a target Struct or type.
(impl Printable Point (let format (Func self "${self:x},${self:y}")))
derive #
(derive Struct-Type Trait1 Trait2 ...)
Automatically synthesizes standard trait implementations (Eq, Hash, Ord, Clone, To-String, Default, To-JSON, From-JSON) for a Struct.
(derive Point Eq Hash Ord Clone To-String Default)
use #
(use {sym1 sym2} /module/path)
Imports a module or selective symbol bindings from @standard (/path), a package (@scope/pkg), or a relative path (./mod). Supports #lazy deferred loading.
(use {join split} /string)
<- #
(<- target new-value)
Reassigns a #var binding or updates a #mut struct field / collection element in place (+<- increments in place).
(let #var x 1)
(<- x 2)
#lazy / #static #
(let #lazy x expr), (let #static cache expr)
#lazy defers evaluation of a binding or (use #lazy ...) module until first access; #static evaluates a function-local binding once and caches it across calls.
(let #static lookup-table {:a 1 :b 2})
%file / %dir / %module / %profile #
%file, %dir, %module, %profile
Compile-time context intrinsics expanding to the current source file path (%file), parent directory (%dir), module path (%module), and active build profile (%profile).
(let config-path "${%dir}/config.data.tan")
Control flow & pattern matching #
Branching, structural pattern matching, iteration, and early-return error handling.
if #
(if cond then-body... (else else-body...))
Evaluates cond (which must be a strict Bool); runs then-body when true or the optional (else ...) block when false.
(if (> x 0) "positive" (else "non-positive"))
unless #
(unless cond body...)
Executes body when cond evaluates to false.
(unless (is-empty? items) (process items))
cond #
(cond test1 expr1 test2 expr2 _ default-expr)
Multi-branch conditional evaluating flat test expr pairs in order; _ provides the fallback arm.
(cond (== code 200) :ok (== code 404) :not-found _ :error)
when #
(when target pattern1 expr1 ... _ default-expr)
Structural pattern matching over literals, runtime types (Int, String, Error), arrays ([x ...xs]), and maps ({:status 200}).
(when resp {:status 200 :body b} b Error "failed" _ "other")
for #
(for [binding seq] body...)
Iterates over any sequence, range, map, or iterator for side effects. Supports [item seq] and [[key val] map].
(for [x 0..5] (say x))
for->seq #
(for->seq [binding seq] body...)
List/Array comprehension collecting the result of each iteration into a new Array. Call (continue) to skip an element.
(for->seq [x [1 2 3]] (* x 10)) ; => [10 20 30]
while #
(while cond body...)
Repeatedly evaluates body while cond remains true. Supports (break) and (continue).
(while (< i 10) (+<- i 1))
try #
(try expr (else fallback-return-expr))
Unwraps a computation if it is Some (neither () nor Error); on Error or (), strictly early-returns the failure or the (else ...) value from the enclosing function.
(let data (try (decode raw-json)))
some-or #
(some-or cand1 ... default-expr)
Short-circuiting local fallback for () (None): returns the first non-() candidate, or default-expr (passes Error values through unchanged).
(let port (some-or config?port 8005))
ok-or #
(ok-or cand1 ... fallback-expr)
Short-circuiting local fallback for both Error and () (None): returns the first valid candidate, or fallback-expr without early-returning from the function.
(let parsed (ok-or (Int input) 0))
|> #
(|> initial-value (step1 %0) (step2 %0 arg) ...)
Pipeline operator threading the result of each expression into %0 (or %) of the next step.
(|> " hello " (trim %0) (to-upper-case %0)) ; => "HELLO"
Universal sequence & collection intrinsics #
Polymorphic functions available without imports across Array, List, String, Map, Set, Range, and Slab.
count-of #
(count-of coll) -> Int
Returns the number of elements in a collection, Unicode scalar values in a String, or delegates to the Countable trait.
(count-of [10 20 30]) ; => 3
byte-count-of #
(byte-count-of str-or-slab) -> Int
Returns the exact UTF-8 byte length of a String or byte length of a Slab in O(1) time.
(byte-count-of "café") ; => 5
is-empty? #
(is-empty? coll) -> Bool
Returns true if coll has zero elements (count-of == 0).
(is-empty? []) ; => true
contains? #
(contains? coll item) -> Bool
Checks element membership in an Array/List/Set/Range, substring presence in a String, key presence in a Map, or invokes the Contains trait.
(contains? [1 2 3] 2) ; => true
contains-key? #
(contains-key? map key) -> Bool
Returns true if map contains key.
(contains-key? {:a 1} :a) ; => true
first-of #
(first-of seq) -> (Or Any None)
Returns the first element of seq, or () if empty.
(first-of [10 20 30]) ; => 10
last-of #
(last-of seq) -> (Or Any None)
Returns the last element of seq, or () if empty.
(last-of [10 20 30]) ; => 30
nth-of #
(nth-of seq index) -> (Or Any None)
Returns the element at zero-based index (supporting negative indices from the end).
(nth-of [10 20 30] 1) ; => 20
rest-of #
(rest-of seq) -> Array
Returns a slice containing all elements after the first.
(rest-of [1 2 3]) ; => [2 3]
slice #
(slice seq start end?) -> Seq
Extracts a sub-slice from start up to end (supporting negative offsets like -1).
(slice [10 20 30 40] 1 -1) ; => [20 30]
byte-slice #
(byte-slice str-or-slab start end) -> String | Slab
Extracts a zero-copy or O(k) byte range [start..end) from a String or Slab.
(byte-slice "hello world" 0 5) ; => "hello"
reverse #
(reverse seq) -> Seq
Returns a new Array, List, or String with elements in reverse order.
(reverse [1 2 3]) ; => [3 2 1]
concat #
(concat seq1 seq2 ...) -> Seq
Concatenates multiple arrays, lists, or strings into a single sequence.
(concat [1 2] [3 4]) ; => [1 2 3 4]
push #
(push #mut array item...) -> Array
Appends one or more elements to the end of a mutable Array.
(let #mut a [1])
(push a 2 3)
pop #
(pop #mut array) -> (Or Any None)
Removes and returns the last element of a mutable Array.
(pop a)
put #
(put #mut coll key-or-item value?) -> Coll
Inserts or updates a key-value pair in a mutable Map, or inserts an element into a Set.
(put m :status :ready)
put-all / put-many #
(put-all #mut coll source-coll), (put-many #mut map [k1 v1] [k2 v2] ...)
Merges all entries from source-coll (put-all) or multiple [key value] pairs (put-many) into a mutable Map or Set.
(put-all m {:host "127.0.0.1" :port 8005})
remove / swap-remove #
(remove #mut coll key-or-index) -> Any, (swap-remove #mut array index) -> Any
remove deletes and returns an entry by key (Map/Set) or index (Array); swap-remove removes an Array element in O(1) time by swapping it with the last element.
(remove m :status)
keys-of #
(keys-of map) -> Array
Returns an Array of all keys in map.
(keys-of {:a 1 :b 2})
values-of #
(values-of map) -> Array
Returns an Array of all values in map.
(values-of {:a 1 :b 2})
entries-of #
(entries-of map) -> Array
Returns an Array of [key value] pairs from map.
(entries-of {:a 1}) ; => [[:a 1]]
sort / sort<- #
(sort array) -> Array, (sort<- #mut array) -> Array
sort returns a sorted copy of array using natural Ord comparison; sort<- sorts a #mut array in place.
(sort [3 1 2]) ; => [1 2 3]
sort-by #
(sort-by array key-or-cmp-fn) -> Array
Sorts array by a key-extractor function (Func x key) or comparator (Func [a b] Int).
(sort-by users (Func u u:age))
reverse<- / concat<- / roll #
(reverse<- #mut array), (concat<- #mut array other), (roll seq offset)
In-place array reversal (reverse<-), in-place array extension (concat<-), and circular element rotation (roll).
(roll [1 2 3 4] 1) ; => [4 1 2 3]
map #
(map seq fn) -> Array
Applies fn to each element of seq and returns a new Array.
(map [1 2 3] (* %0 2)) ; => [2 4 6]
filter #
(filter seq pred-fn) -> Array
Returns a new Array containing elements of seq for which pred-fn returns true.
(filter [1 2 3 4] (> %0 2)) ; => [3 4]
collect #
(collect seq-or-iter) -> Array
Materializes any lazy iterator, range, set, or sequence into a contiguous Array.
(collect 0..5) ; => [0 1 2 3 4]
String intrinsics #
Built-in UTF-8 string search, splitting, replacement, and case conversion.
trim #
(trim str) -> String
Strips leading and trailing whitespace (trim-start and trim-end strip one side).
(trim " hi ") ; => "hi"
split #
(split str delimiter) -> (Array String)
Splits str around delimiter into an Array of substrings.
(split "a,b,c" ",") ; => ["a" "b" "c"]
join #
(join array separator?) -> String
Joins elements of array into a single String separated by separator.
(join ["a" "b"] "-") ; => "a-b"
replace #
(replace str pattern replacement) -> String
Replaces all occurrences of pattern in str with replacement (replace-first replaces only the first).
(replace "foo-bar" "-" "_") ; => "foo_bar"
starts-with? #
(starts-with? str prefix) -> Bool
Returns true if str starts with prefix.
(starts-with? "/stdlib-web" "/stdlib") ; => true
ends-with? #
(ends-with? str suffix) -> Bool
Returns true if str ends with suffix.
(ends-with? "main.tan" ".tan") ; => true
to-lower-case #
(to-lower-case str) -> String
Converts str to lowercase Unicode characters.
(to-lower-case "Tangu") ; => "tangu"
to-upper-case #
(to-upper-case str) -> String
Converts str to uppercase Unicode characters.
(to-upper-case "tangu") ; => "TANGU"
Types, introspection & sized integers #
Runtime type predicates, deep cloning, hashing, and explicit sized integer constructors.
type-of #
(type-of value) -> Symbol
Returns the runtime type name of value (Int, Float, Dec, String, Array, Map, or a Struct name).
(type-of [1 2]) ; => Array
is-a? #
(is-a? Type value) -> Bool
Returns true if value is an instance of Type (or implements trait Type).
(is-a? Int 42) ; => true
is-some? #
(is-some? value) -> Bool
Returns true if value is neither () (None) nor an Error.
(is-some? 0) ; => true
is-none? #
(is-none? value) -> Bool
Returns true if value is () (None).
(is-none? ()) ; => true
is-error? #
(is-error? value) -> Bool
Returns true if value is an Error.
(is-error? (Error :fail "msg")) ; => true
clone #
(clone value) -> Any
Returns a deep structural copy of value, duplicating mutable collections and structs.
(let copy (clone original))
hash #
(hash value) -> Int
Computes the deterministic 64-bit hash of any value or Struct implementing Hash.
(hash {:a 1 :b 2})
I8 / I16 / I32 / I64 / I128 / ISize #
12i8, 123i16, 12_345i32, -10isize, (I32 val) -> I32
Signed sized integer literal suffixes and constructors wrapping modulo the bit width (8, 16, 32, 64, 128, or pointer width).
(let offset 12_345i32)
U8 / U16 / U32 / U64 / U128 / USize #
255u8, 8005u16, 1000usize, (U8 val) -> U8
Unsigned sized integer literal suffixes and constructors (U8 is also aliased as Byte).
(let port 8005u16)
cast #
(cast Target-Type value) -> Target-Type
Performs an explicit numeric or structural type conversion to Target-Type.
(cast Float 42) ; => 42.0
Core & derivable traits #
Built-in traits supported by (derive My-Struct ...) and custom (impl Trait My-Struct ...).
Eq #
(derive My-Struct Eq)
Structural equality comparison via (== a b) and (!= a b).
(derive Point Eq)
Ord #
(derive My-Struct Ord)
Total ordering comparison via <, <=, >, >=, and sort.
(derive Point Eq Ord)
Hash #
(derive My-Struct Hash)
Deterministic hashing via (hash x), enabling use as Map keys and Set elements.
(derive Point Eq Hash)
Clone #
(derive My-Struct Clone)
Deep structural duplication via (clone x).
(derive Point Clone)
To-String #
(derive My-Struct To-String)
Human-readable string conversion via (String x) and string interpolation.
(derive Point To-String)
Default #
(derive My-Struct Default)
Zero-argument default construction via (construct-default My-Struct).
(derive Point Default)
Countable #
(def Countable (Trait #(Func This Int) (count-of (Func this))))
Custom length/size reporting for (count-of x) and (is-empty? x).
(impl Countable Queue (let count-of (Func self (count-of self:items))))
Contains #
(def Contains (Trait #(Func [This Any] Bool) (contains? (Func [this item]))))
Custom membership testing for (contains? x item).
(impl Contains Span (let contains? (Func [self v] (and (>= v self:lo) (<= v self:hi)))))
To-JSON / From-JSON #
(derive My-Struct To-JSON From-JSON)
Zero-boilerplate JSON serialization with (encode x) and typed deserialization with (from-json My-Struct data) or (decode raw My-Struct).
(derive Point To-JSON From-JSON)
Arithmetic, bitwise & math intrinsics #
Numeric operators and transcendental functions available in the prelude.
+ / - / * / / / % / ** #
(+ a b ...), (- a b), (* a b ...), (/ a b), (% a b), (** base exp)
Arithmetic addition, subtraction, multiplication, division, remainder (%), and exponentiation (**) across Int, Float, Dec, and sized integers.
(+ 10 20 30) ; => 60
== / != / < / <= / > / >= #
(== a b), (!= a b), (< a b), (<= a b), (> a b), (>= a b)
Equality and relational ordering comparisons returning Bool.
(<= 10 20) ; => true
and / or / not #
(and a b ...), (or a b ...), (not a)
Short-circuiting boolean conjunction (and), disjunction (or), and negation (not).
(and (> x 0) (< x 100))
abs / min / max / clamp #
(abs x), (min a b), (max a b), (clamp x lo hi)
Absolute value, minimum, maximum, and range clamping.
(clamp 150 0 100) ; => 100
floor / ceil / round / trunc #
(floor x), (ceil x), (round x), (trunc x)
Floating-point and decimal rounding functions.
(round 3.6) ; => 4.0
sqrt / sin / cos / tan / log / exp #
(sqrt x), (sin x), (cos x), (tan x), (log x), (exp x)
Square root, trigonometric functions, natural logarithm, and exponential.
(sqrt 16.0) ; => 4.0
bit-and / bit-or / bit-xor / bit-not / bit-shl / bit-shr #
(bit-and a b), (bit-or a b), (bit-xor a b), (bit-shl x n), (bit-shr x n)
Bitwise AND, OR, XOR, NOT, left shift (bit-shl), and arithmetic/logical right shift (bit-shr).
(bit-shl 1 8) ; => 256
I/O, data parsing & assertion intrinsics #
Console output, safe .data.tan loading, AST parsing, and test assertions.
say / echo #
(say value...), (echo value...)
say prints arguments to stdout followed by a newline; echo prints without a trailing newline.
(say "Listening on port ${port}")
read / write #
(read path) -> String, (write path content) -> None
Convenience prelude functions to read a UTF-8 file into a String or write a String to disk.
(let text (read "readme.text"))
read-data / load-data #
(read-data str) -> Any, (load-data path) -> Any
Safely parses a pure .data.tan literal from a string or file without evaluating executable calls.
(let manifest (load-data "manifest.data.tan"))
parse-expr / parse-exprs #
(parse-expr str) -> Expr, (parse-exprs str) -> (Array Expr)
Parses Tangu source code into homoiconic s-expression AST nodes.
(let ast (parse-expr "(+ 1 2)"))
assert / assert-eq! / assert-ne! #
(assert cond msg?), (assert-eq! left right), (assert-ne! left right)
Test and invariant assertions that panic with source location and diff details when violated.
(assert-eq! (+ 2 2) 4)
panic! #
(panic! message)
Immediately aborts the current evaluation or test with message.
(panic! "unreachable state")