diff options
-rw-r--r-- | compiler.c | 10 | ||||
-rw-r--r-- | compiler.h | 2 | ||||
-rw-r--r-- | tests/custom/03_bugs/22_compile_break_continue_scoping | 59 |
3 files changed, 65 insertions, 6 deletions
@@ -2031,8 +2031,8 @@ static void uc_compiler_compile_while(uc_compiler *compiler) { uc_chunk *chunk = uc_compiler_current_chunk(compiler); + uc_patchlist p = { .depth = compiler->scope_depth }; size_t cond_off, jmpz_off, end_off; - uc_patchlist p = { 0 }; p.parent = compiler->patchlist; compiler->patchlist = &p; @@ -2079,8 +2079,8 @@ static void uc_compiler_compile_for_in(uc_compiler *compiler, bool local, uc_token *kvar, uc_token *vvar) { uc_chunk *chunk = uc_compiler_current_chunk(compiler); + uc_patchlist p = { .depth = compiler->scope_depth + 1 }; size_t skip_jmp, test_jmp, key_slot, val_slot; - uc_patchlist p = { 0 }; p.parent = compiler->patchlist; compiler->patchlist = &p; @@ -2190,7 +2190,7 @@ uc_compiler_compile_for_count(uc_compiler *compiler, bool local, uc_token *var) { uc_chunk *chunk = uc_compiler_current_chunk(compiler); size_t test_off = 0, incr_off, skip_off, cond_off = 0; - uc_patchlist p = { 0 }; + uc_patchlist p = { .depth = compiler->scope_depth + 1 }; p.parent = compiler->patchlist; compiler->patchlist = &p; @@ -2344,9 +2344,9 @@ uc_compiler_compile_switch(uc_compiler *compiler) { size_t i, test_jmp, skip_jmp, next_jmp, value_slot, default_off = 0; uc_chunk *chunk = uc_compiler_current_chunk(compiler); + uc_patchlist p = { .depth = compiler->scope_depth }; uc_locals *locals = &compiler->locals; uc_jmplist cases = { 0 }; - uc_patchlist p = { 0 }; p.parent = compiler->patchlist; compiler->patchlist = &p; @@ -2599,7 +2599,7 @@ uc_compiler_compile_control(uc_compiler *compiler) } /* pop locals in scope up to this point */ - for (i = locals->count; i > 0 && (size_t)locals->entries[i - 1].depth == compiler->scope_depth; i--) + for (i = locals->count; i > 0 && (size_t)locals->entries[i - 1].depth > p->depth; i--) uc_compiler_emit_insn(compiler, 0, I_POP); uc_vector_grow(p); @@ -66,7 +66,7 @@ typedef enum { struct uc_patchlist { struct uc_patchlist *parent; - size_t count, *entries; + size_t depth, count, *entries; }; typedef struct uc_patchlist uc_patchlist; diff --git a/tests/custom/03_bugs/22_compile_break_continue_scoping b/tests/custom/03_bugs/22_compile_break_continue_scoping new file mode 100644 index 0000000..461b144 --- /dev/null +++ b/tests/custom/03_bugs/22_compile_break_continue_scoping @@ -0,0 +1,59 @@ +When compiling a break or continue statement, the compiler emitted pop +instructions for local variables within the scope the break or continue +keyword appeared in, but it must also pop local variables in enclosing +scopes up until the scope of the containing loop or switch body. + +-- Expect stdout -- +1 +2 +3 +-- End -- + +-- Testcase -- +{% + for (let i = 1; i <= 3; i++) { + while (true) { + let n = i; + + print(n, "\n"); + + { + // The `let n` stack slot is not popped since it is + // outside of break's scope... + break; + } + } + } +%} +-- End -- + +-- Expect stdout -- +1 +2 +3 +2 +4 +6 +3 +6 +9 +-- End -- + +-- Testcase -- +{% + for (let i = 1; i <= 3; i++) { + for (let j = 1; j <= 3; j++) { + let n = i * j; + + print(n, "\n"); + + if (j == 1) + { + // The `let n` stack slot is not popped since it is + // outside of continue's scope... + continue; + } + } + } +%} +-- End -- |