diff options
author | Jo-Philipp Wich <jo@mein.io> | 2021-05-11 20:11:01 +0200 |
---|---|---|
committer | Jo-Philipp Wich <jo@mein.io> | 2021-05-11 20:11:01 +0200 |
commit | 3f801169760a1817876648e6d22288ebd8ce97b8 (patch) | |
tree | 53f2627eef96b51f08280e8babccd4a707cfd3fe | |
parent | f20b56ff64b3144d618d228fbe1a3d07aad96450 (diff) |
compiler: fix local for-loop initializer variable declarations
In a loop statement like `for (let x = 1, y = 2; ...)` the initialization
statement was incorrectly interpreted as `let x = 1; y = 2` instead of the
correct `let ..., y = 2`, triggering reference error exceptions in strict
mode.
Solve the issue by continue parsing the rest of the comma expression
seqence as declaration list expression when the initializer is compiled
in local mode.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r-- | compiler.c | 18 | ||||
-rw-r--r-- | tests/custom/00_syntax/16_for_loop | 8 | ||||
-rw-r--r-- | tests/custom/03_bugs/24_compiler_local_for_loop_declaration | 18 |
3 files changed, 37 insertions, 7 deletions
@@ -1869,7 +1869,7 @@ uc_compiler_declare_internal(uc_compiler *compiler, size_t srcpos, const char *n } static void -uc_compiler_compile_local(uc_compiler *compiler) +uc_compiler_compile_declexpr(uc_compiler *compiler) { ssize_t slot; @@ -1899,7 +1899,12 @@ uc_compiler_compile_local(uc_compiler *compiler) } } while (uc_compiler_parse_match(compiler, TK_COMMA)); +} +static void +uc_compiler_compile_local(uc_compiler *compiler) +{ + uc_compiler_compile_declexpr(compiler); uc_compiler_parse_consume(compiler, TK_SCOL); } @@ -2218,8 +2223,15 @@ uc_compiler_compile_for_count(uc_compiler *compiler, bool local, uc_token *var) /* If followed by a comma, continue parsing expression */ if (uc_compiler_parse_match(compiler, TK_COMMA)) { - uc_compiler_compile_expression(compiler); - uc_compiler_emit_insn(compiler, 0, I_POP); + /* Is a continuation of a declaration list... */ + if (local) { + uc_compiler_compile_declexpr(compiler); + } + /* ... otherwise an unrelated expression */ + else { + uc_compiler_compile_expression(compiler); + uc_compiler_emit_insn(compiler, 0, I_POP); + } } } /* ... otherwise try parsing an entire expression (which might be absent) */ diff --git a/tests/custom/00_syntax/16_for_loop b/tests/custom/00_syntax/16_for_loop index 67edc21..b206b07 100644 --- a/tests/custom/00_syntax/16_for_loop +++ b/tests/custom/00_syntax/16_for_loop @@ -220,10 +220,10 @@ rejected. -- Expect stderr -- Syntax error: Unexpected token Expecting ';' -In line 2, byte 24: +In line 2, byte 19: ` for (let x, y, z in {})` - Near here ----------------^ + Near here -----------^ -- End -- @@ -241,10 +241,10 @@ Ensure that assignments in for-in loop expressions are rejected. -- Expect stderr -- Syntax error: Unexpected token Expecting ';' -In line 2, byte 25: +In line 2, byte 20: ` for (let x = 1, y in {})` - Near here -----------------^ + Near here ------------^ -- End -- diff --git a/tests/custom/03_bugs/24_compiler_local_for_loop_declaration b/tests/custom/03_bugs/24_compiler_local_for_loop_declaration new file mode 100644 index 0000000..aafde55 --- /dev/null +++ b/tests/custom/03_bugs/24_compiler_local_for_loop_declaration @@ -0,0 +1,18 @@ +When compiling a for-loop local variable initializer expression, the compiler +incorrectly treated subsequent declarations as global variable assignments, +triggering reference error exceptions in strict mode. + +-- Expect stdout -- +1 +-- End -- + +-- Testcase -- +{% + "use strict"; + + // The initializer expression below was incorrectly interpreted as + // `let x = 0; y = 1` instead of the correct `let ..., y = 1`. + for (let x = 0, y = 1; x < 1; x++) + print(y, "\n"); +%} +-- End -- |