From 2c6183da1ee9026a321dd4cd212891b8ca4ae0fe Mon Sep 17 00:00:00 2001 From: davidot Date: Thu, 17 Feb 2022 18:03:41 +0100 Subject: LibJS: Allow methods in classes named 'async' Also add tests for all static, setter and getter cases. --- Userland/Libraries/LibJS/Parser.cpp | 4 +++- .../Libraries/LibJS/Tests/classes/class-constructor.js | 7 +++++++ Userland/Libraries/LibJS/Tests/classes/class-getters.js | 12 ++++++++++++ Userland/Libraries/LibJS/Tests/classes/class-methods.js | 12 ++++++++++++ Userland/Libraries/LibJS/Tests/classes/class-setters.js | 15 +++++++++++++++ .../Libraries/LibJS/Tests/classes/class-static-getters.js | 11 +++++++++++ .../Libraries/LibJS/Tests/classes/class-static-setters.js | 14 ++++++++++++++ Userland/Libraries/LibJS/Tests/classes/class-static.js | 11 +++++++++++ 8 files changed, 85 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibJS/Parser.cpp b/Userland/Libraries/LibJS/Parser.cpp index 8bb5439ded..946c27a148 100644 --- a/Userland/Libraries/LibJS/Parser.cpp +++ b/Userland/Libraries/LibJS/Parser.cpp @@ -1086,7 +1086,9 @@ NonnullRefPtr Parser::parse_class_expression(bool expect_class_ if (match(TokenType::Async)) { auto lookahead_token = next_token(); - if (lookahead_token.type() != TokenType::Semicolon && lookahead_token.type() != TokenType::CurlyClose + // If async is followed by a Semicolon or CurlyClose it is a field (CurlyClose indicates end of class) + // Otherwise if it is followed by a ParenOpen it is a function named async + if (lookahead_token.type() != TokenType::Semicolon && lookahead_token.type() != TokenType::CurlyClose && lookahead_token.type() != TokenType::ParenOpen && !lookahead_token.trivia_contains_line_terminator()) { consume(); is_async = true; diff --git a/Userland/Libraries/LibJS/Tests/classes/class-constructor.js b/Userland/Libraries/LibJS/Tests/classes/class-constructor.js index 54a601e10c..98d70081c4 100644 --- a/Userland/Libraries/LibJS/Tests/classes/class-constructor.js +++ b/Userland/Libraries/LibJS/Tests/classes/class-constructor.js @@ -65,3 +65,10 @@ test("implicit constructor", () => { expect(new A()).toBeInstanceOf(A); }); + +test("can call constructor without parentheses", () => { + class A {} + + // prettier-ignore + expect(new A).toBeInstanceOf(A); +}); diff --git a/Userland/Libraries/LibJS/Tests/classes/class-getters.js b/Userland/Libraries/LibJS/Tests/classes/class-getters.js index 5b51910b3e..42472e7ac6 100644 --- a/Userland/Libraries/LibJS/Tests/classes/class-getters.js +++ b/Userland/Libraries/LibJS/Tests/classes/class-getters.js @@ -73,3 +73,15 @@ test("inherited getter overriding", () => { expect(new Child().x).toBe(10); }); + +test("static getter named 'async'", () => { + class A { + get async() { + return "getter named async"; + } + } + + const a = new A(); + expect("async" in a).toBeTrue(); + expect(a.async).toBe("getter named async"); +}); diff --git a/Userland/Libraries/LibJS/Tests/classes/class-methods.js b/Userland/Libraries/LibJS/Tests/classes/class-methods.js index 0add75635c..d300c555fe 100644 --- a/Userland/Libraries/LibJS/Tests/classes/class-methods.js +++ b/Userland/Libraries/LibJS/Tests/classes/class-methods.js @@ -49,3 +49,15 @@ test("extended name syntax", () => { expect(a[12]()).toBe(2); expect(a.hello()).toBe(3); }); + +test("method named 'async'", () => { + class A { + async() { + return "function named async"; + } + } + + const a = new A(); + expect("async" in a).toBeTrue(); + expect(a.async()).toBe("function named async"); +}); diff --git a/Userland/Libraries/LibJS/Tests/classes/class-setters.js b/Userland/Libraries/LibJS/Tests/classes/class-setters.js index 99c307994b..3df1e54749 100644 --- a/Userland/Libraries/LibJS/Tests/classes/class-setters.js +++ b/Userland/Libraries/LibJS/Tests/classes/class-setters.js @@ -106,3 +106,18 @@ test("inherited static setter overriding", () => { c.x = 10; expect(c.x).toBe(30); }); + +test("static setter named 'async'", () => { + let called = false; + class A { + set async(value) { + called = true; + expect(value).toBe("value set on setter named async"); + } + } + + const a = new A(); + expect("async" in a).toBeTrue(); + a.async = "value set on setter named async"; + expect(called).toBeTrue(); +}); diff --git a/Userland/Libraries/LibJS/Tests/classes/class-static-getters.js b/Userland/Libraries/LibJS/Tests/classes/class-static-getters.js index c158a00595..0801cec0a6 100644 --- a/Userland/Libraries/LibJS/Tests/classes/class-static-getters.js +++ b/Userland/Libraries/LibJS/Tests/classes/class-static-getters.js @@ -85,3 +85,14 @@ describe("errors", () => { }`).not.toEval(); }); }); + +test("static getter named 'async'", () => { + class A { + static get async() { + return "static getter named async"; + } + } + + expect("async" in A).toBeTrue(); + expect(A.async).toBe("static getter named async"); +}); diff --git a/Userland/Libraries/LibJS/Tests/classes/class-static-setters.js b/Userland/Libraries/LibJS/Tests/classes/class-static-setters.js index 38cbbe2394..89e58b7326 100644 --- a/Userland/Libraries/LibJS/Tests/classes/class-static-setters.js +++ b/Userland/Libraries/LibJS/Tests/classes/class-static-setters.js @@ -110,3 +110,17 @@ describe("errors", () => { }`).not.toEval(); }); }); + +test("static setter named 'async'", () => { + let called = false; + class A { + static set async(value) { + called = true; + expect(value).toBe("value set on static setter named async"); + } + } + + expect("async" in A).toBeTrue(); + A.async = "value set on static setter named async"; + expect(called).toBeTrue(); +}); diff --git a/Userland/Libraries/LibJS/Tests/classes/class-static.js b/Userland/Libraries/LibJS/Tests/classes/class-static.js index 5bfd28c3da..cb2436cf33 100644 --- a/Userland/Libraries/LibJS/Tests/classes/class-static.js +++ b/Userland/Libraries/LibJS/Tests/classes/class-static.js @@ -70,3 +70,14 @@ test("static method overriding", () => { expect(Parent.method()).toBe(3); expect(Child.method()).toBe(10); }); + +test("static function named 'async'", () => { + class A { + static async() { + return "static function named async"; + } + } + + expect("async" in A).toBeTrue(); + expect(A.async()).toBe("static function named async"); +}); -- cgit v1.2.3