summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--compiler.c4
-rw-r--r--tests/03_bugs/12_altblock_stack_mismatch26
2 files changed, 30 insertions, 0 deletions
diff --git a/compiler.c b/compiler.c
index 21e691b..362ca8b 100644
--- a/compiler.c
+++ b/compiler.c
@@ -1867,12 +1867,16 @@ uc_compiler_compile_local(uc_compiler *compiler)
static uc_tokentype_t
uc_compiler_compile_altifblock(uc_compiler *compiler)
{
+ uc_compiler_enter_scope(compiler);
+
while (true) {
switch (compiler->parser->curr.type) {
case TK_ELIF:
case TK_ELSE:
case TK_ENDIF:
case TK_EOF:
+ uc_compiler_leave_scope(compiler);
+
return compiler->parser->curr.type;
default:
diff --git a/tests/03_bugs/12_altblock_stack_mismatch b/tests/03_bugs/12_altblock_stack_mismatch
new file mode 100644
index 0000000..6805888
--- /dev/null
+++ b/tests/03_bugs/12_altblock_stack_mismatch
@@ -0,0 +1,26 @@
+When compiling alternative syntax blocks, such as `for ...: endfor`,
+`if ...: endif` etc., the compiler didn't assign the contained statements
+to a dedicated lexical scope, which caused a stack mismatch between
+compiler and vm when such blocks declaring local variables weren't
+actually executed.
+
+-- Expect stdout --
+2
+-- End --
+
+-- Testcase --
+{%
+ if (false):
+ let a = 1;
+ endif;
+
+ /* Due to lack of own lexical scope above, the compiler assumed
+ * that `a` is still on stack but the code to initialize it was
+ * never executed, so stack offsets were shifted by one from here
+ * on throughout the rest of the program. */
+
+ let b = 2;
+
+ print(b, "\n");
+%}
+-- End --