• 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 
18 #include "varbinder/privateBinding.h"
19 #include "parser/program/program.h"
20 #include "util/helpers.h"
21 #include "varbinder/scope.h"
22 #include "varbinder/tsBinding.h"
23 #include "es2panda.h"
24 #include "ir/astNode.h"
25 #include "ir/base/catchClause.h"
26 #include "ir/base/classDefinition.h"
27 #include "ir/base/classProperty.h"
28 #include "ir/base/classStaticBlock.h"
29 #include "ir/base/methodDefinition.h"
30 #include "ir/base/property.h"
31 #include "ir/base/scriptFunction.h"
32 #include "ir/base/spreadElement.h"
33 #include "ir/expressions/arrayExpression.h"
34 #include "ir/expressions/assignmentExpression.h"
35 #include "ir/expressions/blockExpression.h"
36 #include "ir/expressions/memberExpression.h"
37 #include "ir/expressions/identifier.h"
38 #include "ir/expressions/objectExpression.h"
39 #include "ir/statements/blockStatement.h"
40 #include "ir/statements/doWhileStatement.h"
41 #include "ir/statements/forInStatement.h"
42 #include "ir/statements/forOfStatement.h"
43 #include "ir/statements/forUpdateStatement.h"
44 #include "ir/statements/ifStatement.h"
45 #include "ir/statements/switchStatement.h"
46 #include "ir/statements/variableDeclaration.h"
47 #include "ir/statements/variableDeclarator.h"
48 #include "ir/statements/whileStatement.h"
49 #include "ir/module/exportNamedDeclaration.h"
50 #include "ir/module/importDeclaration.h"
51 #include "ir/ts/tsFunctionType.h"
52 #include "ir/ts/tsConstructorType.h"
53 #include "ir/ts/tsTypeParameterDeclaration.h"
54 #include "ir/ts/tsTypeAliasDeclaration.h"
55 #include "ir/ts/tsTypeReference.h"
56 #include "ir/ts/tsInterfaceDeclaration.h"
57 #include "ir/ets/etsNewClassInstanceExpression.h"
58 #include "ir/ets/etsTypeReference.h"
59 #include "ir/base/tsSignatureDeclaration.h"
60 #include "ir/base/tsMethodSignature.h"
61 #include "public/public.h"
62 
63 namespace ark::es2panda::varbinder {
InitTopScope()64 void VarBinder::InitTopScope()
65 {
66     if (program_->Kind() == parser::ScriptKind::MODULE) {
67         topScope_ = Allocator()->New<ModuleScope>(Allocator());
68     } else {
69         topScope_ = Allocator()->New<GlobalScope>(Allocator());
70     }
71 
72     scope_ = topScope_;
73     varScope_ = topScope_;
74 }
75 
AddParamDecl(ir::AstNode * param)76 std::tuple<ParameterDecl *, Variable *> VarBinder::AddParamDecl(ir::AstNode *param)
77 {
78     ASSERT(scope_->IsFunctionParamScope() || scope_->IsCatchParamScope());
79     auto [decl, node, var] = static_cast<ParamScope *>(scope_)->AddParamDecl(Allocator(), param);
80 
81     if (node == nullptr) {
82         return {decl, var};
83     }
84 
85     ThrowRedeclaration(node->Start(), decl->Name());
86 }
87 
ThrowRedeclaration(const lexer::SourcePosition & pos,const util::StringView & name) const88 void VarBinder::ThrowRedeclaration(const lexer::SourcePosition &pos, const util::StringView &name) const
89 {
90     std::stringstream ss;
91     ss << "Variable '" << name << "' has already been declared.";
92     ThrowError(pos, ss.str());
93 }
94 
ThrowUnresolvableVariable(const lexer::SourcePosition & pos,const util::StringView & name) const95 void VarBinder::ThrowUnresolvableVariable(const lexer::SourcePosition &pos, const util::StringView &name) const
96 {
97     std::stringstream ss;
98     ss << "Cannot find variable '" << name << "'.";
99     ThrowError(pos, ss.str());
100 }
101 
ThrowUnresolvableType(const lexer::SourcePosition & pos,const util::StringView & name) const102 void VarBinder::ThrowUnresolvableType(const lexer::SourcePosition &pos, const util::StringView &name) const
103 {
104     std::stringstream ss;
105     ss << "Cannot find type '" << name << "'.";
106     ThrowError(pos, ss.str());
107 }
108 
ThrowTDZ(const lexer::SourcePosition & pos,const util::StringView & name) const109 void VarBinder::ThrowTDZ(const lexer::SourcePosition &pos, const util::StringView &name) const
110 {
111     std::stringstream ss;
112     ss << "Variable '" << name << "' is accessed before it's initialization.";
113     ThrowError(pos, ss.str());
114 }
115 
ThrowInvalidCapture(const lexer::SourcePosition & pos,const util::StringView & name) const116 void VarBinder::ThrowInvalidCapture(const lexer::SourcePosition &pos, const util::StringView &name) const
117 {
118     std::stringstream ss;
119     ss << "Cannot capture variable'" << name << "'.";
120     ThrowError(pos, ss.str());
121 }
122 
ThrowPrivateFieldMismatch(const lexer::SourcePosition & pos,const util::StringView & name) const123 void VarBinder::ThrowPrivateFieldMismatch(const lexer::SourcePosition &pos, const util::StringView &name) const
124 {
125     std::stringstream ss;
126     ss << "Private field '" << name << "' must be declared in an enclosing class";
127 
128     ThrowError(pos, ss.str());
129 }
130 
ThrowError(const lexer::SourcePosition & pos,const std::string_view & msg) const131 void VarBinder::ThrowError(const lexer::SourcePosition &pos, const std::string_view &msg) const
132 {
133     lexer::LineIndex index(program_->SourceCode());
134     lexer::SourceLocation loc = index.GetLocation(pos);
135 
136     throw Error(ErrorType::SYNTAX, program_->SourceFilePath().Utf8(), msg, loc.line, loc.col);
137 }
138 
IdentifierAnalysis()139 void VarBinder::IdentifierAnalysis()
140 {
141     ASSERT(program_->Ast());
142     ASSERT(scope_ == topScope_);
143     ASSERT(varScope_ == topScope_);
144 
145     functionScopes_.push_back(topScope_);
146     topScope_->BindName(MAIN);
147     topScope_->BindInternalName(BuildFunctionName(MAIN, 0));
148 
149     topScope_->CheckDirectEval(context_);
150 
151     ResolveReferences(program_->Ast());
152     AddMandatoryParams();
153 }
154 
LookupReference(const util::StringView & name)155 void VarBinder::LookupReference(const util::StringView &name)
156 {
157     auto res = scope_->Find(name);
158     if (res.level == 0) {
159         return;
160     }
161 
162     ASSERT(res.variable);
163     res.variable->SetLexical(res.scope);
164 }
165 
InstantiateArgumentsImpl(Scope ** scope,Scope * iter,const ir::AstNode * node)166 bool VarBinder::InstantiateArgumentsImpl(Scope **scope, Scope *iter, const ir::AstNode *node)
167 {
168     if (node->AsScriptFunction()->IsArrow()) {
169         return false;
170     }
171     auto *argumentsVariable =
172         (*scope)->AddDecl<ConstDecl, LocalVariable>(Allocator(), FUNCTION_ARGUMENTS, VariableFlags::INITIALIZED);
173     if (iter->IsFunctionParamScope()) {
174         if (argumentsVariable == nullptr) {
175             return true;
176         }
177 
178         *scope = iter->AsFunctionParamScope()->GetFunctionScope();
179         (*scope)->InsertBinding(argumentsVariable->Name(), argumentsVariable);
180     }
181 
182     (*scope)->AddFlag(ScopeFlags::USE_ARGS);
183     return true;
184 }
185 
InstantiateArguments()186 void VarBinder::InstantiateArguments()
187 {
188     auto *iter = scope_;
189     while (true) {
190         Scope *scope = iter->IsFunctionParamScope() ? iter : iter->EnclosingVariableScope();
191 
192         const auto *node = scope->Node();
193 
194         if (scope->IsLoopScope()) {
195             iter = scope->Parent();
196             continue;
197         }
198 
199         if (!node->IsScriptFunction()) {
200             break;
201         }
202 
203         if (InstantiateArgumentsImpl(&scope, iter, node)) {
204             break;
205         }
206 
207         iter = scope->Parent();
208     }
209 }
210 
PropagateDirectEval() const211 void VarBinder::PropagateDirectEval() const
212 {
213     auto *iter = scope_;
214 
215     do {
216         VariableScope *scope = iter->IsFunctionParamScope() ? iter->AsFunctionParamScope()->GetFunctionScope()
217                                                             : iter->EnclosingVariableScope();
218 
219         scope->AddFlag(ScopeFlags::NO_REG_STORE);
220         iter = iter->Parent();
221     } while (iter != nullptr);
222 }
223 
InstantiatePrivateContext(const ir::Identifier * ident) const224 void VarBinder::InstantiatePrivateContext(const ir::Identifier *ident) const
225 {
226     auto *classDef = util::Helpers::GetContainingClassDefinition(ident);
227 
228     while (classDef != nullptr) {
229         auto *scope = classDef->Scope();
230         Variable *variable = scope->FindLocal(classDef->PrivateId(), varbinder::ResolveBindingOptions::BINDINGS);
231 
232         if (!variable->HasFlag(VariableFlags::INITIALIZED)) {
233             break;
234         }
235 
236         if (classDef->HasMatchingPrivateKey(ident->Name())) {
237             variable->SetLexical(scope);
238             return;
239         }
240 
241         classDef = util::Helpers::GetContainingClassDefinition(classDef->Parent());
242     }
243 
244     ThrowPrivateFieldMismatch(ident->Start(), ident->Name());
245 }
246 
LookupIdentReference(ir::Identifier * ident)247 void VarBinder::LookupIdentReference(ir::Identifier *ident)
248 {
249     if (!ident->IsReference()) {
250         return;
251     }
252 
253     if (ident->Name().Is(FUNCTION_ARGUMENTS)) {
254         InstantiateArguments();
255     }
256 
257     if (ident->IsPrivateIdent()) {
258         InstantiatePrivateContext(ident);
259         return;
260     }
261 
262     auto res = scope_->Find(ident->Name(), BindingOptions());
263     if (res.level != 0) {
264         ASSERT(res.variable);
265         res.variable->SetLexical(res.scope);
266     }
267 
268     if (res.variable == nullptr) {
269         return;
270     }
271 
272     if (res.variable->Declaration()->IsLetOrConstDecl() && !res.variable->HasFlag(VariableFlags::INITIALIZED)) {
273         ident->SetTdz();
274     }
275 
276     ident->SetVariable(res.variable);
277 }
278 
BuildFunctionName(util::StringView name,uint32_t idx)279 util::StringView VarBinder::BuildFunctionName(util::StringView name, uint32_t idx)
280 {
281     std::stringstream ss;
282     ss << "func_" << name << "_" << std::to_string(idx);
283     util::UString internalName(ss.str(), Allocator());
284 
285     return internalName.View();
286 }
287 
BuildInternalName(ir::ScriptFunction * scriptFunc)288 bool VarBinder::BuildInternalName(ir::ScriptFunction *scriptFunc)
289 {
290     auto *funcScope = scriptFunc->Scope();
291     auto name = util::Helpers::FunctionName(Allocator(), scriptFunc);
292 
293     uint32_t idx = functionScopes_.size();
294     funcScope->BindName(name);
295     funcScope->BindInternalName(BuildFunctionName(name, idx));
296 
297     return !scriptFunc->IsOverload();
298 }
299 
BuildVarDeclaratorId(ir::AstNode * childNode)300 void VarBinder::BuildVarDeclaratorId(ir::AstNode *childNode)
301 {
302     switch (childNode->Type()) {
303         case ir::AstNodeType::IDENTIFIER: {
304             auto *ident = childNode->AsIdentifier();
305             const auto &name = ident->Name();
306 
307             if (util::Helpers::IsGlobalIdentifier(name)) {
308                 break;
309             }
310 
311             auto *variable = scope_->FindLocal(name, varbinder::ResolveBindingOptions::BINDINGS);
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     AddCompilableFunction(func);
519 
520     auto scopeCtx = LexicalScope<FunctionScope>::Enter(this, funcScope);
521 
522     if (func->Body() != nullptr) {
523         ResolveReference(func->Body());
524     }
525 }
526 
VisitScriptFunctionWithPotentialTypeParams(ir::ScriptFunction * func)527 void VarBinder::VisitScriptFunctionWithPotentialTypeParams(ir::ScriptFunction *func)
528 {
529     if (func->TypeParams() != nullptr) {
530         auto typeParamScopeCtx = LexicalScope<Scope>::Enter(this, func->TypeParams()->Scope());
531         VisitScriptFunction(func);
532         return;
533     }
534 
535     VisitScriptFunction(func);
536 }
537 
ResolveReference(ir::AstNode * childNode)538 void VarBinder::ResolveReference(ir::AstNode *childNode)
539 {
540     switch (childNode->Type()) {
541         case ir::AstNodeType::IDENTIFIER: {
542             auto *ident = childNode->AsIdentifier();
543 
544             LookupIdentReference(ident);
545             ResolveReferences(childNode);
546             break;
547         }
548         case ir::AstNodeType::SUPER_EXPRESSION: {
549             VariableScope *varScope = scope_->EnclosingVariableScope();
550             varScope->AddFlag(ScopeFlags::USE_SUPER);
551             ResolveReferences(childNode);
552             break;
553         }
554         case ir::AstNodeType::SCRIPT_FUNCTION: {
555             VisitScriptFunctionWithPotentialTypeParams(childNode->AsScriptFunction());
556             break;
557         }
558         case ir::AstNodeType::VARIABLE_DECLARATOR: {
559             BuildVarDeclarator(childNode->AsVariableDeclarator());
560             break;
561         }
562         case ir::AstNodeType::CLASS_DEFINITION: {
563             BuildClassDefinition(childNode->AsClassDefinition());
564             break;
565         }
566         case ir::AstNodeType::CLASS_PROPERTY: {
567             BuildClassProperty(childNode->AsClassProperty());
568             break;
569         }
570         case ir::AstNodeType::BLOCK_STATEMENT: {
571             auto scopeCtx = LexicalScope<Scope>::Enter(this, childNode->AsBlockStatement()->Scope());
572 
573             ResolveReferences(childNode);
574             break;
575         }
576         case ir::AstNodeType::BLOCK_EXPRESSION: {
577             auto scopeCtx = LexicalScope<Scope>::Enter(this, childNode->AsBlockExpression()->Scope());
578 
579             ResolveReferences(childNode);
580             break;
581         }
582         case ir::AstNodeType::SWITCH_STATEMENT: {
583             auto scopeCtx = LexicalScope<LocalScope>::Enter(this, childNode->AsSwitchStatement()->Scope());
584 
585             ResolveReferences(childNode);
586             break;
587         }
588         case ir::AstNodeType::DO_WHILE_STATEMENT: {
589             auto *doWhileStatement = childNode->AsDoWhileStatement();
590 
591             {
592                 auto loopScopeCtx = LexicalScope<LoopScope>::Enter(this, doWhileStatement->Scope());
593                 ResolveReference(doWhileStatement->Body());
594             }
595 
596             ResolveReference(doWhileStatement->Test());
597             break;
598         }
599         case ir::AstNodeType::WHILE_STATEMENT: {
600             auto *whileStatement = childNode->AsWhileStatement();
601             ResolveReference(whileStatement->Test());
602 
603             auto loopScopeCtx = LexicalScope<LoopScope>::Enter(this, whileStatement->Scope());
604             ResolveReference(whileStatement->Body());
605 
606             break;
607         }
608         case ir::AstNodeType::FOR_UPDATE_STATEMENT: {
609             BuildForUpdateLoop(childNode->AsForUpdateStatement());
610             break;
611         }
612         case ir::AstNodeType::FOR_IN_STATEMENT: {
613             auto *forInStmt = childNode->AsForInStatement();
614             BuildForInOfLoop(forInStmt->Scope(), forInStmt->Left(), forInStmt->Right(), forInStmt->Body());
615 
616             break;
617         }
618         case ir::AstNodeType::FOR_OF_STATEMENT: {
619             auto *forOfStmt = childNode->AsForOfStatement();
620             BuildForInOfLoop(forOfStmt->Scope(), forOfStmt->Left(), forOfStmt->Right(), forOfStmt->Body());
621             break;
622         }
623         case ir::AstNodeType::CATCH_CLAUSE: {
624             BuildCatchClause(childNode->AsCatchClause());
625             break;
626         }
627         case ir::AstNodeType::TS_TYPE_ALIAS_DECLARATION: {
628             BuildTypeAliasDeclaration(childNode->AsTSTypeAliasDeclaration());
629             break;
630         }
631         default: {
632             HandleCustomNodes(childNode);
633             break;
634         }
635     }
636 }
637 
ResolveReferences(const ir::AstNode * parent)638 void VarBinder::ResolveReferences(const ir::AstNode *parent)
639 {
640     parent->Iterate([this](auto *childNode) { ResolveReference(childNode); });
641 }
642 
AddMandatoryParam(const std::string_view & name)643 LocalVariable *VarBinder::AddMandatoryParam(const std::string_view &name)
644 {
645     ASSERT(scope_->IsFunctionParamScope());
646 
647     auto *decl = Allocator()->New<ParameterDecl>(name);
648     auto *param = Allocator()->New<LocalVariable>(decl, VariableFlags::VAR);
649 
650     auto &funcParams = scope_->AsFunctionParamScope()->Params();
651 
652     funcParams.insert(funcParams.begin(), param);
653     scope_->AsFunctionParamScope()->GetFunctionScope()->InsertBinding(decl->Name(), param);
654     scope_->InsertBinding(decl->Name(), param);
655 
656     return param;
657 }
658 
LookUpMandatoryReferences(const FunctionScope * funcScope,bool needLexicalFuncObj)659 void VarBinder::LookUpMandatoryReferences(const FunctionScope *funcScope, bool needLexicalFuncObj)
660 {
661     LookupReference(MANDATORY_PARAM_NEW_TARGET);
662     LookupReference(MANDATORY_PARAM_THIS);
663 
664     if (funcScope->HasFlag(ScopeFlags::USE_ARGS)) {
665         LookupReference(FUNCTION_ARGUMENTS);
666     }
667 
668     if (needLexicalFuncObj) {
669         LookupReference(MANDATORY_PARAM_FUNC);
670     }
671 }
672 
AddMandatoryParams()673 void VarBinder::AddMandatoryParams()
674 {
675     ASSERT(scope_ == topScope_);
676     ASSERT(!functionScopes_.empty());
677     auto iter = functionScopes_.begin();
678     [[maybe_unused]] auto *funcScope = *iter++;
679 
680     ASSERT(funcScope->IsGlobalScope() || funcScope->IsModuleScope());
681 
682     const auto &options = context_->config->options->CompilerOptions();
683     if (options.isDirectEval) {
684         AddMandatoryParams(EVAL_SCRIPT_MANDATORY_PARAMS);
685         topScope_->ParamScope()->Params().back()->SetLexical(topScope_);
686     } else {
687         AddMandatoryParams(FUNCTION_MANDATORY_PARAMS);
688     }
689 
690     if (options.isFunctionEval) {
691         ASSERT(iter != functionScopes_.end());
692         funcScope = *iter++;
693         auto scopeCtx = LexicalScope<FunctionScope>::Enter(this, funcScope);
694         AddMandatoryParams(ARROW_MANDATORY_PARAMS);
695         LookUpMandatoryReferences(funcScope, false);
696     }
697 
698     for (; iter != functionScopes_.end(); iter++) {
699         funcScope = *iter;
700         const auto *scriptFunc = funcScope->Node()->AsScriptFunction();
701 
702         auto scopeCtx = LexicalScope<FunctionScope>::Enter(this, funcScope);
703 
704         if (!scriptFunc->IsArrow()) {
705             AddMandatoryParams(FUNCTION_MANDATORY_PARAMS);
706             continue;
707         }
708 
709         const ir::ScriptFunction *ctor = util::Helpers::GetContainingConstructor(scriptFunc);
710         bool lexicalFunctionObject {};
711 
712         if (ctor != nullptr && util::Helpers::GetClassDefiniton(ctor)->Super() != nullptr &&
713             funcScope->HasFlag(ScopeFlags::USE_SUPER)) {
714             ASSERT(ctor->Scope()->HasFlag(ScopeFlags::INNER_ARROW));
715             ctor->Scope()->AddFlag(ScopeFlags::SET_LEXICAL_FUNCTION);
716             lexicalFunctionObject = true;
717             AddMandatoryParams(CTOR_ARROW_MANDATORY_PARAMS);
718         } else {
719             AddMandatoryParams(ARROW_MANDATORY_PARAMS);
720         }
721 
722         LookUpMandatoryReferences(funcScope, lexicalFunctionObject);
723     }
724 }
725 }  // namespace ark::es2panda::varbinder
726