Browse Source

LibJS: Disallow await keywords in static init blocks

In static init blocks 'await' cannot be used. Note that this does not
cover all the cases since the parser currently cannot distinguish
between expressions within parenthesis and direct expressions.
davidot 3 years ago
parent
commit
cbbfcd35e7

+ 13 - 3
Userland/Libraries/LibJS/Parser.cpp

@@ -713,6 +713,7 @@ RefPtr<FunctionExpression> Parser::try_parse_arrow_function_expression(bool expe
     auto function_body_result = [&]() -> RefPtr<FunctionBody> {
     auto function_body_result = [&]() -> RefPtr<FunctionBody> {
         TemporaryChange change(m_state.in_arrow_function_context, true);
         TemporaryChange change(m_state.in_arrow_function_context, true);
         TemporaryChange async_context_change(m_state.in_async_function_context, is_async);
         TemporaryChange async_context_change(m_state.in_async_function_context, is_async);
+        TemporaryChange in_class_static_init_block_change(m_state.in_class_static_init_block, false);
 
 
         if (match(TokenType::CurlyOpen)) {
         if (match(TokenType::CurlyOpen)) {
             // Parse a function body with statements
             // Parse a function body with statements
@@ -779,7 +780,7 @@ RefPtr<Statement> Parser::try_parse_labelled_statement(AllowLabelledFunction all
         return {};
         return {};
     }
     }
 
 
-    if (m_state.current_token.value() == "await"sv && (m_program_type == Program::Type::Module || m_state.in_async_function_context)) {
+    if (m_state.current_token.value() == "await"sv && (m_program_type == Program::Type::Module || m_state.in_async_function_context || m_state.in_class_static_init_block)) {
         return {};
         return {};
     }
     }
 
 
@@ -895,6 +896,9 @@ NonnullRefPtr<ClassExpression> Parser::parse_class_expression(bool expect_class_
         : "";
         : "";
 
 
     check_identifier_name_for_assignment_validity(class_name, true);
     check_identifier_name_for_assignment_validity(class_name, true);
+    if (m_state.in_class_static_init_block && class_name == "await"sv)
+        syntax_error("Identifier must not be a reserved word in modules ('await')");
+
     if (match(TokenType::Extends)) {
     if (match(TokenType::Extends)) {
         consume();
         consume();
         auto [expression, should_continue_parsing] = parse_primary_expression();
         auto [expression, should_continue_parsing] = parse_primary_expression();
@@ -2287,7 +2291,6 @@ NonnullRefPtr<FunctionNodeType> Parser::parse_function_node(u8 parse_options)
     TemporaryChange break_context_rollback(m_state.in_break_context, false);
     TemporaryChange break_context_rollback(m_state.in_break_context, false);
     TemporaryChange continue_context_rollback(m_state.in_continue_context, false);
     TemporaryChange continue_context_rollback(m_state.in_continue_context, false);
     TemporaryChange class_field_initializer_rollback(m_state.in_class_field_initializer, false);
     TemporaryChange class_field_initializer_rollback(m_state.in_class_field_initializer, false);
-    TemporaryChange class_static_initializer_rollback(m_state.in_class_static_init_block, false);
     TemporaryChange might_need_arguments_object_rollback(m_state.function_might_need_arguments_object, false);
     TemporaryChange might_need_arguments_object_rollback(m_state.function_might_need_arguments_object, false);
 
 
     constexpr auto is_function_expression = IsSame<FunctionNodeType, FunctionExpression>;
     constexpr auto is_function_expression = IsSame<FunctionNodeType, FunctionExpression>;
@@ -2320,7 +2323,11 @@ NonnullRefPtr<FunctionNodeType> Parser::parse_function_node(u8 parse_options)
             name = consume().value();
             name = consume().value();
 
 
         check_identifier_name_for_assignment_validity(name);
         check_identifier_name_for_assignment_validity(name);
+
+        if (m_state.in_class_static_init_block && name == "await"sv)
+            syntax_error("'await' is a reserved word");
     }
     }
+    TemporaryChange class_static_initializer_rollback(m_state.in_class_static_init_block, false);
     TemporaryChange generator_change(m_state.in_generator_function_context, function_kind == FunctionKind::Generator || function_kind == FunctionKind::AsyncGenerator);
     TemporaryChange generator_change(m_state.in_generator_function_context, function_kind == FunctionKind::Generator || function_kind == FunctionKind::AsyncGenerator);
     TemporaryChange async_change(m_state.in_async_function_context, function_kind == FunctionKind::Async || function_kind == FunctionKind::AsyncGenerator);
     TemporaryChange async_change(m_state.in_async_function_context, function_kind == FunctionKind::Async || function_kind == FunctionKind::AsyncGenerator);
 
 
@@ -3050,7 +3057,10 @@ NonnullRefPtr<CatchClause> Parser::parse_catch_clause()
     if (match(TokenType::ParenOpen)) {
     if (match(TokenType::ParenOpen)) {
         should_expect_parameter = true;
         should_expect_parameter = true;
         consume();
         consume();
-        if (match_identifier_name() && (!match(TokenType::Yield) || !m_state.in_generator_function_context) && (!match(TokenType::Async) || !m_state.in_async_function_context))
+        if (match_identifier_name()
+            && (!match(TokenType::Yield) || !m_state.in_generator_function_context)
+            && (!match(TokenType::Async) || !m_state.in_async_function_context)
+            && (!match(TokenType::Await) || !m_state.in_class_static_init_block))
             parameter = consume().value();
             parameter = consume().value();
         else
         else
             pattern_parameter = parse_binding_pattern(AllowDuplicates::No, AllowMemberExpressions::No);
             pattern_parameter = parse_binding_pattern(AllowDuplicates::No, AllowMemberExpressions::No);

+ 16 - 0
Userland/Libraries/LibJS/Tests/syntax/async-await.js

@@ -168,3 +168,19 @@ describe("non async function declaration usage of async still works", () => {
         expect(evalResult).toBeTrue();
         expect(evalResult).toBeTrue();
     });
     });
 });
 });
+
+describe("await cannot be used in class static init blocks", () => {
+    test("directly", () => {
+        expect("class A{ static { await; } }").not.toEval();
+        expect("class A{ static { let await = 3; } }").not.toEval();
+        expect("class A{ static { call(await); } }").not.toEval();
+        expect("class A{ static { for(const await = 1; false ;) {} } }").not.toEval();
+    });
+
+    test("via declaration", () => {
+        expect("class A{ static { class await {} } }").not.toEval();
+        expect("class A{ static { function await() {} } }").not.toEval();
+        expect("class A{ static { function* await() {} } }").not.toEval();
+        expect("class A{ static { async function* await() {} } }").not.toEval();
+    });
+});