From 08a303172dd214dca291c0b3244556e689da5ef5 Mon Sep 17 00:00:00 2001 From: Linus Groh Date: Sat, 17 Jul 2021 23:19:03 +0100 Subject: [PATCH] LibJS: Extend class 'extends' RHS expression parsing Instead of only parsing a primary expression, we should also allow member expressions, call expressions, and tagged template literals (and optional chains, which we don't have yet). In the spec, all of this is covered by `LeftHandSideExpression` (https://tc39.es/ecma262/#prod-LeftHandSideExpression). --- Userland/Libraries/LibJS/Parser.cpp | 16 ++++++++++++++++ .../LibJS/Tests/classes/class-inheritance.js | 18 ++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/Userland/Libraries/LibJS/Parser.cpp b/Userland/Libraries/LibJS/Parser.cpp index 70eda3e757b..da6ab77466c 100644 --- a/Userland/Libraries/LibJS/Parser.cpp +++ b/Userland/Libraries/LibJS/Parser.cpp @@ -559,6 +559,22 @@ NonnullRefPtr Parser::parse_class_expression(bool expect_class_ if (match(TokenType::Extends)) { consume(); auto [expression, should_continue_parsing] = parse_primary_expression(); + + // Basically a (much) simplified parse_secondary_expression(). + for (;;) { + if (match(TokenType::TemplateLiteralStart)) { + auto template_literal = parse_template_literal(true); + expression = create_ast_node({ m_state.current_token.filename(), rule_start.position(), position() }, move(expression), move(template_literal)); + continue; + } + if (match(TokenType::BracketOpen) || match(TokenType::Period) || match(TokenType::ParenOpen)) { + auto precedence = g_operator_precedence.get(m_state.current_token.type()); + expression = parse_secondary_expression(move(expression), precedence); + continue; + } + break; + } + super_class = move(expression); (void)should_continue_parsing; } diff --git a/Userland/Libraries/LibJS/Tests/classes/class-inheritance.js b/Userland/Libraries/LibJS/Tests/classes/class-inheritance.js index 421e6a0c95e..36c6bd9f2c6 100644 --- a/Userland/Libraries/LibJS/Tests/classes/class-inheritance.js +++ b/Userland/Libraries/LibJS/Tests/classes/class-inheritance.js @@ -132,6 +132,24 @@ test("super constructor call from child class with argument", () => { expect(c.x).toBe(10); }); +test("advanced 'extends' RHS", () => { + const foo = { + bar() { + return { + baz() { + return function () { + return function () { + return { quux: Number }; + }; + }; + }, + }; + }, + }; + class Foo extends foo.bar()["baz"]()`qux`().quux {} + expect(new Foo()).toBeInstanceOf(Number); +}); + test("issue #7045, super constructor call from child class in catch {}", () => { class Parent { constructor(x) {