machdocs
Home GitHub

Statements

Statements are the runtime steps that fill function bodies and blocks. Every statement ends with ;, except the ones that end with a block {...}.

Conditionals: if / or

An if head opens a branch chain. Each or (cond) { ... } adds another conditional branch, and a trailing or { ... } with no condition is the catch-all. Every body is a block; there is no brace-less single-statement form.

if (cond) {
    ...
}
or (cond) {
    ...
}
or {
    ...                     # final else (no condition)
}

Loops: for

mach has a single condition-driven loop. The body repeats while the condition holds. There is no for-each form.

var i: i64 = 0;
for (i < 10) {
    i = i + 1;
}

Returning: ret

ret expr; returns a value; bare ret; returns from a void function.

ret expr;                   # return a value
ret;                        # return from a void function

Loop control: brk / cnt

brk exits the enclosing for; cnt skips to the next iteration.

for (i < 10) {
    if (i == 3) { cnt; }
    if (i == 8) { brk; }
    i = i + 1;
}
Note

Both are operand-less, so they are keywords only in their bare brk; / cnt; form. The same word followed by anything else is an ordinary identifier: a variable named cnt reads and assigns normally (cnt = x;), even inside a loop that also uses bare cnt; for control flow.

Deferred cleanup: fin

fin schedules a statement or block to run when the enclosing scope exits, in reverse order of declaration. It is for cleanup that should happen regardless of how the scope is left.

{
    fin counter = counter - 1;
    fin { counter = counter * 2; }

    # ... code ...
}
# at scope exit: fin block runs first, then fin counter = counter - 1

fin takes either a single statement (fin stmt;) or a block (fin { ... }). There is no bare-expression form.

Blocks

{ ... } introduces a new lexical scope. Statements inside run in order, and a block can stand alone to bound the lifetime of locals.

{
    val tmp: i64 = compute();
    use_tmp(tmp);
}

See also