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 "scope.h"
17 
18 #include "varbinder/declaration.h"
19 #include "util/helpers.h"
20 #include "varbinder/tsBinding.h"
21 #include "varbinder/variable.h"
22 #include "varbinder/variableFlags.h"
23 #include "ir/astNode.h"
24 #include "ir/expressions/identifier.h"
25 #include "ir/statements/classDeclaration.h"
26 #include "ir/base/classDefinition.h"
27 #include "ir/base/scriptFunction.h"
28 #include "ir/base/classProperty.h"
29 #include "ir/base/methodDefinition.h"
30 #include "ir/module/exportAllDeclaration.h"
31 #include "ir/module/exportNamedDeclaration.h"
32 #include "ir/module/exportSpecifier.h"
33 #include "ir/module/importDeclaration.h"
34 #include "ir/expressions/literals/stringLiteral.h"
35 #include "ir/expressions/literals/booleanLiteral.h"
36 #include "ir/ts/tsInterfaceDeclaration.h"
37 #include "ir/ts/tsEnumDeclaration.h"
38 #include "ir/ts/tsTypeAliasDeclaration.h"
39 #include "compiler/base/literals.h"
40 #include "macros.h"
41 #include "util/ustring.h"
42 #include "generated/signatures.h"
43 #include "public/public.h"
44 
45 namespace ark::es2panda::varbinder {
EnclosingVariableScope()46 VariableScope *Scope::EnclosingVariableScope()
47 {
48     Scope *iter = this;
49 
50     while (iter != nullptr) {
51         if (iter->IsVariableScope()) {
52             return iter->AsVariableScope();
53         }
54 
55         iter = iter->Parent();
56     }
57 
58     return nullptr;
59 }
60 
EnclosingVariableScope() const61 const VariableScope *Scope::EnclosingVariableScope() const
62 {
63     const auto *iter = this;
64 
65     while (iter != nullptr) {
66         if (iter->IsVariableScope()) {
67             return iter->AsVariableScope();
68         }
69 
70         iter = iter->Parent();
71     }
72 
73     return nullptr;
74 }
75 
IsSuperscopeOf(const varbinder::Scope *subscope) const76 bool Scope::IsSuperscopeOf(const varbinder::Scope *subscope) const
77 {
78     while (subscope != nullptr) {
79         if (subscope == this) {
80             return true;
81         }
82         subscope = ir::AstNode::EnclosingScope(subscope->Node()->Parent());
83     }
84     return false;
85 }
86 
87 // NOTE(psiket): Duplication
EnclosingClassScope()88 ClassScope *Scope::EnclosingClassScope()
89 {
90     Scope *iter = this;
91 
92     while (iter != nullptr) {
93         if (iter->IsClassScope()) {
94             return iter->AsClassScope();
95         }
96 
97         iter = iter->Parent();
98     }
99 
100     return nullptr;
101 }
102 
EnclosingClassScope() const103 const ClassScope *Scope::EnclosingClassScope() const
104 {
105     const auto *iter = this;
106 
107     while (iter != nullptr) {
108         if (iter->IsVariableScope()) {
109             return iter->AsClassScope();
110         }
111 
112         iter = iter->Parent();
113     }
114 
115     return nullptr;
116 }
117 
FindLocal(const util::StringView &name, ResolveBindingOptions options) const118 Variable *Scope::FindLocal(const util::StringView &name, ResolveBindingOptions options) const
119 {
120     if ((options & ResolveBindingOptions::INTERFACES) != 0) {
121         std::string tsBindingName = varbinder::TSBinding::ToTSBinding(name);
122         util::StringView interfaceNameView(tsBindingName);
123 
124         auto res = bindings_.find(interfaceNameView);
125         if (res != bindings_.end()) {
126             return res->second;
127         }
128 
129         if ((options & ResolveBindingOptions::BINDINGS) == 0) {
130             return nullptr;
131         }
132     }
133 
134     auto res = bindings_.find(name);
135     if (res == bindings_.end()) {
136         return nullptr;
137     }
138 
139     return res->second;
140 }
141 
InsertBinding(const util::StringView &name, Variable *const var)142 Scope::InsertResult Scope::InsertBinding(const util::StringView &name, Variable *const var)
143 {
144     ASSERT(var != nullptr);
145     auto insertResult = bindings_.emplace(name, var);
146     if (insertResult.second) {
147         decls_.push_back(var->Declaration());
148     }
149 
150     return insertResult;
151 }
152 
TryInsertBinding(const util::StringView &name, Variable *const var)153 Scope::InsertResult Scope::TryInsertBinding(const util::StringView &name, Variable *const var)
154 {
155     ASSERT(var != nullptr);
156     return bindings_.try_emplace(name, var);
157 }
158 
MergeBindings(VariableMap const &bindings)159 void Scope::MergeBindings(VariableMap const &bindings)
160 {
161     for (auto &[k, v] : bindings) {
162         bindings_.try_emplace(k, v);
163     }
164 }
165 
EraseBinding(const util::StringView &name)166 Scope::VariableMap::size_type Scope::EraseBinding(const util::StringView &name)
167 {
168     if (auto toBeErased = bindings_.find(name);
169         toBeErased == bindings_.end() ||
170         (toBeErased->second->IsLocalVariable() &&
171          toBeErased->second->AsLocalVariable()->Declaration()->Node()->IsImportNamespaceSpecifier())) {
172         return 0;
173     }
174 
175     return bindings_.erase(name);
176 }
177 
FindInGlobal(const util::StringView &name, const ResolveBindingOptions options) const178 ConstScopeFindResult Scope::FindInGlobal(const util::StringView &name, const ResolveBindingOptions options) const
179 {
180     const auto *scopeIter = this;
181     const auto *scopeParent = this->Parent();
182     // One scope below true global is ETSGLOBAL
183     while (scopeParent != nullptr && !scopeParent->IsGlobalScope()) {
184         scopeIter = scopeParent;
185         scopeParent = scopeIter->Parent();
186     }
187 
188     auto *resolved = scopeIter->FindLocal(name, options);
189     if (resolved == nullptr && scopeParent != nullptr) {
190         // If the variable cannot be found in the scope of the local ETSGLOBAL, than we still need to check the true
191         // global scope which contains all the imported ETSGLOBALs
192         resolved = scopeParent->FindLocal(name, options);
193     }
194 
195     return {name, scopeIter, 0, 0, resolved};
196 }
197 
FindInFunctionScope(const util::StringView &name, const ResolveBindingOptions options) const198 ConstScopeFindResult Scope::FindInFunctionScope(const util::StringView &name, const ResolveBindingOptions options) const
199 {
200     const auto *scopeIter = this;
201     while (scopeIter != nullptr && !scopeIter->IsGlobalScope()) {
202         if (!scopeIter->IsClassScope()) {
203             if (auto *const resolved = scopeIter->FindLocal(name, options); resolved != nullptr) {
204                 return ConstScopeFindResult(name, scopeIter, 0, 0, resolved);
205             }
206         }
207         scopeIter = scopeIter->Parent();
208     }
209 
210     return ConstScopeFindResult(name, scopeIter, 0, 0, nullptr);
211 }
212 
Find(const util::StringView &name, const ResolveBindingOptions options)213 ScopeFindResult Scope::Find(const util::StringView &name, const ResolveBindingOptions options)
214 {
215     return FindImpl<ScopeFindResult>(this, name, options);
216 }
217 
Find(const util::StringView &name, const ResolveBindingOptions options) const218 ConstScopeFindResult Scope::Find(const util::StringView &name, const ResolveBindingOptions options) const
219 {
220     return FindImpl<ConstScopeFindResult>(this, name, options);
221 }
222 
FindDecl(const util::StringView &name) const223 Decl *Scope::FindDecl(const util::StringView &name) const
224 {
225     for (auto *it : decls_) {
226         if (it->Name() == name) {
227             return it;
228         }
229     }
230 
231     return nullptr;
232 }
233 
IterateShadowedVariables(const util::StringView &name, const VariableVisitor &visitor)234 std::tuple<Scope *, bool> Scope::IterateShadowedVariables(const util::StringView &name, const VariableVisitor &visitor)
235 {
236     auto *iter = this;
237 
238     while (iter != nullptr) {
239         auto *v = iter->FindLocal(name, varbinder::ResolveBindingOptions::BINDINGS);
240 
241         if (v != nullptr && visitor(v)) {
242             return {iter, true};
243         }
244 
245         if (iter->IsFunctionVariableScope()) {
246             break;
247         }
248 
249         iter = iter->Parent();
250     }
251 
252     return {iter, false};
253 }
254 
AddLocalVar(ArenaAllocator *allocator, Decl *newDecl)255 Variable *Scope::AddLocalVar(ArenaAllocator *allocator, Decl *newDecl)
256 {
257     auto [scope, shadowed] =
258         IterateShadowedVariables(newDecl->Name(), [](const Variable *v) { return !v->HasFlag(VariableFlags::VAR); });
259 
260     if (shadowed) {
261         return nullptr;
262     }
263 
264     VariableFlags varFlags = VariableFlags::HOIST_VAR | VariableFlags::LEXICAL_VAR;
265     if (scope->IsGlobalScope()) {
266         return scope->InsertBinding(newDecl->Name(), allocator->New<GlobalVariable>(newDecl, varFlags)).first->second;
267     }
268 
269     return scope->PropagateBinding<LocalVariable>(allocator, newDecl->Name(), newDecl, varFlags);
270 }
271 
AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)272 Variable *Scope::AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
273                           [[maybe_unused]] ScriptExtension extension)
274 {
275     VariableFlags flags = VariableFlags::LEXICAL;
276     switch (newDecl->Type()) {
277         case DeclType::VAR: {
278             return AddLocalVar(allocator, newDecl);
279         }
280         case DeclType::ENUM: {
281             return bindings_.insert({newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)}).first->second;
282         }
283         case DeclType::ENUM_LITERAL: {
284             return bindings_
285                 .insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::ENUM_LITERAL)})
286                 .first->second;
287         }
288         case DeclType::INTERFACE: {
289             return bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::INTERFACE)})
290                 .first->second;
291         }
292         case DeclType::CLASS: {
293             return bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::CLASS)})
294                 .first->second;
295         }
296         case DeclType::TYPE_PARAMETER: {
297             return bindings_
298                 .insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::TYPE_PARAMETER)})
299                 .first->second;
300         }
301         case DeclType::FUNC: {
302             flags = VariableFlags::HOIST;
303             [[fallthrough]];
304         }
305         default: {
306             if (currentVariable != nullptr) {
307                 return nullptr;
308             }
309 
310             auto [_, shadowed] = IterateShadowedVariables(
311                 newDecl->Name(), [](const Variable *v) { return v->HasFlag(VariableFlags::LEXICAL_VAR); });
312             (void)_;
313 
314             if (shadowed) {
315                 return nullptr;
316             }
317 
318             return bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, flags)}).first->second;
319         }
320     }
321 }
322 
CheckDirectEval(public_lib::Context *context)323 void VariableScope::CheckDirectEval(public_lib::Context *context)
324 {
325     ASSERT(context);
326     const auto &varMap = Bindings();
327 
328     if (!HasFlag(ScopeFlags::NO_REG_STORE) || varMap.empty()) {
329         evalBindings_ = compiler::INVALID_LITERAL_BUFFER_ID;
330         return;
331     }
332 
333     size_t constBindings = 0;
334     for (const auto &[name, var] : varMap) {
335         (void)name;
336         var->SetLexical(this);
337 
338         if (var->LexicalBound() && var->Declaration()->IsConstDecl()) {
339             constBindings++;
340         }
341     }
342 
343     std::vector<compiler::Literal> literals(LexicalSlots() + constBindings, compiler::Literal(util::StringView()));
344 
345     if (constBindings == 0U) {
346         for (const auto &[name, variable] : varMap) {
347             if (!variable->LexicalBound()) {
348                 continue;
349             }
350 
351             literals[variable->AsLocalVariable()->LexIdx()] = compiler::Literal(name);
352         }
353     } else {
354         std::vector<varbinder::Variable *> bindings(LexicalSlots());
355 
356         for (const auto &[name, variable] : varMap) {
357             (void)name;
358             if (!variable->LexicalBound()) {
359                 continue;
360             }
361 
362             bindings[variable->AsLocalVariable()->LexIdx()] = variable;
363         }
364 
365         uint32_t buffIndex = 0;
366         for (const auto *variable : bindings) {
367             if (variable == nullptr) {
368                 ASSERT(literals[buffIndex].GetString().empty());
369                 buffIndex++;
370                 continue;
371             }
372             if (variable->Declaration()->IsConstDecl()) {
373                 literals[buffIndex++] = compiler::Literal(true);
374             }
375             literals[buffIndex++] = compiler::Literal(variable->Name());
376         }
377     }
378     context->contextLiterals.emplace_back(literals);
379     evalBindings_ = context->contextLiterals.size() - 1;
380 }
381 
AddParam(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags)382 Variable *ParamScope::AddParam(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags)
383 {
384     ASSERT(newDecl->IsParameterDecl());
385 
386     if (currentVariable != nullptr) {
387         return nullptr;
388     }
389 
390     auto *param = allocator->New<LocalVariable>(newDecl, flags);
391     param->SetScope(this);
392 
393     params_.push_back(param);
394     InsertBinding(newDecl->Name(), param);
395     return param;
396 }
397 
AddParamDecl(ArenaAllocator *allocator, ir::AstNode *param)398 std::tuple<ParameterDecl *, ir::AstNode *, Variable *> ParamScope::AddParamDecl(ArenaAllocator *allocator,
399                                                                                 ir::AstNode *param)
400 {
401     const auto [name, pattern] = util::Helpers::ParamName(allocator, param, params_.size());
402 
403     auto *decl = NewDecl<ParameterDecl>(allocator, name);
404     auto *var = AddParam(allocator, FindLocal(name, varbinder::ResolveBindingOptions::BINDINGS), decl,
405                          VariableFlags::VAR | VariableFlags::LOCAL);
406 
407     if (var == nullptr) {
408         return {decl, param, nullptr};
409     }
410 
411     if (!pattern) {
412         decl->BindNode(param);
413         return {decl, nullptr, var};
414     }
415 
416     std::vector<ir::Identifier *> bindings = util::Helpers::CollectBindingNames(param);
417 
418     for (auto *binding : bindings) {
419         auto *varDecl = NewDecl<VarDecl>(allocator, binding->Name());
420         varDecl->BindNode(binding);
421 
422         if (FindLocal(varDecl->Name(), varbinder::ResolveBindingOptions::BINDINGS) != nullptr) {
423             return {decl, binding, nullptr};
424         }
425 
426         auto *paramVar = allocator->New<LocalVariable>(varDecl, VariableFlags::VAR | VariableFlags::LOCAL);
427         TryInsertBinding(varDecl->Name(), paramVar);
428     }
429 
430     return {decl, nullptr, var};
431 }
432 
BindName(ArenaAllocator *allocator, util::StringView name)433 void FunctionParamScope::BindName(ArenaAllocator *allocator, util::StringView name)
434 {
435     nameVar_ = AddDecl<ConstDecl, LocalVariable>(allocator, name, VariableFlags::INITIALIZED);
436     if (!functionScope_->InsertBinding(name, nameVar_).second) {
437         nameVar_ = nullptr;
438     }
439 }
440 
AddBinding([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] Variable *currentVariable, [[maybe_unused]] Decl *newDecl, [[maybe_unused]] ScriptExtension extension)441 Variable *FunctionParamScope::AddBinding([[maybe_unused]] ArenaAllocator *allocator,
442                                          [[maybe_unused]] Variable *currentVariable, [[maybe_unused]] Decl *newDecl,
443                                          [[maybe_unused]] ScriptExtension extension)
444 {
445     UNREACHABLE();
446 }
447 
AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)448 Variable *FunctionScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
449                                     [[maybe_unused]] ScriptExtension extension)
450 {
451     ir::Identifier *ident {};
452     Variable *var {};
453     switch (newDecl->Type()) {
454         case DeclType::VAR: {
455             return AddVar<LocalVariable>(allocator, currentVariable, newDecl);
456         }
457         case DeclType::FUNC: {
458             return AddFunction<LocalVariable>(allocator, currentVariable, newDecl, extension);
459         }
460         case DeclType::ENUM: {
461             return InsertBinding(newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)).first->second;
462         }
463         case DeclType::ENUM_LITERAL: {
464             return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::ENUM_LITERAL);
465         }
466         // NOTE(psiket):Duplication
467         case DeclType::INTERFACE: {
468             ident = newDecl->Node()->AsTSInterfaceDeclaration()->Id();
469             auto interfaceVar = allocator->New<LocalVariable>(newDecl, VariableFlags::INTERFACE);
470             var = InsertBinding(newDecl->Name(), interfaceVar).first->second;
471             break;
472         }
473         case DeclType::CLASS: {
474             ident = newDecl->Node()->AsClassDefinition()->Ident();
475             auto classVar = allocator->New<LocalVariable>(newDecl, VariableFlags::CLASS);
476             var = InsertBinding(newDecl->Name(), classVar).first->second;
477             break;
478         }
479         case DeclType::TYPE_ALIAS: {
480             ident = newDecl->Node()->AsTSTypeAliasDeclaration()->Id();
481             var = typeAliasScope_->AddBinding(allocator, currentVariable, newDecl, extension);
482             break;
483         }
484         default: {
485             return AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
486         }
487     }
488     if (var != nullptr) {
489         var->SetScope(this);
490         if (ident != nullptr) {
491             ident->SetVariable(var);
492         }
493     }
494     return var;
495 }
496 
AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)497 Variable *GlobalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
498                                   [[maybe_unused]] ScriptExtension extension)
499 {
500     switch (newDecl->Type()) {
501         case DeclType::VAR: {
502             return AddVar<GlobalVariable>(allocator, currentVariable, newDecl);
503         }
504         case DeclType::FUNC: {
505             return AddFunction<GlobalVariable>(allocator, currentVariable, newDecl, extension);
506         }
507         case DeclType::ENUM: {
508             return InsertBinding(newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)).first->second;
509         }
510         case DeclType::ENUM_LITERAL: {
511             return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::ENUM_LITERAL);
512         }
513         case DeclType::INTERFACE: {
514             return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
515         }
516         default: {
517             return AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
518         }
519     }
520 }
521 
InsertBinding(const util::StringView &name, Variable *const var)522 Scope::InsertResult GlobalScope::InsertBinding(const util::StringView &name, Variable *const var)
523 {
524     return GlobalScope::InsertImpl(name, var, false, false);
525 }
526 
TryInsertBinding(const util::StringView &name, Variable *const var)527 Scope::InsertResult GlobalScope::TryInsertBinding(const util::StringView &name, Variable *const var)
528 {
529     const auto insRes = Scope::TryInsertBinding(name, var);
530     if (insRes.second) {
531         [[maybe_unused]] const bool insertSuccess = std::get<1>(foreignBindings_.try_emplace(name, var));
532         ASSERT(insertSuccess);
533     }
534 
535     return insRes;
536 }
537 
MergeBindings([[maybe_unused]] const VariableMap &bindings)538 void GlobalScope::MergeBindings([[maybe_unused]] const VariableMap &bindings)
539 {
540     UNREACHABLE();
541 }
542 
EraseBinding(const util::StringView &name)543 Scope::VariableMap::size_type GlobalScope::EraseBinding(const util::StringView &name)
544 {
545     const auto erased = Scope::EraseBinding(name);
546     if (erased != 0) {
547         [[maybe_unused]] const auto erasedForeign = foreignBindings_.erase(name);
548         ASSERT(erasedForeign != 0);
549     }
550 
551     return erased;
552 }
553 
InsertForeignBinding(const util::StringView &name, Variable *const var)554 Scope::InsertResult GlobalScope::InsertForeignBinding(const util::StringView &name, Variable *const var)
555 {
556     return GlobalScope::InsertImpl(name, var, true, false);
557 }
558 
InsertImpl(const util::StringView &name, Variable *const var, const bool isForeign, const bool isDynamic)559 Scope::InsertResult GlobalScope::InsertImpl(const util::StringView &name, Variable *const var, const bool isForeign,
560                                             const bool isDynamic)
561 {
562     if (!isDynamic && isForeign && !var->Declaration()->Name().Is(compiler::Signatures::ETS_GLOBAL)) {
563         const auto *const node = var->Declaration()->Node();
564 
565         if (!(node->IsExported() || node->IsDefaultExported() || node->IsExportedType())) {
566             return Scope::InsertResult {Bindings().end(), false};
567         }
568     }
569 
570     const auto insRes = Scope::InsertBinding(name, var);
571     if (insRes.second) {
572         [[maybe_unused]] const bool insertSuccess = std::get<1>(foreignBindings_.emplace(name, isForeign));
573         ASSERT(insertSuccess);
574     }
575 
576     return insRes;
577 }
578 
IsForeignBinding(const util::StringView &name) const579 bool GlobalScope::IsForeignBinding(const util::StringView &name) const
580 {
581     // Asserts make sure that the passed in key comes from this scope
582     ASSERT(Bindings().find(name) != Bindings().end());
583     ASSERT(foreignBindings_.find(name) != foreignBindings_.end());
584 
585     return foreignBindings_.at(name);
586 }
587 
InsertDynamicBinding(const util::StringView &name, Variable *const var)588 Scope::InsertResult GlobalScope::InsertDynamicBinding(const util::StringView &name, Variable *const var)
589 {
590     return InsertImpl(name, var, true, true);
591 }
592 
593 // ModuleScope
594 
AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)595 Variable *ModuleScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
596                                   [[maybe_unused]] ScriptExtension extension)
597 {
598     switch (newDecl->Type()) {
599         case DeclType::VAR: {
600             return AddVar<LocalVariable>(allocator, currentVariable, newDecl);
601         }
602         case DeclType::FUNC: {
603             return AddFunction<LocalVariable>(allocator, currentVariable, newDecl, extension);
604         }
605         case DeclType::ENUM: {
606             return InsertBinding(newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)).first->second;
607         }
608         case DeclType::ENUM_LITERAL: {
609             return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::ENUM_LITERAL);
610         }
611         case DeclType::INTERFACE: {
612             return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
613         }
614         case DeclType::IMPORT: {
615             return AddImport(allocator, currentVariable, newDecl);
616         }
617         case DeclType::EXPORT: {
618             return allocator->New<LocalVariable>(newDecl, VariableFlags::NONE);
619         }
620         default: {
621             return AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
622         }
623     }
624 }
625 
AddImportDecl(ir::ImportDeclaration *importDecl, ImportDeclList &&decls)626 void ModuleScope::AddImportDecl(ir::ImportDeclaration *importDecl, ImportDeclList &&decls)
627 {
628     auto res = imports_.emplace_back(importDecl, decls);
629 
630     for (auto &decl : res.second) {
631         decl->BindNode(importDecl);
632     }
633 }
634 
AddExportDecl(ir::AstNode *exportDecl, ExportDecl *decl)635 void ModuleScope::AddExportDecl(ir::AstNode *exportDecl, ExportDecl *decl)
636 {
637     decl->BindNode(exportDecl);
638 
639     ArenaVector<ExportDecl *> decls(allocator_->Adapter());
640     decls.push_back(decl);
641 
642     AddExportDecl(exportDecl, std::move(decls));
643 }
644 
AddExportDecl(ir::AstNode *exportDecl, ExportDeclList &&decls)645 void ModuleScope::AddExportDecl(ir::AstNode *exportDecl, ExportDeclList &&decls)
646 {
647     auto res = exports_.emplace_back(exportDecl, decls);
648 
649     for (auto &decl : res.second) {
650         decl->BindNode(exportDecl);
651     }
652 }
653 
AddImport(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)654 Variable *ModuleScope::AddImport(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)
655 {
656     if (currentVariable != nullptr && currentVariable->Declaration()->Type() != DeclType::VAR) {
657         return nullptr;
658     }
659 
660     if (newDecl->Node()->IsImportNamespaceSpecifier()) {
661         return InsertBinding(newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::READONLY))
662             .first->second;
663     }
664 
665     auto *variable = allocator->New<ModuleVariable>(newDecl, VariableFlags::NONE);
666     variable->ExoticName() = newDecl->AsImportDecl()->ImportName();
667     InsertBinding(newDecl->Name(), variable);
668     return variable;
669 }
670 
ExportAnalysis()671 bool ModuleScope::ExportAnalysis()
672 {
673     std::set<util::StringView> exportedNames;
674 
675     for (const auto &[exportDecl, decls] : exports_) {
676         if (exportDecl->IsExportAllDeclaration()) {
677             const auto *exportAllDecl = exportDecl->AsExportAllDeclaration();
678 
679             if (exportAllDecl->Exported() == nullptr) {
680                 continue;
681             }
682 
683             auto result = exportedNames.insert(exportAllDecl->Exported()->Name());
684             if (!result.second) {
685                 return false;
686             }
687 
688             continue;
689         }
690 
691         if (exportDecl->IsExportNamedDeclaration()) {
692             const auto *exportNamedDecl = exportDecl->AsExportNamedDeclaration();
693 
694             if (exportNamedDecl->Source() != nullptr) {
695                 continue;
696             }
697         }
698 
699         for (const auto *decl : decls) {
700             varbinder::Variable *variable = FindLocal(decl->LocalName(), varbinder::ResolveBindingOptions::BINDINGS);
701 
702             if (variable == nullptr) {
703                 continue;
704             }
705 
706             auto result = exportedNames.insert(decl->ExportName());
707             if (!result.second) {
708                 return false;
709             }
710 
711             if (!variable->IsModuleVariable()) {
712                 variable->AddFlag(VariableFlags::LOCAL_EXPORT);
713                 localExports_.insert({variable, decl->ExportName()});
714             }
715         }
716     }
717 
718     return true;
719 }
720 
FindLocal(const util::StringView &name, ResolveBindingOptions options) const721 Variable *FunctionScope::FindLocal(const util::StringView &name, ResolveBindingOptions options) const
722 {
723     if ((options & ResolveBindingOptions::TYPE_ALIASES) != 0) {
724         auto found = typeAliasScope_->Bindings().find(name);
725         if (found != typeAliasScope_->Bindings().end()) {
726             return found->second;
727         }
728     }
729 
730     if ((options & ResolveBindingOptions::ALL_NON_TYPE) == 0) {
731         return nullptr;
732     }
733 
734     if ((options & ResolveBindingOptions::INTERFACES) != 0) {
735         std::string tsBindingName = varbinder::TSBinding::ToTSBinding(name);
736         util::StringView interfaceNameView(tsBindingName);
737 
738         auto res = Bindings().find(interfaceNameView);
739         if (res != Bindings().end()) {
740             return res->second;
741         }
742 
743         if ((options & ResolveBindingOptions::BINDINGS) == 0) {
744             return nullptr;
745         }
746     }
747 
748     auto res = Bindings().find(name);
749     if (res == Bindings().end()) {
750         return nullptr;
751     }
752 
753     return res->second;
754 }
755 
756 // LocalScope
757 
AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)758 Variable *LocalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
759                                  [[maybe_unused]] ScriptExtension extension)
760 {
761     return AddLocal(allocator, currentVariable, newDecl, extension);
762 }
763 
AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)764 Variable *LocalScopeWithTypeAlias::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
765                                               [[maybe_unused]] ScriptExtension extension)
766 {
767     if (newDecl->IsTypeAliasDecl()) {
768         auto *ident = newDecl->Node()->AsTSTypeAliasDeclaration()->Id();
769         auto *var = typeAliasScope_->AddBinding(allocator, currentVariable, newDecl, extension);
770         if (var != nullptr) {
771             var->SetScope(this);
772             if (ident != nullptr) {
773                 ident->SetVariable(var);
774             }
775         }
776         return var;
777     }
778     return AddLocal(allocator, currentVariable, newDecl, extension);
779 }
780 
FindLocal(const util::StringView &name, ResolveBindingOptions options) const781 Variable *LocalScopeWithTypeAlias::FindLocal(const util::StringView &name, ResolveBindingOptions options) const
782 {
783     if ((options & ResolveBindingOptions::TYPE_ALIASES) != 0) {
784         auto found = typeAliasScope_->Bindings().find(name);
785         if (found != typeAliasScope_->Bindings().end()) {
786             return found->second;
787         }
788     }
789 
790     if ((options & ResolveBindingOptions::ALL_NON_TYPE) == 0) {
791         return nullptr;
792     }
793 
794     if ((options & ResolveBindingOptions::INTERFACES) != 0) {
795         std::string tsBindingName = varbinder::TSBinding::ToTSBinding(name);
796         util::StringView interfaceNameView(tsBindingName);
797 
798         auto res = Bindings().find(interfaceNameView);
799         if (res != Bindings().end()) {
800             return res->second;
801         }
802 
803         if ((options & ResolveBindingOptions::BINDINGS) == 0) {
804             return nullptr;
805         }
806     }
807 
808     auto res = Bindings().find(name);
809     if (res == Bindings().end()) {
810         return nullptr;
811     }
812 
813     return res->second;
814 }
815 
FindLocal(const util::StringView &name, ResolveBindingOptions options) const816 Variable *ClassScope::FindLocal(const util::StringView &name, ResolveBindingOptions options) const
817 {
818     if ((options & ResolveBindingOptions::TYPE_ALIASES) != 0) {
819         auto found = TypeAliasScope()->Bindings().find(name);
820         if (found != TypeAliasScope()->Bindings().end()) {
821             return found->second;
822         }
823     }
824 
825     if ((options & ResolveBindingOptions::VARIABLES) != 0) {
826         auto found = instanceFieldScope_->Bindings().find(name);
827         if (found != instanceFieldScope_->Bindings().end()) {
828             return found->second;
829         }
830     }
831 
832     if ((options & ResolveBindingOptions::STATIC_VARIABLES) != 0) {
833         auto found = staticFieldScope_->Bindings().find(name);
834         if (found != staticFieldScope_->Bindings().end()) {
835             return found->second;
836         }
837     }
838 
839     if ((options & ResolveBindingOptions::DECLARATION) != 0) {
840         auto found = instanceDeclScope_->Bindings().find(name);
841         if (found != instanceDeclScope_->Bindings().end()) {
842             return found->second;
843         }
844     }
845 
846     if ((options & ResolveBindingOptions::STATIC_DECLARATION) != 0) {
847         auto found = staticDeclScope_->Bindings().find(name);
848         if (found != staticDeclScope_->Bindings().end()) {
849             return found->second;
850         }
851     }
852 
853     if ((options & ResolveBindingOptions::METHODS) != 0) {
854         auto found = instanceMethodScope_->Bindings().find(name);
855         if (found != instanceMethodScope_->Bindings().end()) {
856             return found->second;
857         }
858     }
859 
860     if ((options & ResolveBindingOptions::STATIC_METHODS) != 0) {
861         auto found = staticMethodScope_->Bindings().find(name);
862         if (found != staticMethodScope_->Bindings().end()) {
863             return found->second;
864         }
865     }
866 
867     return nullptr;
868 }
869 
SetBindingProps(Decl *newDecl, BindingProps *props, bool isStatic)870 void ClassScope::SetBindingProps(Decl *newDecl, BindingProps *props, bool isStatic)
871 {
872     switch (newDecl->Type()) {
873         case DeclType::CONST:
874         case DeclType::READONLY:
875         case DeclType::LET: {
876             props->SetBindingProps(VariableFlags::PROPERTY, newDecl->Node()->AsClassProperty()->Id(),
877                                    isStatic ? staticFieldScope_ : instanceFieldScope_);
878             break;
879         }
880         case DeclType::INTERFACE: {
881             props->SetBindingProps(VariableFlags::INTERFACE, newDecl->Node()->AsTSInterfaceDeclaration()->Id(),
882                                    isStatic ? staticDeclScope_ : instanceDeclScope_);
883             break;
884         }
885         case DeclType::CLASS: {
886             props->SetBindingProps(VariableFlags::CLASS, newDecl->Node()->AsClassDefinition()->Ident(),
887                                    isStatic ? staticDeclScope_ : instanceDeclScope_);
888             break;
889         }
890         case DeclType::ENUM_LITERAL: {
891             props->SetBindingProps(VariableFlags::ENUM_LITERAL, newDecl->Node()->AsTSEnumDeclaration()->Key(),
892                                    isStatic ? staticDeclScope_ : instanceDeclScope_);
893             break;
894         }
895         case DeclType::TYPE_ALIAS: {
896             props->SetBindingProps(VariableFlags::TYPE_ALIAS, newDecl->Node()->AsTSTypeAliasDeclaration()->Id(),
897                                    TypeAliasScope());
898             break;
899         }
900         default: {
901             UNREACHABLE();
902             break;
903         }
904     }
905 }
906 
AddBinding(ArenaAllocator *allocator, [[maybe_unused]] Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)907 Variable *ClassScope::AddBinding(ArenaAllocator *allocator, [[maybe_unused]] Variable *currentVariable, Decl *newDecl,
908                                  [[maybe_unused]] ScriptExtension extension)
909 {
910     bool isStatic = newDecl->Node()->IsStatic();
911     BindingProps props;
912 
913     if (isStatic) {
914         props.SetFlagsType(VariableFlags::STATIC);
915     }
916 
917     SetBindingProps(newDecl, &props, isStatic);
918 
919     auto options = newDecl->Type() != DeclType::TYPE_ALIAS ? ResolveBindingOptions::ALL_NON_TYPE
920                                                            : ResolveBindingOptions::TYPE_ALIASES;
921 
922     const auto *foundVar = FindLocal(newDecl->Name(), options);
923     if (foundVar != nullptr) {
924         if (!newDecl->IsLetOrConstDecl()) {
925             return nullptr;
926         }
927 
928         foundVar = FindLocal(newDecl->Name(),
929                              ResolveBindingOptions::ALL ^ (isStatic ? ResolveBindingOptions::VARIABLES
930                                                                     : ResolveBindingOptions::STATIC_VARIABLES));
931         if (foundVar != nullptr) {
932             return nullptr;
933         }
934     }
935 
936     auto *var = props.GetTargetScope()->AddBinding(allocator, nullptr, newDecl, extension);
937     if (var == nullptr) {
938         return nullptr;
939     }
940 
941     if (auto node = newDecl->Node();
942         node->IsStatement() &&
943         (node->AsStatement()->IsMethodDefinition() || node->IsClassProperty() || node->IsClassStaticBlock()) &&
944         node->AsStatement()->AsClassElement()->Value() != nullptr) {
945         props.SetFlagsType(VariableFlags::INITIALIZED);
946     }
947 
948     var->SetScope(this);
949     var->AddFlag(props.GetFlags());
950 
951     if (props.GetIdent() != nullptr) {
952         props.GetIdent()->SetVariable(var);
953     }
954 
955     return var;
956 }
957 
ConvertToVariableScope(ArenaAllocator *allocator)958 void LoopDeclarationScope::ConvertToVariableScope(ArenaAllocator *allocator)
959 {
960     if (NeedLexEnv()) {
961         return;
962     }
963 
964     const auto &bindings = Bindings();
965     for (auto &[name, var] : bindings) {
966         if (!var->LexicalBound() || !var->Declaration()->IsLetOrConstDecl()) {
967             continue;
968         }
969 
970         slotIndex_++;
971         loopType_ = ScopeType::LOOP_DECL;
972         auto *copiedVar = var->AsLocalVariable()->Copy(allocator, var->Declaration());
973         copiedVar->AddFlag(VariableFlags::INITIALIZED | VariableFlags::PER_ITERATION);
974         var->AddFlag(VariableFlags::LOOP_DECL);
975         loopScope_->InsertBinding(name, copiedVar);
976     }
977 
978     if (loopType_ == ScopeType::LOOP_DECL) {
979         auto *parentVarScope = Parent()->EnclosingVariableScope();
980         slotIndex_ = std::max(slotIndex_, parentVarScope->LexicalSlots());
981         evalBindings_ = parentVarScope->EvalBindings();
982         initScope_ = allocator->New<LocalScope>(allocator, Parent());
983         initScope_->BindNode(Node());
984         initScope_->MergeBindings(bindings);
985     }
986 }
987 
ConvertToVariableScope(ArenaAllocator *allocator)988 void LoopScope::ConvertToVariableScope(ArenaAllocator *allocator)
989 {
990     declScope_->ConvertToVariableScope(allocator);
991 
992     if (loopType_ != ScopeType::LOCAL) {
993         return;
994     }
995 
996     for (const auto &[_, var] : Bindings()) {
997         (void)_;
998         if (var->LexicalBound() && var->Declaration()->IsLetDecl()) {
999             ASSERT(declScope_->NeedLexEnv());
1000             loopType_ = ScopeType::LOOP;
1001             break;
1002         }
1003     }
1004 
1005     if (loopType_ == ScopeType::LOOP) {
1006         slotIndex_ = std::max(slotIndex_, declScope_->LexicalSlots());
1007         evalBindings_ = declScope_->EvalBindings();
1008     }
1009 }
1010 
AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)1011 Variable *CatchParamScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
1012                                       [[maybe_unused]] ScriptExtension extension)
1013 {
1014     return AddParam(allocator, currentVariable, newDecl, VariableFlags::INITIALIZED);
1015 }
1016 
AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)1017 Variable *CatchScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
1018                                  [[maybe_unused]] ScriptExtension extension)
1019 {
1020     if (!newDecl->IsVarDecl() &&
1021         (paramScope_->FindLocal(newDecl->Name(), varbinder::ResolveBindingOptions::BINDINGS) != nullptr)) {
1022         return nullptr;
1023     }
1024 
1025     if (newDecl->IsTypeAliasDecl()) {
1026         auto *ident = newDecl->Node()->AsTSTypeAliasDeclaration()->Id();
1027         auto *var = TypeAliasScope()->AddBinding(allocator, currentVariable, newDecl, extension);
1028         if (var != nullptr) {
1029             var->SetScope(this);
1030             if (ident != nullptr) {
1031                 ident->SetVariable(var);
1032             }
1033         }
1034         return var;
1035     }
1036 
1037     return AddLocal(allocator, currentVariable, newDecl, extension);
1038 }
1039 }  // namespace ark::es2panda::varbinder
1040