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