diff --git a/Userland/Libraries/LibJS/Parser.cpp b/Userland/Libraries/LibJS/Parser.cpp index 12478418d2..0ef735b92e 100644 --- a/Userland/Libraries/LibJS/Parser.cpp +++ b/Userland/Libraries/LibJS/Parser.cpp @@ -596,13 +596,15 @@ bool Parser::match_invalid_escaped_keyword() const if (m_state.current_token.type() != TokenType::EscapedKeyword) return false; auto token_value = m_state.current_token.value(); - if (token_value == "await"sv) { - return m_program_type == Program::Type::Module; - } - if (m_state.strict_mode) { + if (token_value == "await"sv) + return m_program_type == Program::Type::Module || m_state.in_async_function_context; + if (token_value == "async"sv) + return false; + if (token_value == "yield"sv) + return m_state.in_generator_function_context; + if (m_state.strict_mode) return true; - } - return token_value != "yield"sv && token_value != "let"sv; + return token_value != "let"sv; } static constexpr AK::Array strict_reserved_words = { "implements", "interface", "let", "package", "private", "protected", "public", "static", "yield" }; @@ -1230,7 +1232,7 @@ Parser::PrimaryExpressionParseResult Parser::parse_primary_expression() syntax_error("'super' keyword unexpected here"); return { create_ast_node({ m_state.current_token.filename(), rule_start.position(), position() }) }; case TokenType::EscapedKeyword: - if (m_state.strict_mode || (m_state.current_token.value() != "let"sv && (m_state.in_generator_function_context || m_state.current_token.value() != "yield"sv) && (m_state.in_async_function_context || m_state.current_token.value() != "await"sv))) + if (match_invalid_escaped_keyword()) syntax_error("Keyword must not contain escaped characters"); [[fallthrough]]; case TokenType::Identifier: { diff --git a/Userland/Libraries/LibJS/Tests/syntax/async-await.js b/Userland/Libraries/LibJS/Tests/syntax/async-await.js index d7f5b367be..22c6c2b19d 100644 --- a/Userland/Libraries/LibJS/Tests/syntax/async-await.js +++ b/Userland/Libraries/LibJS/Tests/syntax/async-await.js @@ -9,6 +9,10 @@ describe("parsing freestanding async functions", () => { expect(`async function foo() { await; }`).not.toEval(); expect(`function foo() { await bar(); }`).not.toEval(); expect(`function foo() { await; }`).toEval(); + + expect(`\\u0061sync function foo() { await bar(); }`).not.toEval(); + expect(`\\u0061sync function foo() { \\u0061wait bar(); }`).not.toEval(); + expect(`async function foo() { \\u0061wait bar(); }`).not.toEval(); }); }); @@ -82,11 +86,15 @@ describe("async arrow functions", () => { expect("async (b = await) => await b;").not.toEval(); expect("async (b = await 3) => await b;").not.toEval(); - // Cannot escape the async keyword. + // Cannot escape the async keyword and get an async arrow function. expect("\\u0061sync () => await 3").not.toEval(); - expect("for (async of => {};;) {}").toEval(); + expect("for (async of => {};false;) {}").toEval(); expect("for (async of []) {}").not.toEval(); + + expect("for (\\u0061sync of []) {}").toEval(); + expect("for (\\u0061sync of => {};false;) {}").not.toEval(); + expect("for (\\u0061sync => {};false;) {}").toEval(); }); test("async within a for-loop", () => {