/ Specification
Playground Docs Performance GitHub
Chapter 5

Statements

Statements are the basic units of execution in Lattice. Unlike expressions, statements do not produce values (or produce Unit). Lattice defines 12 statement forms.

Binding Statements

binding  ::= phase_kw identifier [ ":" type_expr ] "=" expression
phase_kw ::= "flux" | "fix" | "let"

A binding statement introduces a new variable into the current scope. The phase keyword determines the variable's mutability:

flux counter = 0       // mutable
fix PI = 3.14159        // immutable
let name = "Lattice"    // inferred

// With type annotation
flux items: Array = []
fix max: Int = 100

Assignment Statements

assignment  ::= lvalue "=" expression
lvalue      ::= identifier
            |   expression "." identifier
            |   expression "[" expression "]"

Assignment statements update the value of an existing binding, struct field, or array/map element. Assignment to a fix variable is a runtime error. Assignment produces Unit.

Compound Assignment

compound_assign  ::= lvalue compound_op expression
compound_op      ::= "+=" | "-=" | "*=" | "/=" | "%="
                 |   "&=" | "|=" | "^=" | "<<=" | ">>="

Compound assignment operators are syntactic sugar. The expression x += 1 is desugared to x = x + 1 at parse time. All 10 compound operators follow this pattern.

flux x = 10
x += 5       // x = x + 5 → 15
x *= 2       // x = x * 2 → 30
x &= 0xFF    // x = x & 0xFF

Destructuring Statements

destructure  ::= phase_kw destruct_pattern "=" expression

destruct_pattern  ::= "[" array_pattern "]"
                  |   "{" struct_pattern "}"

array_pattern   ::= identifier { "," identifier } [ "," "..." identifier ]
struct_pattern  ::= identifier { "," identifier }

Destructuring binds multiple variables from a compound value in a single statement. Array destructuring supports a rest element with ....

// Array destructuring
let [first, second, ...rest] = [1, 2, 3, 4, 5]
// first = 1, second = 2, rest = [3, 4, 5]

// Struct destructuring
let { x, y } = Point { x: 10, y: 20 }
// x = 10, y = 20

Return Statements

return_stmt  ::= "return" [ expression ]

A return statement exits the enclosing function with the given value, or Unit if no expression is provided. Using return outside of a function is a parse error.

Break and Continue

break_stmt     ::= "break"
continue_stmt  ::= "continue"

break exits the innermost enclosing loop. continue skips to the next iteration of the innermost enclosing loop. Both are errors if used outside a loop.

Defer Statements

defer_stmt  ::= "defer" block

A defer statement schedules a block to be executed when the enclosing scope exits, regardless of whether the exit is normal or due to an error. Multiple defers execute in LIFO (last-in, first-out) order.

fn process() {
    let fd = open("file.txt")
    defer { close(fd) }       // runs last
    defer { print("cleanup") } // runs first
    // ... work with fd ...
}

See Error Handling: Defer for details.

Expression Statements

Any expression can appear as a statement. The expression is evaluated and its value is discarded. This is commonly used for function calls that produce side effects.

Import Statements

import_stmt  ::= "import" string_literal [ "as" identifier ]
             |   "import" "{" import_list "}" "from" string_literal
import_list  ::= identifier { "," identifier }

Import statements load and execute another Lattice source file, making its exports available in the current scope. See Modules for details.

import "./utils.lat" as utils
import { sin, cos, PI } from "./math.lat"