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