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