summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordavidot <davidot@serenityos.org>2022-02-17 18:03:41 +0100
committerLinus Groh <mail@linusgroh.de>2022-02-18 13:47:47 +0000
commit2c6183da1ee9026a321dd4cd212891b8ca4ae0fe (patch)
treec21fd91c92a49005585dc8825f13db1f64cd368d
parent65bebb52416b182f8058a5619e142d309aff51cd (diff)
downloadserenity-2c6183da1ee9026a321dd4cd212891b8ca4ae0fe.zip
LibJS: Allow methods in classes named 'async'
Also add tests for all static, setter and getter cases.
-rw-r--r--Userland/Libraries/LibJS/Parser.cpp4
-rw-r--r--Userland/Libraries/LibJS/Tests/classes/class-constructor.js7
-rw-r--r--Userland/Libraries/LibJS/Tests/classes/class-getters.js12
-rw-r--r--Userland/Libraries/LibJS/Tests/classes/class-methods.js12
-rw-r--r--Userland/Libraries/LibJS/Tests/classes/class-setters.js15
-rw-r--r--Userland/Libraries/LibJS/Tests/classes/class-static-getters.js11
-rw-r--r--Userland/Libraries/LibJS/Tests/classes/class-static-setters.js14
-rw-r--r--Userland/Libraries/LibJS/Tests/classes/class-static.js11
8 files changed, 85 insertions, 1 deletions
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<ClassExpression> 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");
+});