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