From 7cddfe84ca6a77d4d536a6c4f4eae6004ff085b4 Mon Sep 17 00:00:00 2001 From: Ilya Rodionov Date: Mon, 12 Jun 2023 13:14:11 +0300 Subject: [PATCH] [javascript] Class elements (fixes #3474, fixes #3451) --- javascript/javascript/JavaScriptParser.g4 | 34 +++++++++++++++---- javascript/javascript/examples/AsyncAwait.js | 3 +- javascript/javascript/examples/ClassFields.js | 13 +++++++ javascript/javascript/examples/ClassStatic.js | 12 +++++++ 4 files changed, 53 insertions(+), 9 deletions(-) create mode 100644 javascript/javascript/examples/ClassFields.js create mode 100644 javascript/javascript/examples/ClassStatic.js diff --git a/javascript/javascript/JavaScriptParser.g4 b/javascript/javascript/JavaScriptParser.g4 index 031438724d..001687c056 100644 --- a/javascript/javascript/JavaScriptParser.g4 +++ b/javascript/javascript/JavaScriptParser.g4 @@ -262,15 +262,29 @@ classTail ; classElement - : (Static | {this.n("static")}? identifier | Async)* (methodDefinition | assignable '=' objectLiteral ';') + : (Static | {this.n("static")}? identifier)? methodDefinition + | (Static | {this.n("static")}? identifier)? fieldDefinition + | (Static | {this.n("static")}? identifier) block | emptyStatement_ - | '#'? propertyName '=' singleExpression ; methodDefinition - : '*'? '#'? propertyName '(' formalParameterList? ')' functionBody - | '*'? '#'? getter '(' ')' functionBody - | '*'? '#'? setter '(' formalParameterList? ')' functionBody + : (Async {this.notLineTerminator()}?)? '*'? classElementName '(' formalParameterList? ')' functionBody + | '*'? getter '(' ')' functionBody + | '*'? setter '(' formalParameterList? ')' functionBody + ; + +fieldDefinition + : classElementName initializer? + ; + +classElementName + : propertyName + | privateIdentifier + ; + +privateIdentifier + : '#' identifierName ; formalParameterList @@ -386,6 +400,12 @@ singleExpression | '(' expressionSequence ')' # ParenthesizedExpression ; +initializer +// TODO: must be `= AssignmentExpression` and we have such label alredy but it doesn't respect the specification. +// See https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#prod-Initializer + : '=' singleExpression + ; + assignable : identifier | arrayLiteral @@ -461,11 +481,11 @@ bigintLiteral ; getter - : {this.n("get")}? identifier propertyName + : {this.n("get")}? identifier classElementName ; setter - : {this.n("set")}? identifier propertyName + : {this.n("set")}? identifier classElementName ; identifierName diff --git a/javascript/javascript/examples/AsyncAwait.js b/javascript/javascript/examples/AsyncAwait.js index ad96ee20a5..b734e3442a 100644 --- a/javascript/javascript/examples/AsyncAwait.js +++ b/javascript/javascript/examples/AsyncAwait.js @@ -3,9 +3,8 @@ async function f(){} class C { async method(){} static async method1(){} - async static #method2(){} + static async #method2(){} async *gen(){} - async get v(){return 1}; } async ()=>{}; diff --git a/javascript/javascript/examples/ClassFields.js b/javascript/javascript/examples/ClassFields.js new file mode 100644 index 0000000000..500692bd7c --- /dev/null +++ b/javascript/javascript/examples/ClassFields.js @@ -0,0 +1,13 @@ +const PREFIX = "prefix"; + +class ClassWithField { + field; + fieldWithInitializer = "instance field"; + [`${PREFIX}Field`] = "prefixed field"; +} + +const instance = new ClassWithField(); +console.log(Object.hasOwn(instance, "field")); // true +console.log(instance.field); // undefined +console.log(instance.fieldWithInitializer); // "instance field" +console.log(instance.prefixField); // "prefixed field" diff --git a/javascript/javascript/examples/ClassStatic.js b/javascript/javascript/examples/ClassStatic.js new file mode 100644 index 0000000000..15d3104627 --- /dev/null +++ b/javascript/javascript/examples/ClassStatic.js @@ -0,0 +1,12 @@ +class ClassWithStaticInitializationBlock { + static staticProperty1 = 'Property 1'; + static staticProperty2; + static { + this.staticProperty2 = 'Property 2'; + } +} + +console.log(ClassWithStaticInitializationBlock.staticProperty1); +// Expected output: "Property 1" +console.log(ClassWithStaticInitializationBlock.staticProperty2); +// Expected output: "Property 2" \ No newline at end of file