Преглед изворни кода

LibJS: Require initializer for 'const' variable declaration

Linus Groh пре 4 година
родитељ
комит
563d3c8055

+ 15 - 13
Libraries/LibJS/Parser.cpp

@@ -1374,26 +1374,24 @@ Vector<FunctionNode::Parameter> Parser::parse_function_parameters(int& function_
     return parameters;
     return parameters;
 }
 }
 
 
-NonnullRefPtr<VariableDeclaration> Parser::parse_variable_declaration(bool with_semicolon)
+NonnullRefPtr<VariableDeclaration> Parser::parse_variable_declaration(bool for_loop_variable_declaration)
 {
 {
     DeclarationKind declaration_kind;
     DeclarationKind declaration_kind;
 
 
     switch (m_parser_state.m_current_token.type()) {
     switch (m_parser_state.m_current_token.type()) {
     case TokenType::Var:
     case TokenType::Var:
         declaration_kind = DeclarationKind::Var;
         declaration_kind = DeclarationKind::Var;
-        consume(TokenType::Var);
         break;
         break;
     case TokenType::Let:
     case TokenType::Let:
         declaration_kind = DeclarationKind::Let;
         declaration_kind = DeclarationKind::Let;
-        consume(TokenType::Let);
         break;
         break;
     case TokenType::Const:
     case TokenType::Const:
         declaration_kind = DeclarationKind::Const;
         declaration_kind = DeclarationKind::Const;
-        consume(TokenType::Const);
         break;
         break;
     default:
     default:
         ASSERT_NOT_REACHED();
         ASSERT_NOT_REACHED();
     }
     }
+    consume();
 
 
     NonnullRefPtrVector<VariableDeclarator> declarations;
     NonnullRefPtrVector<VariableDeclarator> declarations;
     for (;;) {
     for (;;) {
@@ -1402,6 +1400,8 @@ NonnullRefPtr<VariableDeclaration> Parser::parse_variable_declaration(bool with_
         if (match(TokenType::Equals)) {
         if (match(TokenType::Equals)) {
             consume();
             consume();
             init = parse_expression(2);
             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<VariableDeclarator>(create_ast_node<Identifier>(move(id)), move(init)));
         declarations.append(create_ast_node<VariableDeclarator>(create_ast_node<Identifier>(move(id)), move(init)));
         if (match(TokenType::Comma)) {
         if (match(TokenType::Comma)) {
@@ -1410,7 +1410,7 @@ NonnullRefPtr<VariableDeclaration> Parser::parse_variable_declaration(bool with_
         }
         }
         break;
         break;
     }
     }
-    if (with_semicolon)
+    if (!for_loop_variable_declaration)
         consume_or_insert_semicolon();
         consume_or_insert_semicolon();
 
 
     auto declaration = create_ast_node<VariableDeclaration>(declaration_kind, move(declarations));
     auto declaration = create_ast_node<VariableDeclaration>(declaration_kind, move(declarations));
@@ -1651,9 +1651,15 @@ NonnullRefPtr<Statement> Parser::parse_for_statement()
                 m_parser_state.m_let_scopes.append(NonnullRefPtrVector<VariableDeclaration>());
                 m_parser_state.m_let_scopes.append(NonnullRefPtrVector<VariableDeclaration>());
                 in_scope = true;
                 in_scope = true;
             }
             }
-            init = parse_variable_declaration(false);
+            init = parse_variable_declaration(true);
             if (match_for_in_of())
             if (match_for_in_of())
                 return parse_for_in_of_statement(*init);
                 return parse_for_in_of_statement(*init);
+            if (static_cast<VariableDeclaration&>(*init).declaration_kind() == DeclarationKind::Const) {
+                for (auto& declaration : static_cast<VariableDeclaration&>(*init).declarations()) {
+                    if (!declaration.init())
+                        syntax_error("Missing initializer in 'const' variable declaration");
+                }
+            }
         } else {
         } else {
             syntax_error("Unexpected token in for loop");
             syntax_error("Unexpected token in for loop");
         }
         }
@@ -1686,15 +1692,11 @@ NonnullRefPtr<Statement> Parser::parse_for_statement()
 NonnullRefPtr<Statement> Parser::parse_for_in_of_statement(NonnullRefPtr<ASTNode> lhs)
 NonnullRefPtr<Statement> Parser::parse_for_in_of_statement(NonnullRefPtr<ASTNode> lhs)
 {
 {
     if (lhs->is_variable_declaration()) {
     if (lhs->is_variable_declaration()) {
-        auto declarations = static_cast<VariableDeclaration*>(lhs.ptr())->declarations();
-        if (declarations.size() > 1) {
+        auto declarations = static_cast<VariableDeclaration&>(*lhs).declarations();
+        if (declarations.size() > 1)
             syntax_error("multiple declarations not allowed in for..in/of");
             syntax_error("multiple declarations not allowed in for..in/of");
-            lhs = create_ast_node<ErrorExpression>();
-        }
-        if (declarations.first().init() != nullptr) {
+        if (declarations.first().init() != nullptr)
             syntax_error("variable initializer not allowed in for..in/of");
             syntax_error("variable initializer not allowed in for..in/of");
-            lhs = create_ast_node<ErrorExpression>();
-        }
     }
     }
     auto in_or_of = consume();
     auto in_or_of = consume();
     auto rhs = parse_expression(0);
     auto rhs = parse_expression(0);

+ 1 - 1
Libraries/LibJS/Parser.h

@@ -66,7 +66,7 @@ public:
     NonnullRefPtr<BlockStatement> parse_block_statement();
     NonnullRefPtr<BlockStatement> parse_block_statement();
     NonnullRefPtr<BlockStatement> parse_block_statement(bool& is_strict);
     NonnullRefPtr<BlockStatement> parse_block_statement(bool& is_strict);
     NonnullRefPtr<ReturnStatement> parse_return_statement();
     NonnullRefPtr<ReturnStatement> parse_return_statement();
-    NonnullRefPtr<VariableDeclaration> parse_variable_declaration(bool with_semicolon = true);
+    NonnullRefPtr<VariableDeclaration> parse_variable_declaration(bool for_loop_variable_declaration = false);
     NonnullRefPtr<Statement> parse_for_statement();
     NonnullRefPtr<Statement> parse_for_statement();
     NonnullRefPtr<Statement> parse_for_in_of_statement(NonnullRefPtr<ASTNode> lhs);
     NonnullRefPtr<Statement> parse_for_in_of_statement(NonnullRefPtr<ASTNode> lhs);
     NonnullRefPtr<IfStatement> parse_if_statement();
     NonnullRefPtr<IfStatement> parse_if_statement();

+ 5 - 0
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();
+});