diff options
| author | Paul Buetow <paul@buetow.org> | 2026-02-19 00:33:17 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-02-19 00:33:17 +0200 |
| commit | 147153bf6aadd52d32f6beffc17f610c837ce17f (patch) | |
| tree | 8041cea988dc11bc0cefeedd7d895fe9bdb02274 /src/core/interpret.c | |
| parent | 7a0407c03a0af18a38fcea4312796f18a276e541 (diff) | |
Implement break and next for while/until loops
TT_BREAK and TT_NEXT were already tokenised; this wires them up:
- _program(): guard statement loop with ct == CONTROL_NONE so a break/next
flag set inside a loop body stops block execution and propagates upward
- _control(): add TT_BREAK and TT_NEXT cases that set CONTROL_BREAK /
CONTROL_NEXT on p_interpret->ct and return immediately
- while/until loop: replace the commented-out switch with active if/else
logic that clears the flag and either stops iteration (break) or lets
the loop re-evaluate its condition (next)
Add examples/break_next.fy to exercise both keywords in while and until
loops; expected output: 5 / 12 / 7.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'src/core/interpret.c')
| -rw-r--r-- | src/core/interpret.c | 36 |
1 files changed, 24 insertions, 12 deletions
diff --git a/src/core/interpret.c b/src/core/interpret.c index 5b5e80b..0667148 100644 --- a/src/core/interpret.c +++ b/src/core/interpret.c @@ -168,7 +168,9 @@ int _program(Interpret *p_interpret) { _CHECK TRACK - while (_statement(p_interpret) == 1) + /* Stop executing statements as soon as break/next is active so the + * control flag propagates cleanly up to the enclosing loop. */ + while (_statement(p_interpret) == 1 && p_interpret->ct == CONTROL_NONE) garbage_collect(); return (1); @@ -496,6 +498,18 @@ _control(Interpret *p_interpret) { Token *p_token = p_interpret->p_token; switch (p_interpret->tt) { + /* break; — set the break flag; the statement loop in _program() will + * stop and the flag propagates up to the enclosing while/until. */ + case TT_BREAK: + p_interpret->ct = CONTROL_BREAK; + _NEXT + return (1); + /* next; — set the next flag to skip the rest of the loop body and + * let the loop re-evaluate its condition on the next iteration. */ + case TT_NEXT: + p_interpret->ct = CONTROL_NEXT; + _NEXT + return (1); case TT_IF: case TT_IFNOT: { @@ -584,18 +598,16 @@ _control(Interpret *p_interpret) { } } - /* - switch (p_interpret->ct) { - case CONTROL_BREAK: - p_interpret->ct = CONTROL_NONE; - b_flag = false; - break; - case CONTROL_NEXT: - p_interpret->ct = CONTROL_NONE; - break; - NO_DEFAULT; + /* Act on any break/next flag set during loop body execution. + * break clears the flag and stops iteration; next clears it + * and lets the loop re-evaluate the condition naturally. */ + if (p_interpret->ct == CONTROL_BREAK) { + p_interpret->ct = CONTROL_NONE; + b_flag = false; + } else if (p_interpret->ct == CONTROL_NEXT) { + p_interpret->ct = CONTROL_NONE; + /* b_flag stays true; condition re-evaluated next iteration */ } - */ } else { _INTERPRET_ERROR("Expected expression after control keyword", |
