diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp index 75a74811c2..a99c057a35 100644 --- a/Libraries/LibJS/Parser.cpp +++ b/Libraries/LibJS/Parser.cpp @@ -1374,26 +1374,24 @@ Vector Parser::parse_function_parameters(int& function_ return parameters; } -NonnullRefPtr Parser::parse_variable_declaration(bool with_semicolon) +NonnullRefPtr Parser::parse_variable_declaration(bool for_loop_variable_declaration) { DeclarationKind declaration_kind; switch (m_parser_state.m_current_token.type()) { case TokenType::Var: declaration_kind = DeclarationKind::Var; - consume(TokenType::Var); break; case TokenType::Let: declaration_kind = DeclarationKind::Let; - consume(TokenType::Let); break; case TokenType::Const: declaration_kind = DeclarationKind::Const; - consume(TokenType::Const); break; default: ASSERT_NOT_REACHED(); } + consume(); NonnullRefPtrVector declarations; for (;;) { @@ -1402,6 +1400,8 @@ NonnullRefPtr Parser::parse_variable_declaration(bool with_ if (match(TokenType::Equals)) { consume(); init = parse_expression(2); + } else if (!for_loop_variable_declaration && declaration_kind == DeclarationKind::Const) { + syntax_error("Missing initializer in 'const' variable declaration"); } declarations.append(create_ast_node(create_ast_node(move(id)), move(init))); if (match(TokenType::Comma)) { @@ -1410,7 +1410,7 @@ NonnullRefPtr Parser::parse_variable_declaration(bool with_ } break; } - if (with_semicolon) + if (!for_loop_variable_declaration) consume_or_insert_semicolon(); auto declaration = create_ast_node(declaration_kind, move(declarations)); @@ -1651,9 +1651,15 @@ NonnullRefPtr Parser::parse_for_statement() m_parser_state.m_let_scopes.append(NonnullRefPtrVector()); in_scope = true; } - init = parse_variable_declaration(false); + init = parse_variable_declaration(true); if (match_for_in_of()) return parse_for_in_of_statement(*init); + if (static_cast(*init).declaration_kind() == DeclarationKind::Const) { + for (auto& declaration : static_cast(*init).declarations()) { + if (!declaration.init()) + syntax_error("Missing initializer in 'const' variable declaration"); + } + } } else { syntax_error("Unexpected token in for loop"); } @@ -1686,15 +1692,11 @@ NonnullRefPtr Parser::parse_for_statement() NonnullRefPtr Parser::parse_for_in_of_statement(NonnullRefPtr lhs) { if (lhs->is_variable_declaration()) { - auto declarations = static_cast(lhs.ptr())->declarations(); - if (declarations.size() > 1) { + auto declarations = static_cast(*lhs).declarations(); + if (declarations.size() > 1) syntax_error("multiple declarations not allowed in for..in/of"); - lhs = create_ast_node(); - } - if (declarations.first().init() != nullptr) { + if (declarations.first().init() != nullptr) syntax_error("variable initializer not allowed in for..in/of"); - lhs = create_ast_node(); - } } auto in_or_of = consume(); auto rhs = parse_expression(0); diff --git a/Libraries/LibJS/Parser.h b/Libraries/LibJS/Parser.h index 4be755ca8d..620cfd497c 100644 --- a/Libraries/LibJS/Parser.h +++ b/Libraries/LibJS/Parser.h @@ -66,7 +66,7 @@ public: NonnullRefPtr parse_block_statement(); NonnullRefPtr parse_block_statement(bool& is_strict); NonnullRefPtr parse_return_statement(); - NonnullRefPtr parse_variable_declaration(bool with_semicolon = true); + NonnullRefPtr parse_variable_declaration(bool for_loop_variable_declaration = false); NonnullRefPtr parse_for_statement(); NonnullRefPtr parse_for_in_of_statement(NonnullRefPtr lhs); NonnullRefPtr parse_if_statement(); diff --git a/Libraries/LibJS/Tests/const-declaration-missing-initializer.js b/Libraries/LibJS/Tests/const-declaration-missing-initializer.js new file mode 100644 index 0000000000..5bbf2ef9e2 --- /dev/null +++ b/Libraries/LibJS/Tests/const-declaration-missing-initializer.js @@ -0,0 +1,5 @@ +test("missing initializer in 'const' variable declaration is syntax error", () => { + expect("const foo").not.toEval(); + expect("const foo = 1, bar").not.toEval(); + expect("const foo = 1, bar, baz = 2").not.toEval(); +});