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 <util/ustring.h>
19
20 #include "binder/scope.h"
21 #include "ir/base/catchClause.h"
22 #include "ir/base/classDefinition.h"
23 #include "ir/base/classProperty.h"
24 #include "ir/base/decorator.h"
25 #include "ir/base/methodDefinition.h"
26 #include "ir/base/scriptFunction.h"
27 #include "ir/base/templateElement.h"
28 #include "ir/expressions/assignmentExpression.h"
29 #include "ir/expressions/binaryExpression.h"
30 #include "ir/expressions/callExpression.h"
31 #include "ir/expressions/classExpression.h"
32 #include "ir/expressions/functionExpression.h"
33 #include "ir/expressions/identifier.h"
34 #include "ir/expressions/literals/bigIntLiteral.h"
35 #include "ir/expressions/literals/numberLiteral.h"
36 #include "ir/expressions/literals/stringLiteral.h"
37 #include "ir/expressions/memberExpression.h"
38 #include "ir/expressions/objectExpression.h"
39 #include "ir/expressions/sequenceExpression.h"
40 #include "ir/expressions/superExpression.h"
41 #include "ir/expressions/templateLiteral.h"
42 #include "ir/expressions/thisExpression.h"
43 #include "ir/module/exportDefaultDeclaration.h"
44 #include "ir/module/exportNamedDeclaration.h"
45 #include "ir/module/exportSpecifier.h"
46 #include "ir/statements/blockStatement.h"
47 #include "ir/statements/classDeclaration.h"
48 #include "ir/statements/doWhileStatement.h"
49 #include "ir/statements/emptyStatement.h"
50 #include "ir/statements/expressionStatement.h"
51 #include "ir/statements/forInStatement.h"
52 #include "ir/statements/forOfStatement.h"
53 #include "ir/statements/forUpdateStatement.h"
54 #include "ir/statements/functionDeclaration.h"
55 #include "ir/statements/switchStatement.h"
56 #include "ir/statements/variableDeclaration.h"
57 #include "ir/statements/variableDeclarator.h"
58 #include "ir/statements/whileStatement.h"
59 #include "ir/ts/tsConstructorType.h"
60 #include "ir/ts/tsEnumDeclaration.h"
61 #include "ir/ts/tsEnumMember.h"
62 #include "ir/ts/tsFunctionType.h"
63 #include "ir/ts/tsImportEqualsDeclaration.h"
64 #include "ir/ts/tsInterfaceDeclaration.h"
65 #include "ir/ts/tsMethodSignature.h"
66 #include "ir/ts/tsModuleBlock.h"
67 #include "ir/ts/tsModuleDeclaration.h"
68 #include "ir/ts/tsParameterProperty.h"
69 #include "ir/ts/tsPrivateIdentifier.h"
70 #include "ir/ts/tsQualifiedName.h"
71 #include "ir/ts/tsSignatureDeclaration.h"
72 #include "ir/ts/tsTypeParameterDeclaration.h"
73 #include "util/helpers.h"
74
75 namespace panda::es2panda::parser {
76
Transform(Program * program)77 void Transformer::Transform(Program *program)
78 {
79 program_ = program;
80 if (Extension() == ScriptExtension::TS) {
81 TransformFromTS();
82 }
83 }
84
TransformFromTS()85 void Transformer::TransformFromTS()
86 {
87 ASSERT(Extension() == ScriptExtension::TS);
88 VisitTSNodes(program_->Ast());
89 PushVariablesToNearestStatements(program_->Ast());
90 }
91
VisitTSNodes(ir::AstNode * parent)92 ir::AstNode *Transformer::VisitTSNodes(ir::AstNode *parent)
93 {
94 if (!parent) {
95 return nullptr;
96 }
97 parent->UpdateSelf([this](auto *childNode) { return VisitTSNode(childNode); }, Binder());
98 return parent;
99 }
100
AddVariableToNearestStatements(util::StringView name)101 void Transformer::AddVariableToNearestStatements(util::StringView name)
102 {
103 /*
104 * Add variable declare like 'var ##var_1;' to nearest statements in namespace function or top level scope
105 * Record the variable name and scope in tempVarDeclStatements_ and will push the VariableDeclaration nodes
106 * to statements in PushVariablesToNearestStatements
107 */
108 auto currentScope = Scope();
109 while (currentScope != nullptr) {
110 if (currentScope->IsTSModuleScope()) {
111 auto node = currentScope->Node();
112 ASSERT(node->IsTSModuleDeclaration());
113 if (node->AsTSModuleDeclaration()->Body()->IsTSModuleBlock()) {
114 break;
115 }
116 }
117 if (currentScope->IsFunctionScope()) {
118 auto node = currentScope->Node();
119 ASSERT(node->IsScriptFunction());
120 if (!node->AsScriptFunction()->FunctionBodyIsExpression()) {
121 break;
122 }
123 }
124 currentScope = currentScope->Parent();
125 }
126 tempVarDeclStatements_.insert({name, currentScope});
127 }
128
PushVariablesToNearestStatements(ir::BlockStatement * ast)129 void Transformer::PushVariablesToNearestStatements(ir::BlockStatement *ast)
130 {
131 /*
132 * Push the VariableDeclaration nodes to nearest statements
133 * For example, transform:
134 * namespace ns {
135 * ...
136 * }
137 *
138 * To:
139 * namespace ns {
140 * var ##var_1;
141 * ...
142 * }
143 */
144 if (tempVarDeclStatements_.empty()) {
145 return;
146 }
147 for (auto it : tempVarDeclStatements_) {
148 auto *scope = it.second;
149 if (scope == nullptr) {
150 auto scopeCtx = binder::LexicalScope<binder::Scope>::Enter(Binder(), ast->Scope());
151 ast->AddStatementAtPos(0, CreateVariableDeclarationWithIdentify(it.first, VariableParsingFlags::VAR,
152 nullptr, false));
153 } else if (scope->IsFunctionScope() || scope->IsTSModuleScope()) {
154 auto *body = scope->Node()->AsScriptFunction()->Body();
155 ASSERT(body->IsBlockStatement());
156 auto scopeCtx = binder::LexicalScope<binder::Scope>::Enter(Binder(), scope);
157 body->AsBlockStatement()->AddStatementAtPos(0, CreateVariableDeclarationWithIdentify(it.first,
158 VariableParsingFlags::VAR, nullptr, false));
159 }
160 }
161 }
162
FindExportVariableInTsModuleScope(util::StringView name) const163 binder::Scope *Transformer::FindExportVariableInTsModuleScope(util::StringView name) const
164 {
165 bool isExport = false;
166 auto currentScope = Scope();
167 while (currentScope != nullptr) {
168 binder::Variable *v = currentScope->FindLocal(name, binder::ResolveBindingOptions::BINDINGS);
169 bool isTSModuleScope = currentScope->IsTSModuleScope();
170 if (v != nullptr) {
171 if (!v->Declaration()->IsVarDecl() && !v->Declaration()->IsLetDecl() && !v->Declaration()->IsConstDecl()) {
172 break;
173 }
174 if (isTSModuleScope && v->Declaration()->IsExportDeclInTsModule()) {
175 isExport = true;
176 }
177 break;
178 }
179 if (currentScope->InLocalTSBindings(name) &&
180 !currentScope->FindLocalTSVariable<binder::TSBindingType::IMPORT_EQUALS>(name)) {
181 break;
182 }
183 if (isTSModuleScope && currentScope->AsTSModuleScope()->InExportBindings(name)) {
184 isExport = true;
185 break;
186 }
187 currentScope = currentScope->Parent();
188 }
189 if (!isExport) {
190 return nullptr;
191 }
192 return currentScope;
193 }
194
VisitTSNode(ir::AstNode * childNode)195 ir::UpdateNodes Transformer::VisitTSNode(ir::AstNode *childNode)
196 {
197 ASSERT(childNode != nullptr);
198 switch (childNode->Type()) {
199 case ir::AstNodeType::IDENTIFIER: {
200 auto *ident = childNode->AsIdentifier();
201 if (!ident->IsReference() || (!IsTsModule() && !IsTsEnum())) {
202 return VisitTSNodes(childNode);
203 }
204
205 auto name = ident->Name();
206 if (IsTsEnum()) {
207 auto scope = FindEnumMemberScope(name);
208 if (scope) {
209 return CreateMemberExpressionFromIdentifier(scope, ident);
210 }
211 }
212 if (IsTsModule()) {
213 auto scope = FindExportVariableInTsModuleScope(name);
214 if (scope) {
215 return CreateMemberExpressionFromIdentifier(scope, ident);
216 }
217 }
218
219 return VisitTSNodes(childNode);
220 }
221 case ir::AstNodeType::TS_MODULE_DECLARATION: {
222 auto *node = childNode->AsTSModuleDeclaration();
223 if (node->Declare() || !node->IsInstantiated()) {
224 return childNode;
225 }
226 auto res = VisitTsModuleDeclaration(node);
227 SetOriginalNode(res, childNode);
228 return res;
229 }
230 case ir::AstNodeType::TS_ENUM_DECLARATION: {
231 auto *node = childNode->AsTSEnumDeclaration();
232 if (node->IsDeclare()) {
233 return childNode;
234 }
235 auto res = VisitTsEnumDeclaration(node);
236 SetOriginalNode(res, childNode);
237 return res;
238 }
239 case ir::AstNodeType::EXPORT_NAMED_DECLARATION: {
240 auto *node = childNode->AsExportNamedDeclaration();
241 auto *decl = node->Decl();
242 if (!decl) {
243 return VisitTSNodes(childNode);
244 }
245
246 if (decl->IsTSModuleDeclaration()) {
247 auto *tsModuleDeclaration = decl->AsTSModuleDeclaration();
248 if (tsModuleDeclaration->Declare() || !tsModuleDeclaration->IsInstantiated()) {
249 return childNode;
250 }
251 auto res = VisitTsModuleDeclaration(tsModuleDeclaration, true);
252 SetOriginalNode(res, childNode);
253 return res;
254 }
255
256 if (decl->IsTSEnumDeclaration()) {
257 if (decl->AsTSEnumDeclaration()->IsDeclare()) {
258 return childNode;
259 }
260 auto res = VisitTsEnumDeclaration(decl->AsTSEnumDeclaration(), true);
261 SetOriginalNode(res, childNode);
262 return res;
263 }
264
265 if (IsTsModule()) {
266 auto res = VisitExportNamedVariable(decl);
267 SetOriginalNode(res, node);
268 return res;
269 }
270
271 if (decl->IsClassDeclaration()) {
272 return VisitExportClassDeclaration<ir::ExportNamedDeclaration>(node);
273 }
274
275 return VisitTSNodes(node);
276 }
277 case ir::AstNodeType::EXPORT_DEFAULT_DECLARATION: {
278 auto *node = childNode->AsExportDefaultDeclaration();
279 auto *decl = node->Decl();
280 ASSERT(decl != nullptr);
281 if (decl->IsClassDeclaration()) {
282 return VisitExportClassDeclaration<ir::ExportDefaultDeclaration>(node);
283 }
284 // When we export default an identify 'a', a maybe a interface or type. So we should check here.
285 // if decl is not an identifier, it's won't be a type.
286 if (decl->IsIdentifier() && !IsValueReference(decl->AsIdentifier())) {
287 RemoveDefaultLocalExportEntry();
288 return nullptr;
289 }
290 return VisitTSNodes(childNode);
291 }
292 case ir::AstNodeType::TS_IMPORT_EQUALS_DECLARATION: {
293 auto *node = childNode->AsTSImportEqualsDeclaration();
294 auto *express = node->ModuleReference();
295 if (express->IsTSExternalModuleReference()) {
296 return VisitTSNodes(childNode);
297 }
298 auto *res = VisitTsImportEqualsDeclaration(node);
299 SetOriginalNode(res, childNode);
300 return res;
301 }
302 case ir::AstNodeType::CLASS_DECLARATION: {
303 auto *node = childNode->AsClassDeclaration();
304 if (node->Definition()->Declare()) {
305 return node;
306 }
307 DuringClass duringClass(&classList_, node->Definition()->GetName());
308 node = VisitTSNodes(node)->AsClassDeclaration();
309 auto res = VisitClassDeclaration(node);
310 SetOriginalNode(res, childNode);
311 return res;
312 }
313 case ir::AstNodeType::CLASS_EXPRESSION: {
314 auto *node = childNode->AsClassExpression();
315 DuringClass duringClass(&classList_, node->Definition()->GetName());
316 node = VisitTSNodes(node)->AsClassExpression();
317 auto res = VisitClassExpression(node);
318 SetOriginalNode(res, childNode);
319 return res;
320 }
321 case ir::AstNodeType::CLASS_DEFINITION: {
322 auto *node = childNode->AsClassDefinition();
323 VisitPrivateProperty(node);
324 VisitComputedProperty(node);
325 auto res = VisitTSNodes(childNode);
326 SetOriginalNode(res, childNode);
327 return res;
328 }
329 case ir::AstNodeType::TS_PRIVATE_IDENTIFIER: {
330 auto id = childNode->AsTSPrivateIdentifier()->Key()->AsIdentifier();
331 auto name = FindPrivatePropertyBindName(id->Name());
332 auto res = CreateReferenceIdentifier(name);
333 SetOriginalNode(res, childNode);
334 return res;
335 }
336 default: {
337 return VisitTSNodes(childNode);
338 }
339 }
340 }
341
342 template <typename T>
VisitExportClassDeclaration(T * node)343 ir::UpdateNodes Transformer::VisitExportClassDeclaration(T *node)
344 {
345 auto *decl = node->Decl();
346 auto newDecl = VisitTSNode(decl);
347 if (std::holds_alternative<ir::AstNode *>(newDecl)) {
348 auto statement = std::get<ir::AstNode *>(newDecl);
349 ASSERT(statement->IsClassDeclaration());
350 node->SetDecl(statement->AsClassDeclaration());
351 return node;
352 } else {
353 auto statements = std::get<std::vector<ir::AstNode *>>(newDecl);
354 std::vector<ir::AstNode *> res;
355 auto firstStatement = statements.front();
356 statements.erase(statements.begin());
357 if (firstStatement->IsVariableDeclaration()) {
358 node->SetDecl(firstStatement->AsVariableDeclaration());
359 } else {
360 ASSERT(firstStatement->IsClassDeclaration());
361 node->SetDecl(firstStatement->AsClassDeclaration());
362 }
363 res.push_back(node);
364 res.insert(res.end(), statements.begin(), statements.end());
365 return res;
366 }
367 }
368
CreateNewVariable(bool needAddToStatements)369 util::StringView Transformer::CreateNewVariable(bool needAddToStatements)
370 {
371 util::StringView name = CreateNewVariableName();
372 if (needAddToStatements) {
373 AddVariableToNearestStatements(name);
374 }
375 return name;
376 }
377
CreateUniqueName(const std::string & head,size_t * index) const378 util::StringView Transformer::CreateUniqueName(const std::string &head, size_t *index) const
379 {
380 util::StringView name;
381 size_t idx = 0;
382 if (index != nullptr) {
383 idx = *index;
384 }
385 do {
386 idx++;
387 std::stringstream ss;
388 ss << head << std::to_string(idx);
389 auto s = ss.str();
390 if (!Binder()->HasVariableName(util::StringView(s))) {
391 name = util::UString(s, Allocator()).View();
392 break;
393 }
394 } while (true);
395 if (index != nullptr) {
396 *index = idx;
397 }
398 Binder()->AddDeclarationName(name);
399 return name;
400 }
401
CreateNewVariableName() const402 util::StringView Transformer::CreateNewVariableName() const
403 {
404 auto name = CreateUniqueName(std::string(NEW_VAR_PREFIX) + std::string(NEW_VAR_HEAD));
405 return name;
406 }
407
VisitClassExpression(ir::ClassExpression * node)408 ir::UpdateNodes Transformer::VisitClassExpression(ir::ClassExpression *node)
409 {
410 /*
411 * Transform:
412 * var c = class C {
413 * static a = 1
414 * }
415 *
416 * To:
417 * var ##var_1;
418 * var c = (##var_1 = class C {},
419 * ##var_1.a = 1,
420 * ##var_1)
421 */
422 auto instanceComputedProperty = VisitInstanceProperty(node->Definition());
423
424 VisitTSParameterProperty(node->Definition());
425
426 auto varName = CreateNewVariable(false);
427 auto staticProperty = VisitStaticProperty(node->Definition(), varName);
428 if (instanceComputedProperty.empty() && staticProperty.empty()) {
429 return node;
430 }
431 AddVariableToNearestStatements(varName);
432
433 auto assignment = AllocNode<ir::AssignmentExpression>(CreateReferenceIdentifier(varName),
434 node->AsExpression(), lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
435 ArenaVector<ir::Expression *> sequence(Allocator()->Adapter());
436 sequence.push_back(assignment);
437
438 for (auto *it : instanceComputedProperty) {
439 sequence.push_back(it->GetExpression());
440 }
441 for (auto *it : staticProperty) {
442 sequence.push_back(it->GetExpression());
443 }
444
445 sequence.push_back(CreateReferenceIdentifier(varName));
446 return AllocNode<ir::SequenceExpression>(std::move(sequence));
447 }
448
VisitComputedProperty(ir::ClassDefinition * node)449 void Transformer::VisitComputedProperty(ir::ClassDefinition *node)
450 {
451 /*
452 * Only create variable for the computed members with decorators or static class property
453 * The new value will be used in the decorators or static property initialize
454 * Transform:
455 * class C {
456 * @f
457 * [a](){}
458 * static [b] = 1
459 * [c] = 1
460 * }
461 *
462 * To:
463 * var ##var_1;
464 * var ##var_2;
465 * var ##var_3;
466 * class C {
467 * @f
468 * [##var_1 = a](){}
469 * static [##var_2 = b] = 1
470 * [##var_3 = c] = 1
471 * }
472 */
473 for (auto *it : node->Body()) {
474 if (it->IsClassProperty()) {
475 auto *classProperty = it->AsClassProperty();
476 if (!classProperty->IsComputed()) {
477 continue;
478 }
479 auto *key = classProperty->Key();
480 auto name = CreateNewVariable();
481 auto *newKey = AllocNode<ir::AssignmentExpression>(CreateReferenceIdentifier(name),
482 key, lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
483 classProperty->SetKey(newKey);
484 AddComputedPropertyBinding(it, name);
485 } else if (it->IsMethodDefinition()) {
486 auto *methodDefinition = it->AsMethodDefinition();
487 if (!methodDefinition->Computed() ||
488 (!methodDefinition->HasDecorators() && !methodDefinition->HasParamDecorators())) {
489 continue;
490 }
491 auto *key = methodDefinition->Key();
492 auto name = CreateNewVariable();
493 auto *newKey = AllocNode<ir::AssignmentExpression>(CreateReferenceIdentifier(name),
494 key, lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
495 methodDefinition->SetKey(newKey);
496 AddComputedPropertyBinding(it, name);
497 }
498 }
499 }
500
VisitPrivateProperty(ir::ClassDefinition * node)501 void Transformer::VisitPrivateProperty(ir::ClassDefinition *node)
502 {
503 /*
504 * Create an unique variable name for private property member in class
505 * Transform:
506 * class C {
507 * #a = 1
508 * }
509 *
510 * To:
511 * class C {
512 * ##${RecordName}#C#a#1 = 1
513 * }
514 */
515 for (auto *it : node->Body()) {
516 if (!it->IsClassProperty()) {
517 continue;
518 }
519 auto *key = it->AsClassProperty()->Key();
520 if (!key->IsTSPrivateIdentifier()) {
521 continue;
522 }
523 auto name = key->AsTSPrivateIdentifier()->Key()->AsIdentifier()->Name();
524 auto bindName = CreatePrivatePropertyBindName(name);
525 AddPrivatePropertyBinding(name, bindName);
526 }
527 }
528
FindPrivatePropertyBindName(util::StringView name)529 util::StringView Transformer::FindPrivatePropertyBindName(util::StringView name)
530 {
531 for (size_t i = classList_.size() - 1; i >= 0; i--) {
532 auto res = classList_[i].bindNameMap->find(name);
533 if (res != classList_[i].bindNameMap->end()) {
534 return res->second;
535 }
536 }
537 UNREACHABLE();
538 }
539
CreatePrivatePropertyBindName(util::StringView name)540 util::StringView Transformer::CreatePrivatePropertyBindName(util::StringView name)
541 {
542 std::stringstream head;
543 head << NEW_VAR_PREFIX << std::string(RecordName());
544 for (auto it : classList_) {
545 head << PRIVATE_PROPERTY_SIGN << std::string(it.name);
546 }
547 head << PRIVATE_PROPERTY_SIGN << std::string(name) << PRIVATE_PROPERTY_SIGN;
548 size_t index = GetCurrentClassInfoPropertyIndex();
549 auto uniqueName = CreateUniqueName(head.str(), &index);
550 SetCurrentClassInfoPropertyIndex(index);
551 return uniqueName;
552 }
553
GetInsertPosForConstructor(ir::ClassDefinition * node)554 size_t Transformer::GetInsertPosForConstructor(ir::ClassDefinition *node)
555 {
556 size_t insertPos = 0;
557 ir::BlockStatement *blockStat = node->Ctor()->Function()->Body()->AsBlockStatement();
558 for (auto iter = blockStat->Statements().begin(); iter != blockStat->Statements().end();) {
559 if ((*iter)->IsExpressionStatement() &&
560 (*iter)->AsExpressionStatement()->GetExpression()->IsStringLiteral()) {
561 iter++;
562 insertPos++;
563 } else {
564 break;
565 }
566 }
567
568 return (node->Super() == nullptr || node->Super()->IsNullLiteral()) ? insertPos : (insertPos + 1);
569 }
570
VisitInstanceProperty(ir::ClassDefinition * node)571 std::vector<ir::ExpressionStatement *> Transformer::VisitInstanceProperty(ir::ClassDefinition *node)
572 {
573 /*
574 * Move class InstanceProperty to constructor.
575 * Transform:
576 * class C {
577 * "prop" = 1;
578 * }
579 *
580 * To:
581 * class C {
582 * constructor () {
583 * this["prop"] = 1;
584 * }
585 * }
586 */
587 std::vector<ir::ClassProperty *> addToCtor;
588 // Non-null computed properties need to be added outside the class. It is a subset of addToCtor.
589 std::vector<ir::ExpressionStatement *> computedProps;
590 for (auto *it : node->Body()) {
591 if (it->IsClassProperty() && !it->AsClassProperty()->IsStatic() && it->AsClassProperty()->Value() != nullptr) {
592 addToCtor.push_back(it->AsClassProperty());
593 }
594 }
595 if (addToCtor.empty()) {
596 return {};
597 }
598
599 auto ctorScopeCtx = binder::LexicalScope<binder::FunctionScope>::Enter(Binder(), node->Ctor()->Function()->Scope());
600
601 ir::BlockStatement *blockStat = node->Ctor()->Function()->Body()->AsBlockStatement();
602 size_t insertPos = GetInsertPosForConstructor(node);
603 for (auto *it : addToCtor) {
604 if (it->IsComputed()) {
605 computedProps.push_back(AllocNode<ir::ExpressionStatement>(it->Key()));
606 }
607
608 ir::MemberExpression *left = nullptr;
609 auto *member = GetClassMemberName(it->Key(), it->IsComputed(), it, false);
610 if (member->IsIdentifier() && !it->IsComputed()) {
611 left = AllocNode<ir::MemberExpression>(AllocNode<ir::ThisExpression>(), member,
612 ir::MemberExpression::MemberExpressionKind::PROPERTY_ACCESS,
613 false, false);
614 } else {
615 left = AllocNode<ir::MemberExpression>(AllocNode<ir::ThisExpression>(), member,
616 ir::MemberExpression::MemberExpressionKind::ELEMENT_ACCESS,
617 true, false);
618 }
619 auto assignment = AllocNode<ir::AssignmentExpression>(left, it->Value(),
620 lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
621
622 ResetParentScopeForAstNode(assignment);
623 blockStat->AddStatementAtPos(insertPos, AllocNode<ir::ExpressionStatement>(assignment));
624 insertPos++;
625 }
626 return computedProps;
627 }
628
VisitTSParameterProperty(ir::ClassDefinition * node)629 void Transformer::VisitTSParameterProperty(ir::ClassDefinition *node)
630 {
631 /*
632 * Add class property for the parameter property declaration in constructor
633 * Transform:
634 * class C {
635 * constructor(public a = 1) {}
636 * }
637 *
638 * To:
639 * class C {
640 * constructor(public a = 1) {
641 * this.a = a;
642 * }
643 * }
644 */
645 auto *func = node->Ctor()->Function();
646 auto *body = func->Body();
647 if (body == nullptr) {
648 return;
649 }
650 auto blockStatement = body->AsBlockStatement();
651 size_t insertPos = GetInsertPosForConstructor(node);
652 for (auto *it : func->Params()) {
653 if (!it->IsTSParameterProperty()) {
654 continue;
655 }
656 auto *parameter = it->AsTSParameterProperty()->Parameter();
657 util::StringView name;
658 // TSParameterPropert only can be identifier or assignment pattern
659 if (parameter->IsIdentifier()) {
660 name = parameter->AsIdentifier()->Name();
661 } else {
662 ASSERT(parameter->IsAssignmentPattern());
663 auto *left = parameter->AsAssignmentPattern()->Left();
664 ASSERT(left->IsIdentifier());
665 name = left->AsIdentifier()->Name();
666 }
667 auto left = AllocNode<ir::MemberExpression>(AllocNode<ir::ThisExpression>(),
668 AllocNode<ir::Identifier>(name),
669 ir::MemberExpression::MemberExpressionKind::PROPERTY_ACCESS, false, false);
670 auto right = CreateReferenceIdentifier(name);
671 auto assignment = AllocNode<ir::AssignmentExpression>(left, right,
672 lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
673 blockStatement->AddStatementAtPos(insertPos, AllocNode<ir::ExpressionStatement>(assignment));
674 insertPos++;
675 }
676 }
677
VisitStaticProperty(ir::ClassDefinition * node,util::StringView name)678 std::vector<ir::ExpressionStatement *> Transformer::VisitStaticProperty(ir::ClassDefinition *node,
679 util::StringView name)
680 {
681 /*
682 * Create statement for static class property
683 * If it's a conputed property, we should initialize it's new variable first.
684 * Transform:
685 * var ##var_1;
686 * class C {
687 * static a = 1
688 * static [##var_1 = s] = 1
689 * }
690 *
691 * To:
692 * var ##var_1;
693 * class C {
694 * }
695 * C.a = 1;
696 * ##var_1 = s;
697 * C[##var_1] = 1;
698 *
699 * TODO(xucheng): should support static private property
700 */
701 std::vector<ir::ExpressionStatement *> res;
702 auto classDefinitionBody = node->Body();
703 for (auto *it : classDefinitionBody) {
704 if (!it->IsClassProperty()) {
705 continue;
706 }
707 auto *classProperty = it->AsClassProperty();
708 if (!classProperty->IsStatic()) {
709 continue;
710 }
711 if (classProperty->IsComputed()) {
712 res.push_back(AllocNode<ir::ExpressionStatement>(classProperty->Key()));
713 }
714 auto right = classProperty->Value();
715 if (right == nullptr) {
716 continue;
717 }
718
719 ir::MemberExpression *left = nullptr;
720 auto *member = GetClassMemberName(classProperty->Key(), classProperty->IsComputed(), classProperty, false);
721 if (member->IsIdentifier() && !classProperty->IsComputed()) {
722 left = AllocNode<ir::MemberExpression>(CreateReferenceIdentifier(name), member,
723 ir::MemberExpression::MemberExpressionKind::PROPERTY_ACCESS,
724 false, false);
725 } else {
726 left = AllocNode<ir::MemberExpression>(CreateReferenceIdentifier(name), member,
727 ir::MemberExpression::MemberExpressionKind::ELEMENT_ACCESS,
728 true, false);
729 }
730 auto assignment = AllocNode<ir::AssignmentExpression>(left, right, lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
731 res.push_back(AllocNode<ir::ExpressionStatement>(assignment));
732 }
733 return res;
734 }
735
VisitClassDeclaration(ir::ClassDeclaration * node)736 ir::UpdateNodes Transformer::VisitClassDeclaration(ir::ClassDeclaration *node)
737 {
738 // TODO(xucheng): maybe will support metadata later
739 auto name = node->Definition()->GetName();
740 std::vector<ir::AstNode *> res;
741 bool hasClassDecorators = node->HasDecorators();
742 if (hasClassDecorators) {
743 auto definiton = node->Definition();
744 auto *clsExpression = AllocNode<ir::ClassExpression>(definiton);
745 res.push_back(CreateVariableDeclarationWithIdentify(name, VariableParsingFlags::LET, node, false,
746 clsExpression, false));
747 } else {
748 res.push_back(node);
749 }
750
751 auto instanceComputedProperty = VisitInstanceProperty(node->Definition());
752 // instanceComputedProperty has been transformed by VisitComputedPerporty before, here is an assignmentExpression.
753 if (!instanceComputedProperty.empty()) {
754 res.insert(res.end(), instanceComputedProperty.begin(), instanceComputedProperty.end());
755 }
756
757 VisitTSParameterProperty(node->Definition());
758
759 auto staticProperty = VisitStaticProperty(node->Definition(), name);
760 if (!staticProperty.empty()) {
761 res.insert(res.end(), staticProperty.begin(), staticProperty.end());
762 }
763
764 auto classDefinitionBody = node->Definition()->Body();
765 // decorators of static members, should be called after instance members
766 std::vector<ir::AstNode *> staticMemberDecorators;
767 for (auto *it : classDefinitionBody) {
768 if (it->IsMethodDefinition()) {
769 auto *definition = it->AsMethodDefinition();
770 bool isStatic = definition->IsStatic();
771
772 auto variableDeclarations = CreateVariableDeclarationForDecorators(definition);
773 if (isStatic) {
774 staticMemberDecorators.insert(staticMemberDecorators.end(),
775 variableDeclarations.begin(), variableDeclarations.end());
776 } else {
777 res.insert(res.end(), variableDeclarations.begin(), variableDeclarations.end());
778 }
779
780 auto paramDecorators = CreateParamDecorators(name, definition, variableDeclarations, false, isStatic);
781 if (isStatic) {
782 staticMemberDecorators.insert(staticMemberDecorators.end(),
783 paramDecorators.begin(), paramDecorators.end());
784 } else {
785 res.insert(res.end(), paramDecorators.begin(), paramDecorators.end());
786 }
787 if (!definition->HasDecorators()) {
788 continue;
789 }
790 auto methodDecorators = CreateMethodDecorators(name, definition, variableDeclarations, isStatic);
791 if (isStatic) {
792 staticMemberDecorators.insert(staticMemberDecorators.end(),
793 methodDecorators.begin(), methodDecorators.end());
794 } else {
795 res.insert(res.end(), methodDecorators.begin(), methodDecorators.end());
796 }
797 } else if (it->IsClassProperty()) {
798 auto *classProperty = it->AsClassProperty();
799 bool isStatic = classProperty->IsStatic();
800 if (!classProperty->HasDecorators()) {
801 continue;
802 }
803
804 if (classProperty->IsComputed() && !isStatic && classProperty->Value() == nullptr) {
805 res.push_back(AllocNode<ir::ExpressionStatement>(classProperty->Key()));
806 }
807
808 auto variableDeclarations = CreateVariableDeclarationForDecorators(classProperty);
809 if (isStatic) {
810 staticMemberDecorators.insert(staticMemberDecorators.end(),
811 variableDeclarations.begin(), variableDeclarations.end());
812 } else {
813 res.insert(res.end(), variableDeclarations.begin(), variableDeclarations.end());
814 }
815
816 auto propertyDecorators = CreatePropertyDecorators(name, classProperty, variableDeclarations, isStatic);
817 if (isStatic) {
818 staticMemberDecorators.insert(staticMemberDecorators.end(),
819 propertyDecorators.begin(), propertyDecorators.end());
820 } else {
821 res.insert(res.end(), propertyDecorators.begin(), propertyDecorators.end());
822 }
823 }
824 }
825
826 if (!staticMemberDecorators.empty()) {
827 res.insert(res.end(), staticMemberDecorators.begin(), staticMemberDecorators.end());
828 }
829
830 auto variableDeclarationsForCtorOrClass = CreateVariableDeclarationForDecorators(node);
831 res.insert(res.end(), variableDeclarationsForCtorOrClass.begin(), variableDeclarationsForCtorOrClass.end());
832
833 // constructor decorators
834 auto *ctor = node->Definition()->Ctor();
835 auto ctorParamDecorators = CreateParamDecorators(name, ctor, variableDeclarationsForCtorOrClass, true, false);
836 res.insert(res.end(), ctorParamDecorators.begin(), ctorParamDecorators.end());
837
838 // class decorators
839 if (hasClassDecorators) {
840 auto classDecorators = CreateClassDecorators(node, variableDeclarationsForCtorOrClass);
841 res.insert(res.end(), classDecorators.begin(), classDecorators.end());
842 }
843 if (res.size() == 1) {
844 return res.front();
845 }
846 return res;
847 }
848
CreateVariableDeclarationForDecorators(ir::AstNode * node)849 std::vector<ir::AstNode *> Transformer::CreateVariableDeclarationForDecorators(ir::AstNode *node)
850 {
851 std::vector<ir::AstNode *> res;
852
853 switch (node->Type()) {
854 case ir::AstNodeType::METHOD_DEFINITION: {
855 auto methodDecorators = node->AsMethodDefinition()->Decorators();
856 for (size_t i = 0; i < methodDecorators.size(); i++) {
857 util::StringView varName = CreateNewVariable(false);
858 res.push_back(CreateVariableDeclarationWithIdentify(varName, VariableParsingFlags::LET, nullptr,
859 false, methodDecorators[i]->Expr(), true));
860 }
861
862 auto paramsDecorators = node->AsMethodDefinition()->GetParamDecorators();
863 for (size_t i = 0; i < paramsDecorators.size(); i++) {
864 auto paramDecorators = paramsDecorators[i].decorators;
865 for (size_t j = 0; j < paramDecorators.size(); j++) {
866 util::StringView varName = CreateNewVariable(false);
867 res.push_back(CreateVariableDeclarationWithIdentify(varName, VariableParsingFlags::LET, nullptr,
868 false, paramDecorators[j]->Expr(), true));
869 }
870 }
871 return res;
872 }
873 case ir::AstNodeType::CLASS_PROPERTY: {
874 auto propDecorators = node->AsClassProperty()->Decorators();
875 for (size_t i = 0; i < propDecorators.size(); i++) {
876 util::StringView varName = CreateNewVariable(false);
877 res.push_back(CreateVariableDeclarationWithIdentify(varName, VariableParsingFlags::LET, nullptr,
878 false, propDecorators[i]->Expr(), true));
879 }
880 return res;
881 }
882 case ir::AstNodeType::CLASS_DECLARATION: {
883 auto classDecorators = node->AsClassDeclaration()->Decorators();
884 for (size_t i = 0; i < classDecorators.size(); i++) {
885 util::StringView varName = CreateNewVariable(false);
886 res.push_back(CreateVariableDeclarationWithIdentify(varName, VariableParsingFlags::LET, nullptr,
887 false, classDecorators[i]->Expr(), true));
888 }
889
890 auto ctorParamsDecorators = node->AsClassDeclaration()->Definition()->Ctor()->GetParamDecorators();
891 for (size_t i = 0; i < ctorParamsDecorators.size(); i++) {
892 auto ctorParamDecorators = ctorParamsDecorators[i].decorators;
893 for (size_t j = 0; j < ctorParamDecorators.size(); j++) {
894 util::StringView varName = CreateNewVariable(false);
895 res.push_back(CreateVariableDeclarationWithIdentify(varName, VariableParsingFlags::LET, nullptr,
896 false, ctorParamDecorators[j]->Expr(), true));
897 }
898 }
899 return res;
900 }
901 default: {
902 UNREACHABLE();
903 }
904 }
905 }
906
CreateParamDecorators(util::StringView className,ir::MethodDefinition * node,const std::vector<ir::AstNode * > & variableDeclarations,bool isConstructor,bool isStatic)907 std::vector<ir::AstNode *> Transformer::CreateParamDecorators(util::StringView className,
908 ir::MethodDefinition *node,
909 const std::vector<ir::AstNode *> &variableDeclarations,
910 bool isConstructor,
911 bool isStatic)
912 {
913 /*
914 * Param decorators
915 * Transform:
916 * class C {
917 * f(@g a){}
918 * }
919 *
920 * To:
921 * class C {
922 * f(a){}
923 * }
924 * g(C.prototype, "f", 0)
925 *
926 * Static method or constructor will use constructor function of the class instead of prototype of class
927 */
928 std::vector<ir::AstNode *> res;
929 int pos = variableDeclarations.size();
930 auto paramsDecorators = node->GetParamDecorators();
931 for (int i = paramsDecorators.size() - 1; i >= 0; i--) {
932 auto paramIndex = paramsDecorators[i].paramIndex;
933 auto decorators = paramsDecorators[i].decorators;
934 for (int j = decorators.size() - 1; j >= 0; j--) {
935 ArenaVector<ir::Expression *> arguments(Allocator()->Adapter());
936 arguments.push_back(CreateDecoratorTarget(className, isConstructor || isStatic));
937 arguments.push_back(isConstructor ?
938 CreateReferenceIdentifier(CONSTRUCTOR_NAME) :
939 GetClassMemberName(node->Key(), node->Computed(), node));
940 arguments.push_back(AllocNode<ir::NumberLiteral>(paramIndex));
941 auto *callExpr = AllocNode<ir::CallExpression>(
942 variableDeclarations[--pos]->AsVariableDeclaration()->Declarators().front()->Id(),
943 std::move(arguments), nullptr, false);
944 res.push_back(AllocNode<ir::ExpressionStatement>(callExpr));
945 }
946 }
947 return res;
948 }
949
CreatePropertyDecorators(util::StringView className,ir::ClassProperty * node,const std::vector<ir::AstNode * > & variableDeclarations,bool isStatic)950 std::vector<ir::AstNode *> Transformer::CreatePropertyDecorators(util::StringView className,
951 ir::ClassProperty *node,
952 const std::vector<ir::AstNode *> &variableDeclarations,
953 bool isStatic)
954 {
955 /*
956 * Property decorators
957 * Transform:
958 * class C {
959 * @f a = 1
960 * }
961 *
962 * To:
963 * class C {
964 * a = 1
965 * }
966 * f(C.prototype, "a")
967 *
968 * Static property will use constructor function of the class instead of prototype of class
969 */
970 std::vector<ir::AstNode *> res;
971 auto decorators = node->Decorators();
972 for (int i = decorators.size() - 1; i >= 0; i--) {
973 ArenaVector<ir::Expression *> arguments(Allocator()->Adapter());
974 arguments.push_back(CreateDecoratorTarget(className, isStatic));
975 arguments.push_back(GetClassMemberName(node->Key(), node->IsComputed(), node));
976 auto *callExpr = AllocNode<ir::CallExpression>(
977 variableDeclarations[i]->AsVariableDeclaration()->Declarators().front()->Id(),
978 std::move(arguments), nullptr, false);
979
980 res.push_back(AllocNode<ir::ExpressionStatement>(callExpr));
981 }
982 return res;
983 }
984
CreateMethodDecorators(util::StringView className,ir::MethodDefinition * node,const std::vector<ir::AstNode * > & variableDeclarations,bool isStatic)985 std::vector<ir::AstNode *> Transformer::CreateMethodDecorators(util::StringView className,
986 ir::MethodDefinition *node,
987 const std::vector<ir::AstNode *> &variableDeclarations,
988 bool isStatic)
989 {
990 /*
991 * Method decorators and accessor decorators
992 * Transform:
993 * class C {
994 * @g
995 * f(){}
996 * }
997 *
998 * To:
999 * class C {
1000 * f(){}
1001 * }
1002 * var ###a = Object.getOwnPropertyDescriptor(C.prototype, "f");
1003 * Object.defineProperty(C.prototype, "f",
1004 * g(C.prototype, "f", ###a) || ###a);
1005 *
1006 * static method will use constructor function of the class instead of prototype of class
1007 * If the decorator has a return value, it will be set as the new property of the method
1008 */
1009 std::vector<ir::AstNode *> res;
1010 int pos = node->Decorators().size();
1011 auto decorators = node->Decorators();
1012 for (int i = decorators.size() - 1; i >= 0; i--) {
1013 ArenaVector<ir::Expression *> arguments(Allocator()->Adapter());
1014 arguments.push_back(CreateDecoratorTarget(className, isStatic));
1015 arguments.push_back(GetClassMemberName(node->Key(), node->Computed(), node));
1016 util::StringView varName = CreateNewVariable(false);
1017 auto getOwnPropertyDescriptorCall = CreateGetOwnPropertyDescriptorCall(
1018 CreateDecoratorTarget(className, isStatic), GetClassMemberName(node->Key(), node->Computed(), node));
1019 res.push_back(CreateVariableDeclarationWithIdentify(varName, VariableParsingFlags::LET, nullptr,
1020 false, getOwnPropertyDescriptorCall, true));
1021 arguments.push_back(AllocNode<ir::Identifier>(varName));
1022 auto *callExpr = AllocNode<ir::CallExpression>(
1023 variableDeclarations[--pos]->AsVariableDeclaration()->Declarators().front()->Id(),
1024 std::move(arguments), nullptr, false);
1025
1026 auto newValue = AllocNode<ir::BinaryExpression>(callExpr, AllocNode<ir::Identifier>(varName),
1027 lexer::TokenType::PUNCTUATOR_LOGICAL_OR);
1028
1029 auto *defineProperty = CreateDefinePropertyCall(CreateDecoratorTarget(className, isStatic),
1030 GetClassMemberName(node->Key(), node->Computed(), node), newValue);
1031
1032 res.push_back(AllocNode<ir::ExpressionStatement>(defineProperty));
1033 }
1034 return res;
1035 }
1036
CreateDecoratorTarget(util::StringView className,bool isStatic)1037 ir::Expression *Transformer::CreateDecoratorTarget(util::StringView className, bool isStatic)
1038 {
1039 if (isStatic) {
1040 return CreateReferenceIdentifier(className);
1041 }
1042 return CreateClassPrototype(className);
1043 }
1044
CreateClassPrototype(util::StringView className)1045 ir::MemberExpression *Transformer::CreateClassPrototype(util::StringView className)
1046 {
1047 auto *cls = CreateReferenceIdentifier(className);
1048 return AllocNode<ir::MemberExpression>(cls, AllocNode<ir::Identifier>(CLASS_PROTOTYPE),
1049 ir::MemberExpression::MemberExpressionKind::PROPERTY_ACCESS, false, false);
1050 }
1051
CreateDefinePropertyCall(ir::Expression * target,ir::Expression * key,ir::Expression * value)1052 ir::CallExpression *Transformer::CreateDefinePropertyCall(ir::Expression *target,
1053 ir::Expression *key,
1054 ir::Expression *value)
1055 {
1056 auto *id = CreateReferenceIdentifier(OBJECT_VAR_NAME);
1057 auto *caller = AllocNode<ir::MemberExpression>(id, AllocNode<ir::Identifier>(FUNC_NAME_OF_DEFINE_PROPERTY),
1058 ir::MemberExpression::MemberExpressionKind::PROPERTY_ACCESS, false, false);
1059 ArenaVector<ir::Expression *> arguments(Allocator()->Adapter());
1060 arguments.push_back(target);
1061 arguments.push_back(key);
1062 arguments.push_back(value);
1063 return AllocNode<ir::CallExpression>(caller, std::move(arguments), nullptr, false);
1064 }
1065
CreateGetOwnPropertyDescriptorCall(ir::Expression * target,ir::Expression * key)1066 ir::CallExpression *Transformer::CreateGetOwnPropertyDescriptorCall(ir::Expression *target, ir::Expression *key)
1067 {
1068 auto *id = CreateReferenceIdentifier(OBJECT_VAR_NAME);
1069 auto *caller = AllocNode<ir::MemberExpression>(id,
1070 AllocNode<ir::Identifier>(FUNC_NAME_OF_GET_OWN_PROPERTY_DESCRIPTOR),
1071 ir::MemberExpression::MemberExpressionKind::PROPERTY_ACCESS, false, false);
1072 ArenaVector<ir::Expression *> arguments(Allocator()->Adapter());
1073 arguments.push_back(target);
1074 arguments.push_back(key);
1075 return AllocNode<ir::CallExpression>(caller, std::move(arguments), nullptr, false);
1076 }
1077
GetClassMemberName(ir::Expression * key,bool isComputed,ir::Statement * node,bool inDecorator)1078 ir::Expression *Transformer::GetClassMemberName(ir::Expression *key, bool isComputed,
1079 ir::Statement *node, bool inDecorator)
1080 {
1081 if (isComputed) {
1082 auto name = GetComputedPropertyBinding(node);
1083 return AllocNode<ir::Identifier>(name);
1084 }
1085 if (key->IsIdentifier()) {
1086 if (inDecorator) {
1087 return AllocNode<ir::StringLiteral>(key->AsIdentifier()->Name());
1088 } else {
1089 return AllocNode<ir::Identifier>(key->AsIdentifier()->Name());
1090 }
1091 } else if (key->IsStringLiteral()) {
1092 return AllocNode<ir::StringLiteral>(key->AsStringLiteral()->Str());
1093 } else if (key->IsNumberLiteral()) {
1094 return AllocNode<ir::NumberLiteral>(key->AsNumberLiteral()->Number(), key->AsNumberLiteral()->Str());
1095 } else if (key->IsBigIntLiteral()) {
1096 return AllocNode<ir::BigIntLiteral>(key->AsBigIntLiteral()->Str());
1097 }
1098 UNREACHABLE();
1099 return nullptr;
1100 }
1101
CreateClassDecorators(ir::ClassDeclaration * node,const std::vector<ir::AstNode * > & variableDeclarations)1102 std::vector<ir::AstNode *> Transformer::CreateClassDecorators(ir::ClassDeclaration *node,
1103 const std::vector<ir::AstNode *> &variableDeclarations)
1104 {
1105 /*
1106 * Class decorators
1107 * Transform:
1108 * @f
1109 * class C {
1110 * }
1111 *
1112 * To:
1113 * class C {
1114 * }
1115 * C = f(C) || C;
1116 *
1117 * If the decorator has a return value, it will be used as the new declaration of the class
1118 */
1119 auto name = node->Definition()->GetName();
1120 auto decorators = node->Decorators();
1121 auto size = decorators.size();
1122 int pos = size;
1123 std::vector<ir::AstNode *> res;
1124 for (int i = size - 1; i >= 0; i--) {
1125 ArenaVector<ir::Expression *> arguments(Allocator()->Adapter());
1126 arguments.push_back(CreateReferenceIdentifier(name));
1127 auto *callExpr = AllocNode<ir::CallExpression>(
1128 variableDeclarations[--pos]->AsVariableDeclaration()->Declarators().front()->Id(),
1129 std::move(arguments), nullptr, false);
1130
1131 auto left = CreateReferenceIdentifier(name);
1132 auto id = CreateReferenceIdentifier(name);
1133 auto right = AllocNode<ir::BinaryExpression>(callExpr, id, lexer::TokenType::PUNCTUATOR_LOGICAL_OR);
1134 auto *assignExpr = AllocNode<ir::AssignmentExpression>(left, right,
1135 lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
1136
1137 res.push_back(AllocNode<ir::ExpressionStatement>(assignExpr));
1138 }
1139 return res;
1140 }
1141
VisitTsImportEqualsDeclaration(ir::TSImportEqualsDeclaration * node)1142 ir::AstNode *Transformer::VisitTsImportEqualsDeclaration(ir::TSImportEqualsDeclaration *node)
1143 {
1144 if (!IsInstantiatedImportEquals(node, Scope())) {
1145 return node;
1146 }
1147 auto *express = node->ModuleReference();
1148 auto name = node->Id()->Name();
1149 if (IsTsModule() && node->IsExport()) {
1150 auto moduleName = GetCurrentTSModuleName();
1151 auto *id = CreateReferenceIdentifier(moduleName);
1152 auto *left = AllocNode<ir::MemberExpression>(id, AllocNode<ir::Identifier>(name),
1153 ir::MemberExpression::MemberExpressionKind::PROPERTY_ACCESS, false, false);
1154 ir::Expression *right = CreateMemberExpressionFromQualified(express);
1155 auto *assignExpr = AllocNode<ir::AssignmentExpression>(left, right,
1156 lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
1157 auto *res = AllocNode<ir::ExpressionStatement>(assignExpr);
1158 return res;
1159 }
1160
1161 ir::Expression *init = CreateMemberExpressionFromQualified(express);
1162 ir::Statement *res = CreateVariableDeclarationWithIdentify(name, VariableParsingFlags::VAR, node,
1163 node->IsExport(), init);
1164 if (node->IsExport()) {
1165 ArenaVector<ir::ExportSpecifier *> specifiers(Allocator()->Adapter());
1166 res = AllocNode<ir::ExportNamedDeclaration>(res, std::move(specifiers));
1167 AddExportLocalEntryItem(name, node->Id());
1168 }
1169 return res;
1170 }
1171
IsInstantiatedImportEquals(const ir::TSImportEqualsDeclaration * node,binder::Scope * scope) const1172 bool Transformer::IsInstantiatedImportEquals(const ir::TSImportEqualsDeclaration *node, binder::Scope *scope) const
1173 {
1174 if (!node) {
1175 return false;
1176 }
1177 bool isType = true;
1178 auto *var = FindTSModuleVariable(node->ModuleReference(), scope, &isType);
1179 if (var == nullptr) {
1180 return !isType;
1181 }
1182 auto *decl = var->Declaration();
1183 ASSERT(decl->IsNamespaceDecl());
1184 return decl->AsNamespaceDecl()->IsInstantiated();
1185 return false;
1186 }
1187
FindTSModuleVariable(const ir::Expression * node,const binder::Scope * scope,bool * isType) const1188 binder::Variable *Transformer::FindTSModuleVariable(const ir::Expression *node,
1189 const binder::Scope *scope,
1190 bool *isType) const
1191 {
1192 if (node == nullptr || !(node->IsTSQualifiedName() || node->IsIdentifier())) {
1193 return nullptr;
1194 }
1195 if (node->IsTSQualifiedName()) {
1196 auto *tsQualifiedName = node->AsTSQualifiedName();
1197 auto *var = FindTSModuleVariable(tsQualifiedName->Left(), scope, isType);
1198 if (var == nullptr) {
1199 // If it's not a namespace, we would set isType flag before. So we don't set isType here.
1200 return nullptr;
1201 }
1202 auto *exportTSBindings = var->AsNamespaceVariable()->GetExportBindings();
1203 auto name = tsQualifiedName->Right()->Name();
1204 binder::Variable *res = exportTSBindings->FindExportTSVariable<binder::TSBindingType::NAMESPACE>(name);
1205 if (res != nullptr) {
1206 return res;
1207 }
1208 res = exportTSBindings->FindExportTSVariable<binder::TSBindingType::IMPORT_EQUALS>(name);
1209 if (res != nullptr) {
1210 auto *node = res->Declaration()->Node();
1211 return FindTSModuleVariable(node->Parent()->AsTSImportEqualsDeclaration()->ModuleReference(),
1212 res->AsImportEqualsVariable()->GetScope(), isType);
1213 }
1214
1215 // We process namespace and import equals before. So it should be a type, if it's not a js value or enum.
1216 // And const enum was processed as enum in es2abc, so we don't thought it as type here.
1217 // We should process const enum as type, if we change const enum to literal in es2abc later.
1218 *isType = exportTSBindings->FindExportVariable(name) == nullptr &&
1219 exportTSBindings->FindExportTSVariable<binder::TSBindingType::ENUMLITERAL>(name) == nullptr;
1220
1221 return nullptr;
1222 }
1223
1224 auto name = node->AsIdentifier()->Name();
1225 auto *currentScope = scope;
1226 while (currentScope != nullptr) {
1227 auto *res = FindTSVariable<binder::TSBindingType::NAMESPACE>(currentScope, name);
1228 if (res != nullptr) {
1229 return res;
1230 }
1231
1232 res = FindTSVariable<binder::TSBindingType::IMPORT_EQUALS>(currentScope, name);
1233 if (res != nullptr) {
1234 auto *node = res->Declaration()->Node();
1235 return FindTSModuleVariable(node->Parent()->AsTSImportEqualsDeclaration()->ModuleReference(),
1236 res->AsImportEqualsVariable()->GetScope(), isType);
1237 }
1238
1239 // Enum is not a module, so we return null here.
1240 // Const enum was processed as enum in es2abc, so we don't process it as type here.
1241 res = FindTSVariable<binder::TSBindingType::ENUMLITERAL>(currentScope, name);
1242 if (res != nullptr) {
1243 *isType = false;
1244 return nullptr;
1245 }
1246
1247 res = currentScope->FindLocal(name, binder::ResolveBindingOptions::BINDINGS);
1248 if (res != nullptr) {
1249 *isType = false;
1250 return nullptr;
1251 }
1252
1253 currentScope = currentScope->Parent();
1254 }
1255
1256 // can not find variable
1257 *isType = true;
1258 return nullptr;
1259 }
1260
1261 template <binder::TSBindingType type>
FindTSVariable(const binder::Scope * scope,const util::StringView & name) const1262 binder::Variable *Transformer::FindTSVariable(const binder::Scope *scope, const util::StringView &name) const
1263 {
1264 binder::Variable *res = scope->FindLocalTSVariable<type>(name);
1265 if (res == nullptr && scope->IsTSModuleScope()) {
1266 res = scope->AsTSModuleScope()->FindExportTSVariable<type>(name);
1267 }
1268 return res;
1269 }
1270
VisitExportNamedVariable(ir::Statement * decl)1271 std::vector<ir::AstNode *> Transformer::VisitExportNamedVariable(ir::Statement *decl)
1272 {
1273 std::vector<ir::AstNode *> res;
1274 if (decl->IsVariableDeclaration()) {
1275 auto declarators = decl->AsVariableDeclaration()->Declarators();
1276 for (auto *it : declarators) {
1277 if (it->Init()) {
1278 auto *left = std::get<ir::AstNode *>(VisitTSNode(it->Id()))->AsExpression();
1279 auto *right = std::get<ir::AstNode *>(VisitTSNode(it->Init()))->AsExpression();
1280 auto *assignExpr = AllocNode<ir::AssignmentExpression>(left, right,
1281 lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
1282 res.push_back(AllocNode<ir::ExpressionStatement>(assignExpr));
1283 }
1284 }
1285 } else if (decl->IsFunctionDeclaration() || decl->IsClassDeclaration()) {
1286 auto newDecl = VisitTSNode(decl);
1287 if (std::holds_alternative<ir::AstNode *>(newDecl)) {
1288 res.push_back(std::get<ir::AstNode *>(newDecl));
1289 } else {
1290 auto statements = std::get<std::vector<ir::AstNode *>>(newDecl);
1291 res.insert(res.end(), statements.begin(), statements.end());
1292 }
1293
1294 auto name = decl->IsFunctionDeclaration() ?
1295 decl->AsFunctionDeclaration()->Function()->Id() :
1296 decl->AsClassDeclaration()->Definition()->Ident();
1297 ASSERT(name != nullptr);
1298 res.push_back(CreateTsModuleAssignment(name->Name()));
1299 }
1300 return res;
1301 }
1302
CreateMemberExpressionFromQualified(ir::Expression * node)1303 ir::Expression *Transformer::CreateMemberExpressionFromQualified(ir::Expression *node)
1304 {
1305 if (node->IsTSQualifiedName()) {
1306 auto *tsQualifiedName = node->AsTSQualifiedName();
1307 auto *left = CreateMemberExpressionFromQualified(tsQualifiedName->Left());
1308 auto *right = AllocNode<ir::Identifier>(tsQualifiedName->Right()->Name());
1309 return AllocNode<ir::MemberExpression>(left, right,
1310 ir::MemberExpression::MemberExpressionKind::PROPERTY_ACCESS, false, false);
1311 }
1312 ASSERT(node->IsIdentifier());
1313 auto *id = CreateReferenceIdentifier(node->AsIdentifier()->Name());
1314 return id;
1315 }
1316
SetOriginalNode(ir::UpdateNodes res,ir::AstNode * originalNode) const1317 void Transformer::SetOriginalNode(ir::UpdateNodes res, ir::AstNode *originalNode) const
1318 {
1319 if (std::holds_alternative<ir::AstNode *>(res)) {
1320 auto *node = std::get<ir::AstNode *>(res);
1321 if (node == nullptr || node == originalNode) {
1322 return;
1323 }
1324 node->SetOriginal(originalNode);
1325 node->SetRange(originalNode->Range());
1326 } else {
1327 auto nodes = std::get<std::vector<ir::AstNode *>>(res);
1328 for (auto *it : nodes) {
1329 it->SetOriginal(originalNode);
1330 it->SetRange(originalNode->Range());
1331 }
1332 }
1333 }
1334
CreateTsModuleAssignment(util::StringView name)1335 ir::ExpressionStatement *Transformer::CreateTsModuleAssignment(util::StringView name)
1336 {
1337 auto moduleName = GetCurrentTSModuleName();
1338 auto *id = CreateReferenceIdentifier(moduleName);
1339 auto *left = AllocNode<ir::MemberExpression>(id, AllocNode<ir::Identifier>(name),
1340 ir::MemberExpression::MemberExpressionKind::PROPERTY_ACCESS, false, false);
1341 auto *right = CreateReferenceIdentifier(name);
1342 auto *assignExpr = AllocNode<ir::AssignmentExpression>(left, right, lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
1343 return AllocNode<ir::ExpressionStatement>(assignExpr);
1344 }
1345
GetNameFromModuleDeclaration(ir::TSModuleDeclaration * node) const1346 util::StringView Transformer::GetNameFromModuleDeclaration(ir::TSModuleDeclaration *node) const
1347 {
1348 return node->Name()->AsIdentifier()->Name();
1349 }
1350
CreateVariableDeclarationWithIdentify(util::StringView name,VariableParsingFlags flags,ir::AstNode * node,bool isExport,ir::Expression * init,bool needBinding)1351 ir::VariableDeclaration *Transformer::CreateVariableDeclarationWithIdentify(util::StringView name,
1352 VariableParsingFlags flags,
1353 ir::AstNode *node,
1354 bool isExport,
1355 ir::Expression *init,
1356 bool needBinding)
1357 {
1358 auto *ident = CreateReferenceIdentifier(name);
1359 auto *declarator = AllocNode<ir::VariableDeclarator>(ident, init);
1360 ArenaVector<ir::VariableDeclarator *> declarators(Allocator()->Adapter());
1361 declarators.push_back(declarator);
1362
1363 auto varKind = ir::VariableDeclaration::VariableDeclarationKind::VAR;
1364 if (flags & VariableParsingFlags::VAR) {
1365 } else if (flags & VariableParsingFlags::LET) {
1366 varKind = ir::VariableDeclaration::VariableDeclarationKind::LET;
1367 } else {
1368 varKind = ir::VariableDeclaration::VariableDeclarationKind::CONST;
1369 }
1370 auto *declaration = AllocNode<ir::VariableDeclaration>(varKind, std::move(declarators), false);
1371
1372 lexer::SourcePosition startPos(0, 0);
1373 if (node != nullptr) {
1374 startPos = node->Start();
1375 }
1376 if (needBinding) {
1377 binder::Decl *decl = nullptr;
1378 binder::DeclarationFlags declflag = isExport ?
1379 binder::DeclarationFlags::EXPORT :
1380 binder::DeclarationFlags::NONE;
1381 if (flags & VariableParsingFlags::VAR) {
1382 decl = Binder()->AddDecl<binder::VarDecl>(startPos, declflag, false, name);
1383 } else if (flags & VariableParsingFlags::LET) {
1384 decl = Binder()->AddDecl<binder::LetDecl>(startPos, declflag, false, name);
1385 } else {
1386 decl = Binder()->AddDecl<binder::ConstDecl>(startPos, declflag, false, name);
1387 }
1388 decl->BindNode(declaration);
1389 }
1390
1391 return declaration;
1392 }
1393
GetParamName(ir::AstNode * node,util::StringView name) const1394 util::StringView Transformer::GetParamName(ir::AstNode *node, util::StringView name) const
1395 {
1396 if (node->IsTSModuleDeclaration()) {
1397 auto scope = node->AsTSModuleDeclaration()->Scope();
1398 if (scope && !scope->HasVariableName(name)) {
1399 return name;
1400 }
1401 }
1402 if (node->IsTSEnumDeclaration()) {
1403 auto scope = node->AsTSEnumDeclaration()->Scope();
1404 if (scope && !scope->HasDeclarationName(name)) {
1405 return name;
1406 }
1407 }
1408
1409 auto uniqueName = CreateUniqueName(std::string(name) + std::string(INDEX_DIVISION));
1410 return uniqueName;
1411 }
1412
CreateCallExpressionForTsModule(ir::TSModuleDeclaration * node,util::StringView name,bool isExport)1413 ir::CallExpression *Transformer::CreateCallExpressionForTsModule(ir::TSModuleDeclaration *node,
1414 util::StringView name,
1415 bool isExport)
1416 {
1417 ir::ScriptFunction *funcNode = nullptr;
1418
1419 binder::FunctionScope *funcScope = node->Scope();
1420 binder::FunctionParamScope *funcParamScope = funcScope->ParamScope();
1421 auto paramName = GetParamName(node, name);
1422 {
1423 auto paramScopeCtx = binder::LexicalScope<binder::FunctionParamScope>::Enter(Binder(), funcParamScope);
1424
1425 ArenaVector<ir::Expression *> params(Allocator()->Adapter());
1426 auto *parameter = CreateReferenceIdentifier(paramName);
1427 Binder()->AddParamDecl(parameter);
1428 params.push_back(parameter);
1429
1430 ir::BlockStatement *blockNode = nullptr;
1431 {
1432 auto scopeCtx = binder::LexicalScope<binder::FunctionScope>::Enter(Binder(), funcScope);
1433 tsModuleList_.push_back({paramName, funcScope});
1434 if (node->Body()->IsTSModuleDeclaration()) {
1435 auto *tsModule = node->Body()->AsTSModuleDeclaration();
1436 auto body = std::get<std::vector<ir::AstNode *>>(VisitTsModuleDeclaration(tsModule, true));
1437 ArenaVector<ir::Statement *> statements(Allocator()->Adapter());
1438 for (auto *it : body) {
1439 statements.push_back(static_cast<ir::Statement *>(it));
1440 }
1441 blockNode = AllocNode<ir::BlockStatement>(funcScope, std::move(statements));
1442 } else {
1443 auto body = VisitTSNodes(node->Body());
1444 blockNode = AllocNode<ir::BlockStatement>(funcScope,
1445 std::move(body->AsTSModuleBlock()->Statements()));
1446 }
1447 tsModuleList_.pop_back();
1448 funcScope->AddBindsFromParam();
1449 }
1450
1451 funcNode = AllocNode<ir::ScriptFunction>(funcScope, std::move(params), nullptr, blockNode, nullptr,
1452 ir::ScriptFunctionFlags::NONE, false, Extension() == ScriptExtension::TS);
1453
1454 funcScope->BindNode(funcNode);
1455 funcParamScope->BindNode(funcNode);
1456 }
1457
1458 auto *funcExpr = AllocNode<ir::FunctionExpression>(funcNode);
1459
1460 ArenaVector<ir::Expression *> arguments = CreateCallExpressionArguments(name, isExport);
1461 auto *callExpr = AllocNode<ir::CallExpression>(funcExpr, std::move(arguments), nullptr, false);
1462
1463 return callExpr;
1464 }
1465
CreateTsModuleParam(util::StringView paramName,bool isExport)1466 ir::Expression *Transformer::CreateTsModuleParam(util::StringView paramName, bool isExport)
1467 {
1468 if (isExport) {
1469 auto moduleName = GetCurrentTSModuleName();
1470 auto *id = CreateReferenceIdentifier(moduleName);
1471 return AllocNode<ir::MemberExpression>(id, AllocNode<ir::Identifier>(paramName),
1472 ir::MemberExpression::MemberExpressionKind::PROPERTY_ACCESS, false, false);
1473 }
1474
1475 auto *id = CreateReferenceIdentifier(paramName);
1476 return id;
1477 }
1478
AddExportLocalEntryItem(util::StringView name,const ir::Identifier * identifier)1479 void Transformer::AddExportLocalEntryItem(util::StringView name, const ir::Identifier *identifier)
1480 {
1481 auto moduleRecord = GetSourceTextModuleRecord();
1482 auto *entry = moduleRecord->NewEntry<SourceTextModuleRecord::ExportEntry>(name, name, identifier, identifier);
1483 [[maybe_unused]] bool res = moduleRecord->AddLocalExportEntry(entry);
1484 ASSERT(res);
1485 }
1486
VisitTsModuleDeclaration(ir::TSModuleDeclaration * node,bool isExport)1487 ir::UpdateNodes Transformer::VisitTsModuleDeclaration(ir::TSModuleDeclaration *node, bool isExport)
1488 {
1489 std::vector<ir::AstNode *> res;
1490
1491 util::StringView name = GetNameFromModuleDeclaration(node);
1492
1493 auto findRes = Scope()->FindLocal(name, binder::ResolveBindingOptions::BINDINGS);
1494 if (findRes == nullptr) {
1495 res.push_back(CreateVariableDeclarationForTSEnumOrTSModule(name, node, isExport));
1496 }
1497
1498 auto *callExpr = CreateCallExpressionForTsModule(node, name, isExport && IsTsModule());
1499 auto *exprStatementNode = AllocNode<ir::ExpressionStatement>(callExpr);
1500 res.push_back(exprStatementNode);
1501
1502 return res;
1503 }
1504
CreateReferenceIdentifier(util::StringView name)1505 ir::Identifier *Transformer::CreateReferenceIdentifier(util::StringView name)
1506 {
1507 auto *node = AllocNode<ir::Identifier>(name);
1508 node->AsIdentifier()->SetReference();
1509 return node;
1510 }
1511
VisitTsEnumDeclaration(ir::TSEnumDeclaration * node,bool isExport)1512 ir::UpdateNodes Transformer::VisitTsEnumDeclaration(ir::TSEnumDeclaration *node, bool isExport)
1513 {
1514 std::vector<ir::AstNode *> res;
1515
1516 util::StringView name = GetNameFromTsEnumDeclaration(node);
1517
1518 auto findRes = Scope()->FindLocal(name); // Find if the variable with the same name is already defined
1519 if (findRes == nullptr) {
1520 res.push_back(CreateVariableDeclarationForTSEnumOrTSModule(name, node, isExport));
1521 }
1522
1523 auto *callExpr = CreateCallExpressionForTsEnum(node, name, isExport && IsTsModule());
1524 auto *exprStatementNode = AllocNode<ir::ExpressionStatement>(callExpr);
1525 res.push_back(exprStatementNode);
1526
1527 return res;
1528 }
1529
CreateVariableDeclarationForTSEnumOrTSModule(util::StringView name,ir::AstNode * node,bool isExport)1530 ir::AstNode *Transformer::CreateVariableDeclarationForTSEnumOrTSModule(util::StringView name,
1531 ir::AstNode *node, bool isExport)
1532 {
1533 auto flag = Scope()->Parent() == nullptr ? VariableParsingFlags::VAR : VariableParsingFlags::LET;
1534 auto *variableDeclaration = CreateVariableDeclarationWithIdentify(name, flag, node, isExport);
1535 bool doExport = isExport && !IsTsModule();
1536 if (doExport) { // export var
1537 ArenaVector<ir::ExportSpecifier *> specifiers(Allocator()->Adapter());
1538 auto *exportDeclaration = AllocNode<ir::ExportNamedDeclaration>(variableDeclaration, std::move(specifiers));
1539 auto *ident = node->IsTSEnumDeclaration() ?
1540 node->AsTSEnumDeclaration()->Key()->AsIdentifier() : node->AsTSModuleDeclaration()->Name()->AsIdentifier();
1541 AddExportLocalEntryItem(name, ident);
1542 return exportDeclaration;
1543 }
1544 return variableDeclaration;
1545 }
1546
GetNameFromTsEnumDeclaration(const ir::TSEnumDeclaration * node) const1547 util::StringView Transformer::GetNameFromTsEnumDeclaration(const ir::TSEnumDeclaration *node) const
1548 {
1549 auto *name = node->AsTSEnumDeclaration()->Key();
1550 return name->AsIdentifier()->Name();
1551 }
1552
CreateCallExpressionForTsEnum(ir::TSEnumDeclaration * node,util::StringView name,bool isExport)1553 ir::CallExpression *Transformer::CreateCallExpressionForTsEnum(ir::TSEnumDeclaration *node, util::StringView name,
1554 bool isExport)
1555 {
1556 ir::ScriptFunction *funcNode = nullptr;
1557
1558 binder::FunctionScope *funcScope = node->Scope();
1559 binder::FunctionParamScope *funcParamScope = funcScope->ParamScope();
1560 util::StringView paramName = GetParamName(node, name); // modify the name of the function param
1561 {
1562 auto paramScopeCtx = binder::LexicalScope<binder::FunctionParamScope>::Enter(Binder(), funcParamScope);
1563 // create function param
1564 ArenaVector<ir::Expression *> params(Allocator()->Adapter());
1565 auto *parameter = CreateReferenceIdentifier(paramName);
1566 Binder()->AddParamDecl(parameter);
1567 params.push_back(parameter);
1568 // create function body
1569 ir::BlockStatement *blockNode = nullptr;
1570 {
1571 auto scopeCtx = binder::LexicalScope<binder::FunctionScope>::Enter(Binder(), funcScope);
1572 tsEnumList_.push_back({paramName, funcScope});
1573
1574 ArenaVector<ir::TSEnumMember *> members = node->Members();
1575 ArenaVector<ir::Statement *> statements(Allocator()->Adapter());
1576 ir::TSEnumMember *preTsEnumMember = nullptr;
1577 for (auto member : members) {
1578 auto *currTsEnumMember = member->AsTSEnumMember();
1579 auto statement = CreateTsEnumMember(currTsEnumMember, preTsEnumMember, paramName);
1580 preTsEnumMember = currTsEnumMember;
1581 statements.push_back(statement);
1582 }
1583
1584 blockNode = AllocNode<ir::BlockStatement>(funcScope, std::move(statements));
1585 tsEnumList_.pop_back();
1586 funcScope->AddBindsFromParam();
1587 }
1588 funcNode = AllocNode<ir::ScriptFunction>(funcScope, std::move(params), nullptr, blockNode, nullptr,
1589 ir::ScriptFunctionFlags::NONE, false, Extension() == ScriptExtension::TS);
1590
1591 funcScope->BindNode(funcNode);
1592 funcParamScope->BindNode(funcNode);
1593 }
1594 auto *funcExpr = AllocNode<ir::FunctionExpression>(funcNode);
1595
1596 ArenaVector<ir::Expression *> arguments = CreateCallExpressionArguments(name, isExport);
1597 auto *callExpr = AllocNode<ir::CallExpression>(funcExpr, std::move(arguments), nullptr, false);
1598
1599 return callExpr;
1600 }
1601
CreateCallExpressionArguments(util::StringView name,bool isExport)1602 ArenaVector<ir::Expression *> Transformer::CreateCallExpressionArguments(util::StringView name, bool isExport)
1603 {
1604 ArenaVector<ir::Expression *> arguments(Allocator()->Adapter());
1605 ArenaVector<ir::Expression *> properties(Allocator()->Adapter());
1606 auto *objectExpression = AllocNode<ir::ObjectExpression>(ir::AstNodeType::OBJECT_EXPRESSION,
1607 std::move(properties),
1608 false);
1609 auto assignExpr = AllocNode<ir::AssignmentExpression>(CreateTsModuleParam(name, isExport),
1610 objectExpression,
1611 lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
1612 auto argument = AllocNode<ir::BinaryExpression>(CreateTsModuleParam(name, isExport),
1613 assignExpr,
1614 lexer::TokenType::PUNCTUATOR_LOGICAL_OR);
1615 if (isExport) {
1616 auto *id = CreateReferenceIdentifier(name);
1617 arguments.push_back(AllocNode<ir::AssignmentExpression>(id, argument,
1618 lexer::TokenType::PUNCTUATOR_SUBSTITUTION));
1619 } else {
1620 arguments.push_back(argument);
1621 }
1622
1623 return arguments;
1624 }
1625
CreateTsEnumMember(ir::TSEnumMember * node,ir::TSEnumMember * preNode,util::StringView enumLiteralName)1626 ir::ExpressionStatement *Transformer::CreateTsEnumMember(ir::TSEnumMember *node, ir::TSEnumMember *preNode,
1627 util::StringView enumLiteralName)
1628 {
1629 util::StringView enumMemberName = GetNameFromEnumMember(node);
1630 binder::Variable *enumVar = Scope()->AsTSEnumScope()->FindEnumMemberVariable(enumMemberName);
1631 ASSERT(enumVar);
1632 if (node->Init() != nullptr) {
1633 bool isStringInit = enumVar->AsEnumVariable()->StringInit();
1634 if (!enumVar->AsEnumVariable()->IsVisited()) {
1635 isStringInit = IsStringInitForEnumMember(node->Init(), Scope());
1636 if (isStringInit) {
1637 enumVar->AsEnumVariable()->SetStringInit();
1638 }
1639 enumVar->AsEnumVariable()->SetVisited();
1640 }
1641 return isStringInit ? CreateTsEnumMemberWithStringInit(node, enumLiteralName, enumMemberName) :
1642 CreateTsEnumMemberWithNumberInit(node, enumLiteralName, enumMemberName);
1643 }
1644
1645 enumVar->AsEnumVariable()->SetVisited();
1646 return CreateTsEnumMemberWithoutInit(node, preNode, enumLiteralName, enumMemberName);
1647 }
1648
CreateTsEnumMemberWithStringInit(ir::TSEnumMember * node,util::StringView enumLiteralName,util::StringView enumMemberName)1649 ir::ExpressionStatement *Transformer::CreateTsEnumMemberWithStringInit(ir::TSEnumMember *node,
1650 util::StringView enumLiteralName,
1651 util::StringView enumMemberName)
1652 {
1653 // transform to the shape like E["a"] = "str";
1654 auto *object = CreateReferenceIdentifier(enumLiteralName);
1655 auto *property = AllocNode<ir::StringLiteral>(enumMemberName);
1656 auto *left = AllocNode<ir::MemberExpression>(object, property,
1657 ir::MemberExpression::MemberExpressionKind::ELEMENT_ACCESS,
1658 true, false);
1659 auto *right = std::get<ir::AstNode *>(VisitTSNode(node->Init()))->AsExpression();
1660
1661 auto *assignExpr = AllocNode<ir::AssignmentExpression>(left, right, lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
1662 auto *exprStatementNode = AllocNode<ir::ExpressionStatement>(assignExpr);
1663
1664 return exprStatementNode;
1665 }
1666
CreateTsEnumMemberWithNumberInit(ir::TSEnumMember * node,util::StringView enumLiteralName,util::StringView enumMemberName)1667 ir::ExpressionStatement *Transformer::CreateTsEnumMemberWithNumberInit(ir::TSEnumMember *node,
1668 util::StringView enumLiteralName,
1669 util::StringView enumMemberName)
1670 {
1671 // transform to the shape like E[E["a"] = init] = "a";
1672 auto *innerObject = CreateReferenceIdentifier(enumLiteralName);
1673 auto *innerProperty = AllocNode<ir::StringLiteral>(enumMemberName);
1674 auto *innerLeft = AllocNode<ir::MemberExpression>(innerObject, innerProperty,
1675 ir::MemberExpression::MemberExpressionKind::ELEMENT_ACCESS,
1676 true, false);
1677 auto *innerRight = std::get<ir::AstNode *>(VisitTSNode(node->Init()))->AsExpression();
1678
1679 auto *object = CreateReferenceIdentifier(enumLiteralName);
1680 auto *property = AllocNode<ir::AssignmentExpression>(innerLeft, innerRight,
1681 lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
1682 auto *left = AllocNode<ir::MemberExpression>(object, property,
1683 ir::MemberExpression::MemberExpressionKind::ELEMENT_ACCESS,
1684 true, false);
1685
1686 auto *right = AllocNode<ir::StringLiteral>(enumMemberName);
1687
1688 auto *assignExpr = AllocNode<ir::AssignmentExpression>(left, right, lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
1689 auto *exprStatementNode = AllocNode<ir::ExpressionStatement>(assignExpr);
1690
1691 return exprStatementNode;
1692 }
1693
CreateTsEnumMemberWithoutInit(ir::TSEnumMember * node,ir::TSEnumMember * preNode,util::StringView enumLiteralName,util::StringView enumMemberName)1694 ir::ExpressionStatement *Transformer::CreateTsEnumMemberWithoutInit(ir::TSEnumMember *node,
1695 ir::TSEnumMember *preNode,
1696 util::StringView enumLiteralName,
1697 util::StringView enumMemberName)
1698 {
1699 // transform to the shape like E[E["a"] = value] = "a";
1700 auto *innerObject = CreateReferenceIdentifier(enumLiteralName);
1701 auto *innerProperty = AllocNode<ir::StringLiteral>(enumMemberName);
1702 auto *innerLeft = AllocNode<ir::MemberExpression>(innerObject, innerProperty,
1703 ir::MemberExpression::MemberExpressionKind::ELEMENT_ACCESS,
1704 true, false);
1705
1706 ir::AssignmentExpression *property = nullptr;
1707 if (preNode == nullptr) { // first enumMember, value = 0
1708 auto *innerRight = AllocNode<ir::NumberLiteral>(0);
1709 property = AllocNode<ir::AssignmentExpression>(innerLeft, innerRight,
1710 lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
1711 } else { // not first enumMember, value = E.prenode + 1
1712 auto *innerRightObject = CreateReferenceIdentifier(enumLiteralName);
1713 auto *innerPropertyForMemberExpr = AllocNode<ir::Identifier>(GetNameFromEnumMember(preNode));
1714 auto *innerMemberExpr = AllocNode<ir::MemberExpression>(innerRightObject, innerPropertyForMemberExpr,
1715 ir::MemberExpression::MemberExpressionKind::PROPERTY_ACCESS, false, false);
1716 auto *innerRight = AllocNode<ir::BinaryExpression>(innerMemberExpr, AllocNode<ir::NumberLiteral>(1),
1717 lexer::TokenType::PUNCTUATOR_PLUS);
1718 property = AllocNode<ir::AssignmentExpression>(innerLeft, innerRight,
1719 lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
1720 }
1721 auto *object = CreateReferenceIdentifier(enumLiteralName);
1722 auto *left = AllocNode<ir::MemberExpression>(object, property,
1723 ir::MemberExpression::MemberExpressionKind::ELEMENT_ACCESS,
1724 true, false);
1725
1726 auto *right = AllocNode<ir::StringLiteral>(enumMemberName);
1727
1728 auto *assignExpr = AllocNode<ir::AssignmentExpression>(left, right, lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
1729 auto *exprStatementNode = AllocNode<ir::ExpressionStatement>(assignExpr);
1730
1731 return exprStatementNode;
1732 }
1733
IsStringInitForEnumMember(const ir::Expression * expr,binder::Scope * scope) const1734 bool Transformer::IsStringInitForEnumMember(const ir::Expression *expr, binder::Scope *scope) const
1735 {
1736 if (expr == nullptr) {
1737 return false;
1738 }
1739
1740 // The string enumMember is either initialized with a string literal, or with another string enumMember.
1741 switch (expr->Type()) {
1742 case ir::AstNodeType::STRING_LITERAL:
1743 case ir::AstNodeType::TEMPLATE_LITERAL: {
1744 // TemplateLiteral in Enum must be a string literal.
1745 return true;
1746 }
1747 case ir::AstNodeType::IDENTIFIER: {
1748 // Return true if this identifier is a string enumMember of the current Enum.
1749 util::StringView identName = expr->AsIdentifier()->Name();
1750 ASSERT(scope && scope->IsTSEnumScope());
1751 binder::Variable *v = scope->AsTSEnumScope()->FindEnumMemberVariable(identName);
1752 if (v == nullptr) {
1753 return false;
1754 }
1755 if (!v->AsEnumVariable()->IsVisited()) { // visit the quoted item
1756 auto *initExpr = v->AsEnumVariable()->Declaration()->Node()->AsTSEnumMember()->Init();
1757 if (IsStringInitForEnumMember(initExpr, scope)) {
1758 v->AsEnumVariable()->SetStringInit();
1759 }
1760 v->AsEnumVariable()->SetVisited();
1761 }
1762 if (v->AsEnumVariable()->IsVisited() && v->AsEnumVariable()->StringInit()) {
1763 return true;
1764 }
1765
1766 return false;
1767 }
1768 case ir::AstNodeType::MEMBER_EXPRESSION: {
1769 return IsStringForMemberExpression(expr->AsMemberExpression(), scope);
1770 }
1771 case ir::AstNodeType::BINARY_EXPRESSION: {
1772 auto *left = expr->AsBinaryExpression()->Left();
1773 auto *right = expr->AsBinaryExpression()->Right();
1774 if (expr->AsBinaryExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_PLUS &&
1775 IsStringInitForEnumMember(right, scope) && IsStringInitForEnumMember(left, scope)) {
1776 return true;
1777 }
1778 return false;
1779 }
1780 default:
1781 return false;
1782 }
1783
1784 return false;
1785 }
1786
IsStringForMemberExpression(const ir::MemberExpression * memberExpr,binder::Scope * scope) const1787 bool Transformer::IsStringForMemberExpression(const ir::MemberExpression *memberExpr, binder::Scope *scope) const
1788 {
1789 // Return true only if memberExpression is a string enumMember.
1790 const ir::Expression *expr = memberExpr;
1791 ArenaDeque<const ir::Expression *> members(Allocator()->Adapter());
1792 while (expr->IsMemberExpression()) {
1793 if (expr->AsMemberExpression()->Property()->IsIdentifier() ||
1794 expr->AsMemberExpression()->Property()->IsStringLiteral() ||
1795 expr->AsMemberExpression()->Property()->IsTemplateLiteral()) {
1796 members.push_front(expr->AsMemberExpression()->Property());
1797 expr = expr->AsMemberExpression()->Object();
1798 } else {
1799 return false;
1800 }
1801 }
1802 if (!expr->IsIdentifier()) {
1803 return false;
1804 }
1805 members.push_front(expr->AsIdentifier());
1806
1807 // Find front Ident TSVariables
1808 ArenaVector<binder::Variable *> findRes = FindFrontIdentifierTSVariables(members.front()->AsIdentifier(), scope);
1809 members.pop_front();
1810
1811 for (auto currVar : findRes) {
1812 if (VerifyMemberExpressionDeque(currVar, members)) {
1813 return true;
1814 }
1815 }
1816 return false;
1817 }
1818
FindFrontIdentifierTSVariables(const ir::Identifier * ident,binder::Scope * scope) const1819 ArenaVector<binder::Variable *> Transformer::FindFrontIdentifierTSVariables(const ir::Identifier *ident,
1820 binder::Scope *scope) const
1821 {
1822 util::StringView name = ident->Name();
1823 binder::Variable *v = nullptr;
1824 ArenaVector<binder::Variable *> findRes(Allocator()->Adapter());
1825 while (scope != nullptr) {
1826 // find enumMemberBindings_
1827 if (scope->IsTSEnumScope()) {
1828 v = scope->AsTSEnumScope()->FindEnumMemberVariable(name);
1829 if (v != nullptr) {
1830 break;
1831 }
1832 }
1833
1834 const std::vector<binder::TSBindingType> types = {binder::TSBindingType::NAMESPACE,
1835 binder::TSBindingType::ENUMLITERAL,
1836 binder::TSBindingType::IMPORT_EQUALS};
1837 // find tsBindings_
1838 FindLocalTSVariables(scope, name, types, findRes);
1839 // find exportTSBindings_
1840 if (scope->IsTSModuleScope()) {
1841 FindExportTSVariables(scope, name, types, findRes);
1842 }
1843
1844 if (!findRes.empty()) {
1845 break;
1846 }
1847
1848 // find js variable
1849 v = scope->FindLocal(name);
1850 if (v != nullptr) {
1851 if (scope->IsTSModuleScope() || scope->IsTSEnumScope()) { // v may be converted from ts variable
1852 v = scope->Parent()->FindLocal(name);
1853 if (v == nullptr) {
1854 break;
1855 }
1856 } else {
1857 break;
1858 }
1859 }
1860 if (scope->IsTSModuleScope()) {
1861 v = scope->AsTSModuleScope()->FindExportVariable(name);
1862 if (v != nullptr) {
1863 break;
1864 }
1865 }
1866
1867 if (scope->IsTSModuleScope() || scope->IsTSEnumScope()) {
1868 scope = scope->Parent();
1869 }
1870 scope = scope->Parent();
1871 }
1872
1873 return findRes;
1874 }
1875
IsInstantiatedNamespaceVariable(binder::Variable * var) const1876 bool Transformer::IsInstantiatedNamespaceVariable(binder::Variable *var) const
1877 {
1878 ASSERT(var->IsNamespaceVariable());
1879 auto *decl = var->AsNamespaceVariable()->Declaration();
1880 ASSERT(decl->IsNamespaceDecl());
1881 ArenaVector<ir::TSModuleDeclaration *> nodes = decl->AsNamespaceDecl()->Decls();
1882 for (ir::TSModuleDeclaration *node : nodes) {
1883 if (node->IsInstantiated()) {
1884 return true;
1885 }
1886 }
1887 return false;
1888 }
1889
FindLocalTSVariables(binder::Scope * scope,const util::StringView name,const std::vector<binder::TSBindingType> & types,ArenaVector<binder::Variable * > & findRes) const1890 void Transformer::FindLocalTSVariables(binder::Scope *scope, const util::StringView name,
1891 const std::vector<binder::TSBindingType> &types,
1892 ArenaVector<binder::Variable *> &findRes) const
1893 {
1894 for (binder::TSBindingType type : types) {
1895 binder::Variable *v = nullptr;
1896 switch (type) {
1897 case binder::TSBindingType::NAMESPACE: {
1898 v = scope->FindLocalTSVariable<binder::TSBindingType::NAMESPACE>(name);
1899 if (v != nullptr && !IsInstantiatedNamespaceVariable(v)) {
1900 v = nullptr;
1901 }
1902 break;
1903 }
1904 case binder::TSBindingType::ENUMLITERAL: {
1905 v = scope->FindLocalTSVariable<binder::TSBindingType::ENUMLITERAL>(name);
1906 break;
1907 }
1908 case binder::TSBindingType::IMPORT_EQUALS: {
1909 v = scope->FindLocalTSVariable<binder::TSBindingType::IMPORT_EQUALS>(name);
1910 if (v != nullptr &&
1911 !IsInstantiatedImportEquals(v->AsImportEqualsVariable()->Declaration()->Node()->
1912 Parent()->AsTSImportEqualsDeclaration(), scope)) {
1913 v = nullptr;
1914 }
1915 break;
1916 }
1917 default:
1918 continue;
1919 }
1920 if (v != nullptr) {
1921 findRes.push_back(v);
1922 }
1923 }
1924 }
1925
FindExportTSVariables(binder::Scope * scope,const util::StringView name,const std::vector<binder::TSBindingType> & types,ArenaVector<binder::Variable * > & findRes) const1926 void Transformer::FindExportTSVariables(binder::Scope *scope, const util::StringView name,
1927 const std::vector<binder::TSBindingType> &types,
1928 ArenaVector<binder::Variable *> &findRes) const
1929 {
1930 for (binder::TSBindingType type : types) {
1931 binder::Variable *v = nullptr;
1932 switch (type) {
1933 case binder::TSBindingType::NAMESPACE: {
1934 v = scope->AsTSModuleScope()->FindExportTSVariable<binder::TSBindingType::NAMESPACE>(name);
1935 if (v != nullptr && !IsInstantiatedNamespaceVariable(v)) {
1936 v = nullptr;
1937 }
1938 break;
1939 }
1940 case binder::TSBindingType::ENUMLITERAL: {
1941 v = scope->AsTSModuleScope()->FindExportTSVariable<binder::TSBindingType::ENUMLITERAL>(name);
1942 break;
1943 }
1944 case binder::TSBindingType::IMPORT_EQUALS: {
1945 v = scope->AsTSModuleScope()->FindExportTSVariable<binder::TSBindingType::IMPORT_EQUALS>(name);
1946 if (v != nullptr &&
1947 !IsInstantiatedImportEquals(v->AsImportEqualsVariable()->Declaration()->Node()->
1948 Parent()->AsTSImportEqualsDeclaration(), scope)) {
1949 v = nullptr;
1950 }
1951 break;
1952 }
1953 default:
1954 continue;
1955 }
1956 if (v != nullptr) {
1957 findRes.push_back(v);
1958 }
1959 }
1960 }
1961
VerifyMemberExpressionDeque(binder::Variable * currVar,ArenaDeque<const ir::Expression * > members) const1962 bool Transformer::VerifyMemberExpressionDeque(binder::Variable *currVar,
1963 ArenaDeque<const ir::Expression *> members) const
1964 {
1965 ASSERT(!members.empty());
1966 switch (currVar->Flags()) {
1967 case binder::VariableFlags::ENUM_LITERAL: {
1968 // the recursion ends.
1969 util::StringView enumMemberName = GetNameForMemberExpressionItem(members.front());
1970 members.pop_front();
1971 if (!members.empty()) {
1972 return false;
1973 }
1974 binder::Variable *enumMemberVar = currVar->AsEnumLiteralVariable()->FindEnumMemberVariable(enumMemberName);
1975 if (enumMemberVar == nullptr) {
1976 return false;
1977 }
1978 if (!enumMemberVar->AsEnumVariable()->IsVisited()) { // visit the quoted item
1979 auto *scope = enumMemberVar->AsEnumVariable()->Declaration()->
1980 Node()->Parent()->AsTSEnumDeclaration()->Scope();
1981 auto *initExpr = enumMemberVar->AsEnumVariable()->Declaration()->Node()->AsTSEnumMember()->Init();
1982 if (IsStringInitForEnumMember(initExpr, scope)) {
1983 enumMemberVar->AsEnumVariable()->SetStringInit();
1984 }
1985 enumMemberVar->AsEnumVariable()->SetVisited();
1986 }
1987 if (enumMemberVar->AsEnumVariable()->IsVisited() && enumMemberVar->AsEnumVariable()->StringInit()) {
1988 return true;
1989 }
1990
1991 return false;
1992 }
1993 case binder::VariableFlags::NAMESPACE: {
1994 auto *exportTSBindings = currVar->AsNamespaceVariable()->GetExportBindings();
1995 if (exportTSBindings != nullptr) {
1996 ArenaVector<binder::Variable *> findRes(Allocator()->Adapter());
1997 util::StringView name = GetNameForMemberExpressionItem(members.front());
1998 binder::Variable *v = exportTSBindings->FindExportTSVariable<binder::TSBindingType::NAMESPACE>(name);
1999 if (v != nullptr && IsInstantiatedNamespaceVariable(v)) {
2000 findRes.push_back(v);
2001 }
2002 v = exportTSBindings->FindExportTSVariable<binder::TSBindingType::ENUMLITERAL>(name);
2003 if (v != nullptr) {
2004 findRes.push_back(v);
2005 }
2006 v = exportTSBindings->FindExportTSVariable<binder::TSBindingType::IMPORT_EQUALS>(name);
2007 if (v != nullptr) {
2008 findRes.push_back(v);
2009 }
2010 members.pop_front();
2011
2012 for (auto itemVar : findRes) {
2013 if (VerifyMemberExpressionDeque(itemVar, members)) {
2014 return true;
2015 }
2016 }
2017 return false;
2018 }
2019 return false;
2020 }
2021 case binder::VariableFlags::IMPORT_EQUALS: {
2022 // Replace import_equal
2023 auto *node = currVar->Declaration()->Node()->Parent()->AsTSImportEqualsDeclaration()->ModuleReference();
2024 while (node->IsTSQualifiedName()) {
2025 members.push_front(node->AsTSQualifiedName()->Right()->AsIdentifier());
2026 node = node->AsTSQualifiedName()->Left();
2027 }
2028 members.push_front(node->AsIdentifier());
2029
2030 ArenaVector<binder::Variable *> findRes = FindFrontIdentifierTSVariables(
2031 members.front()->AsIdentifier(), currVar->AsImportEqualsVariable()->GetScope());
2032 members.pop_front();
2033
2034 for (auto itemVar : findRes) {
2035 if (VerifyMemberExpressionDeque(itemVar, members)) {
2036 return true;
2037 }
2038 }
2039 return false;
2040 }
2041 default:
2042 return false;
2043 }
2044
2045 return false;
2046 }
2047
GetNameForMemberExpressionItem(const ir::Expression * node) const2048 util::StringView Transformer::GetNameForMemberExpressionItem(const ir::Expression *node) const
2049 {
2050 util::StringView name {};
2051 if (node->IsIdentifier()) {
2052 name = node->AsIdentifier()->Name();
2053 } else if (node->IsStringLiteral()) {
2054 name = node->AsStringLiteral()->Str();
2055 } else if (node->IsTemplateLiteral()) {
2056 name = node->AsTemplateLiteral()->Quasis().front()->Raw();
2057 }
2058 return name;
2059 }
2060
GetNameFromEnumMember(const ir::TSEnumMember * node) const2061 util::StringView Transformer::GetNameFromEnumMember(const ir::TSEnumMember *node) const
2062 {
2063 util::StringView name {};
2064 if (node->Key()->IsIdentifier()) {
2065 name = node->Key()->AsIdentifier()->Name();
2066 } else if (node->Key()->IsStringLiteral()) {
2067 name = node->Key()->AsStringLiteral()->Str();
2068 }
2069 return name;
2070 }
2071
FindEnumMemberScope(const util::StringView name) const2072 binder::Scope *Transformer::FindEnumMemberScope(const util::StringView name) const
2073 {
2074 // Transform is required only if ident is an enumMember.
2075 auto scope = Scope();
2076 while (scope != nullptr) {
2077 if (scope->InLocalTSBindings(name)) {
2078 return nullptr;
2079 }
2080 if (scope->IsTSModuleScope() && scope->AsTSModuleScope()->InExportBindings(name)) {
2081 return nullptr;
2082 }
2083 if (scope->IsTSEnumScope() && scope->AsTSEnumScope()->FindEnumMemberVariable(name)) {
2084 return scope;
2085 }
2086 if (scope->FindLocal(name)) {
2087 return nullptr;
2088 }
2089
2090 if (scope->IsTSModuleScope() || scope->IsTSEnumScope()) {
2091 scope = scope->Parent();
2092 }
2093 scope = scope->Parent();
2094 }
2095
2096 return nullptr;
2097 }
2098
CreateMemberExpressionFromIdentifier(binder::Scope * scope,ir::Identifier * node)2099 ir::MemberExpression *Transformer::CreateMemberExpressionFromIdentifier(binder::Scope *scope, ir::Identifier *node)
2100 {
2101 auto identName = node->Name();
2102 auto moduleName = scope->IsTSEnumScope() ? FindTSEnumNameByScope(scope) : FindTSModuleNameByScope(scope);
2103 auto *id = CreateReferenceIdentifier(moduleName);
2104 auto *res = AllocNode<ir::MemberExpression>(id, AllocNode<ir::Identifier>(identName),
2105 ir::MemberExpression::MemberExpressionKind::PROPERTY_ACCESS,
2106 false, false);
2107 SetOriginalNode(res, node);
2108 return res;
2109 }
2110
CheckTransformedAstStructure(const Program * program) const2111 void Transformer::CheckTransformedAstStructure(const Program *program) const
2112 {
2113 bool passed = true;
2114 CheckTransformedAstNodes(program->Ast(), &passed);
2115 if (passed) {
2116 std::cout << "Transformed AST structure check passed." << std::endl;
2117 }
2118 }
2119
CheckTransformedAstNodes(const ir::AstNode * parent,bool * passed) const2120 void Transformer::CheckTransformedAstNodes(const ir::AstNode *parent, bool *passed) const
2121 {
2122 parent->Iterate([this, parent, passed](auto *childNode) { CheckTransformedAstNode(parent, childNode, passed); });
2123 }
2124
CheckTransformedAstNode(const ir::AstNode * parent,ir::AstNode * childNode,bool * passed) const2125 void Transformer::CheckTransformedAstNode(const ir::AstNode *parent, ir::AstNode *childNode, bool *passed) const
2126 {
2127 if (!(*passed)) {
2128 return;
2129 }
2130 if (childNode->IsClassProperty() &&
2131 (childNode->AsClassProperty()->IsStatic() || childNode->AsClassProperty()->Value() != nullptr)) {
2132 return;
2133 }
2134 if (childNode->IsMethodDefinition() &&
2135 childNode->AsMethodDefinition()->Kind() == ir::MethodDefinitionKind::CONSTRUCTOR) {
2136 return;
2137 }
2138 if (childNode->IsDecorator()) {
2139 return;
2140 }
2141 if (childNode->Parent() != parent) {
2142 std::cout << "Illegal ast structure after transform." << std::endl;
2143 *passed = false;
2144 return;
2145 }
2146 CheckTransformedAstNodes(childNode, passed);
2147 }
2148
ResetParentScopeForAstNodes(const ir::AstNode * parent) const2149 void Transformer::ResetParentScopeForAstNodes(const ir::AstNode *parent) const
2150 {
2151 parent->Iterate([this](auto *childNode) { ResetParentScopeForAstNode(childNode); });
2152 }
2153
ResetParentScopeForAstNode(ir::AstNode * childNode) const2154 void Transformer::ResetParentScopeForAstNode(ir::AstNode *childNode) const
2155 {
2156 switch (childNode->Type()) {
2157 case ir::AstNodeType::SCRIPT_FUNCTION: {
2158 auto scope = childNode->AsScriptFunction()->Scope();
2159 ASSERT(scope != nullptr);
2160 scope->SetParent(Scope());
2161 break;
2162 }
2163 case ir::AstNodeType::CATCH_CLAUSE: {
2164 auto scope = childNode->AsCatchClause()->Scope();
2165 ASSERT(scope != nullptr);
2166 scope->SetParent(Scope());
2167 break;
2168 }
2169 case ir::AstNodeType::CLASS_DEFINITION: {
2170 auto scope = childNode->AsClassDefinition()->Scope();
2171 ASSERT(scope != nullptr);
2172 scope->SetParent(Scope());
2173 break;
2174 }
2175 case ir::AstNodeType::BLOCK_STATEMENT: {
2176 auto scope = childNode->AsBlockStatement()->Scope();
2177 ASSERT(scope != nullptr);
2178 scope->SetParent(Scope());
2179 break;
2180 }
2181 case ir::AstNodeType::DO_WHILE_STATEMENT: {
2182 auto scope = childNode->AsDoWhileStatement()->Scope();
2183 ASSERT(scope != nullptr);
2184 scope->SetParent(Scope());
2185 break;
2186 }
2187 case ir::AstNodeType::WHILE_STATEMENT: {
2188 auto scope = childNode->AsWhileStatement()->Scope();
2189 ASSERT(scope != nullptr);
2190 scope->SetParent(Scope());
2191 break;
2192 }
2193 case ir::AstNodeType::FOR_IN_STATEMENT: {
2194 auto scope = childNode->AsForInStatement()->Scope();
2195 ASSERT(scope != nullptr);
2196 scope->SetParent(Scope());
2197 break;
2198 }
2199 case ir::AstNodeType::FOR_OF_STATEMENT: {
2200 auto scope = childNode->AsForOfStatement()->Scope();
2201 ASSERT(scope != nullptr);
2202 scope->SetParent(Scope());
2203 break;
2204 }
2205 case ir::AstNodeType::FOR_UPDATE_STATEMENT: {
2206 auto scope = childNode->AsForUpdateStatement()->Scope();
2207 ASSERT(scope != nullptr);
2208 scope->SetParent(Scope());
2209 break;
2210 }
2211 case ir::AstNodeType::SWITCH_STATEMENT: {
2212 auto scope = childNode->AsSwitchStatement()->Scope();
2213 ASSERT(scope != nullptr);
2214 scope->SetParent(Scope());
2215 break;
2216 }
2217 case ir::AstNodeType::TS_ENUM_DECLARATION: {
2218 auto scope = childNode->AsTSEnumDeclaration()->Scope();
2219 ASSERT(scope != nullptr);
2220 scope->SetParent(Scope());
2221 break;
2222 }
2223 case ir::AstNodeType::TS_INTERFACE_DECLARATION: {
2224 auto scope = childNode->AsTSInterfaceDeclaration()->Scope();
2225 ASSERT(scope != nullptr);
2226 scope->SetParent(Scope());
2227 break;
2228 }
2229 case ir::AstNodeType::TS_METHOD_SIGNATURE: {
2230 auto scope = childNode->AsTSMethodSignature()->Scope();
2231 ASSERT(scope != nullptr);
2232 scope->SetParent(Scope());
2233 break;
2234 }
2235 case ir::AstNodeType::TS_MODULE_DECLARATION: {
2236 auto scope = childNode->AsTSModuleDeclaration()->Scope();
2237 ASSERT(scope != nullptr);
2238 scope->SetParent(Scope());
2239 break;
2240 }
2241 case ir::AstNodeType::TS_SIGNATURE_DECLARATION: {
2242 auto scope = childNode->AsTSSignatureDeclaration()->Scope();
2243 ASSERT(scope != nullptr);
2244 scope->SetParent(Scope());
2245 break;
2246 }
2247 case ir::AstNodeType::TS_TYPE_PARAMETER_DECLARATION: {
2248 auto scope = childNode->AsTSTypeParameterDeclaration()->Scope();
2249 ASSERT(scope != nullptr);
2250 scope->SetParent(Scope());
2251 break;
2252 }
2253 case ir::AstNodeType::TS_CONSTRUCTOR_TYPE: {
2254 auto scope = childNode->AsTSConstructorType()->Scope();
2255 ASSERT(scope != nullptr);
2256 scope->SetParent(Scope());
2257 break;
2258 }
2259 case ir::AstNodeType::TS_FUNCTION_TYPE: {
2260 auto scope = childNode->AsTSFunctionType()->Scope();
2261 ASSERT(scope != nullptr);
2262 scope->SetParent(Scope());
2263 break;
2264 }
2265 default: {
2266 ResetParentScopeForAstNodes(childNode);
2267 break;
2268 }
2269 }
2270 }
2271
IsValueReference(ir::Identifier * node)2272 bool Transformer::IsValueReference(ir::Identifier *node)
2273 {
2274 auto scope = Scope();
2275 ASSERT(scope != nullptr);
2276 auto name = node->Name();
2277 // If it's js value or enum, it won't be a type.
2278 // Const enum was processed as enum in es2abc, so we don't process it as type here.
2279 if (scope->FindLocal(name, binder::ResolveBindingOptions::BINDINGS) != nullptr ||
2280 scope->FindLocalTSVariable<binder::TSBindingType::ENUMLITERAL>(name) != nullptr) {
2281 return true;
2282 }
2283
2284 binder::Variable *var = nullptr;
2285
2286 var = scope->FindLocalTSVariable<binder::TSBindingType::NAMESPACE>(name);
2287 if (var != nullptr) {
2288 auto *decl = var->Declaration()->AsNamespaceDecl();
2289 return decl->IsInstantiated();
2290 }
2291
2292 var = scope->FindLocalTSVariable<binder::TSBindingType::IMPORT_EQUALS>(name);
2293 if (var != nullptr) {
2294 auto *node = var->Declaration()->Node()->AsTSImportEqualsDeclaration();
2295 return IsInstantiatedImportEquals(node, scope);
2296 }
2297
2298 return false;
2299 }
2300
RemoveDefaultLocalExportEntry()2301 void Transformer::RemoveDefaultLocalExportEntry()
2302 {
2303 auto *moduleRecord = GetSourceTextModuleRecord();
2304 moduleRecord->RemoveDefaultLocalExportEntry();
2305 }
2306
2307 } // namespace panda::es2panda::parser
2308