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 ¶ms) 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