From cbbfcd35e72ec48560e96e5c3d7920799e64099c Mon Sep 17 00:00:00 2001 From: davidot Date: Fri, 26 Nov 2021 23:29:05 +0100 Subject: [PATCH] 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. --- Userland/Libraries/LibJS/Parser.cpp | 16 +++++++++++++--- .../Libraries/LibJS/Tests/syntax/async-await.js | 16 ++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) 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(); + }); +});