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