Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

@for

@for runs its body once for each element of a source, binding the element to a name.

Syntax

@for name in source {
    ...
}

Looping over a range

macro squares(n: int) {
    @for i in 0..n {
        @emit i * i
    }
}

squares 5
0 1 4 9 16

See Ranges for .. and ..=.

Looping over a struct

A struct value works as a source too. @for visits its pub fields in declaration order, skipping fields marked skip. That’s how you loop over an array or a string:

from std.array import Array

macro sum<const N: int>(values: Array<int, N>) -> int {
    const total = @fold acc = 0 @for v in values {
        @next acc + v
    }
    @return total
}

macro each_char() {
    @for c in "hi" {
        @emit c
    }
}

macro show(value: int) {
    @emit value
}

show sum(Array<int, 3> { __el0: 1, __el1: 2, __el2: 3 })
each_char
6 104 105

See Struct fields: pub and skip.

Details

  • Each iteration is fresh. Nothing carries over from one iteration to the next: a const in the body only exists for that iteration. To carry a value along, such as a running total, use @fold.
  • @return ends the whole macro, not just the loop.
  • At most 1,000,000 iterations.
  • At the top level, the source must be a range written in place, such as 0..32. The loop is unrolled before anything else in the file is evaluated, so it can generate declarations:
@for i in 0..4 {
    pub const r`i` = i * 10
}

macro show(value: int) {
    @emit value
}

show r3
30

That’s how architecture packages declare their registers. The backticks in r`i` build each name; see Spliced names.

In struct declarations and constructions

@for can also generate a struct’s fields, or the values of a construction. See Structs.