compile/for-each
Symbol: compile/for-each
Syntax: (for-each [BINDING EXPR] BODY... [else: ELSEBODY...])
Use-case: Iterate over the sequence produced by EXPR, binding each element
to BINDING and evaluating BODY on each iteration. Supports compile/break and
compile/continue inside the body. An optional trailing [else: ELSEBODY...]
keyword clause runs only when the iterator is exhausted naturally (i.e. not via
compile/break); its value becomes the loop’s expression value. Without an
else clause the loop’s value is the value of its last iteration: the body’s
last form, or the value given to compile/continue; None when the
sequence was empty. (break VAL) makes VAL the loop’s value. In block
syntax, the same clause comes from an else: peer; see
layout/while (shared layout_loop handler for
for-each and while).
Behaviour: Emits CONST None (default loop result), compiles EXPR (the
iterable), then PUSH_FOREACH whose break target is set to a label after
POP_FOREACH. The continue target (first instruction after PUSH_FOREACH) is
ITER_NEXT. On each iteration, ITER_NEXT pushes the next value or jumps to the
else label on exhaustion. The value is stored with VAR_STORE into the binding
name. The body is compiled with helper_begin; CONTINUE 0 resets the stack
block and jumps back to ITER_NEXT.
On exhaustion, CLEAR_FOREACH marks natural exit and disables the region.
When an else body is present, it is compiled next and POP_FOREACH delivers
its value from the region’s stack; a compile/break or compile/continue
written in the else body belongs to the enclosing loop, since this one has
finished. When there is no else body, POP_FOREACH pushes the region’s result
(None unless a compile/continue set one). User compile/break from the
body jumps to after_pop with its value already on the parent stack.
Examples:
;; Basic iteration; loop value is None
(for-each [i items]
(append result i))
;; Else fires when iterator exhausts without a break
(for-each [i items]
(cond
[(> i 4) (break)]
[else: (append result i)])
[else: "finished"])
;; Break with a value
(for-each [i items]
(cond
[(== i target) (break "found")]
[else: None]))
Also: layout handler for-each.