summaryrefslogtreecommitdiff
path: root/src/core/interpret.c
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-02-19 00:33:17 +0200
committerPaul Buetow <paul@buetow.org>2026-02-19 00:33:17 +0200
commit147153bf6aadd52d32f6beffc17f610c837ce17f (patch)
tree8041cea988dc11bc0cefeedd7d895fe9bdb02274 /src/core/interpret.c
parent7a0407c03a0af18a38fcea4312796f18a276e541 (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.c36
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",