From 95362ed6fce0b74b706d015aa8163caf78f61437 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Sun, 24 May 2026 18:53:45 +1000 Subject: [PATCH] Added break and continue support to for loops --- repl/bytecode_inspector.c | 2 +- scripts/hello_world.toy | 4 ++-- source/toy_compiler.c | 35 +++++++++++++++++++++++++++++++++++ source/toy_vm.c | 8 +++++--- 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/repl/bytecode_inspector.c b/repl/bytecode_inspector.c index a3d8589..99121b6 100644 --- a/repl/bytecode_inspector.c +++ b/repl/bytecode_inspector.c @@ -289,7 +289,7 @@ int inspect_instruction(unsigned char* bytecode, unsigned int pc, unsigned int j return 8; case TOY_OPCODE_ESCAPE: - printf(MARKER TOY_CC_DEBUG "ESCAPE relative %s%d (GOTO %u) and pop %d\n" TOY_CC_RESET, MARKER_VALUE(pc, unsigned char), + printf(MARKER TOY_CC_DEBUG "ESCAPE relative %s%d (GOTO %u) and pop %d scopes\n" TOY_CC_RESET, MARKER_VALUE(pc, unsigned char), (*(int*)(bytecode + pc + 4)) > 0 ? "+" : "", //show a + sign when positive (*(int*)(bytecode + pc + 4)), (*(int*)(bytecode + pc + 4)) + pc + 12, diff --git a/scripts/hello_world.toy b/scripts/hello_world.toy index 4258f7f..bbc260c 100644 --- a/scripts/hello_world.toy +++ b/scripts/hello_world.toy @@ -1,10 +1,10 @@ -var array = ["foo", "bar"]; +var array = ["foo", "bar", "buzz", "fizz"]; for (var i in array) { + if (i == "buzz") break; //use break or continue print i; - break; } print "done"; \ No newline at end of file diff --git a/source/toy_compiler.c b/source/toy_compiler.c index c43382c..cdcf53d 100644 --- a/source/toy_compiler.c +++ b/source/toy_compiler.c @@ -784,6 +784,41 @@ static unsigned int writeInstructionForThen(Toy_Bytecode** mb, Toy_AstForThen as //end of the loop, overwrite the parameter OVERWRITE_INT(mb, code, thenParamAddr, CURRENT_ADDRESS(mb, code) - (thenParamAddr + 4)); + //set the break & continue data + while ((*mb)->breakEscapes->count > 0) { + //extract + unsigned int addr = (*mb)->breakEscapes->data[(*mb)->breakEscapes->count - 1].addr; + unsigned int depth = (*mb)->breakEscapes->data[(*mb)->breakEscapes->count - 1].depth; + + unsigned int diff = depth - (*mb)->currentScopeDepth; + + OVERWRITE_INT(mb, code, addr, CURRENT_ADDRESS(mb, code) - (addr + 8)); //tell break to come here AFTER reading the instruction + OVERWRITE_INT(mb, code, addr, diff); + + //tick down + (*mb)->breakEscapes->count--; + } + + while ((*mb)->continueEscapes->count > 0) { + //extract + unsigned int addr = (*mb)->continueEscapes->data[(*mb)->continueEscapes->count - 1].addr; + unsigned int depth = (*mb)->continueEscapes->data[(*mb)->continueEscapes->count - 1].depth; + + unsigned int diff = depth - (*mb)->currentScopeDepth; + + OVERWRITE_INT(mb, code, addr, beginAddr - (addr + 8)); //tell continue to return to the start AFTER reading the instruction + OVERWRITE_INT(mb, code, addr, diff); + + //tick down + (*mb)->continueEscapes->count--; + } + + //eliminate the value & counter from within the bytecode, so they're cleaned up after breaks + EMIT_BYTE(mb, code,TOY_OPCODE_ELIMINATE); + EMIT_BYTE(mb, code, 2); + EMIT_BYTE(mb, code, 0); + EMIT_BYTE(mb, code, 0); + return 0; } diff --git a/source/toy_vm.c b/source/toy_vm.c index f529fc8..d8c3edc 100644 --- a/source/toy_vm.c +++ b/source/toy_vm.c @@ -499,9 +499,11 @@ static void processIterate(Toy_VM* vm) { //check out-of-bounds if (index >= array->count) { - Toy_freeValue(counter); - Toy_freeValue(compound); - Toy_pushStack(&vm->stack, TOY_VALUE_FROM_NULL()); //force a jump + //DON'T free the iterable & counter, that's embedded in the bytecode + Toy_pushStack(&vm->stack, compound); + Toy_pushStack(&vm->stack, counter); + //force a jump then exit + Toy_pushStack(&vm->stack, TOY_VALUE_FROM_NULL()); processJump(vm); return; }