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