From eec7e9fd190496b026f4fde32efb706c26c78efa Mon Sep 17 00:00:00 2001 From: Matthew Gaudet Date: Thu, 27 May 2021 15:01:35 +0000 Subject: [PATCH] Bug 1712138 - Implement Reflect.parse for static class blocks r=arai Differential Revision: https://phabricator.services.mozilla.com/D115629 --- js/src/builtin/ReflectParse.cpp | 36 ++++++++++++++++++- .../jit-test/tests/class/class-static-02.js | 10 ++++++ js/src/jsast.tbl | 1 + .../non262/reflect-parse/PatternBuilders.js | 3 ++ .../non262/reflect-parse/class-static.js | 8 +++++ 5 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 js/src/jit-test/tests/class/class-static-02.js create mode 100644 js/src/tests/non262/reflect-parse/class-static.js diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp index 134b11c46b7a..36433a303fc6 100644 --- a/js/src/builtin/ReflectParse.cpp +++ b/js/src/builtin/ReflectParse.cpp @@ -635,6 +635,8 @@ class NodeBuilder { MutableHandleValue dst); [[nodiscard]] bool classField(HandleValue name, HandleValue initializer, TokenPos* pos, MutableHandleValue dst); + [[nodiscard]] bool staticClassBlock(HandleValue body, TokenPos* pos, + MutableHandleValue dst); /* * expressions @@ -1625,6 +1627,16 @@ bool NodeBuilder::classField(HandleValue name, HandleValue initializer, return newNode(AST_CLASS_FIELD, pos, "name", name, "init", initializer, dst); } +bool NodeBuilder::staticClassBlock(HandleValue body, TokenPos* pos, + MutableHandleValue dst) { + RootedValue cb(cx, callbacks[AST_STATIC_CLASS_BLOCK]); + if (!cb.isNull()) { + return callback(cb, body, pos, dst); + } + + return newNode(AST_STATIC_CLASS_BLOCK, pos, "body", body, dst); +} + bool NodeBuilder::classMembers(NodeVector& members, MutableHandleValue dst) { return newArray(members, dst); } @@ -1749,6 +1761,8 @@ class ASTSerializer { bool classMethod(ClassMethod* classMethod, MutableHandleValue dst); bool classField(ClassField* classField, MutableHandleValue dst); + bool staticClassBlock(StaticClassBlock* staticClassBlock, + MutableHandleValue dst); bool optIdentifier(HandleAtom atom, TokenPos* pos, MutableHandleValue dst) { if (!atom) { @@ -2621,7 +2635,13 @@ bool ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst) { members.infallibleAppend(prop); } else if (item->is()) { // StaticClassBlock* block = &item->as(); - MOZ_CRASH("MG:XXX: Still have to write reflect.parse for this"); + StaticClassBlock* scb = &item->as(); + MOZ_ASSERT(memberList->pn_pos.encloses(scb->pn_pos)); + RootedValue prop(cx); + if (!staticClassBlock(scb, &prop)) { + return false; + } + members.infallibleAppend(prop); } else if (!item->isKind(ParseNodeKind::DefaultConstructor)) { ClassMethod* method = &item->as(); MOZ_ASSERT(memberList->pn_pos.encloses(method->pn_pos)); @@ -2699,6 +2719,20 @@ bool ASTSerializer::classField(ClassField* classField, MutableHandleValue dst) { builder.classField(key, val, &classField->pn_pos, dst); } +bool ASTSerializer::staticClassBlock(StaticClassBlock* staticClassBlock, + MutableHandleValue dst) { + FunctionNode* fun = staticClassBlock->function(); + + NodeVector args(cx); + NodeVector defaults(cx); + + RootedValue body(cx), rest(cx); + rest.setNull(); + return functionArgsAndBody(fun->body(), args, defaults, false, false, &body, + &rest) && + builder.staticClassBlock(body, &staticClassBlock->pn_pos, dst); +} + bool ASTSerializer::leftAssociate(ListNode* node, MutableHandleValue dst) { MOZ_ASSERT(!node->empty()); diff --git a/js/src/jit-test/tests/class/class-static-02.js b/js/src/jit-test/tests/class/class-static-02.js new file mode 100644 index 000000000000..0450441bbf91 --- /dev/null +++ b/js/src/jit-test/tests/class/class-static-02.js @@ -0,0 +1,10 @@ +// |jit-test| --enable-class-static-blocks; + +Reflect.parse(`class A { + static { print('hi'); } +}`) + +Reflect.parse(`class A { + static x = 10; + static { this.x++ } +}`); \ No newline at end of file diff --git a/js/src/jsast.tbl b/js/src/jsast.tbl index 126a7f5ce4fb..209e776a5615 100644 --- a/js/src/jsast.tbl +++ b/js/src/jsast.tbl @@ -85,4 +85,5 @@ ASTDEF(AST_COMPUTED_NAME, "ComputedName", "computedNam ASTDEF(AST_CLASS_STMT, "ClassStatement", "classStatement") ASTDEF(AST_CLASS_METHOD, "ClassMethod", "classMethod") ASTDEF(AST_CLASS_FIELD, "ClassField", "classField") +ASTDEF(AST_STATIC_CLASS_BLOCK, "StaticClassBlock", "staticClassBlock") /* AST_LIMIT = last + 1 */ diff --git a/js/src/tests/non262/reflect-parse/PatternBuilders.js b/js/src/tests/non262/reflect-parse/PatternBuilders.js index e1ad9c046f1b..6415e405fbb1 100644 --- a/js/src/tests/non262/reflect-parse/PatternBuilders.js +++ b/js/src/tests/non262/reflect-parse/PatternBuilders.js @@ -170,6 +170,9 @@ function classField(id, init) { name: id, init: init }); } +function staticClassBlock(body) { + return Pattern({ type: "StaticClassBlock", body: body }); +} function funExpr(id, args, body, gen) { return Pattern({ type: "FunctionExpression", diff --git a/js/src/tests/non262/reflect-parse/class-static.js b/js/src/tests/non262/reflect-parse/class-static.js new file mode 100644 index 000000000000..07d79dcdd494 --- /dev/null +++ b/js/src/tests/non262/reflect-parse/class-static.js @@ -0,0 +1,8 @@ +// |reftest| skip-if(!xulRuntime.shell) shell-option(--enable-class-static-blocks) +// Classes +function testClassStaticBlock() { + + assertExpr("(class C { static { 2; } })", classExpr(ident("C"), null, [staticClassBlock(blockStmt([exprStmt(lit(2))]))])); +} + +runtest(testClassStaticBlock); \ No newline at end of file