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