Skip to content

Statements

Block = "{" { Statement } "}" .
Statement = Binding | Assignment | If | While | For | Match
| Defer | Return | Break | Continue | Try | Raise | ExprStmt .
Binding = ( "let" | "var" ) BindTarget [ ":" Type ] "=" Expr
| "let" BindTarget "=" Expr "else" Block // let-else
| "async" "let" identifier [ ":" Type ] "=" Expr
| ConstDecl .
BindTarget = identifier | "(" identifier { "," identifier } ")" . // tuple destructure
Assignment = Lvalue ( "=" | "+=" | "-=" | "*=" | "/=" ) Expr .
Lvalue = identifier { "." identifier | "[" Expr "]" } .
If = "if" Expr Block { "else" "if" Expr Block } [ "else" Block ] .
While = "while" Expr Block .
For = "for" BindTarget "in" Expr Block .
Defer = "defer" Block .
Return = "return" [ Expr ] .
Try = "try" Block CatchClause { CatchClause } .
CatchClause = "catch" [ "(" Type [ identifier ] ")" ] Block .
Raise = "raise" identifier "(" [ ArgList ] ")" .
ExprStmt = Expr .

Conditions take no parentheses; braces are mandatory on every block.

let binds an immutable name; var a mutable one; const a compile-time literal (folding rules and ES1011 in Declarations). Immutability of let is enforced by the compiler, not the CLR. A binding may destructure a tuple: let (a, b) = pair. async let starts its initializer concurrently and is awaited at first reference; its initializer shall be a call or awaitable (ES3005), and a sync user-function initializer is auto-wrapped in Task.Run with ES3004. Assignment targets are locals, parameters, member chains, and index expressions.

let user = db.find(id) else { return error(.notFound) }

If the initializer is nil, the else block runs and shall leave the scope (return, break, …); after the statement the bound name is non-nil.

for … in iterates collections, ranges (0..n), and channels. A for target may destructure a tuple (for (k, v) in entries). defer runs its block on scope exit, LIFO; it lowers to try/finally and is the cleanup mechanism (there is no finally keyword).

Match = "match" ( Expr | "(" Expr ":" Type ")" ) "{" { Arm } "}" .
Arm = Pattern Block | Pattern Expr . // statement body or expression body
Pattern = DotCase [ "(" [ Binding { "," Binding } ] ")" ] // choice / enum case
| literal // int / string / bool literal pattern
| "default" .

match dispatches over a choice, ref choice, enum, or literal value. The type annotation (expr: T) is required only when the scrutinee’s static type is ambiguous (e.g. a value flowing through object, or an enum reached via dot-case); otherwise the bare form suffices.

  • Destructuring. A case arm binds payloads positionally (.message(lvl, txt)); a value-choice arm may instead bind a single case-view name whose members are the payloads (.pair(p)p.a, p.b). For a single-payload case the view is transparent — the binding doubles as the payload value. A ref choice arm matches with an isinst type pattern.
  • Literal patterns (int, string, bool) match by value; exhaustiveness does not apply to them, so default handles the open set.
  • Exhaustiveness. A match over a choice / ref choice / enum that omits a variant is warned; default suppresses it.
  • As an expression. match in expression position requires every arm to yield one common type (see Expressions).

A non-void function shall return on every path; a fall-through is ES2140. The analysis is exhaustive-match-aware: an if/else whose arms all return, or an exhaustive match whose arms all terminate, counts as returning — no redundant trailing return is required. return, throw, and an infinite loop with no break are terminators.

try/catch is the BCL boundary mechanism; in-language flow uses Result. Three catch shapes are accepted:

catch (FormatException e) { ... } // typed + bound
catch (Exception e) { ... } // base type + bound
catch { ... } // bare — any exception, no binding

There is no finally (use defer inside the try). throw with no operand rethrows, and is valid only inside a catch.

raise Name(args) fires the field-style event Name declared on the enclosing ref data; it is null-safe (a capture-then-invoke lowering) and a no-op with no subscribers. raise on an undeclared event is ES2142. See Delegates & events.