diff --git a/Userland/Libraries/LibJS/Parser.cpp b/Userland/Libraries/LibJS/Parser.cpp index 0ef735b92e..f2c91390ea 100644 --- a/Userland/Libraries/LibJS/Parser.cpp +++ b/Userland/Libraries/LibJS/Parser.cpp @@ -713,6 +713,7 @@ RefPtr Parser::try_parse_arrow_function_expression(bool expe auto function_body_result = [&]() -> RefPtr { TemporaryChange change(m_state.in_arrow_function_context, true); 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)) { // Parse a function body with statements @@ -779,7 +780,7 @@ RefPtr Parser::try_parse_labelled_statement(AllowLabelledFunction all 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 {}; } @@ -895,6 +896,9 @@ NonnullRefPtr Parser::parse_class_expression(bool expect_class_ : ""; 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)) { consume(); auto [expression, should_continue_parsing] = parse_primary_expression(); @@ -2287,7 +2291,6 @@ NonnullRefPtr Parser::parse_function_node(u8 parse_options) TemporaryChange break_context_rollback(m_state.in_break_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_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); constexpr auto is_function_expression = IsSame; @@ -2320,7 +2323,11 @@ NonnullRefPtr Parser::parse_function_node(u8 parse_options) name = consume().value(); 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 async_change(m_state.in_async_function_context, function_kind == FunctionKind::Async || function_kind == FunctionKind::AsyncGenerator); @@ -3050,7 +3057,10 @@ NonnullRefPtr Parser::parse_catch_clause() if (match(TokenType::ParenOpen)) { should_expect_parameter = true; 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(); else pattern_parameter = parse_binding_pattern(AllowDuplicates::No, AllowMemberExpressions::No); diff --git a/Userland/Libraries/LibJS/Tests/syntax/async-await.js b/Userland/Libraries/LibJS/Tests/syntax/async-await.js index 22c6c2b19d..2512be6be2 100644 --- a/Userland/Libraries/LibJS/Tests/syntax/async-await.js +++ b/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(); }); }); + +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(); + }); +});