← Back to AILP Home

Nested when

when loops nest to arbitrary depth, and a when may appear in another when's body, then block, or end block. Each then / end binds to the nearest unmatched when, and break / continue target the innermost enclosing loop — the same rules as every other loop form.

Nesting in the body

when (a < 1i32) {
    a = a + 1i32;
    when (b < 1i32) {
        b = b + 1i32;
    } then {
        r = r + 1i32;     // inner then
    } end {
        r = r + 2i32;
    }
} then {
    r = r + 100i32;       // outer then
} end {
    r = r + 200i32;
}
// both loops complete cleanly: 1 + 100 = 101

Nesting in then and end

A completion block is an ordinary block, so it can host its own when:

when (cond) {
    // ...
} then {
    when (inner) { ... } then { ... } end { ... }   // runs only on clean exit
} end {
    when (inner) { ... } then { ... } end { ... }   // runs only on a short-circuit
}

Because then and end are mutually exclusive, only one of these inner loops can ever execute on a given run.

Three-level nesting

Binding is purely lexical — innermost then/end pair to innermost when:

when (a < 1i32) {
    a = a + 1i32;
    when (b < 1i32) {
        b = b + 1i32;
        when (c < 1i32) {
            c = c + 1i32;
        } then { r = r + 1i32; }   end { r = r + 2i32; }
    } then { r = r + 10i32; }      end { r = r + 20i32; }
} then { r = r + 100i32; }         end { r = r + 200i32; }
// all clean: 1 + 10 + 100 = 111

Escaping an outer when

A bare break; only ends the innermost when. To route an outer when to its end from inside an inner loop, label the outer when and use a labeled break:

outer: when (a < 5i32) {
    a = a + 1i32;
    when (b < 5i32) {
        b = b + 1i32;
        break(outer);     // ends the OUTER when -> outer end runs
    } then {
        r = r + 1i32;     // inner then: skipped
    } end {
        r = r + 10i32;    // inner end: skipped (we broke past it)
    }
} then {
    r = 2i32;             // outer then: skipped
} end {
    r = 3i32;             // outer end: runs
}
// r = 3

A labeled break(outer) jumps straight past the inner completion blocks and routes the labeled loop to its end. Labeled continue(label) likewise re-tests the labeled loop's condition without marking it complete. The label syntax and rules are shared with the other loops — see Labeled control.