• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 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 "varbinder.h"
17 #include "varbinder/privateBinding.h"
18 #include "parser/program/program.h"
19 #include "util/helpers.h"
20 #include "varbinder/scope.h"
21 #include "varbinder/tsBinding.h"
22 #include "es2panda.h"
23 #include "ir/astNode.h"
24 #include "ir/base/catchClause.h"
25 #include "ir/base/classDefinition.h"
26 #include "ir/base/classProperty.h"
27 #include "ir/base/classStaticBlock.h"
28 #include "ir/base/methodDefinition.h"
29 #include "ir/base/property.h"
30 #include "ir/base/scriptFunction.h"
31 #include "ir/base/spreadElement.h"
32 #include "ir/expressions/arrayExpression.h"
33 #include "ir/expressions/assignmentExpression.h"
34 #include "ir/expressions/blockExpression.h"
35 #include "ir/expressions/memberExpression.h"
36 #include "ir/expressions/identifier.h"
37 #include "ir/expressions/objectExpression.h"
38 #include "ir/statements/blockStatement.h"
39 #include "ir/statements/doWhileStatement.h"
40 #include "ir/statements/forInStatement.h"
41 #include "ir/statements/forOfStatement.h"
42 #include "ir/statements/forUpdateStatement.h"
43 #include "ir/statements/ifStatement.h"
44 #include "ir/statements/switchStatement.h"
45 #include "ir/statements/variableDeclaration.h"
46 #include "ir/statements/variableDeclarator.h"
47 #include "ir/statements/whileStatement.h"
48 #include "ir/module/exportNamedDeclaration.h"
49 #include "ir/module/importDeclaration.h"
50 #include "ir/ts/tsFunctionType.h"
51 #include "ir/ts/tsConstructorType.h"
52 #include "ir/ts/tsTypeParameterDeclaration.h"
53 #include "ir/ts/tsTypeAliasDeclaration.h"
54 #include "ir/ts/tsTypeReference.h"
55 #include "ir/ts/tsInterfaceDeclaration.h"
56 #include "ir/ets/etsNewClassInstanceExpression.h"
57 #include "ir/ets/etsTypeReference.h"
58 #include "ir/base/tsSignatureDeclaration.h"
59 #include "ir/base/tsMethodSignature.h"
60 #include "public/public.h"
61 
62 namespace ark::es2panda::varbinder {
InitTopScope()63 void VarBinder::InitTopScope()
64 {
65     if (program_->Kind() == parser::ScriptKind::MODULE) {
66         topScope_ = Allocator()->New<ModuleScope>(Allocator());
67     } else {
68         topScope_ = Allocator()->New<GlobalScope>(Allocator());
69     }
70 
71     scope_ = topScope_;
72     varScope_ = topScope_;
73 }
74 
AddParamDecl(ir::AstNode * param)75 std::tuple<ParameterDecl *, Variable *> VarBinder::AddParamDecl(ir::AstNode *param)
76 {
77     ASSERT(scope_->IsFunctionParamScope() || scope_->IsCatchParamScope());
78     auto [decl, node, var] = static_cast<ParamScope *>(scope_)->AddParamDecl(Allocator(), param);
79 
80     if (node == nullptr) {
81         return {decl, var};
82     }
83 
84     ThrowRedeclaration(node->Start(), decl->Name());
85 }
86 
ThrowRedeclaration(const lexer::SourcePosition & pos,const util::StringView & name) const87 void VarBinder::ThrowRedeclaration(const lexer::SourcePosition &pos, const util::StringView &name) const
88 {
89     std::stringstream ss;
90     ss << "Variable '" << name << "' has already been declared.";
91     ThrowError(pos, ss.str());
92 }
93 
ThrowUnresolvableVariable(const lexer::SourcePosition & pos,const util::StringView & name) const94 void VarBinder::ThrowUnresolvableVariable(const lexer::SourcePosition &pos, const util::StringView &name) const
95 {
96     std::stringstream ss;
97     ss << "Cannot find variable '" << name << "'.";
98     ThrowError(pos, ss.str());
99 }
100 
ThrowUnresolvableType(const lexer::SourcePosition & pos,const util::StringView & name) const101 void VarBinder::ThrowUnresolvableType(const lexer::SourcePosition &pos, const util::StringView &name) const
102 {
103     std::stringstream ss;
104     ss << "Cannot find type '" << name << "'.";
105     ThrowError(pos, ss.str());
106 }
107 
ThrowTDZ(const lexer::SourcePosition & pos,const util::StringView & name) const108 void VarBinder::ThrowTDZ(const lexer::SourcePosition &pos, const util::StringView &name) const
109 {
110     std::stringstream ss;
111     ss << "Variable '" << name << "' is accessed before it's initialization.";
112     ThrowError(pos, ss.str());
113 }
114 
ThrowInvalidCapture(const lexer::SourcePosition & pos,const util::StringView & name) const115 void VarBinder::ThrowInvalidCapture(const lexer::SourcePosition &pos, const util::StringView &name) const
116 {
117     std::stringstream ss;
118     ss << "Cannot capture variable'" << name << "'.";
119     ThrowError(pos, ss.str());
120 }
121 
ThrowPrivateFieldMismatch(const lexer::SourcePosition & pos,const util::StringView & name) const122 void VarBinder::ThrowPrivateFieldMismatch(const lexer::SourcePosition &pos, const util::StringView &name) const
123 {
124     std::stringstream ss;
125     ss << "Private field '" << name << "' must be declared in an enclosing class";
126 
127     ThrowError(pos, ss.str());
128 }
129 
ThrowError(const lexer::SourcePosition & pos,const std::string_view & msg) const130 void VarBinder::ThrowError(const lexer::SourcePosition &pos, const std::string_view &msg) const
131 {
132     lexer::LineIndex index(program_->SourceCode());
133     lexer::SourceLocation loc = index.GetLocation(pos);
134 
135     throw Error(ErrorType::SYNTAX, program_->SourceFilePath().Utf8(), msg, loc.line, loc.col);
136 }
137 
IdentifierAnalysis()138 void VarBinder::IdentifierAnalysis()
139 {
140     ASSERT(program_->Ast());
141     ASSERT(scope_ == topScope_);
142     ASSERT(varScope_ == topScope_);
143 
144     functionScopes_.push_back(topScope_);
145     topScope_->BindName(MAIN);
146     topScope_->BindInternalName(BuildFunctionName(MAIN, 0));
147 
148     topScope_->CheckDirectEval(context_);
149 
150     ResolveReferences(program_->Ast());
151     AddMandatoryParams();
152 }
153 
LookupReference(const util::StringView & name)154 void VarBinder::LookupReference(const util::StringView &name)
155 {
156     auto res = scope_->Find(name);
157     if (res.level == 0) {
158         return;
159     }
160 
161     ASSERT(res.variable);
162     res.variable->SetLexical(res.scope);
163 }
164 
InstantiateArgumentsImpl(Scope ** scope,Scope * iter,const ir::AstNode * node)165 bool VarBinder::InstantiateArgumentsImpl(Scope **scope, Scope *iter, const ir::AstNode *node)
166 {
167     if (node->AsScriptFunction()->IsArrow()) {
168         return false;
169     }
170     auto *argumentsVariable =
171         (*scope)->AddDecl<ConstDecl, LocalVariable>(Allocator(), FUNCTION_ARGUMENTS, VariableFlags::INITIALIZED);
172     if (iter->IsFunctionParamScope()) {
173         if (argumentsVariable == nullptr) {
174             return true;
175         }
176 
177         *scope = iter->AsFunctionParamScope()->GetFunctionScope();
178         (*scope)->InsertBinding(argumentsVariable->Name(), argumentsVariable);
179     }
180 
181     (*scope)->AddFlag(ScopeFlags::USE_ARGS);
182     return true;
183 }
184 
InstantiateArguments()185 void VarBinder::InstantiateArguments()
186 {
187     auto *iter = scope_;
188     while (true) {
189         Scope *scope = iter->IsFunctionParamScope() ? iter : iter->EnclosingVariableScope();
190 
191         const auto *node = scope->Node();
192 
193         if (scope->IsLoopScope()) {
194             iter = scope->Parent();
195             continue;
196         }
197 
198         if (!node->IsScriptFunction()) {
199             break;
200         }
201 
202         if (InstantiateArgumentsImpl(&scope, iter, node)) {
203             break;
204         }
205 
206         iter = scope->Parent();
207     }
208 }
209 
PropagateDirectEval() const210 void VarBinder::PropagateDirectEval() const
211 {
212     auto *iter = scope_;
213 
214     do {
215         VariableScope *scope = iter->IsFunctionParamScope() ? iter->AsFunctionParamScope()->GetFunctionScope()
216                                                             : iter->EnclosingVariableScope();
217 
218         scope->AddFlag(ScopeFlags::NO_REG_STORE);
219         iter = iter->Parent();
220     } while (iter != nullptr);
221 }
222 
InstantiatePrivateContext(const ir::Identifier * ident) const223 void VarBinder::InstantiatePrivateContext(const ir::Identifier *ident) const
224 {
225     auto *classDef = util::Helpers::GetContainingClassDefinition(ident);
226 
227     while (classDef != nullptr) {
228         auto *scope = classDef->Scope();
229         Variable *variable = scope->FindLocal(classDef->PrivateId(), varbinder::ResolveBindingOptions::BINDINGS);
230 
231         if (!variable->HasFlag(VariableFlags::INITIALIZED)) {
232             break;
233         }
234 
235         if (classDef->HasMatchingPrivateKey(ident->Name())) {
236             variable->SetLexical(scope);
237             return;
238         }
239 
240         classDef = util::Helpers::GetContainingClassDefinition(classDef->Parent());
241     }
242 
243     ThrowPrivateFieldMismatch(ident->Start(), ident->Name());
244 }
245 
LookupIdentReference(ir::Identifier * ident)246 void VarBinder::LookupIdentReference(ir::Identifier *ident)
247 {
248     if (!ident->IsReference(Extension())) {
249         return;
250     }
251 
252     if (ident->Name().Is(FUNCTION_ARGUMENTS)) {
253         InstantiateArguments();
254     }
255 
256     if (ident->IsPrivateIdent()) {
257         InstantiatePrivateContext(ident);
258         return;
259     }
260 
261     auto res = scope_->Find(ident->Name(), BindingOptions());
262     if (res.level != 0) {
263         ASSERT(res.variable);
264         res.variable->SetLexical(res.scope);
265     }
266 
267     if (res.variable == nullptr) {
268         return;
269     }
270 
271     if (res.variable->Declaration()->IsLetOrConstDecl() && !res.variable->HasFlag(VariableFlags::INITIALIZED)) {
272         ident->SetTdz();
273     }
274 
275     ident->SetVariable(res.variable);
276 }
277 
BuildFunctionName(util::StringView name,uint32_t idx)278 util::StringView VarBinder::BuildFunctionName(util::StringView name, uint32_t idx)
279 {
280     std::stringstream ss;
281     ss << "func_" << name << "_" << std::to_string(idx);
282     util::UString internalName(ss.str(), Allocator());
283 
284     return internalName.View();
285 }
286 
BuildInternalName(ir::ScriptFunction * scriptFunc)287 bool VarBinder::BuildInternalName(ir::ScriptFunction *scriptFunc)
288 {
289     auto *funcScope = scriptFunc->Scope();
290     auto name = util::Helpers::FunctionName(Allocator(), scriptFunc);
291 
292     uint32_t idx = functionScopes_.size();
293     funcScope->BindName(name);
294     funcScope->BindInternalName(BuildFunctionName(name, idx));
295 
296     return !scriptFunc->IsOverload();
297 }
298 
BuildVarDeclaratorId(ir::AstNode * childNode)299 void VarBinder::BuildVarDeclaratorId(ir::AstNode *childNode)
300 {
301     switch (childNode->Type()) {
302         case ir::AstNodeType::IDENTIFIER: {
303             auto *ident = childNode->AsIdentifier();
304             const auto &name = ident->Name();
305 
306             if (util::Helpers::IsGlobalIdentifier(name)) {
307                 break;
308             }
309 
310             auto *variable = scope_->FindLocal(name, varbinder::ResolveBindingOptions::BINDINGS);
311             ASSERT(variable);
312             ident->SetVariable(variable);
313             BuildSignatureDeclarationBaseParams(ident->TypeAnnotation());
314             variable->AddFlag(VariableFlags::INITIALIZED);
315             break;
316         }
317         case ir::AstNodeType::OBJECT_PATTERN: {
318             auto *objPattern = childNode->AsObjectPattern();
319 
320             for (auto *prop : objPattern->Properties()) {
321                 BuildVarDeclaratorId(prop);
322             }
323 
324             BuildSignatureDeclarationBaseParams(objPattern->TypeAnnotation());
325             break;
326         }
327         case ir::AstNodeType::ARRAY_PATTERN: {
328             auto *arrayPattern = childNode->AsArrayPattern();
329 
330             for (auto *element : childNode->AsArrayPattern()->Elements()) {
331                 BuildVarDeclaratorId(element);
332             }
333 
334             BuildSignatureDeclarationBaseParams(arrayPattern->TypeAnnotation());
335             break;
336         }
337         case ir::AstNodeType::ASSIGNMENT_PATTERN: {
338             ResolveReference(childNode->AsAssignmentPattern()->Right());
339             BuildVarDeclaratorId(childNode->AsAssignmentPattern()->Left());
340             break;
341         }
342         case ir::AstNodeType::PROPERTY: {
343             ResolveReference(childNode->AsProperty()->Key());
344             BuildVarDeclaratorId(childNode->AsProperty()->Value());
345             break;
346         }
347         case ir::AstNodeType::REST_ELEMENT: {
348             BuildVarDeclaratorId(childNode->AsRestElement()->Argument());
349             break;
350         }
351         default:
352             break;
353     }
354 }
355 
BuildVarDeclarator(ir::VariableDeclarator * varDecl)356 void VarBinder::BuildVarDeclarator(ir::VariableDeclarator *varDecl)
357 {
358     if (varDecl->Parent()->AsVariableDeclaration()->Kind() == ir::VariableDeclaration::VariableDeclarationKind::VAR) {
359         ResolveReferences(varDecl);
360         return;
361     }
362 
363     if (varDecl->Init() != nullptr) {
364         ResolveReference(varDecl->Init());
365     }
366 
367     BuildVarDeclaratorId(varDecl->Id());
368 }
369 
BuildClassProperty(const ir::ClassProperty * prop)370 void VarBinder::BuildClassProperty(const ir::ClassProperty *prop)
371 {
372     const ir::ScriptFunction *ctor = util::Helpers::GetContainingConstructor(prop);
373     auto scopeCtx = LexicalScope<FunctionScope>::Enter(this, ctor->Scope());
374 
375     ResolveReferences(prop);
376 }
377 
InitializeClassBinding(ir::ClassDefinition * classDef)378 void VarBinder::InitializeClassBinding(ir::ClassDefinition *classDef)
379 {
380     auto res = scope_->Find(classDef->Ident()->Name());
381 
382     ASSERT(res.variable && res.variable->Declaration()->IsLetDecl());
383     res.variable->AddFlag(VariableFlags::INITIALIZED);
384 }
385 
InitializeClassIdent(ir::ClassDefinition * classDef)386 void VarBinder::InitializeClassIdent(ir::ClassDefinition *classDef)
387 {
388     auto res = scope_->Find(classDef->Ident()->Name());
389 
390     ASSERT(res.variable &&
391            (res.variable->Declaration()->IsConstDecl() || res.variable->Declaration()->IsReadonlyDecl()));
392     res.variable->AddFlag(VariableFlags::INITIALIZED);
393 }
394 
BuildClassDefinition(ir::ClassDefinition * classDef)395 void VarBinder::BuildClassDefinition(ir::ClassDefinition *classDef)
396 {
397     if (classDef->Parent()->IsClassDeclaration() || classDef->Parent()->IsETSStructDeclaration()) {
398         InitializeClassBinding(classDef);
399     }
400 
401     auto scopeCtx = LexicalScope<LocalScope>::Enter(this, classDef->Scope());
402 
403     if (classDef->Super() != nullptr) {
404         ResolveReference(classDef->Super());
405     }
406 
407     Variable *variable = scope_->FindLocal(classDef->PrivateId(), varbinder::ResolveBindingOptions::BINDINGS);
408     variable->AddFlag(VariableFlags::INITIALIZED);
409 
410     if (classDef->Ident() != nullptr) {
411         InitializeClassIdent(classDef);
412     }
413 
414     ResolveReference(classDef->Ctor());
415 
416     for (auto *stmt : classDef->Body()) {
417         ResolveReference(stmt);
418     }
419 }
420 
BuildForUpdateLoop(ir::ForUpdateStatement * forUpdateStmt)421 void VarBinder::BuildForUpdateLoop(ir::ForUpdateStatement *forUpdateStmt)
422 {
423     auto *loopScope = forUpdateStmt->Scope();
424 
425     auto declScopeCtx = LexicalScope<LoopDeclarationScope>::Enter(this, loopScope->DeclScope());
426 
427     if (forUpdateStmt->Init() != nullptr) {
428         ResolveReference(forUpdateStmt->Init());
429     }
430 
431     if (forUpdateStmt->Update() != nullptr) {
432         ResolveReference(forUpdateStmt->Update());
433     }
434 
435     auto loopCtx = LexicalScope<LoopScope>::Enter(this, loopScope);
436 
437     if (forUpdateStmt->Test() != nullptr) {
438         ResolveReference(forUpdateStmt->Test());
439     }
440 
441     ResolveReference(forUpdateStmt->Body());
442 
443     loopCtx.GetScope()->ConvertToVariableScope(Allocator());
444 }
445 
BuildForInOfLoop(varbinder::LoopScope * loopScope,ir::AstNode * left,ir::Expression * right,ir::Statement * body)446 void VarBinder::BuildForInOfLoop(varbinder::LoopScope *loopScope, ir::AstNode *left, ir::Expression *right,
447                                  ir::Statement *body)
448 {
449     auto declScopeCtx = LexicalScope<LoopDeclarationScope>::Enter(this, loopScope->DeclScope());
450 
451     ResolveReference(right);
452     ResolveReference(left);
453 
454     auto loopCtx = LexicalScope<LoopScope>::Enter(this, loopScope);
455 
456     ResolveReference(body);
457     loopCtx.GetScope()->ConvertToVariableScope(Allocator());
458 }
459 
BuildCatchClause(ir::CatchClause * catchClauseStmt)460 void VarBinder::BuildCatchClause(ir::CatchClause *catchClauseStmt)
461 {
462     if (catchClauseStmt->Param() != nullptr) {
463         auto paramScopeCtx = LexicalScope<CatchParamScope>::Enter(this, catchClauseStmt->Scope()->ParamScope());
464         ResolveReference(catchClauseStmt->Param());
465     }
466 
467     auto scopeCtx = LexicalScope<CatchScope>::Enter(this, catchClauseStmt->Scope());
468     ResolveReference(catchClauseStmt->Body());
469 }
470 
BuildTypeAliasDeclaration(ir::TSTypeAliasDeclaration * const typeAliasDecl)471 void VarBinder::BuildTypeAliasDeclaration(ir::TSTypeAliasDeclaration *const typeAliasDecl)
472 {
473     if (typeAliasDecl->TypeParams() != nullptr) {
474         const auto typeAliasScope = LexicalScope<LocalScope>::Enter(this, typeAliasDecl->TypeParams()->Scope());
475         ResolveReferences(typeAliasDecl);
476         return;
477     }
478 
479     ResolveReferences(typeAliasDecl);
480 }
481 
AddCompilableFunction(ir::ScriptFunction * func)482 void VarBinder::AddCompilableFunction(ir::ScriptFunction *func)
483 {
484     if (func->IsArrow()) {
485         VariableScope *outerVarScope = scope_->EnclosingVariableScope();
486         ASSERT(outerVarScope != nullptr);
487         outerVarScope->AddFlag(ScopeFlags::INNER_ARROW);
488     }
489 
490     AddCompilableFunctionScope(func->Scope());
491 }
492 
AddCompilableFunctionScope(varbinder::FunctionScope * funcScope)493 void VarBinder::AddCompilableFunctionScope(varbinder::FunctionScope *funcScope)
494 {
495     functionScopes_.push_back(funcScope);
496 }
497 
VisitScriptFunction(ir::ScriptFunction * func)498 void VarBinder::VisitScriptFunction(ir::ScriptFunction *func)
499 {
500     auto *funcScope = func->Scope();
501     {
502         ASSERT(funcScope != nullptr);
503         auto paramScopeCtx = LexicalScope<FunctionParamScope>::Enter(this, funcScope->ParamScope());
504 
505         for (auto *param : func->Params()) {
506             ResolveReference(param);
507         }
508     }
509 
510     if (func->ReturnTypeAnnotation() != nullptr) {
511         ResolveReference(func->ReturnTypeAnnotation());
512     }
513 
514     if (!BuildInternalName(func)) {
515         return;
516     }
517 
518     if (!func->IsDeclare()) {
519         AddCompilableFunction(func);
520     }
521 
522     auto scopeCtx = LexicalScope<FunctionScope>::Enter(this, funcScope);
523 
524     if (func->Body() != nullptr) {
525         ResolveReference(func->Body());
526     }
527 }
528 
VisitScriptFunctionWithPotentialTypeParams(ir::ScriptFunction * func)529 void VarBinder::VisitScriptFunctionWithPotentialTypeParams(ir::ScriptFunction *func)
530 {
531     if (func->TypeParams() != nullptr) {
532         auto typeParamScopeCtx = LexicalScope<Scope>::Enter(this, func->TypeParams()->Scope());
533         VisitScriptFunction(func);
534         return;
535     }
536 
537     VisitScriptFunction(func);
538 }
539 
ResolveReferenceDoWhileHelper(ir::AstNode * childNode)540 void VarBinder::ResolveReferenceDoWhileHelper(ir::AstNode *childNode)
541 {
542     auto *doWhileStatement = childNode->AsDoWhileStatement();
543 
544     {
545         auto loopScopeCtx = LexicalScope<LoopScope>::Enter(this, doWhileStatement->Scope());
546         ResolveReference(doWhileStatement->Body());
547     }
548     return ResolveReference(doWhileStatement->Test());
549 }
550 
ResolveReferenceWhileHelper(ir::AstNode * childNode)551 void VarBinder::ResolveReferenceWhileHelper(ir::AstNode *childNode)
552 {
553     auto *whileStatement = childNode->AsWhileStatement();
554     ResolveReference(whileStatement->Test());
555 
556     auto loopScopeCtx = LexicalScope<LoopScope>::Enter(this, whileStatement->Scope());
557     return ResolveReference(whileStatement->Body());
558 }
559 
ResolveReference(ir::AstNode * childNode)560 void VarBinder::ResolveReference(ir::AstNode *childNode)
561 {
562     switch (childNode->Type()) {
563         case ir::AstNodeType::IDENTIFIER:
564             LookupIdentReference(childNode->AsIdentifier());
565             return ResolveReferences(childNode);
566         case ir::AstNodeType::SUPER_EXPRESSION:
567             scope_->EnclosingVariableScope()->AddFlag(ScopeFlags::USE_SUPER);
568             return ResolveReferences(childNode);
569         case ir::AstNodeType::SCRIPT_FUNCTION:
570             return VisitScriptFunctionWithPotentialTypeParams(childNode->AsScriptFunction());
571         case ir::AstNodeType::VARIABLE_DECLARATOR:
572             return BuildVarDeclarator(childNode->AsVariableDeclarator());
573         case ir::AstNodeType::CLASS_DEFINITION:
574             return BuildClassDefinition(childNode->AsClassDefinition());
575         case ir::AstNodeType::CLASS_PROPERTY:
576             return BuildClassProperty(childNode->AsClassProperty());
577         case ir::AstNodeType::BLOCK_STATEMENT: {
578             auto scopeCtx = LexicalScope<Scope>::Enter(this, childNode->AsBlockStatement()->Scope());
579 
580             return ResolveReferences(childNode);
581         }
582         case ir::AstNodeType::BLOCK_EXPRESSION: {
583             auto scopeCtx = LexicalScope<Scope>::Enter(this, childNode->AsBlockExpression()->Scope());
584 
585             return ResolveReferences(childNode);
586         }
587         case ir::AstNodeType::SWITCH_STATEMENT: {
588             auto scopeCtx = LexicalScope<LocalScope>::Enter(this, childNode->AsSwitchStatement()->Scope());
589 
590             return ResolveReferences(childNode);
591         }
592         case ir::AstNodeType::DO_WHILE_STATEMENT:
593             return ResolveReferenceDoWhileHelper(childNode);
594         case ir::AstNodeType::WHILE_STATEMENT:
595             return ResolveReferenceWhileHelper(childNode);
596         case ir::AstNodeType::FOR_UPDATE_STATEMENT:
597             return BuildForUpdateLoop(childNode->AsForUpdateStatement());
598         case ir::AstNodeType::FOR_IN_STATEMENT: {
599             auto *forInStmt = childNode->AsForInStatement();
600             return BuildForInOfLoop(forInStmt->Scope(), forInStmt->Left(), forInStmt->Right(), forInStmt->Body());
601         }
602         case ir::AstNodeType::FOR_OF_STATEMENT: {
603             auto *forOfStmt = childNode->AsForOfStatement();
604             return BuildForInOfLoop(forOfStmt->Scope(), forOfStmt->Left(), forOfStmt->Right(), forOfStmt->Body());
605         }
606         case ir::AstNodeType::CATCH_CLAUSE:
607             return BuildCatchClause(childNode->AsCatchClause());
608         case ir::AstNodeType::TS_TYPE_ALIAS_DECLARATION:
609             return BuildTypeAliasDeclaration(childNode->AsTSTypeAliasDeclaration());
610         default:
611             return HandleCustomNodes(childNode);
612     }
613 }
614 
ResolveReferences(const ir::AstNode * parent)615 void VarBinder::ResolveReferences(const ir::AstNode *parent)
616 {
617     parent->Iterate([this](auto *childNode) { ResolveReference(childNode); });
618 }
619 
AddMandatoryParam(const std::string_view & name)620 LocalVariable *VarBinder::AddMandatoryParam(const std::string_view &name)
621 {
622     ASSERT(scope_->IsFunctionParamScope());
623 
624     auto *decl = Allocator()->New<ParameterDecl>(name);
625     auto *param = Allocator()->New<LocalVariable>(decl, VariableFlags::VAR);
626 
627     auto &funcParams = scope_->AsFunctionParamScope()->Params();
628 
629     funcParams.insert(funcParams.begin(), param);
630     scope_->AsFunctionParamScope()->GetFunctionScope()->InsertBinding(decl->Name(), param);
631     scope_->InsertBinding(decl->Name(), param);
632 
633     return param;
634 }
635 
LookUpMandatoryReferences(const FunctionScope * funcScope,bool needLexicalFuncObj)636 void VarBinder::LookUpMandatoryReferences(const FunctionScope *funcScope, bool needLexicalFuncObj)
637 {
638     LookupReference(MANDATORY_PARAM_NEW_TARGET);
639     LookupReference(MANDATORY_PARAM_THIS);
640 
641     if (funcScope->HasFlag(ScopeFlags::USE_ARGS)) {
642         LookupReference(FUNCTION_ARGUMENTS);
643     }
644 
645     if (needLexicalFuncObj) {
646         LookupReference(MANDATORY_PARAM_FUNC);
647     }
648 }
649 
AddMandatoryParams()650 void VarBinder::AddMandatoryParams()
651 {
652     ASSERT(scope_ == topScope_);
653     ASSERT(!functionScopes_.empty());
654     auto iter = functionScopes_.begin();
655     [[maybe_unused]] auto *funcScope = *iter++;
656 
657     ASSERT(funcScope->IsGlobalScope() || funcScope->IsModuleScope());
658 
659     const auto &options = context_->config->options->CompilerOptions();
660     if (options.isDirectEval) {
661         AddMandatoryParams(EVAL_SCRIPT_MANDATORY_PARAMS);
662         topScope_->ParamScope()->Params().back()->SetLexical(topScope_);
663     } else {
664         AddMandatoryParams(FUNCTION_MANDATORY_PARAMS);
665     }
666 
667     if (options.isFunctionEval) {
668         ASSERT(iter != functionScopes_.end());
669         funcScope = *iter++;
670         auto scopeCtx = LexicalScope<FunctionScope>::Enter(this, funcScope);
671         AddMandatoryParams(ARROW_MANDATORY_PARAMS);
672         LookUpMandatoryReferences(funcScope, false);
673     }
674 
675     for (; iter != functionScopes_.end(); iter++) {
676         funcScope = *iter;
677         const auto *scriptFunc = funcScope->Node()->AsScriptFunction();
678 
679         auto scopeCtx = LexicalScope<FunctionScope>::Enter(this, funcScope);
680 
681         if (!scriptFunc->IsArrow()) {
682             AddMandatoryParams(FUNCTION_MANDATORY_PARAMS);
683             continue;
684         }
685 
686         const ir::ScriptFunction *ctor = util::Helpers::GetContainingConstructor(scriptFunc);
687         bool lexicalFunctionObject {};
688 
689         if (ctor != nullptr && util::Helpers::GetClassDefiniton(ctor)->Super() != nullptr &&
690             funcScope->HasFlag(ScopeFlags::USE_SUPER)) {
691             ASSERT(ctor->Scope()->HasFlag(ScopeFlags::INNER_ARROW));
692             ctor->Scope()->AddFlag(ScopeFlags::SET_LEXICAL_FUNCTION);
693             lexicalFunctionObject = true;
694             AddMandatoryParams(CTOR_ARROW_MANDATORY_PARAMS);
695         } else {
696             AddMandatoryParams(ARROW_MANDATORY_PARAMS);
697         }
698 
699         LookUpMandatoryReferences(funcScope, lexicalFunctionObject);
700     }
701 }
702 }  // namespace ark::es2panda::varbinder
703