From 675394ace07ce679457168a0318cde7cc664a2fc Mon Sep 17 00:00:00 2001 From: hufeng Date: Fri, 17 Feb 2023 17:12:29 +0800 Subject: [PATCH 1/2] Fix this value in commonjs module Signed-off-by: hufeng Change-Id: I53de58e63fa5121a3e479dee92c18a5c1be9ff7a --- es2panda/parser/commonjs.cpp | 19 ++++++++++++++-- es2panda/parser/parserImpl.h | 2 +- ts2panda/src/base/util.ts | 42 +++++++++++++++++++++--------------- 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/es2panda/parser/commonjs.cpp b/es2panda/parser/commonjs.cpp index d60656615b..b8836c246c 100644 --- a/es2panda/parser/commonjs.cpp +++ b/es2panda/parser/commonjs.cpp @@ -16,9 +16,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -46,11 +48,19 @@ void ParserImpl::AddCommonjsParams(ArenaVector ¶ms) void ParserImpl::AddCommonjsArgs(ArenaVector &args) { + ir::Expression *thisValue = AllocNode(binder::Binder::CJS_MANDATORY_PARAM_EXPORTS); + thisValue->AsIdentifier()->SetReference(); + args.push_back(thisValue); + + ArenaVector elements(Allocator()->Adapter()); for (auto argName : cjsMandatoryParams) { ir::Expression *arg = AllocNode(argName, Allocator()); arg->AsIdentifier()->SetReference(); - args.push_back(arg); + elements.push_back(arg); } + ir::ArrayExpression *cjsArgsArray = + AllocNode(ir::AstNodeType::ARRAY_EXPRESSION, std::move(elements), false); + args.push_back(cjsArgsArray); } void ParserImpl::ParseCommonjs() @@ -84,7 +94,12 @@ void ParserImpl::ParseCommonjs() // create CallExpression ArenaVector arguments(Allocator()->Adapter()); AddCommonjsArgs(arguments); - auto *callExpr = AllocNode(funcExpr, std::move(arguments), nullptr, false); + + auto *apply = AllocNode("apply"); + auto *funcApply = AllocNode( + funcExpr, apply, ir::MemberExpression::MemberExpressionKind::PROPERTY_ACCESS, false, false); + + auto *callExpr = AllocNode(funcApply, std::move(arguments), nullptr, false); // create ExpressionStatement auto *exprStatementNode = AllocNode(callExpr); diff --git a/es2panda/parser/parserImpl.h b/es2panda/parser/parserImpl.h index 008933c30a..075eeb23e6 100644 --- a/es2panda/parser/parserImpl.h +++ b/es2panda/parser/parserImpl.h @@ -220,7 +220,7 @@ private: * Transform the commonjs's AST by wrapping the sourceCode * e.g. (function (exports, require, module, __filename, __dirname) { * [Origin_SourceCode] - * })(exports, require, module, __filename, __dirname); + * }).apply(exports, [exports, require, module, __filename, __dirname]); */ void ParseCommonjs(); void AddCommonjsParams(ArenaVector ¶ms); diff --git a/ts2panda/src/base/util.ts b/ts2panda/src/base/util.ts index 6f5d787e48..a8fcc349e7 100644 --- a/ts2panda/src/base/util.ts +++ b/ts2panda/src/base/util.ts @@ -345,28 +345,36 @@ export function transformCommonjsModule(sourceFile: ts.SourceFile) { Transform the commonjs module's AST by wrap the sourceCode. (function (exports, require, module, __filename, __dirname) { [SourceCode] - })(exports, require, module, __filename, __dirname); + }).apply(exports, [exports, require, module, __filename, __dirname]); */ let newStatements = [ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createParenthesizedExpression(ts.factory.createFunctionExpression( - undefined, undefined, undefined, undefined, - [ - ts.factory.createParameterDeclaration(undefined, undefined, undefined, ts.factory.createIdentifier("exports"), undefined, undefined, undefined), - ts.factory.createParameterDeclaration(undefined, undefined, undefined, ts.factory.createIdentifier("require"), undefined, undefined, undefined), - ts.factory.createParameterDeclaration(undefined, undefined, undefined, ts.factory.createIdentifier("module"), undefined, undefined, undefined), - ts.factory.createParameterDeclaration(undefined, undefined, undefined, ts.factory.createIdentifier("__filename"), undefined, undefined, undefined), - ts.factory.createParameterDeclaration(undefined, undefined, undefined, ts.factory.createIdentifier("__dirname"), undefined, undefined, undefined) - ], - undefined, - ts.factory.createBlock(sourceFile.statements) - )), + ts.factory.createPropertyAccessExpression( + ts.factory.createParenthesizedExpression(ts.factory.createFunctionExpression( + undefined, undefined, undefined, undefined, + [ + ts.factory.createParameterDeclaration(undefined, undefined, undefined, ts.factory.createIdentifier("exports"), undefined, undefined, undefined), + ts.factory.createParameterDeclaration(undefined, undefined, undefined, ts.factory.createIdentifier("require"), undefined, undefined, undefined), + ts.factory.createParameterDeclaration(undefined, undefined, undefined, ts.factory.createIdentifier("module"), undefined, undefined, undefined), + ts.factory.createParameterDeclaration(undefined, undefined, undefined, ts.factory.createIdentifier("__filename"), undefined, undefined, undefined), + ts.factory.createParameterDeclaration(undefined, undefined, undefined, ts.factory.createIdentifier("__dirname"), undefined, undefined, undefined) + ], + undefined, + ts.factory.createBlock(sourceFile.statements) + )), + ts.factory.createIdentifier("apply") + ), undefined, [ ts.factory.createIdentifier("exports"), - ts.factory.createIdentifier("require"), - ts.factory.createIdentifier("module"), - ts.factory.createIdentifier("__filename"), - ts.factory.createIdentifier("__dirname") + ts.factory.createArrayLiteralExpression( + [ + ts.factory.createIdentifier("exports"), + ts.factory.createIdentifier("require"), + ts.factory.createIdentifier("module"), + ts.factory.createIdentifier("__filename"), + ts.factory.createIdentifier("__dirname") + ] + ) ] ))]; -- Gitee From d123609f5b333ed0d2eecec24133962fd2f1cd89 Mon Sep 17 00:00:00 2001 From: hufeng Date: Sat, 18 Feb 2023 17:14:01 +0800 Subject: [PATCH 2/2] Refactor wrapper by Reflect.apply invoking Signed-off-by: hufeng Change-Id: Ia4d602f2bf9ce6473f900c0a65c38efdff95eca3 --- es2panda/parser/commonjs.cpp | 29 +- es2panda/parser/parserImpl.h | 13 +- .../test-top-level-this-value-expected.txt | 2 + .../commonjs/test-top-level-this-value.js | 4 + .../test-commonjs-wrapper-expected.txt | 473 ++++++++++++++++++ .../parser/commonjs/test-commonjs-wrapper.js | 2 + es2panda/test/runner.py | 2 + ts2panda/src/base/util.ts | 24 +- ts2panda/tests/commonjs.test.ts | 25 +- 9 files changed, 541 insertions(+), 33 deletions(-) create mode 100644 es2panda/test/compiler/commonjs/test-top-level-this-value-expected.txt create mode 100644 es2panda/test/compiler/commonjs/test-top-level-this-value.js create mode 100644 es2panda/test/parser/commonjs/test-commonjs-wrapper-expected.txt create mode 100644 es2panda/test/parser/commonjs/test-commonjs-wrapper.js diff --git a/es2panda/parser/commonjs.cpp b/es2panda/parser/commonjs.cpp index b8836c246c..ea43036352 100644 --- a/es2panda/parser/commonjs.cpp +++ b/es2panda/parser/commonjs.cpp @@ -46,27 +46,31 @@ void ParserImpl::AddCommonjsParams(ArenaVector ¶ms) } } -void ParserImpl::AddCommonjsArgs(ArenaVector &args) +void ParserImpl::AddReflectApplyArgs(ArenaVector &args, ir::FunctionExpression *wrapper) { - ir::Expression *thisValue = AllocNode(binder::Binder::CJS_MANDATORY_PARAM_EXPORTS); + ASSERT(wrapper != nullptr); + // wrapper + args.push_back(wrapper); + // thisValue + ir::Expression *thisValue = AllocNode(binder::Binder::CJS_MANDATORY_PARAM_EXPORTS, Allocator()); thisValue->AsIdentifier()->SetReference(); args.push_back(thisValue); - + // wrapper's arguments ArenaVector elements(Allocator()->Adapter()); for (auto argName : cjsMandatoryParams) { ir::Expression *arg = AllocNode(argName, Allocator()); arg->AsIdentifier()->SetReference(); elements.push_back(arg); } - ir::ArrayExpression *cjsArgsArray = + ir::ArrayExpression *wrapperArgsArray = AllocNode(ir::AstNodeType::ARRAY_EXPRESSION, std::move(elements), false); - args.push_back(cjsArgsArray); + args.push_back(wrapperArgsArray); } void ParserImpl::ParseCommonjs() { // create FunctionExpression as callee - ir::FunctionExpression *funcExpr = nullptr; + ir::FunctionExpression *wrapper = nullptr; { FunctionContext functionContext(this, ParserStatus::FUNCTION | ParserStatus::ALLOW_NEW_TARGET); FunctionParameterContext funcParamContext(&context_, Binder()); @@ -88,18 +92,19 @@ void ParserImpl::ParseCommonjs() functionScope->BindNode(funcNode); funcParamScope->BindNode(funcNode); - funcExpr = AllocNode(funcNode); + wrapper = AllocNode(funcNode); } // create CallExpression ArenaVector arguments(Allocator()->Adapter()); - AddCommonjsArgs(arguments); + AddReflectApplyArgs(arguments, wrapper); - auto *apply = AllocNode("apply"); - auto *funcApply = AllocNode( - funcExpr, apply, ir::MemberExpression::MemberExpressionKind::PROPERTY_ACCESS, false, false); + auto *apply = AllocNode("apply", Allocator()); + auto *reflect = AllocNode("Reflect", Allocator()); + auto *reflectApply = AllocNode(reflect, apply, + ir::MemberExpression::MemberExpressionKind::PROPERTY_ACCESS, false, false); - auto *callExpr = AllocNode(funcApply, std::move(arguments), nullptr, false); + auto *callExpr = AllocNode(reflectApply, std::move(arguments), nullptr, false); // create ExpressionStatement auto *exprStatementNode = AllocNode(callExpr); diff --git a/es2panda/parser/parserImpl.h b/es2panda/parser/parserImpl.h index 075eeb23e6..046749c56c 100644 --- a/es2panda/parser/parserImpl.h +++ b/es2panda/parser/parserImpl.h @@ -216,15 +216,18 @@ private: [[nodiscard]] std::unique_ptr InitLexer(const std::string &fileName, const std::string &source); void ParseScript(); void ParseModule(); + /* - * Transform the commonjs's AST by wrapping the sourceCode - * e.g. (function (exports, require, module, __filename, __dirname) { - * [Origin_SourceCode] - * }).apply(exports, [exports, require, module, __filename, __dirname]); + * Transform the commonjs module's AST by wrap the sourceCode & use Reflect.apply to invoke this wrapper with [this] + * pointing to [exports] object + * + * Reflect.apply(function (exports, require, module, __filename, __dirname) { + * [SourceCode] + * }, exports, [exports, require, module, __filename, __dirname]); */ void ParseCommonjs(); void AddCommonjsParams(ArenaVector ¶ms); - void AddCommonjsArgs(ArenaVector &args); + void AddReflectApplyArgs(ArenaVector &args, ir::FunctionExpression *wrapper); void ParseProgram(ScriptKind kind); static ExpressionParseFlags CarryExpressionParserFlag(ExpressionParseFlags origin, ExpressionParseFlags carry); static ExpressionParseFlags CarryPatternFlags(ExpressionParseFlags flags); diff --git a/es2panda/test/compiler/commonjs/test-top-level-this-value-expected.txt b/es2panda/test/compiler/commonjs/test-top-level-this-value-expected.txt new file mode 100644 index 0000000000..25f789b0f9 --- /dev/null +++ b/es2panda/test/compiler/commonjs/test-top-level-this-value-expected.txt @@ -0,0 +1,2 @@ +123 +true diff --git a/es2panda/test/compiler/commonjs/test-top-level-this-value.js b/es2panda/test/compiler/commonjs/test-top-level-this-value.js new file mode 100644 index 0000000000..c897f30129 --- /dev/null +++ b/es2panda/test/compiler/commonjs/test-top-level-this-value.js @@ -0,0 +1,4 @@ +let a = 123; +module.exports.a = a; +print(this.a); +print(exports === this); \ No newline at end of file diff --git a/es2panda/test/parser/commonjs/test-commonjs-wrapper-expected.txt b/es2panda/test/parser/commonjs/test-commonjs-wrapper-expected.txt new file mode 100644 index 0000000000..898b2bf36d --- /dev/null +++ b/es2panda/test/parser/commonjs/test-commonjs-wrapper-expected.txt @@ -0,0 +1,473 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "Identifier", + "name": "Reflect", + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "property": { + "type": "Identifier", + "name": "apply", + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "computed": false, + "optional": false, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "arguments": [ + { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": null, + "generator": false, + "async": false, + "expression": false, + "params": [ + { + "type": "Identifier", + "name": "exports", + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "Identifier", + "name": "require", + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "Identifier", + "name": "module", + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "Identifier", + "name": "__filename", + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "Identifier", + "name": "__dirname", + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + } + ], + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "a", + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 6 + } + } + }, + "init": { + "type": "NumberLiteral", + "value": 123, + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 1, + "column": 12 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 12 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 13 + } + } + }, + { + "type": "ExpressionStatement", + "expression": { + "type": "AssignmentExpression", + "operator": "=", + "left": { + "type": "MemberExpression", + "object": { + "type": "MemberExpression", + "object": { + "type": "Identifier", + "name": "module", + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 7 + } + } + }, + "property": { + "type": "Identifier", + "name": "exports", + "loc": { + "start": { + "line": 2, + "column": 8 + }, + "end": { + "line": 2, + "column": 15 + } + } + }, + "computed": false, + "optional": false, + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 15 + } + } + }, + "property": { + "type": "Identifier", + "name": "a", + "loc": { + "start": { + "line": 2, + "column": 16 + }, + "end": { + "line": 2, + "column": 17 + } + } + }, + "computed": false, + "optional": false, + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 17 + } + } + }, + "right": { + "type": "Identifier", + "name": "a", + "loc": { + "start": { + "line": 2, + "column": 20 + }, + "end": { + "line": 2, + "column": 21 + } + } + }, + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 21 + } + } + }, + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 22 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 2, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "Identifier", + "name": "exports", + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "ArrayExpression", + "elements": [ + { + "type": "Identifier", + "name": "exports", + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "Identifier", + "name": "require", + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "Identifier", + "name": "module", + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "Identifier", + "name": "__filename", + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "Identifier", + "name": "__dirname", + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + } + ], + "optional": false, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } +} diff --git a/es2panda/test/parser/commonjs/test-commonjs-wrapper.js b/es2panda/test/parser/commonjs/test-commonjs-wrapper.js new file mode 100644 index 0000000000..3483488aab --- /dev/null +++ b/es2panda/test/parser/commonjs/test-commonjs-wrapper.js @@ -0,0 +1,2 @@ +let a = 123; +module.exports.a = a; \ No newline at end of file diff --git a/es2panda/test/runner.py b/es2panda/test/runner.py index 572fcfd186..d02b38c339 100755 --- a/es2panda/test/runner.py +++ b/es2panda/test/runner.py @@ -846,6 +846,7 @@ def main(): ["--parse-only", "--module", "--extension=ts"]) runner.add_directory("parser/ts/type_checker", "ts", ["--parse-only", "--enable-type-check", "--module", "--extension=ts"]) + runner.add_directory("parser/commonjs", "js", ["--commonjs", "--parse-only", "--dump-ast"]) runners.append(runner) @@ -859,6 +860,7 @@ def main(): runner = CompilerRunner(args) runner.add_directory("compiler/js", "js", []) runner.add_directory("compiler/ts", "ts", ["--extension=ts"]) + runner.add_directory("compiler/commonjs", "js", ["--commonjs"]) runners.append(runner) diff --git a/ts2panda/src/base/util.ts b/ts2panda/src/base/util.ts index a8fcc349e7..24bd25e9a9 100644 --- a/ts2panda/src/base/util.ts +++ b/ts2panda/src/base/util.ts @@ -342,14 +342,20 @@ export function isBase64Str(input: string): boolean { export function transformCommonjsModule(sourceFile: ts.SourceFile) { /* - Transform the commonjs module's AST by wrap the sourceCode. - (function (exports, require, module, __filename, __dirname) { - [SourceCode] - }).apply(exports, [exports, require, module, __filename, __dirname]); - */ + * Transform the commonjs module's AST by wrap the sourceCode & use Reflect.apply to invoke this wrapper with [this] + * pointing to [exports] object + * + * Reflect.apply(function (exports, require, module, __filename, __dirname) { + * [SourceCode] + * }, exports, [exports, require, module, __filename, __dirname]); + */ let newStatements = [ts.factory.createExpressionStatement(ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression( - ts.factory.createParenthesizedExpression(ts.factory.createFunctionExpression( + ts.factory.createIdentifier("Reflect"), ts.factory.createIdentifier("apply") + ), + undefined, + [ + ts.factory.createFunctionExpression( undefined, undefined, undefined, undefined, [ ts.factory.createParameterDeclaration(undefined, undefined, undefined, ts.factory.createIdentifier("exports"), undefined, undefined, undefined), @@ -360,11 +366,7 @@ export function transformCommonjsModule(sourceFile: ts.SourceFile) { ], undefined, ts.factory.createBlock(sourceFile.statements) - )), - ts.factory.createIdentifier("apply") - ), - undefined, - [ + ), ts.factory.createIdentifier("exports"), ts.factory.createArrayLiteralExpression( [ diff --git a/ts2panda/tests/commonjs.test.ts b/ts2panda/tests/commonjs.test.ts index f814112ec4..7eb54188e7 100644 --- a/ts2panda/tests/commonjs.test.ts +++ b/ts2panda/tests/commonjs.test.ts @@ -20,14 +20,18 @@ import 'mocha'; import { checkInstructions, SnippetCompiler } from "./utils/base"; import { Callarg1, - Callrange, + Callthis3, + Createemptyarray, Definefunc, Returnundefined, Stobjbyname, + Stownbyindex, + Tryldglobalbyname, Imm, Lda, Ldai, LdaStr, + Ldobjbyname, Mov, Sta, VReg, @@ -49,20 +53,31 @@ describe("CommonJsTest", function () { CmdOptions.isCommonJs = () => {return false}; let funcMainInsns = snippetCompiler.getGlobalInsns(); let expected = [ - new Definefunc(new Imm(0), 'UnitTest.#1#', new Imm(5)), + new Tryldglobalbyname(new Imm(0), "Reflect"), new Sta(new VReg()), new Lda(new VReg()), + new Ldobjbyname(new Imm(1), "apply"), new Sta(new VReg()), - new Lda(new VReg()), + new Definefunc(new Imm(3), 'UnitTest.#1#', new Imm(5)), new Sta(new VReg()), new Lda(new VReg()), new Sta(new VReg()), - new Lda(new VReg()), + new Createemptyarray(new Imm(4)), new Sta(new VReg()), new Lda(new VReg()), + new Stownbyindex(new Imm(5), new VReg(), new Imm(0)), + new Lda(new VReg()), + new Stownbyindex(new Imm(7), new VReg(), new Imm(1)), + new Lda(new VReg()), + new Stownbyindex(new Imm(9), new VReg(), new Imm(2)), + new Lda(new VReg()), + new Stownbyindex(new Imm(11), new VReg(), new Imm(3)), + new Lda(new VReg()), + new Stownbyindex(new Imm(13), new VReg(), new Imm(4)), + new Lda(new VReg()), new Sta(new VReg()), new Lda(new VReg()), - new Callrange(new Imm(1), new Imm(5), [new VReg(), new VReg(), new VReg(), new VReg(), new VReg()]), + new Callthis3(new Imm(15), new VReg(), new VReg(), new VReg(), new VReg()), new Returnundefined(), ]; expect(checkInstructions(funcMainInsns, expected)).to.be.true; -- Gitee