1/*
2 * Copyright (c) 2023-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 "util/errorHandler.h"
17#include "scopesInitPhase.h"
18
19namespace ark::es2panda::compiler {
20
21template <typename T>
22varbinder::LexicalScope<T> LexicalScopeCreateOrEnter(varbinder::VarBinder *varBinder, ir::AstNode *ast)
23{
24    if (ast != nullptr && ast->Scope() != nullptr) {
25        return varbinder::LexicalScope<T>::Enter(varBinder, reinterpret_cast<T *>(ast->Scope()));
26    }
27    return varbinder::LexicalScope<T>(varBinder);
28}
29
30template <typename T, typename... Args>
31T *AddOrGetDecl(varbinder::VarBinder *varBinder, util::StringView name, ir::AstNode *ast,
32                const lexer::SourcePosition &pos, Args &&...args)
33{
34    if (auto *var = varBinder->GetScope()->FindLocal(name, varbinder::ResolveBindingOptions::BINDINGS);
35        var != nullptr && var->Declaration() != nullptr && var->Declaration()->Node() == ast) {
36        return reinterpret_cast<T *>(var->Declaration());
37    }
38    return varBinder->AddDecl<T>(pos, args...);
39}
40
41bool ScopesInitPhase::Perform(PhaseContext *ctx, parser::Program *program)
42{
43    Prepare(ctx, program);
44    program->VarBinder()->InitTopScope();
45    HandleBlockStmt(program->Ast(), GetScope());
46    Finalize();
47    return true;
48}
49
50void ScopesInitPhase::VisitScriptFunction(ir::ScriptFunction *scriptFunction)
51{
52    if (auto *const id = scriptFunction->Id(); id != nullptr && id->Variable() == nullptr) {
53        auto const *const curScope = VarBinder()->GetScope();
54        auto const &functionName = id->Name();
55        auto const res =
56            curScope->Find(functionName, scriptFunction->IsStatic() ? varbinder::ResolveBindingOptions::ALL_STATIC
57                                                                    : varbinder::ResolveBindingOptions::ALL_NON_STATIC);
58        if (res.variable != nullptr && res.variable->Declaration()->IsFunctionDecl()) {
59            id->SetVariable(res.variable);
60        }
61    }
62
63    HandleFunction(scriptFunction);
64}
65
66void ScopesInitPhase::VisitBlockStatement(ir::BlockStatement *blockStmt)
67{
68    auto localCtx = LexicalScopeCreateOrEnter<varbinder::LocalScopeWithTypeAlias>(VarBinder(), blockStmt);
69    HandleBlockStmt(blockStmt, GetScope());
70}
71
72void ScopesInitPhase::VisitImportDeclaration(ir::ImportDeclaration *importDeclaration)
73{
74    ImportDeclarationContext importCtx(VarBinder());
75    Iterate(importDeclaration);
76    importCtx.BindImportDecl(importDeclaration);
77}
78
79void ScopesInitPhase::VisitClassStaticBlock(ir::ClassStaticBlock *staticBlock)
80{
81    Iterate(staticBlock);
82}
83
84void ScopesInitPhase::VisitMethodDefinition(ir::MethodDefinition *methodDefinition)
85{
86    Iterate(methodDefinition);
87}
88
89varbinder::FunctionParamScope *ScopesInitPhase::HandleFunctionSig(ir::TSTypeParameterDeclaration *typeParams,
90                                                                  const ir::FunctionSignature::FunctionParams &params,
91                                                                  ir::TypeNode *returnType)
92{
93    auto typeParamsCtx = varbinder::LexicalScope<varbinder::LocalScope>(VarBinder());
94    CallNode(typeParams);
95
96    auto lexicalScope = varbinder::LexicalScope<varbinder::FunctionParamScope>(VarBinder());
97    CallFuncParams(params);
98    CallNode(returnType);
99
100    return lexicalScope.GetScope();
101}
102
103void ScopesInitPhase::HandleFunction(ir::ScriptFunction *function)
104{
105    CallNode(function->Id());
106    // NOTE(gogabr): this will skip type/value parameters when they are added to an existing function sig
107    auto funcParamScope = (function->Scope() == nullptr) ? HandleFunctionSig(function->TypeParams(), function->Params(),
108                                                                             function->ReturnTypeAnnotation())
109                                                         : function->Scope()->ParamScope();
110    auto paramCtx = varbinder::LexicalScope<varbinder::FunctionParamScope>::Enter(VarBinder(), funcParamScope, false);
111
112    auto functionCtx = LexicalScopeCreateOrEnter<varbinder::FunctionScope>(VarBinder(), function);
113    auto *functionScope = functionCtx.GetScope();
114    BindFunctionScopes(functionScope, funcParamScope);
115
116    if (function->Body() != nullptr && function->Body()->IsBlockStatement()) {
117        HandleBlockStmt(function->Body()->AsBlockStatement(), functionScope);
118    } else {
119        Iterate(function->Body());
120    }
121    BindScopeNode(functionScope, function);
122    funcParamScope->BindNode(function);
123}
124
125void ScopesInitPhase::HandleBlockStmt(ir::BlockStatement *block, varbinder::Scope *scope)
126{
127    if (block->Scope() == nullptr) {
128        BindScopeNode(scope, block);
129    }
130    Iterate(block);
131}
132
133void ScopesInitPhase::VisitClassDefinition(ir::ClassDefinition *classDef)
134{
135    auto classCtx = LexicalScopeCreateOrEnter<varbinder::LocalScope>(VarBinder(), classDef);
136    AddOrGetDecl<varbinder::ConstDecl>(VarBinder(), classDef->PrivateId(), classDef, classDef->Start(),
137                                       classDef->PrivateId());
138    BindClassName(classDef);
139
140    auto *classScope = classCtx.GetScope();
141    BindScopeNode(classScope, classDef);
142    Iterate(classDef);
143}
144
145void ScopesInitPhase::VisitForUpdateStatement(ir::ForUpdateStatement *forUpdateStmt)
146{
147    auto declCtx = (forUpdateStmt->Scope() == nullptr)
148                       ? varbinder::LexicalScope<varbinder::LoopDeclarationScope>(VarBinder())
149                       : varbinder::LexicalScope<varbinder::LoopDeclarationScope>::Enter(
150                             VarBinder(), forUpdateStmt->Scope()->DeclScope());
151    CallNode(forUpdateStmt->Init());
152
153    auto lexicalScope = LexicalScopeCreateOrEnter<varbinder::LoopScope>(VarBinder(), forUpdateStmt);
154    AttachLabelToScope(forUpdateStmt);
155    CallNode(forUpdateStmt->Test());
156    CallNode(forUpdateStmt->Update());
157    CallNode(forUpdateStmt->Body());
158    lexicalScope.GetScope()->BindDecls(declCtx.GetScope());
159    HandleFor(declCtx.GetScope(), lexicalScope.GetScope(), forUpdateStmt);
160}
161
162void ScopesInitPhase::VisitForInStatement(ir::ForInStatement *forInStmt)
163{
164    auto declCtx = (forInStmt->Scope() == nullptr)
165                       ? varbinder::LexicalScope<varbinder::LoopDeclarationScope>(VarBinder())
166                       : varbinder::LexicalScope<varbinder::LoopDeclarationScope>::Enter(
167                             VarBinder(), forInStmt->Scope()->DeclScope());
168    CallNode(forInStmt->Left());
169
170    auto lexicalScope = LexicalScopeCreateOrEnter<varbinder::LoopScope>(VarBinder(), forInStmt);
171    CallNode(forInStmt->Right());
172    CallNode(forInStmt->Body());
173    HandleFor(declCtx.GetScope(), lexicalScope.GetScope(), forInStmt);
174}
175void ScopesInitPhase::VisitForOfStatement(ir::ForOfStatement *forOfStmt)
176{
177    auto declCtx = (forOfStmt->Scope() == nullptr)
178                       ? varbinder::LexicalScope<varbinder::LoopDeclarationScope>(VarBinder())
179                       : varbinder::LexicalScope<varbinder::LoopDeclarationScope>::Enter(
180                             VarBinder(), forOfStmt->Scope()->DeclScope());
181    CallNode(forOfStmt->Left());
182
183    auto lexicalScope = LexicalScopeCreateOrEnter<varbinder::LoopScope>(VarBinder(), forOfStmt);
184    AttachLabelToScope(forOfStmt);
185    CallNode(forOfStmt->Right());
186    CallNode(forOfStmt->Body());
187    HandleFor(declCtx.GetScope(), lexicalScope.GetScope(), forOfStmt);
188}
189
190void ScopesInitPhase::VisitCatchClause(ir::CatchClause *catchClause)
191{
192    auto catchParamCtx = (catchClause->Scope() == nullptr)
193                             ? varbinder::LexicalScope<varbinder::CatchParamScope>(VarBinder())
194                             : varbinder::LexicalScope<varbinder::CatchParamScope>::Enter(
195                                   VarBinder(), catchClause->Scope()->ParamScope());
196    auto *catchParamScope = catchParamCtx.GetScope();
197    auto *param = catchClause->Param();
198
199    CallNode(param);
200
201    if (param != nullptr) {
202        auto [param_decl, var] = VarBinder()->AddParamDecl(param);
203        (void)param_decl;
204        if (param->IsIdentifier()) {
205            var->SetScope(catchParamScope);
206            param->AsIdentifier()->SetVariable(var);
207        }
208    }
209
210    // Catch Clause is scope bearer
211    catchParamScope->BindNode(catchClause);
212
213    auto catchCtx = LexicalScopeCreateOrEnter<varbinder::CatchScope>(VarBinder(), catchClause);
214    auto *catchScope = catchCtx.GetScope();
215
216    catchScope->AssignParamScope(catchParamScope);
217    auto body = catchClause->Body();
218    HandleBlockStmt(body, catchScope);
219
220    BindScopeNode(catchScope, catchClause);
221}
222
223void ScopesInitPhase::VisitVariableDeclarator(ir::VariableDeclarator *varDecl)
224{
225    auto init = varDecl->Id();
226    std::vector<ir::Identifier *> bindings = util::Helpers::CollectBindingNames(init);
227    for (auto *binding : bindings) {
228        auto [decl, var] = AddOrGetVarDecl(varDecl->Flag(), varDecl->Start(), binding);
229        BindVarDecl(binding, init, decl, var);
230    }
231    Iterate(varDecl);
232}
233
234void ScopesInitPhase::VisitSwitchStatement(ir::SwitchStatement *switchStmt)
235{
236    CallNode(switchStmt->Discriminant());
237    auto localCtx = LexicalScopeCreateOrEnter<varbinder::LocalScopeWithTypeAlias>(VarBinder(), switchStmt);
238    AttachLabelToScope(switchStmt);
239    BindScopeNode(localCtx.GetScope(), switchStmt);
240    CallNode(switchStmt->Cases());
241}
242
243void ScopesInitPhase::VisitWhileStatement(ir::WhileStatement *whileStmt)
244{
245    CallNode(whileStmt->Test());
246    auto lexicalScope = LexicalScopeCreateOrEnter<varbinder::LoopScope>(VarBinder(), whileStmt);
247    AttachLabelToScope(whileStmt);
248    BindScopeNode(lexicalScope.GetScope(), whileStmt);
249    CallNode(whileStmt->Body());
250}
251
252void ScopesInitPhase::VisitETSStructDeclaration(ir::ETSStructDeclaration *structDecl)
253{
254    Iterate(structDecl);
255    BindClassDefinition(structDecl->Definition());
256}
257
258void ScopesInitPhase::VisitClassDeclaration(ir::ClassDeclaration *classDecl)
259{
260    Iterate(classDecl);
261    BindClassDefinition(classDecl->Definition());
262}
263
264void ScopesInitPhase::VisitDoWhileStatement(ir::DoWhileStatement *doWhileStmt)
265{
266    auto lexicalScope = LexicalScopeCreateOrEnter<varbinder::LoopScope>(VarBinder(), doWhileStmt);
267    AttachLabelToScope(doWhileStmt);
268    BindScopeNode(lexicalScope.GetScope(), doWhileStmt);
269    Iterate(doWhileStmt);
270}
271
272void ScopesInitPhase::VisitFunctionDeclaration(ir::FunctionDeclaration *funcDecl)
273{
274    const auto func = funcDecl->Function();
275    if (!funcDecl->IsAnonymous()) {
276        CreateFuncDecl(func);
277    }
278    Iterate(funcDecl);
279}
280
281void ScopesInitPhase::VisitExportAllDeclaration(ir::ExportAllDeclaration *exportAllDecl)
282{
283    Iterate(exportAllDecl);
284    const auto name = exportAllDecl->Exported() != nullptr ? exportAllDecl->Exported()->Name() : "*";
285    auto *decl =
286        AddOrGetDecl<varbinder::ExportDecl>(VarBinder(), name, exportAllDecl, exportAllDecl->Start(), name, "*");
287    VarBinder()->GetScope()->AsModuleScope()->AddExportDecl(exportAllDecl, decl);
288}
289
290void ScopesInitPhase::VisitImportNamespaceSpecifier(ir::ImportNamespaceSpecifier *importSpec)
291{
292    Iterate(importSpec);
293    AddOrGetDecl<varbinder::ImportDecl>(VarBinder(), importSpec->Local()->Name(), importSpec, importSpec->Start(), "*",
294                                        importSpec->Local()->Name(), importSpec);
295}
296
297void ScopesInitPhase::VisitImportSpecifier(ir::ImportSpecifier *importSpec)
298{
299    Iterate(importSpec);
300    const auto *imported = importSpec->Imported();
301    AddOrGetDecl<varbinder::ImportDecl>(VarBinder(), importSpec->Local()->Name(), importSpec, importSpec->Start(),
302                                        imported->Name(), importSpec->Local()->Name(), importSpec);
303}
304
305void ScopesInitPhase::VisitImportDefaultSpecifier(ir::ImportDefaultSpecifier *importSpec)
306{
307    Iterate(importSpec);
308    const auto *local = importSpec->Local();
309    AddOrGetDecl<varbinder::ImportDecl>(VarBinder(), local->Name(), importSpec, local->Start(), "default",
310                                        local->Name(), importSpec);
311}
312
313void ScopesInitPhase::VisitExportDefaultDeclaration(ir::ExportDefaultDeclaration *exportDecl)
314{
315    ExportDeclarationContext exportDeclCtx(VarBinder());
316    Iterate(exportDecl);
317    exportDeclCtx.BindExportDecl(exportDecl);
318}
319
320void ScopesInitPhase::VisitArrowFunctionExpression(ir::ArrowFunctionExpression *arrowExpr)
321{
322    Iterate(arrowExpr);
323}
324
325void ScopesInitPhase::VisitDirectEvalExpression(ir::DirectEvalExpression *directCallExpr)
326{
327    VarBinder()->PropagateDirectEval();
328    Iterate(directCallExpr);
329}
330
331void ScopesInitPhase::VisitExportNamedDeclaration(ir::ExportNamedDeclaration *exportDecl)
332{
333    if (exportDecl->Decl() != nullptr) {
334        ExportDeclarationContext exportDeclCtx(VarBinder());
335        Iterate(exportDecl);
336        exportDeclCtx.BindExportDecl(exportDecl);
337    } else {
338        varbinder::ModuleScope::ExportDeclList exportDecls(program_->Allocator()->Adapter());
339
340        for (auto *spec : exportDecl->Specifiers()) {
341            auto *decl =
342                AddOrGetDecl<varbinder::ExportDecl>(VarBinder(), spec->Local()->Name(), spec, exportDecl->Start(),
343                                                    spec->Exported()->Name(), spec->Local()->Name(), spec);
344            exportDecls.push_back(decl);
345        }
346        VarBinder()->GetScope()->AsModuleScope()->AddExportDecl(exportDecl, std::move(exportDecls));
347    }
348}
349
350void ScopesInitPhase::VisitTSFunctionType(ir::TSFunctionType *funcType)
351{
352    auto lexicalScope = LexicalScopeCreateOrEnter<varbinder::FunctionParamScope>(VarBinder(), funcType);
353    auto *funcParamScope = lexicalScope.GetScope();
354    BindScopeNode(funcParamScope, funcType);
355    Iterate(funcType);
356}
357
358void ScopesInitPhase::SetProgram(parser::Program *program) noexcept
359{
360    program_ = program;
361}
362
363void ScopesInitPhase::CallFuncParams(const ArenaVector<ir::Expression *> &params)
364{
365    // NOTE: extract params to separate class
366    for (auto *param : params) {
367        if (!param->IsETSParameterExpression()) {
368            VarBinder()->AddParamDecl(param);
369        }
370    }
371    CallNode(params);
372}
373
374void ScopesInitPhase::IterateNoTParams(ir::ClassDefinition *classDef)
375{
376    CallNode(classDef->Super());
377    CallNode(classDef->SuperTypeParams());
378    CallNode(classDef->Implements());
379    CallNode(classDef->Ctor());
380    CallNode(classDef->Body());
381}
382
383void ScopesInitPhase::ThrowSyntaxError(std::string_view errorMessage, const lexer::SourcePosition &pos) const
384{
385    util::ErrorHandler::ThrowSyntaxError(Program(), errorMessage, pos);
386}
387
388void ScopesInitPhase::CreateFuncDecl(ir::ScriptFunction *func)
389{
390    AddOrGetDecl<varbinder::FunctionDecl>(VarBinder(), func->Id()->Name(), func, func->Id()->Start(), Allocator(),
391                                          func->Id()->Name(), func);
392}
393
394util::StringView ScopesInitPhase::FormInterfaceOrEnumDeclarationIdBinding(ir::Identifier *id)
395{
396    return id->Name();
397}
398
399varbinder::Decl *ScopesInitPhase::BindClassName(ir::ClassDefinition *classDef)
400{
401    const auto identNode = classDef->Ident();
402    if (identNode == nullptr) {
403        return nullptr;
404    }
405
406    auto identDecl = AddOrGetDecl<varbinder::ConstDecl>(VarBinder(), identNode->Name(), classDef, identNode->Start(),
407                                                        identNode->Name());
408    if (identDecl != nullptr) {
409        identDecl->BindNode(classDef);
410    }
411    return identDecl;
412}
413
414void ScopesInitPhase::BindFunctionScopes(varbinder::FunctionScope *scope, varbinder::FunctionParamScope *paramScope)
415{
416    scope->BindParamScope(paramScope);
417    paramScope->BindFunctionScope(scope);
418}
419
420void ScopesInitPhase::BindClassDefinition(ir::ClassDefinition *classDef)
421{
422    if (classDef->IsGlobal()) {
423        return;  // We handle it in ClassDeclaration
424    }
425    const auto locStart = classDef->Ident()->Start();
426    const auto &className = classDef->Ident()->Name();
427    if ((classDef->Modifiers() & ir::ClassDefinitionModifiers::CLASS_DECL) != 0U) {
428        AddOrGetDecl<varbinder::ClassDecl>(VarBinder(), className, classDef, locStart, className, classDef);
429    } else {
430        AddOrGetDecl<varbinder::LetDecl>(VarBinder(), className, classDef, locStart, className, classDef);
431    }
432}
433
434std::tuple<varbinder::Decl *, varbinder::Variable *> ScopesInitPhase::AddOrGetVarDecl(ir::VariableDeclaratorFlag flag,
435                                                                                      lexer::SourcePosition startLoc,
436                                                                                      const ir::Identifier *id)
437{
438    if (auto var = id->Variable(); var != nullptr) {
439        return {var->Declaration(), var};
440    }
441    auto name = id->Name();
442    switch (flag) {
443        case ir::VariableDeclaratorFlag::LET:
444            return VarBinder()->NewVarDecl<varbinder::LetDecl>(startLoc, name);
445        case ir::VariableDeclaratorFlag::VAR:
446            return VarBinder()->NewVarDecl<varbinder::VarDecl>(startLoc, name);
447        case ir::VariableDeclaratorFlag::CONST:
448            return VarBinder()->NewVarDecl<varbinder::ConstDecl>(startLoc, name);
449        default:
450            UNREACHABLE();
451    }
452}
453
454void ScopesInitPhase::BindVarDecl([[maybe_unused]] ir::Identifier *binding, ir::Expression *init, varbinder::Decl *decl,
455                                  [[maybe_unused]] varbinder::Variable *var)
456{
457    decl->BindNode(init);
458}
459
460void ScopesInitPhase::AttachLabelToScope([[maybe_unused]] ir::AstNode *node) {}
461
462void ScopesInitPhase::VisitFunctionExpression(ir::FunctionExpression *funcExpr)
463{
464    Iterate(funcExpr);
465    if (!funcExpr->IsAnonymous()) {
466        auto func = funcExpr->Function();
467        auto id = funcExpr->Id();
468        auto *funcParamScope = func->Scope()->ParamScope();
469        funcParamScope->BindName(Allocator(), id->Name());
470        func->SetIdent(id->Clone(Allocator(), nullptr));
471    }
472}
473
474void ScopesInitPhase::Prepare(ScopesInitPhase::PhaseContext *ctx, parser::Program *program)
475{
476    ctx_ = ctx;
477    program_ = program;
478}
479
480void ScopesInitPhase::Finalize()
481{
482    AnalyzeExports();
483}
484
485void ScopesInitPhase::AnalyzeExports()
486{
487    if (Program()->Kind() == parser::ScriptKind::MODULE && VarBinder()->TopScope()->IsModuleScope() &&
488        !VarBinder()->TopScope()->AsModuleScope()->ExportAnalysis()) {
489        ThrowSyntaxError("Invalid exported binding", Program()->Ast()->End());
490    }
491}
492
493void ScopeInitTyped::VisitTSModuleDeclaration(ir::TSModuleDeclaration *moduleDecl)
494{
495    if (!moduleDecl->IsExternalOrAmbient()) {
496        auto name = moduleDecl->Name()->AsIdentifier()->Name();
497        auto *decl = AddOrGetDecl<varbinder::VarDecl>(VarBinder(), name, moduleDecl, moduleDecl->Name()->Start(), name);
498        decl->BindNode(moduleDecl);
499    }
500    auto localCtx = LexicalScopeCreateOrEnter<varbinder::LocalScope>(VarBinder(), moduleDecl);
501    BindScopeNode(localCtx.GetScope(), moduleDecl);
502    Iterate(moduleDecl);
503}
504
505void ScopeInitTyped::VisitTSModuleBlock(ir::TSModuleBlock *block)
506{
507    auto localCtx = LexicalScopeCreateOrEnter<varbinder::LocalScope>(VarBinder(), block);
508    Iterate(block);
509    BindScopeNode(localCtx.GetScope(), block);
510}
511
512void ScopeInitTyped::VisitTSTypeAliasDeclaration(ir::TSTypeAliasDeclaration *typeAliasDecl)
513{
514    const auto id = typeAliasDecl->Id();
515    varbinder::TSBinding tsBinding(Allocator(), id->Name());
516    auto *decl = VarBinder()->AddTsDecl<varbinder::TypeAliasDecl>(id->Start(), tsBinding.View());
517    auto typeParamsCtx = LexicalScopeCreateOrEnter<varbinder::LocalScope>(VarBinder(), typeAliasDecl->TypeParams());
518    decl->BindNode(typeAliasDecl);
519    Iterate(typeAliasDecl);
520}
521
522util::StringView ScopeInitTyped::FormInterfaceOrEnumDeclarationIdBinding(ir::Identifier *id)
523{
524    varbinder::TSBinding tsBinding(Allocator(), id->Name());
525    return tsBinding.View();
526}
527
528void ScopeInitTyped::VisitTSInterfaceDeclaration(ir::TSInterfaceDeclaration *interfDecl)
529{
530    const auto &bindings = VarBinder()->GetScope()->Bindings();
531    const auto ident = interfDecl->Id();
532    const auto name = FormInterfaceOrEnumDeclarationIdBinding(ident);
533    auto res = bindings.find(name);
534
535    varbinder::InterfaceDecl *decl {};
536
537    bool alreadyExists = false;
538    if (res == bindings.end()) {
539        decl = VarBinder()->AddTsDecl<varbinder::InterfaceDecl>(ident->Start(), Allocator(), name);
540    } else if (!AllowInterfaceRedeclaration()) {
541        ThrowSyntaxError("Interface redeclaration is not allowed", interfDecl->Start());
542    } else if (!res->second->Declaration()->IsInterfaceDecl()) {
543        VarBinder()->ThrowRedeclaration(ident->Start(), ident->Name());
544    } else {
545        decl = res->second->Declaration()->AsInterfaceDecl();
546        alreadyExists = true;
547    }
548
549    CallNode(ident);
550    auto typeParamsCtx = LexicalScopeCreateOrEnter<varbinder::LocalScope>(VarBinder(), interfDecl->TypeParams());
551    CallNode(interfDecl->TypeParams());
552    CallNode(interfDecl->Extends());
553
554    auto localScope = LexicalScopeCreateOrEnter<varbinder::LocalScope>(VarBinder(), interfDecl);
555    auto *identDecl =
556        AddOrGetDecl<varbinder::ConstDecl>(VarBinder(), ident->Name(), interfDecl, ident->Start(), ident->Name());
557    identDecl->BindNode(interfDecl);
558    BindScopeNode(localScope.GetScope(), interfDecl);
559
560    CallNode(interfDecl->Body());
561    if (!alreadyExists) {
562        decl->BindNode(interfDecl);
563    }
564    decl->Add(interfDecl);
565}
566
567void ScopeInitTyped::VisitTSEnumMember(ir::TSEnumMember *enumMember)
568{
569    const auto key = enumMember->Key();
570    util::StringView name;
571    if (key->IsIdentifier()) {
572        name = key->AsIdentifier()->Name();
573    } else if (key->IsStringLiteral()) {
574        name = key->AsStringLiteral()->Str();
575    } else {
576        UNREACHABLE();
577    }
578    auto *decl = AddOrGetDecl<varbinder::EnumDecl>(VarBinder(), name, enumMember, key->Start(), name);
579    decl->BindNode(enumMember);
580}
581
582void ScopeInitTyped::VisitTSEnumDeclaration(ir::TSEnumDeclaration *enumDecl)
583{
584    util::StringView ident = FormInterfaceOrEnumDeclarationIdBinding(enumDecl->Key());
585    const auto &bindings = VarBinder()->GetScope()->Bindings();
586    auto res = bindings.find(ident);
587
588    varbinder::EnumLiteralDecl *decl {};
589    if (res == bindings.end()) {
590        decl = VarBinder()->AddTsDecl<varbinder::EnumLiteralDecl>(enumDecl->Start(), ident, enumDecl->IsConst());
591        varbinder::LexicalScope enumCtx = LexicalScopeCreateOrEnter<varbinder::LocalScope>(VarBinder(), enumDecl);
592        decl->BindScope(enumCtx.GetScope());
593        BindScopeNode(VarBinder()->GetScope()->AsLocalScope(), enumDecl);
594    } else if (!res->second->Declaration()->IsEnumLiteralDecl() ||
595               (enumDecl->IsConst() ^ res->second->Declaration()->AsEnumLiteralDecl()->IsConst()) != 0) {
596        auto loc = enumDecl->Key()->End();
597        loc.index++;
598        VarBinder()->ThrowRedeclaration(loc, enumDecl->Key()->Name());
599    } else {
600        decl = res->second->Declaration()->AsEnumLiteralDecl();
601
602        auto scopeCtx = varbinder::LexicalScope<varbinder::LocalScope>::Enter(VarBinder(), decl->Scope());
603    }
604    decl->BindNode(enumDecl);
605    Iterate(enumDecl);
606}
607
608void ScopeInitTyped::VisitTSTypeParameter(ir::TSTypeParameter *typeParam)
609{
610    auto name = typeParam->Name()->Name();
611    auto decl = AddOrGetDecl<varbinder::TypeParameterDecl>(VarBinder(), name, typeParam, typeParam->Start(), name);
612    decl->BindNode(typeParam);
613    Iterate(typeParam);
614}
615
616void ScopeInitTyped::VisitTSTypeParameterDeclaration(ir::TSTypeParameterDeclaration *paramDecl)
617{
618    BindScopeNode(VarBinder()->GetScope()->AsLocalScope(), paramDecl);
619    Iterate(paramDecl);
620}
621
622void ScopeInitTyped::VisitClassDefinition(ir::ClassDefinition *classDef)
623{
624    auto typeParamsCtx = LexicalScopeCreateOrEnter<varbinder::LocalScope>(VarBinder(), classDef->TypeParams());
625    CallNode(classDef->TypeParams());
626
627    auto classCtx = LexicalScopeCreateOrEnter<varbinder::LocalScope>(VarBinder(), classDef);
628    BindClassName(classDef);
629    AddOrGetDecl<varbinder::ConstDecl>(VarBinder(), classDef->PrivateId(), classDef, classDef->Start(),
630                                       classDef->PrivateId());
631    BindScopeNode(classCtx.GetScope(), classDef);
632    IterateNoTParams(classDef);
633}
634
635void InitScopesPhaseTs::VisitExportDefaultDeclaration(ir::ExportDefaultDeclaration *exportDecl)
636{
637    ExportDeclarationContext exportDeclCtx(VarBinder());
638    Iterate(exportDecl);
639}
640
641void InitScopesPhaseTs::VisitExportNamedDeclaration(ir::ExportNamedDeclaration *exportDecl)
642{
643    ExportDeclarationContext exportDeclCtx(VarBinder());
644    Iterate(exportDecl);
645}
646
647void InitScopesPhaseTs::VisitImportDeclaration(ir::ImportDeclaration *importDeclaration)
648{
649    ImportDeclarationContext importCtx(VarBinder());
650    Iterate(importDeclaration);
651}
652
653void InitScopesPhaseTs::VisitTSFunctionType(ir::TSFunctionType *constrType)
654{
655    auto lexicalScope =
656        (constrType->Scope() == nullptr)
657            ? HandleFunctionSig(constrType->TypeParams(), constrType->Params(), constrType->ReturnType())
658            : constrType->Scope();
659    BindScopeNode(lexicalScope, constrType);
660}
661
662void InitScopesPhaseTs::CreateFuncDecl(ir::ScriptFunction *func)
663{
664    const auto identNode = func->Id();
665    const auto startLoc = identNode->Start();
666    const auto &bindings = VarBinder()->GetScope()->Bindings();
667    auto res = bindings.find(identNode->Name());
668    varbinder::FunctionDecl *decl {};
669
670    if (res == bindings.end()) {
671        decl = VarBinder()->AddDecl<varbinder::FunctionDecl>(startLoc, Allocator(), identNode->Name(), func);
672    } else {
673        varbinder::Decl *currentDecl = res->second->Declaration();
674
675        auto &existing = currentDecl->AsFunctionDecl()->Decls();
676        if (std::find(existing.begin(), existing.end(), func) != existing.end()) {
677            return;
678        }
679
680        if (!currentDecl->IsFunctionDecl() ||
681            !currentDecl->AsFunctionDecl()->Node()->AsScriptFunction()->IsOverload()) {
682            VarBinder()->ThrowRedeclaration(startLoc, currentDecl->Name());
683        }
684        decl = currentDecl->AsFunctionDecl();
685    }
686
687    decl->Add(func);
688}
689
690void InitScopesPhaseTs::VisitTSConstructorType(ir::TSConstructorType *constrT)
691{
692    auto funcParamScope = (constrT->Scope() == nullptr)
693                              ? HandleFunctionSig(constrT->TypeParams(), constrT->Params(), constrT->ReturnType())
694                              : constrT->Scope();
695    BindScopeNode(funcParamScope, constrT);
696}
697
698void InitScopesPhaseTs::VisitArrowFunctionExpression(ir::ArrowFunctionExpression *arrowFExpr)
699{
700    auto typeParamsCtx =
701        LexicalScopeCreateOrEnter<varbinder::LocalScope>(VarBinder(), arrowFExpr->Function()->TypeParams());
702    Iterate(arrowFExpr);
703}
704
705void InitScopesPhaseTs::VisitTSSignatureDeclaration(ir::TSSignatureDeclaration *signDecl)
706{
707    auto funcParamScope = (signDecl->Scope() == nullptr) ? HandleFunctionSig(signDecl->TypeParams(), signDecl->Params(),
708                                                                             signDecl->ReturnTypeAnnotation())
709                                                         : signDecl->Scope();
710    BindScopeNode(funcParamScope, signDecl);
711}
712
713void InitScopesPhaseTs::VisitTSMethodSignature(ir::TSMethodSignature *methodSign)
714{
715    auto funcParamScope =
716        (methodSign->Scope() == nullptr)
717            ? HandleFunctionSig(methodSign->TypeParams(), methodSign->Params(), methodSign->ReturnTypeAnnotation())
718            : methodSign->Scope();
719    BindScopeNode(funcParamScope, methodSign);
720}
721
722void InitScopesPhaseETS::RunExternalNode(ir::AstNode *node, varbinder::VarBinder *varbinder)
723{
724    auto program = parser::Program(varbinder->Allocator(), varbinder);
725    RunExternalNode(node, &program);
726}
727
728void InitScopesPhaseETS::RunExternalNode(ir::AstNode *node, parser::Program *ctx)
729{
730    auto scopesPhase = InitScopesPhaseETS();
731    scopesPhase.SetProgram(ctx);
732    scopesPhase.CallNode(node);
733}
734
735bool InitScopesPhaseETS::Perform(PhaseContext *ctx, parser::Program *program)
736{
737    Prepare(ctx, program);
738
739    if (program->VarBinder()->TopScope() == nullptr) {
740        program->VarBinder()->InitTopScope();
741        BindScopeNode(GetScope(), program->Ast());
742        AddGlobalToBinder(program);
743    }
744    HandleProgram(program);
745    Finalize();
746    return true;
747}
748
749void InitScopesPhaseETS::HandleProgram(parser::Program *program)
750{
751    for (auto &[_, prog_list] : program->ExternalSources()) {
752        (void)_;
753        auto savedTopScope(program->VarBinder()->TopScope());
754        auto mainProg = prog_list.front();
755        mainProg->VarBinder()->InitTopScope();
756        AddGlobalToBinder(mainProg);
757        BindScopeNode(mainProg->VarBinder()->GetScope(), mainProg->Ast());
758        auto globalClass = mainProg->GlobalClass();
759        auto globalScope = mainProg->GlobalScope();
760        for (auto &prog : prog_list) {
761            prog->SetGlobalClass(globalClass);
762            BindScopeNode(prog->VarBinder()->GetScope(), prog->Ast());
763            prog->VarBinder()->ResetTopScope(globalScope);
764            if (mainProg->Ast() != nullptr) {
765                InitScopesPhaseETS().Perform(Context(), prog);
766            }
767        }
768        program->VarBinder()->ResetTopScope(savedTopScope);
769    }
770    ASSERT(program->Ast() != nullptr);
771
772    HandleETSScript(program->Ast());
773}
774
775void InitScopesPhaseETS::BindVarDecl(ir::Identifier *binding, ir::Expression *init, varbinder::Decl *decl,
776                                     varbinder::Variable *var)
777{
778    binding->SetVariable(var);
779    var->SetScope(VarBinder()->GetScope());
780    var->AddFlag(varbinder::VariableFlags::LOCAL);
781    decl->BindNode(init);
782}
783
784void InitScopesPhaseETS::VisitBlockExpression(ir::BlockExpression *blockExpr)
785{
786    auto localCtx = LexicalScopeCreateOrEnter<varbinder::LocalScope>(VarBinder(), blockExpr);
787    if (blockExpr->Scope() == nullptr) {
788        BindScopeNode(GetScope(), blockExpr);
789    }
790    Iterate(blockExpr);
791}
792
793void InitScopesPhaseETS::VisitClassStaticBlock(ir::ClassStaticBlock *staticBlock)
794{
795    const auto func = staticBlock->Function();
796
797    {
798        auto funcParamCtx = (func->Scope() == nullptr)
799                                ? varbinder::LexicalScope<varbinder::FunctionParamScope>(VarBinder())
800                                : varbinder::LexicalScope<varbinder::FunctionParamScope>::Enter(
801                                      VarBinder(), func->Scope()->ParamScope());
802        auto *funcParamScope = funcParamCtx.GetScope();
803        auto funcCtx = LexicalScopeCreateOrEnter<varbinder::FunctionScope>(VarBinder(), func);
804        auto *funcScope = funcCtx.GetScope();
805
806        func->Body()->AsBlockStatement()->SetScope(funcScope);
807        BindScopeNode(funcScope, func);
808        funcParamScope->BindNode(func);
809        BindFunctionScopes(funcScope, funcParamScope);
810        Iterate(func->Body()->AsBlockStatement());
811    }
812
813    auto classCtx = varbinder::LexicalScope<varbinder::LocalScope>::Enter(
814        VarBinder(), VarBinder()->GetScope()->AsClassScope()->StaticMethodScope());
815
816    if (func->Id()->Variable() != nullptr) {
817        return;
818    }
819
820    auto [_, var] = VarBinder()->NewVarDecl<varbinder::FunctionDecl>(staticBlock->Start(), Allocator(),
821                                                                     func->Id()->Name(), staticBlock);
822    (void)_;
823    var->AddFlag(varbinder::VariableFlags::METHOD);
824    func->Id()->SetVariable(var);
825}
826
827void InitScopesPhaseETS::VisitImportNamespaceSpecifier(ir::ImportNamespaceSpecifier *importSpec)
828{
829    if (importSpec->Local()->Name().Empty()) {
830        return;
831    }
832    AddOrGetDecl<varbinder::ImportDecl>(VarBinder(), importSpec->Local()->Name(), importSpec, importSpec->Start(),
833                                        importSpec->Local()->Name(), importSpec->Local()->Name(), importSpec);
834    auto var =
835        VarBinder()->GetScope()->FindLocal(importSpec->Local()->Name(), varbinder::ResolveBindingOptions::BINDINGS);
836    importSpec->Local()->SetVariable(var);
837    Iterate(importSpec);
838}
839
840void InitScopesPhaseETS::VisitImportSpecifier(ir::ImportSpecifier *importSpec)
841{
842    if (importSpec->Parent()->AsETSImportDeclaration()->IsPureDynamic()) {
843        auto [decl, var] =
844            VarBinder()->NewVarDecl<varbinder::LetDecl>(importSpec->Start(), importSpec->Local()->Name(), importSpec);
845        var->AddFlag(varbinder::VariableFlags::INITIALIZED);
846    }
847    Iterate(importSpec);
848}
849
850//  Auxiliary method to avoid extra nested levels and too large function size
851void AddOverload(ir::MethodDefinition *overload, varbinder::Variable *variable) noexcept
852{
853    auto *currentNode = variable->Declaration()->Node();
854    currentNode->AsMethodDefinition()->AddOverload(overload);
855    overload->Id()->SetVariable(variable);
856    overload->SetParent(currentNode);
857}
858
859void InitScopesPhaseETS::DeclareClassMethod(ir::MethodDefinition *method)
860{
861    ASSERT(VarBinder()->GetScope()->IsClassScope());
862
863    if ((method->AsMethodDefinition()->Function()->Flags() & ir::ScriptFunctionFlags::OVERLOAD) != 0) {
864        return;
865    }
866
867    const auto methodName = method->Id();
868    auto *const clsScope = VarBinder()->GetScope()->AsClassScope();
869    auto options =
870        method->IsStatic()
871            ? varbinder::ResolveBindingOptions::STATIC_VARIABLES | varbinder::ResolveBindingOptions::STATIC_DECLARATION
872            : varbinder::ResolveBindingOptions::VARIABLES | varbinder::ResolveBindingOptions::DECLARATION;
873    if (clsScope->FindLocal(methodName->Name(), options) != nullptr) {
874        VarBinder()->ThrowRedeclaration(methodName->Start(), methodName->Name());
875    }
876
877    varbinder::LocalScope *targetScope {};
878    if (method->IsStatic() || method->IsConstructor()) {
879        targetScope = clsScope->StaticMethodScope();
880    } else {
881        targetScope = clsScope->InstanceMethodScope();
882    }
883    auto *found = targetScope->FindLocal(methodName->Name(), varbinder::ResolveBindingOptions::BINDINGS);
884
885    MaybeAddOverload(method, methodName, found, clsScope, targetScope);
886}
887
888void InitScopesPhaseETS::MaybeAddOverload(ir::MethodDefinition *method, ir::Identifier *methodName,
889                                          varbinder::Variable *found, varbinder::ClassScope *clsScope,
890                                          varbinder::LocalScope *targetScope)
891{
892    if (found == nullptr) {
893        auto classCtx = varbinder::LexicalScope<varbinder::LocalScope>::Enter(VarBinder(), targetScope);
894
895        auto *var = methodName->Variable();
896        if (var == nullptr) {
897            var = std::get<1>(VarBinder()->NewVarDecl<varbinder::FunctionDecl>(methodName->Start(), Allocator(),
898                                                                               methodName->Name(), method));
899            var->SetScope(clsScope);
900            var->AddFlag(varbinder::VariableFlags::METHOD);
901            methodName->SetVariable(var);
902        }
903        for (auto *overload : method->Overloads()) {
904            ASSERT((overload->Function()->Flags() & ir::ScriptFunctionFlags::OVERLOAD));
905            overload->Id()->SetVariable(var);
906            overload->SetParent(var->Declaration()->Node());
907        }
908    } else {
909        if (methodName->Name().Is(compiler::Signatures::MAIN) && clsScope->Parent()->IsGlobalScope()) {
910            ThrowSyntaxError("Main overload is not enabled", methodName->Start());
911        }
912        AddOverload(method, found);
913        method->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD);
914
915        // default params overloads
916        for (auto *overload : method->Overloads()) {
917            ASSERT((overload->Function()->Flags() & ir::ScriptFunctionFlags::OVERLOAD));
918            AddOverload(overload, found);
919        }
920        method->ClearOverloads();
921    }
922}
923
924void InitScopesPhaseETS::VisitETSReExportDeclaration(ir::ETSReExportDeclaration *reExport)
925{
926    if (reExport->GetETSImportDeclarations()->Language().IsDynamic()) {
927        VarBinder()->AsETSBinder()->AddDynamicImport(reExport->GetETSImportDeclarations());
928    }
929    VarBinder()->AsETSBinder()->AddReExportImport(reExport);
930}
931
932void InitScopesPhaseETS::VisitETSParameterExpression(ir::ETSParameterExpression *paramExpr)
933{
934    auto *const var = std::get<1>(VarBinder()->AddParamDecl(paramExpr));
935    paramExpr->Ident()->SetVariable(var);
936    var->SetScope(VarBinder()->GetScope());
937    Iterate(paramExpr);
938}
939
940void InitScopesPhaseETS::VisitETSImportDeclaration(ir::ETSImportDeclaration *importDecl)
941{
942    ImportDeclarationContext importCtx(VarBinder());
943    if (importDecl->Language().IsDynamic()) {
944        VarBinder()->AsETSBinder()->AddDynamicImport(importDecl);
945    }
946    Iterate(importDecl);
947}
948
949void InitScopesPhaseETS::VisitTSEnumMember(ir::TSEnumMember *enumMember)
950{
951    auto ident = enumMember->Key()->AsIdentifier();
952    if (ident->Variable() != nullptr) {
953        return;
954    }
955    auto [decl, var] = VarBinder()->NewVarDecl<varbinder::LetDecl>(ident->Start(), ident->Name());
956    var->SetScope(VarBinder()->GetScope());
957    var->AddFlag(varbinder::VariableFlags::STATIC);
958    ident->SetVariable(var);
959    decl->BindNode(enumMember);
960    Iterate(enumMember);
961}
962
963void InitScopesPhaseETS::VisitMethodDefinition(ir::MethodDefinition *method)
964{
965    auto *curScope = VarBinder()->GetScope();
966    const auto methodName = method->Id();
967    auto res =
968        curScope->Find(methodName->Name(), method->IsStatic() ? varbinder::ResolveBindingOptions::ALL_STATIC
969                                                              : varbinder::ResolveBindingOptions::ALL_NON_STATIC);
970    if (res.variable != nullptr && !res.variable->Declaration()->IsFunctionDecl() && res.scope == curScope) {
971        VarBinder()->ThrowRedeclaration(methodName->Start(), res.name);
972    }
973    Iterate(method);
974    DeclareClassMethod(method);
975}
976
977void InitScopesPhaseETS::VisitETSFunctionType(ir::ETSFunctionType *funcType)
978{
979    auto typeParamsCtx = LexicalScopeCreateOrEnter<varbinder::LocalScope>(VarBinder(), funcType->TypeParams());
980
981    // Check for existing scope
982    // In some cases we can visit function again with scope that already exists
983    // Example: async lambda, we "move" original function to another place and visit it again
984    if (funcType->Scope() == nullptr) {
985        varbinder::LexicalScope<varbinder::FunctionParamScope> lexicalScope(VarBinder());
986        auto *funcParamScope = lexicalScope.GetScope();
987        BindScopeNode(funcParamScope, funcType);
988        Iterate(funcType);
989    }
990}
991
992void InitScopesPhaseETS::VisitETSNewClassInstanceExpression(ir::ETSNewClassInstanceExpression *newClassExpr)
993{
994    CallNode(newClassExpr->GetArguments());
995    CallNode(newClassExpr->GetTypeRef());
996    if (newClassExpr->ClassDefinition() != nullptr) {
997        const auto classDef = newClassExpr->ClassDefinition();
998        auto *parentClassScope = VarBinder()->GetScope();
999        while (!parentClassScope->IsClassScope()) {
1000            ASSERT(parentClassScope->Parent());
1001            parentClassScope = parentClassScope->Parent();
1002        }
1003        auto classCtx = LexicalScopeCreateOrEnter<varbinder::ClassScope>(VarBinder(), newClassExpr->ClassDefinition());
1004        util::UString anonymousName(util::StringView("#"), Allocator());
1005        anonymousName.Append(std::to_string(parentClassScope->AsClassScope()->GetAndIncrementAnonymousClassIdx()));
1006        classDef->SetInternalName(anonymousName.View());
1007        classDef->Ident()->SetName(anonymousName.View());
1008        CallNode(classDef);
1009    }
1010}
1011
1012void InitScopesPhaseETS::VisitTSTypeParameter(ir::TSTypeParameter *typeParam)
1013{
1014    if (typeParam->Name()->Variable() != nullptr) {
1015        return;
1016    }
1017    auto [decl, var] =
1018        VarBinder()->NewVarDecl<varbinder::TypeParameterDecl>(typeParam->Name()->Start(), typeParam->Name()->Name());
1019    typeParam->Name()->SetVariable(var);
1020    var->SetScope(VarBinder()->GetScope());
1021    var->AddFlag(varbinder::VariableFlags::TYPE_PARAMETER);
1022    decl->BindNode(typeParam);
1023}
1024
1025void InitScopesPhaseETS::VisitTSInterfaceDeclaration(ir::TSInterfaceDeclaration *interfaceDecl)
1026{
1027    {
1028        auto typeParamsCtx = LexicalScopeCreateOrEnter<varbinder::LocalScope>(VarBinder(), interfaceDecl->TypeParams());
1029        CallNode(interfaceDecl->TypeParams());
1030        CallNode(interfaceDecl->Extends());
1031        auto localScope = LexicalScopeCreateOrEnter<varbinder::ClassScope>(VarBinder(), interfaceDecl);
1032        CallNode(interfaceDecl->Body());
1033        BindScopeNode(localScope.GetScope(), interfaceDecl);
1034    }
1035    auto name = FormInterfaceOrEnumDeclarationIdBinding(interfaceDecl->Id());
1036    auto *decl = AddOrGetDecl<varbinder::InterfaceDecl>(VarBinder(), name, interfaceDecl, interfaceDecl->Start(),
1037                                                        Allocator(), name, interfaceDecl);
1038    decl->AsInterfaceDecl()->Add(interfaceDecl);
1039}
1040
1041void InitScopesPhaseETS::VisitTSEnumDeclaration(ir::TSEnumDeclaration *enumDecl)
1042{
1043    {
1044        const auto enumCtx = LexicalScopeCreateOrEnter<varbinder::LocalScope>(VarBinder(), enumDecl);
1045        BindScopeNode(enumCtx.GetScope(), enumDecl);
1046        Iterate(enumDecl);
1047    }
1048    auto name = FormInterfaceOrEnumDeclarationIdBinding(enumDecl->Key());
1049    auto *decl = AddOrGetDecl<varbinder::EnumLiteralDecl>(VarBinder(), name, enumDecl, enumDecl->Start(), name,
1050                                                          enumDecl, enumDecl->IsConst());
1051    decl->BindScope(enumDecl->Scope());
1052}
1053
1054void InitScopesPhaseETS::VisitTSTypeAliasDeclaration(ir::TSTypeAliasDeclaration *typeAlias)
1055{
1056    AddOrGetDecl<varbinder::TypeAliasDecl>(VarBinder(), typeAlias->Id()->Name(), typeAlias, typeAlias->Id()->Start(),
1057                                           typeAlias->Id()->Name(), typeAlias);
1058    auto typeParamsCtx = LexicalScopeCreateOrEnter<varbinder::LocalScope>(VarBinder(), typeAlias->TypeParams());
1059    Iterate(typeAlias);
1060}
1061
1062void InitScopesPhaseETS::AddGlobalToBinder(parser::Program *program)
1063{
1064    auto globalId = program->GlobalClass()->Ident();
1065    if (globalId->Variable() != nullptr) {
1066        return;
1067    }
1068
1069    auto [decl2, var] = program->VarBinder()->NewVarDecl<varbinder::ClassDecl>(globalId->Start(), globalId->Name());
1070
1071    auto classCtx = LexicalScopeCreateOrEnter<varbinder::ClassScope>(program->VarBinder(), program->GlobalClass());
1072    classCtx.GetScope()->BindNode(program->GlobalClass());
1073    program->GlobalClass()->SetScope(classCtx.GetScope());
1074
1075    auto *classDecl = program->GlobalClass()->Parent();
1076    decl2->BindNode(classDecl);
1077    globalId->SetVariable(var);
1078}
1079
1080void InitScopesPhaseETS::HandleETSScript(ir::BlockStatement *script)
1081{
1082    for (auto decl : script->Statements()) {
1083        if (decl->IsETSImportDeclaration()) {
1084            CallNode(decl);
1085        } else {
1086            auto classCtx =
1087                varbinder::LexicalScope<varbinder::ClassScope>::Enter(VarBinder(), Program()->GlobalClassScope());
1088            CallNode(decl);
1089        }
1090    }
1091    auto classCtx = varbinder::LexicalScope<varbinder::ClassScope>::Enter(VarBinder(), Program()->GlobalClassScope());
1092
1093    for (auto decl : script->Statements()) {
1094        AddGlobalDeclaration(decl);
1095    }
1096}
1097
1098void InitScopesPhaseETS::VisitClassDefinition(ir::ClassDefinition *classDef)
1099{
1100    if (classDef->IsGlobal()) {
1101        ParseGlobalClass(classDef);
1102        return;
1103    }
1104    auto typeParamsCtx = LexicalScopeCreateOrEnter<varbinder::LocalScope>(VarBinder(), classDef->TypeParams());
1105    CallNode(classDef->TypeParams());
1106    auto classCtx = LexicalScopeCreateOrEnter<varbinder::ClassScope>(VarBinder(), classDef);
1107
1108    IterateNoTParams(classDef);
1109    FilterOverloads(classDef->Body());
1110    auto *classScope = classCtx.GetScope();
1111    BindScopeNode(classScope, classDef);
1112}
1113
1114void InitScopesPhaseETS::VisitTSInterfaceBody(ir::TSInterfaceBody *interfBody)
1115{
1116    Iterate(interfBody);
1117    FilterInterfaceOverloads(interfBody->Body());
1118}
1119
1120void InitScopesPhaseETS::FilterInterfaceOverloads(ArenaVector<ir::AstNode *, false> &props)
1121{
1122    auto condition = [](ir::AstNode *prop) {
1123        if (prop->IsMethodDefinition()) {
1124            const auto func = prop->AsMethodDefinition()->Function();
1125            return func->IsOverload() && func->Body() != nullptr;
1126        }
1127        return false;
1128    };
1129    props.erase(std::remove_if(props.begin(), props.end(), condition), props.end());
1130}
1131
1132void InitScopesPhaseETS::FilterOverloads(ArenaVector<ir::AstNode *, false> &props)
1133{
1134    auto condition = [](ir::AstNode *prop) {
1135        if (prop->IsMethodDefinition()) {
1136            const auto func = prop->AsMethodDefinition()->Function();
1137            return func->IsOverload();
1138        }
1139        return false;
1140    };
1141    props.erase(std::remove_if(props.begin(), props.end(), condition), props.end());
1142}
1143
1144void InitScopesPhaseETS::VisitClassProperty(ir::ClassProperty *classProp)
1145{
1146    auto curScope = VarBinder()->GetScope();
1147    const auto name = classProp->Key()->AsIdentifier()->Name();
1148    if (classProp->IsClassStaticBlock()) {
1149        ASSERT(curScope->IsClassScope());
1150        auto classCtx = varbinder::LexicalScope<varbinder::LocalScope>::Enter(
1151            VarBinder(), curScope->AsClassScope()->StaticMethodScope());
1152        auto *var = classProp->Id()->Variable();
1153        if (var == nullptr) {
1154            var = std::get<1>(VarBinder()->NewVarDecl<varbinder::FunctionDecl>(classProp->Start(), Allocator(),
1155                                                                               classProp->Id()->Name(), classProp));
1156        }
1157        var->AddFlag(varbinder::VariableFlags::METHOD);
1158        classProp->AsClassStaticBlock()->Function()->Id()->SetVariable(var);
1159    } else if (classProp->IsConst()) {
1160        ASSERT(curScope->Parent() != nullptr);
1161        const auto initializer = classProp->Value();
1162        if (initializer == nullptr && curScope->Parent()->IsGlobalScope() && !classProp->IsDeclare()) {
1163            auto pos = classProp->End();
1164            // NOTE: Just use property Name?
1165            if (!classProp->TypeAnnotation()->IsETSPrimitiveType()) {
1166                pos.index--;
1167            }
1168            ThrowSyntaxError("Missing initializer in const declaration", pos);
1169        }
1170        AddOrGetDecl<varbinder::ConstDecl>(VarBinder(), name, classProp, classProp->Key()->Start(), name, classProp);
1171    } else if (classProp->IsReadonly()) {
1172        ASSERT(curScope->Parent() != nullptr);
1173        if (curScope->Parent()->IsGlobalScope() && !classProp->IsDeclare()) {
1174            auto pos = classProp->End();
1175            ThrowSyntaxError("Readonly field cannot be in Global scope", pos);
1176        }
1177        AddOrGetDecl<varbinder::ReadonlyDecl>(VarBinder(), name, classProp, classProp->Key()->Start(), name, classProp);
1178    } else {
1179        AddOrGetDecl<varbinder::LetDecl>(VarBinder(), name, classProp, classProp->Key()->Start(), name, classProp);
1180    }
1181    Iterate(classProp);
1182}
1183
1184void InitScopesPhaseETS::VisitBreakStatement(ir::BreakStatement *stmt)
1185{
1186    auto label = stmt->Ident();
1187    if (label != nullptr) {
1188        auto scope = VarBinder()->GetScope();
1189        auto var = scope->FindInFunctionScope(label->Name(), varbinder::ResolveBindingOptions::ALL).variable;
1190        label->SetVariable(var);
1191    }
1192}
1193
1194void InitScopesPhaseETS::VisitContinueStatement(ir::ContinueStatement *stmt)
1195{
1196    auto label = stmt->Ident();
1197    if (label != nullptr) {
1198        auto scope = VarBinder()->GetScope();
1199        auto var = scope->FindInFunctionScope(label->Name(), varbinder::ResolveBindingOptions::ALL).variable;
1200        label->SetVariable(var);
1201    }
1202}
1203
1204void InitScopesPhaseETS::AttachLabelToScope(ir::AstNode *node)
1205{
1206    if (node->Parent() == nullptr) {
1207        return;
1208    }
1209
1210    if (!node->Parent()->IsLabelledStatement()) {
1211        return;
1212    }
1213
1214    auto stmt = node->Parent()->AsLabelledStatement();
1215    auto label = stmt->Ident();
1216    if (label == nullptr) {
1217        return;
1218    }
1219
1220    auto decl = AddOrGetDecl<varbinder::LabelDecl>(VarBinder(), label->Name(), stmt, label->Start(), label->Name());
1221    decl->BindNode(stmt);
1222
1223    auto var = VarBinder()->GetScope()->FindLocal(label->Name(), varbinder::ResolveBindingOptions::BINDINGS);
1224    if (var != nullptr) {
1225        label->SetVariable(var);
1226        var->SetScope(VarBinder()->GetScope());
1227        var->AddFlag(varbinder::VariableFlags::LOCAL);
1228    }
1229}
1230
1231void InitScopesPhaseETS::ParseGlobalClass(ir::ClassDefinition *global)
1232{
1233    for (auto decl : global->Body()) {
1234        if (decl->IsDefaultExported()) {
1235            if (VarBinder()->AsETSBinder()->DefaultExport() != nullptr) {
1236                ThrowSyntaxError("Only one default export is allowed in a module", decl->Start());
1237            }
1238            VarBinder()->AsETSBinder()->SetDefaultExport(decl);
1239        }
1240        CallNode(decl);
1241    }
1242    FilterOverloads(global->Body());
1243}
1244
1245void InitScopesPhaseETS::AddGlobalDeclaration(ir::AstNode *node)
1246{
1247    ir::Identifier *ident = nullptr;
1248    bool isBuiltin = false;
1249    switch (node->Type()) {
1250        case ir::AstNodeType::CLASS_DECLARATION: {
1251            auto def = node->AsClassDeclaration()->Definition();
1252            if (def->IsGlobal()) {
1253                return;
1254            }
1255            ident = def->Ident();
1256            isBuiltin = def->IsFromExternal();
1257            break;
1258        }
1259        case ir::AstNodeType::STRUCT_DECLARATION: {
1260            ident = node->AsETSStructDeclaration()->Definition()->Ident();
1261            isBuiltin = node->AsETSStructDeclaration()->Definition()->IsFromExternal();
1262            break;
1263        }
1264        case ir::AstNodeType::TS_INTERFACE_DECLARATION: {
1265            ident = node->AsTSInterfaceDeclaration()->Id();
1266            isBuiltin = node->AsTSInterfaceDeclaration()->IsFromExternal();
1267            break;
1268        }
1269        case ir::AstNodeType::TS_ENUM_DECLARATION: {
1270            ident = node->AsTSEnumDeclaration()->Key();
1271            break;
1272        }
1273        case ir::AstNodeType::TS_TYPE_ALIAS_DECLARATION: {
1274            ident = node->AsTSTypeAliasDeclaration()->Id();
1275            break;
1276        }
1277        default: {
1278            break;
1279        }
1280    }
1281    if (ident != nullptr) {
1282        VarBinder()->TopScope()->InsertBinding(ident->Name(), ident->Variable());
1283        if (isBuiltin) {
1284            ident->Variable()->AddFlag(varbinder::VariableFlags::BUILTIN_TYPE);
1285        }
1286    }
1287}
1288
1289void InitScopesPhaseAS::VisitArrowFunctionExpression(ir::ArrowFunctionExpression *arrowExpr)
1290{
1291    Iterate(arrowExpr);
1292}
1293
1294void InitScopesPhaseAS::VisitExportNamedDeclaration(ir::ExportNamedDeclaration *exportDecl)
1295{
1296    ExportDeclarationContext exportDeclCtx(VarBinder());
1297    Iterate(exportDecl);
1298}
1299
1300}  // namespace ark::es2panda::compiler
1301