1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "transformer.h"
17
18 #include "ir/base/scriptFunction.h"
19 #include "ir/base/classDefinition.h"
20 #include "ir/expressions/assignmentExpression.h"
21 #include "ir/expressions/binaryExpression.h"
22 #include "ir/expressions/callExpression.h"
23 #include "ir/expressions/functionExpression.h"
24 #include "ir/expressions/identifier.h"
25 #include "ir/expressions/memberExpression.h"
26 #include "ir/expressions/objectExpression.h"
27 #include "ir/module/exportNamedDeclaration.h"
28 #include "ir/statements/blockStatement.h"
29 #include "ir/statements/classDeclaration.h"
30 #include "ir/statements/emptyStatement.h"
31 #include "ir/statements/expressionStatement.h"
32 #include "ir/statements/functionDeclaration.h"
33 #include "ir/statements/variableDeclaration.h"
34 #include "ir/statements/variableDeclarator.h"
35 #include "ir/ts/tsImportEqualsDeclaration.h"
36 #include "ir/ts/tsModuleBlock.h"
37 #include "ir/ts/tsModuleDeclaration.h"
38 #include "ir/ts/tsQualifiedName.h"
39 #include "util/helpers.h"
40
41
42 namespace panda::es2panda::parser {
43
Transform(Program * program)44 void Transformer::Transform(Program *program)
45 {
46 program_ = program;
47 if (Extension() == ScriptExtension::TS) {
48 TransformFromTS();
49 }
50 }
51
TransformFromTS()52 void Transformer::TransformFromTS()
53 {
54 ASSERT(Extension() == ScriptExtension::TS);
55 VisitTSNodes(program_->Ast());
56 }
57
VisitTSNodes(ir::AstNode * parent)58 ir::AstNode *Transformer::VisitTSNodes(ir::AstNode *parent)
59 {
60 if (!parent) {
61 return nullptr;
62 }
63 parent->UpdateSelf([this](auto *childNode) { return VisitTSNode(childNode); }, Binder());
64 return parent;
65 }
66
FindExportVariableInTsModuleScope(util::StringView name) const67 binder::Scope *Transformer::FindExportVariableInTsModuleScope(util::StringView name) const
68 {
69 bool isExport = false;
70 auto currentScope = Scope();
71 while (currentScope != nullptr) {
72 binder::Variable *v = currentScope->FindLocal(name, binder::ResolveBindingOptions::ALL);
73 bool isTSModuleScope = currentScope->IsTSModuleScope();
74 if (v != nullptr) {
75 if (!v->HasFlag(binder::VariableFlags::VAR)) {
76 break;
77 }
78 if (isTSModuleScope && currentScope->AsTSModuleScope()->FindExportVariable(name)) {
79 isExport = true;
80 }
81 break;
82 }
83 if (currentScope->InLocalTSBindings(name) &&
84 !currentScope->FindLocalTSVariable<binder::TSBindingType::IMPORT_EQUALS>(name)) {
85 break;
86 }
87 if (isTSModuleScope && currentScope->AsTSModuleScope()->InExportBindings(name)) {
88 isExport = true;
89 break;
90 }
91 currentScope = currentScope->Parent();
92 }
93 if (!isExport) {
94 return nullptr;
95 }
96 return currentScope;
97 }
98
VisitTSNode(ir::AstNode * childNode)99 ir::UpdateNodes Transformer::VisitTSNode(ir::AstNode *childNode)
100 {
101 ASSERT(childNode != nullptr);
102 switch (childNode->Type()) {
103 case ir::AstNodeType::IDENTIFIER: {
104 auto *ident = childNode->AsIdentifier();
105 if (!ident->IsReference() || !IsTsModule()) {
106 return VisitTSNodes(childNode);
107 }
108
109 auto name = ident->Name();
110 auto scope = FindExportVariableInTsModuleScope(name);
111 if (scope) {
112 auto moduleName = FindTSModuleNameByScope(scope);
113 auto *id = AllocNode<ir::Identifier>(moduleName, Allocator());
114 id->AsIdentifier()->SetReference();
115 auto *res = AllocNode<ir::MemberExpression>(id, AllocNode<ir::Identifier>(name, Allocator()),
116 ir::MemberExpression::MemberExpressionKind::PROPERTY_ACCESS, false, false);
117 SetOriginalNode(res, childNode);
118 return res;
119 }
120
121 return VisitTSNodes(childNode);
122 }
123 case ir::AstNodeType::TS_MODULE_DECLARATION: {
124 auto *node = childNode->AsTSModuleDeclaration();
125 if (node->Declare() || !node->IsInstantiated()) {
126 return childNode;
127 }
128 auto res = VisitTsModuleDeclaration(node);
129 SetOriginalNode(res, childNode);
130 return res;
131 }
132 case ir::AstNodeType::EXPORT_NAMED_DECLARATION: {
133 auto *node = childNode->AsExportNamedDeclaration();
134 auto *decl = node->Decl();
135 if (!decl) {
136 return VisitTSNodes(childNode);
137 }
138
139 if (decl->IsTSModuleDeclaration()) {
140 auto *tsModuleDeclaration = decl->AsTSModuleDeclaration();
141 if (tsModuleDeclaration->Declare() || !tsModuleDeclaration->IsInstantiated()) {
142 return childNode;
143 }
144 auto res = VisitTsModuleDeclaration(tsModuleDeclaration, true);
145 SetOriginalNode(res, childNode);
146 return res;
147 }
148
149 if (!IsTsModule()) {
150 return VisitTSNodes(childNode);
151 }
152
153 auto res = VisitExportNamedVariable(decl);
154 SetOriginalNode(res, childNode);
155 return res;
156 }
157 case ir::AstNodeType::TS_IMPORT_EQUALS_DECLARATION: {
158 auto *node = childNode->AsTSImportEqualsDeclaration();
159 auto *express = node->ModuleReference();
160 if (express->IsTSExternalModuleReference()) {
161 return VisitTSNodes(childNode);
162 }
163 auto *res = VisitTsImportEqualsDeclaration(node);
164 SetOriginalNode(res, childNode);
165 return res;
166 }
167 default: {
168 return VisitTSNodes(childNode);
169 }
170 }
171 }
172
VisitTsImportEqualsDeclaration(ir::TSImportEqualsDeclaration * node)173 ir::AstNode *Transformer::VisitTsImportEqualsDeclaration(ir::TSImportEqualsDeclaration *node)
174 {
175 auto *express = node->ModuleReference();
176 if (!IsInstantiatedTSModule(express)) {
177 return node;
178 }
179 auto name = node->Id()->Name();
180 if (IsTsModule() && node->IsExport()) {
181 auto moduleName = GetCurrentTSModuleName();
182 auto *id = AllocNode<ir::Identifier>(moduleName, Allocator());
183 id->AsIdentifier()->SetReference();
184 auto *left = AllocNode<ir::MemberExpression>(id, AllocNode<ir::Identifier>(name, Allocator()),
185 ir::MemberExpression::MemberExpressionKind::PROPERTY_ACCESS, false, false);
186 ir::Expression *right = CreateMemberExpressionFromQualified(express);
187 auto *assignExpr = AllocNode<ir::AssignmentExpression>(left, right,
188 lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
189 auto *res = AllocNode<ir::ExpressionStatement>(assignExpr);
190 return res;
191 }
192
193 ir::Expression *init = CreateMemberExpressionFromQualified(express);
194 ir::Statement *res = CreateVariableDeclarationWithIdentify(name, VariableParsingFlags::VAR, node,
195 node->IsExport(), init);
196 if (node->IsExport()) {
197 ArenaVector<ir::ExportSpecifier *> specifiers(Allocator()->Adapter());
198 res = AllocNode<ir::ExportNamedDeclaration>(res, std::move(specifiers));
199 AddExportLocalEntryItem(name, node->Id());
200 }
201 return res;
202 }
203
IsInstantiatedTSModule(const ir::Expression * node) const204 bool Transformer::IsInstantiatedTSModule(const ir::Expression *node) const
205 {
206 auto *var = FindTSModuleVariable(node, Scope());
207 if (var == nullptr) {
208 return true;
209 }
210 auto *decl = var->Declaration();
211 ASSERT(decl->IsNamespaceDecl());
212 auto tsModules = decl->AsNamespaceDecl()->Decls();
213 for (auto *it : tsModules) {
214 if (it->IsInstantiated()) {
215 return true;
216 }
217 }
218 return false;
219 }
220
FindTSModuleVariable(const ir::Expression * node,binder::Scope * scope) const221 binder::Variable *Transformer::FindTSModuleVariable(const ir::Expression *node, binder::Scope *scope) const
222 {
223 if (node == nullptr) {
224 return nullptr;
225 }
226 if (node->IsTSQualifiedName()) {
227 auto *tsQualifiedName = node->AsTSQualifiedName();
228 auto *var = FindTSModuleVariable(tsQualifiedName->Left(), scope);
229 if (var == nullptr) {
230 return nullptr;
231 }
232 auto *exportTSBindings = var->AsNamespaceVariable()->GetExportBindings();
233 auto name = tsQualifiedName->Right()->Name();
234 auto *res = exportTSBindings->FindExportTSVariable<binder::TSBindingType::NAMESPACE>(name);
235 if (res != nullptr) {
236 return res;
237 }
238 res = exportTSBindings->FindExportTSVariable<binder::TSBindingType::IMPORT_EQUALS>(name);
239 if (res != nullptr) {
240 auto *node = res->Declaration()->Node();
241 return FindTSModuleVariable(node->Parent()->AsTSImportEqualsDeclaration()->ModuleReference(),
242 res->AsImportEqualsVariable()->GetScope());
243 }
244 return nullptr;
245 }
246 ASSERT(node->IsIdentifier());
247 auto name = node->AsIdentifier()->Name();
248 auto *currentScope = scope;
249 while (currentScope != nullptr) {
250 auto *res = currentScope->FindLocalTSVariable<binder::TSBindingType::NAMESPACE>(name);
251 if (res == nullptr && currentScope->IsTSModuleScope()) {
252 res = currentScope->AsTSModuleScope()->FindExportTSVariable<binder::TSBindingType::NAMESPACE>(name);
253 }
254 if (res != nullptr) {
255 return res;
256 }
257 res = currentScope->FindLocalTSVariable<binder::TSBindingType::IMPORT_EQUALS>(name);
258 if (res == nullptr && currentScope->IsTSModuleScope()) {
259 res = currentScope->AsTSModuleScope()->FindExportTSVariable<binder::TSBindingType::IMPORT_EQUALS>(name);
260 }
261 if (res != nullptr) {
262 auto *node = res->Declaration()->Node();
263 return FindTSModuleVariable(node->Parent()->AsTSImportEqualsDeclaration()->ModuleReference(),
264 res->AsImportEqualsVariable()->GetScope());
265 }
266 currentScope = currentScope->Parent();
267 }
268 return nullptr;
269 }
270
VisitExportNamedVariable(ir::Statement * decl)271 std::vector<ir::AstNode *> Transformer::VisitExportNamedVariable(ir::Statement *decl)
272 {
273 std::vector<ir::AstNode *> res;
274 if (decl->IsVariableDeclaration()) {
275 auto declarators = decl->AsVariableDeclaration()->Declarators();
276 for (auto *it : declarators) {
277 if (it->Init()) {
278 auto *left = std::get<ir::AstNode *>(VisitTSNode(it->Id()))->AsExpression();
279 auto *right = std::get<ir::AstNode *>(VisitTSNode(it->Init()))->AsExpression();
280 auto *assignExpr = AllocNode<ir::AssignmentExpression>(left, right,
281 lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
282 res.push_back(AllocNode<ir::ExpressionStatement>(assignExpr));
283 }
284 }
285 } else if (decl->IsFunctionDeclaration() || decl->IsClassDeclaration()) {
286 res.push_back(VisitTSNodes(decl));
287 auto name = decl->IsFunctionDeclaration() ?
288 decl->AsFunctionDeclaration()->Function()->Id() :
289 decl->AsClassDeclaration()->Definition()->Ident();
290 ASSERT(name != nullptr);
291 res.push_back(CreateTsModuleAssignment(name->Name()));
292 }
293 return res;
294 }
295
CreateMemberExpressionFromQualified(ir::Expression * node)296 ir::Expression *Transformer::CreateMemberExpressionFromQualified(ir::Expression *node)
297 {
298 if (node->IsTSQualifiedName()) {
299 auto *tsQualifiedName = node->AsTSQualifiedName();
300 auto *left = CreateMemberExpressionFromQualified(tsQualifiedName->Left());
301 auto *right = AllocNode<ir::Identifier>(tsQualifiedName->Right()->Name(), Allocator());
302 return AllocNode<ir::MemberExpression>(left, right,
303 ir::MemberExpression::MemberExpressionKind::PROPERTY_ACCESS, false, false);
304 }
305 ASSERT(node->IsIdentifier());
306 auto *id = AllocNode<ir::Identifier>(node->AsIdentifier()->Name(), Allocator());
307 id->AsIdentifier()->SetReference();
308 return id;
309 }
310
SetOriginalNode(ir::UpdateNodes res,ir::AstNode * originalNode) const311 void Transformer::SetOriginalNode(ir::UpdateNodes res, ir::AstNode *originalNode) const
312 {
313 if (std::holds_alternative<ir::AstNode *>(res)) {
314 auto *node = std::get<ir::AstNode *>(res);
315 if (node == nullptr || node == originalNode) {
316 return;
317 }
318 node->SetOriginal(originalNode);
319 node->SetRange(originalNode->Range());
320 } else {
321 auto nodes = std::get<std::vector<ir::AstNode *>>(res);
322 for (auto *it : nodes) {
323 it->SetOriginal(originalNode);
324 it->SetRange(originalNode->Range());
325 }
326 }
327 }
328
CreateTsModuleAssignment(util::StringView name)329 ir::ExpressionStatement *Transformer::CreateTsModuleAssignment(util::StringView name)
330 {
331 auto moduleName = GetCurrentTSModuleName();
332 auto *id = AllocNode<ir::Identifier>(moduleName, Allocator());
333 id->AsIdentifier()->SetReference();
334 auto *left = AllocNode<ir::MemberExpression>(id, AllocNode<ir::Identifier>(name, Allocator()),
335 ir::MemberExpression::MemberExpressionKind::PROPERTY_ACCESS, false, false);
336 auto *right = AllocNode<ir::Identifier>(name, Allocator());
337 right->AsIdentifier()->SetReference();
338 auto *assignExpr = AllocNode<ir::AssignmentExpression>(left, right, lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
339 return AllocNode<ir::ExpressionStatement>(assignExpr);
340 }
341
GetNameFromModuleDeclaration(ir::TSModuleDeclaration * node) const342 util::StringView Transformer::GetNameFromModuleDeclaration(ir::TSModuleDeclaration *node) const
343 {
344 return node->Name()->AsIdentifier()->Name();
345 }
346
CreateVariableDeclarationWithIdentify(util::StringView name,VariableParsingFlags flags,ir::AstNode * node,bool isExport,ir::Expression * init)347 ir::VariableDeclaration *Transformer::CreateVariableDeclarationWithIdentify(util::StringView name,
348 VariableParsingFlags flags,
349 ir::AstNode *node,
350 bool isExport,
351 ir::Expression *init)
352 {
353 auto *ident = AllocNode<ir::Identifier>(name, Allocator());
354 ident->AsIdentifier()->SetReference();
355 auto *declarator = AllocNode<ir::VariableDeclarator>(ident, init);
356 ArenaVector<ir::VariableDeclarator *> declarators(Allocator()->Adapter());
357 declarators.push_back(declarator);
358
359 binder::Decl *decl = nullptr;
360 binder::DeclarationFlags declflag = isExport ?
361 binder::DeclarationFlags::EXPORT :
362 binder::DeclarationFlags::NONE;
363 auto varKind = ir::VariableDeclaration::VariableDeclarationKind::VAR;
364 if (flags & VariableParsingFlags::VAR) {
365 decl = Binder()->AddDecl<binder::VarDecl>(node->Start(), declflag, name);
366 } else if (flags & VariableParsingFlags::LET) {
367 varKind = ir::VariableDeclaration::VariableDeclarationKind::LET;
368 decl = Binder()->AddDecl<binder::LetDecl>(node->Start(), declflag, name);
369 } else {
370 varKind = ir::VariableDeclaration::VariableDeclarationKind::CONST;
371 decl = Binder()->AddDecl<binder::ConstDecl>(node->Start(), declflag, name);
372 }
373
374 auto *declaration = AllocNode<ir::VariableDeclaration>(varKind, std::move(declarators), false);
375 decl->BindNode(declaration);
376
377 return declaration;
378 }
379
GetParamName(ir::TSModuleDeclaration * node,util::StringView name) const380 util::StringView Transformer::GetParamName(ir::TSModuleDeclaration *node, util::StringView name) const
381 {
382 auto scope = node->Scope();
383 if (!scope->HasVariableName(name)) {
384 return name;
385 }
386
387 auto pramaName = name;
388 uint32_t idx = 0;
389 do {
390 std::stringstream ss;
391 ss << name;
392 idx++;
393 ss << "_" << std::to_string(idx);
394 util::UString internalName(ss.str(), Allocator());
395 pramaName = internalName.View();
396 } while (Binder()->HasVariableName(pramaName));
397 Binder()->AddDeclarationName(pramaName);
398 return pramaName;
399 }
400
CreateCallExpressionForTsModule(ir::TSModuleDeclaration * node,util::StringView name,bool isExport)401 ir::CallExpression *Transformer::CreateCallExpressionForTsModule(ir::TSModuleDeclaration *node,
402 util::StringView name,
403 bool isExport)
404 {
405 ir::ScriptFunction *funcNode = nullptr;
406
407 binder::FunctionScope *funcScope = node->Scope();
408 binder::FunctionParamScope *funcParamScope = funcScope->ParamScope();
409 auto paramName = GetParamName(node, name);
410 {
411 auto paramScopeCtx = binder::LexicalScope<binder::FunctionParamScope>::Enter(Binder(), funcParamScope);
412
413 ArenaVector<ir::Expression *> params(Allocator()->Adapter());
414 auto *parameter = AllocNode<ir::Identifier>(paramName, Allocator());
415 parameter->AsIdentifier()->SetReference();
416 Binder()->AddParamDecl(parameter);
417 params.push_back(parameter);
418
419 ir::BlockStatement *blockNode = nullptr;
420 {
421 auto scopeCtx = binder::LexicalScope<binder::FunctionScope>::Enter(Binder(), funcScope);
422 tsModuleList_.push_back({paramName, funcScope});
423 if (node->Body()->IsTSModuleDeclaration()) {
424 auto *tsModule = node->Body()->AsTSModuleDeclaration();
425 auto body = std::get<std::vector<ir::AstNode *>>(VisitTsModuleDeclaration(tsModule, true));
426 ArenaVector<ir::Statement *> statements(Allocator()->Adapter());
427 for (auto *it : body) {
428 statements.push_back(static_cast<ir::Statement *>(it));
429 }
430 blockNode = AllocNode<ir::BlockStatement>(funcScope, std::move(statements));
431 } else {
432 auto body = VisitTSNodes(node->Body());
433 blockNode = AllocNode<ir::BlockStatement>(funcScope,
434 std::move(body->AsTSModuleBlock()->Statements()));
435 }
436 tsModuleList_.pop_back();
437 funcScope->AddBindsFromParam();
438 }
439
440 funcNode = AllocNode<ir::ScriptFunction>(funcScope, std::move(params), nullptr, blockNode, nullptr,
441 ir::ScriptFunctionFlags::NONE, false, Extension() == ScriptExtension::TS);
442
443 funcScope->BindNode(funcNode);
444 funcParamScope->BindNode(funcNode);
445 }
446
447 auto *funcExpr = AllocNode<ir::FunctionExpression>(funcNode);
448
449 ArenaVector<ir::Expression *> arguments(Allocator()->Adapter());
450 ArenaVector<ir::Expression *> properties(Allocator()->Adapter());
451 auto *objectExpression = AllocNode<ir::ObjectExpression>(ir::AstNodeType::OBJECT_EXPRESSION,
452 std::move(properties),
453 false);
454 auto assignExpr = AllocNode<ir::AssignmentExpression>(CreateTsModuleParam(name, isExport),
455 objectExpression,
456 lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
457 auto argument = AllocNode<ir::BinaryExpression>(CreateTsModuleParam(name, isExport),
458 assignExpr,
459 lexer::TokenType::PUNCTUATOR_LOGICAL_OR);
460 if (isExport) {
461 auto *id = AllocNode<ir::Identifier>(name, Allocator());
462 id->AsIdentifier()->SetReference();
463 arguments.push_back(AllocNode<ir::AssignmentExpression>(id, argument,
464 lexer::TokenType::PUNCTUATOR_SUBSTITUTION));
465 } else {
466 arguments.push_back(argument);
467 }
468
469 auto *callExpr = AllocNode<ir::CallExpression>(funcExpr, std::move(arguments), nullptr, false);
470
471 return callExpr;
472 }
473
CreateTsModuleParam(util::StringView paramName,bool isExport)474 ir::Expression *Transformer::CreateTsModuleParam(util::StringView paramName, bool isExport)
475 {
476 if (isExport) {
477 auto moduleName = GetCurrentTSModuleName();
478 auto *id = AllocNode<ir::Identifier>(moduleName, Allocator());
479 id->AsIdentifier()->SetReference();
480 return AllocNode<ir::MemberExpression>(id, AllocNode<ir::Identifier>(paramName, Allocator()),
481 ir::MemberExpression::MemberExpressionKind::PROPERTY_ACCESS, false, false);
482 }
483
484 auto *id = AllocNode<ir::Identifier>(paramName, Allocator());
485 id->AsIdentifier()->SetReference();
486 return id;
487 }
488
AddExportLocalEntryItem(util::StringView name,const ir::Identifier * identifier)489 void Transformer::AddExportLocalEntryItem(util::StringView name, const ir::Identifier *identifier)
490 {
491 auto moduleRecord = GetSourceTextModuleRecord();
492 auto *entry = moduleRecord->NewEntry<SourceTextModuleRecord::ExportEntry>(name, name, identifier, identifier);
493 [[maybe_unused]] bool res = moduleRecord->AddLocalExportEntry(entry);
494 ASSERT(res);
495 }
496
VisitTsModuleDeclaration(ir::TSModuleDeclaration * node,bool isExport)497 ir::UpdateNodes Transformer::VisitTsModuleDeclaration(ir::TSModuleDeclaration *node, bool isExport)
498 {
499 std::vector<ir::AstNode *> res;
500
501 util::StringView name = GetNameFromModuleDeclaration(node);
502
503 auto findRes = Scope()->FindLocal(name, binder::ResolveBindingOptions::ALL);
504 if (findRes == nullptr) {
505 bool doExport = isExport && !IsTsModule();
506 auto flag = VariableParsingFlags::VAR;
507 if (IsTsModule()) {
508 flag = VariableParsingFlags::LET;
509 }
510 auto *var = CreateVariableDeclarationWithIdentify(name, flag, node, doExport);
511 if (doExport) {
512 ArenaVector<ir::ExportSpecifier *> specifiers(Allocator()->Adapter());
513 res.push_back(AllocNode<ir::ExportNamedDeclaration>(var, std::move(specifiers)));
514 AddExportLocalEntryItem(name, node->Name()->AsIdentifier());
515 } else {
516 res.push_back(var);
517 }
518 }
519
520 auto *callExpr = CreateCallExpressionForTsModule(node, name, isExport && IsTsModule());
521 auto *exprStatementNode = AllocNode<ir::ExpressionStatement>(callExpr);
522 res.push_back(exprStatementNode);
523
524 return res;
525 }
526
527 } // namespace panda::es2panda::parser
528