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