← Back to AILP Home

till

till(limit, step) counts up from 0, exposing the running value as $. Where loop is "walk an index between two bounds", till is "count up to a limit", and it desugars to loop(0, limit, step).

func:failsafe = int32(tbb32:err) {
    exit 1;
};

func:main = int32() {
    int32:total = 0i32;
    till(5i32, 1i32) {
        total += $;   // $ takes 0, 1, 2, 3, 4
    }
    exit total;       // 10
};

The $ value

Inside a till body, $ is the current running value, starting at 0 and advancing by step until it reaches limit. The semantics match loop(0i32, limit, step) exactly:

till(6i32, 2i32) {
    // $ = 0, 2, 4
}

Desugaring

till(L, S) is defined as loop(0, L, S). Everything that is true of loop holds for till: the exclusive upper bound, the zero-step failsafe, and break / continue semantics. The K semantics encodes this directly — till (L, S) B => loop (0, L, S) B — so both forms share one rule set.

When to use which

Next: for-in.