# KOS_OP_PUSH_FOREACH - **Style**: NOARG. Argument unused; break target is derived at runtime from the extent table (`pop_pc + 1`). - **Stack**: Pops iterable (TOS); creates iterator; pushes the FOREACH node, which owns its segment. Region loop result starts unset. ITER_NEXT uses the node's iterator. Break target = `extent.pop_pc + 1` (instruction after the matching POP_FOREACH). - **Pushes:** KOS_DYN_FOREACH (static extent KOS_EXT_FOREACH; node holds iterator and loop state). - **Invariants**: A KOS_EXT_FOREACH extent must exist at the PUSH_FOREACH PC; otherwise RuntimeError. Extent kind KOS_EXT_FOREACH. - **Compiler form:** Pre-compile arg = 0 (unused). Break target is not stored in the instruction; it is derived at runtime via `kos_extent_find(KOS_EXT_FOREACH)` → `ext->pop_pc + 1`. **Example:** for x in [1,2,3]: body. Stack at entry: [..., iterable]. Pool: 0 = [1,2,3]. | index | opcode | arg | arg view | comment | |------:|--------------|-----|----------|---------| | 0 | CONST | 0 | 0 ([1,2,3]) | stack: [..., iterable] | | 1 | PUSH_FOREACH | 0 | 0 | pop iterable; push FOREACH region; break_pc = pop_pc+1 from extent table | | 2 | ITER_NEXT | 6 | 6 (-> 6) | next from region; else → 6. stack: [..., x] | | 3 | POP | 1 | 1 | body: consume x | | 4 | JUMP | 2 | 2 (-> 2) | loop back | | 5 | POP_FOREACH | 0 | 0 | push loop result (None if unset) | | 6 | LABEL | -- | -- | break / exhausted (= pop_pc+1) |