• 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/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 "compiler/core/compilerContext.h"
41 #include "macros.h"
42 #include "util/ustring.h"
43 #include "generated/signatures.h"
44 
45 namespace panda::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 
FindLocal(const util::StringView & name,ResolveBindingOptions options) const76 Variable *Scope::FindLocal(const util::StringView &name, ResolveBindingOptions options) const
77 {
78     if ((options & ResolveBindingOptions::INTERFACES) != 0) {
79         std::string tsBindingName = varbinder::TSBinding::ToTSBinding(name);
80         util::StringView interfaceNameView(tsBindingName);
81 
82         auto res = bindings_.find(interfaceNameView);
83         if (res != bindings_.end()) {
84             return res->second;
85         }
86 
87         if ((options & ResolveBindingOptions::BINDINGS) == 0) {
88             return nullptr;
89         }
90     }
91 
92     auto res = bindings_.find(name);
93     if (res == bindings_.end()) {
94         return nullptr;
95     }
96 
97     return res->second;
98 }
99 
InsertBinding(const util::StringView & name,Variable * const var)100 Scope::InsertResult Scope::InsertBinding(const util::StringView &name, Variable *const var)
101 {
102     ASSERT(var != nullptr);
103     return bindings_.emplace(name, var);
104 }
105 
TryInsertBinding(const util::StringView & name,Variable * const var)106 Scope::InsertResult Scope::TryInsertBinding(const util::StringView &name, Variable *const var)
107 {
108     ASSERT(var != nullptr);
109     return bindings_.try_emplace(name, var);
110 }
111 
ReplaceBindings(VariableMap bindings)112 void Scope::ReplaceBindings(VariableMap bindings)
113 {
114     bindings_ = std::move(bindings);
115 }
116 
EraseBinding(const util::StringView & name)117 Scope::VariableMap::size_type Scope::EraseBinding(const util::StringView &name)
118 {
119     return bindings_.erase(name);
120 }
121 
FindInGlobal(const util::StringView & name,const ResolveBindingOptions options) const122 ConstScopeFindResult Scope::FindInGlobal(const util::StringView &name, const ResolveBindingOptions options) const
123 {
124     const auto *scopeIter = this;
125     const auto *scopeParent = this->Parent();
126     // One scope below true global is ETSGLOBAL
127     while (scopeParent != nullptr && !scopeParent->IsGlobalScope()) {
128         scopeIter = scopeParent;
129         scopeParent = scopeIter->Parent();
130     }
131 
132     auto *resolved = scopeIter->FindLocal(name, options);
133     if (resolved == nullptr && scopeParent != nullptr) {
134         // If the variable cannot be found in the scope of the local ETSGLOBAL, than we still need to check the true
135         // global scope which contains all the imported ETSGLOBALs
136         resolved = scopeParent->FindLocal(name, options);
137     }
138 
139     return {name, scopeIter, 0, 0, resolved};
140 }
141 
FindInFunctionScope(const util::StringView & name,const ResolveBindingOptions options) const142 ConstScopeFindResult Scope::FindInFunctionScope(const util::StringView &name, const ResolveBindingOptions options) const
143 {
144     const auto *scopeIter = this;
145     while (scopeIter != nullptr && !scopeIter->IsClassScope() && !scopeIter->IsGlobalScope()) {
146         if (auto *const resolved = scopeIter->FindLocal(name, options); resolved != nullptr) {
147             return {name, scopeIter, 0, 0, resolved};
148         }
149         scopeIter = scopeIter->Parent();
150     }
151 
152     return {name, scopeIter, 0, 0, nullptr};
153 }
154 
Find(const util::StringView & name,const ResolveBindingOptions options)155 ScopeFindResult Scope::Find(const util::StringView &name, const ResolveBindingOptions options)
156 {
157     return FindImpl<ScopeFindResult>(this, name, options);
158 }
159 
Find(const util::StringView & name,const ResolveBindingOptions options) const160 ConstScopeFindResult Scope::Find(const util::StringView &name, const ResolveBindingOptions options) const
161 {
162     return FindImpl<ConstScopeFindResult>(this, name, options);
163 }
164 
FindDecl(const util::StringView & name) const165 Decl *Scope::FindDecl(const util::StringView &name) const
166 {
167     for (auto *it : decls_) {
168         if (it->Name() == name) {
169             return it;
170         }
171     }
172 
173     return nullptr;
174 }
175 
IterateShadowedVariables(const util::StringView & name,const VariableVisitor & visitor)176 std::tuple<Scope *, bool> Scope::IterateShadowedVariables(const util::StringView &name, const VariableVisitor &visitor)
177 {
178     auto *iter = this;
179 
180     while (iter != nullptr) {
181         auto *v = iter->FindLocal(name, varbinder::ResolveBindingOptions::BINDINGS);
182 
183         if (v != nullptr && visitor(v)) {
184             return {iter, true};
185         }
186 
187         if (iter->IsFunctionVariableScope()) {
188             break;
189         }
190 
191         iter = iter->Parent();
192     }
193 
194     return {iter, false};
195 }
196 
AddLocalVar(ArenaAllocator * allocator,Decl * newDecl)197 Variable *Scope::AddLocalVar(ArenaAllocator *allocator, Decl *newDecl)
198 {
199     auto [scope, shadowed] =
200         IterateShadowedVariables(newDecl->Name(), [](const Variable *v) { return !v->HasFlag(VariableFlags::VAR); });
201 
202     if (shadowed) {
203         return nullptr;
204     }
205 
206     VariableFlags varFlags = VariableFlags::HOIST_VAR | VariableFlags::LEXICAL_VAR;
207     if (scope->IsGlobalScope()) {
208         return scope->InsertBinding(newDecl->Name(), allocator->New<GlobalVariable>(newDecl, varFlags)).first->second;
209     }
210 
211     return scope->PropagateBinding<LocalVariable>(allocator, newDecl->Name(), newDecl, varFlags);
212 }
213 
AddLocal(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)214 Variable *Scope::AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
215                           [[maybe_unused]] ScriptExtension extension)
216 {
217     VariableFlags flags = VariableFlags::LEXICAL;
218     switch (newDecl->Type()) {
219         case DeclType::VAR: {
220             return AddLocalVar(allocator, newDecl);
221         }
222         case DeclType::ENUM: {
223             return bindings_.insert({newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)}).first->second;
224         }
225         case DeclType::ENUM_LITERAL: {
226             return bindings_
227                 .insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::ENUM_LITERAL)})
228                 .first->second;
229         }
230         case DeclType::INTERFACE: {
231             return bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::INTERFACE)})
232                 .first->second;
233         }
234         case DeclType::TYPE_PARAMETER: {
235             return bindings_
236                 .insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::TYPE_PARAMETER)})
237                 .first->second;
238         }
239         case DeclType::FUNC: {
240             flags = VariableFlags::HOIST;
241             [[fallthrough]];
242         }
243         default: {
244             if (currentVariable != nullptr) {
245                 return nullptr;
246             }
247 
248             auto [_, shadowed] = IterateShadowedVariables(
249                 newDecl->Name(), [](const Variable *v) { return v->HasFlag(VariableFlags::LEXICAL_VAR); });
250             (void)_;
251 
252             if (shadowed) {
253                 return nullptr;
254             }
255 
256             return bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, flags)}).first->second;
257         }
258     }
259 }
260 
CheckDirectEval(compiler::CompilerContext * compilerCtx)261 void VariableScope::CheckDirectEval(compiler::CompilerContext *compilerCtx)
262 {
263     ASSERT(compilerCtx);
264     const auto &varMap = Bindings();
265 
266     if (!HasFlag(ScopeFlags::NO_REG_STORE) || varMap.empty()) {
267         evalBindings_ = compiler::INVALID_LITERAL_BUFFER_ID;
268         return;
269     }
270 
271     size_t constBindings = 0;
272     for (const auto &[name, var] : varMap) {
273         (void)name;
274         var->SetLexical(this);
275 
276         if (var->LexicalBound() && var->Declaration()->IsConstDecl()) {
277             constBindings++;
278         }
279     }
280 
281     std::vector<compiler::Literal> literals(LexicalSlots() + constBindings, compiler::Literal(util::StringView()));
282 
283     if (constBindings == 0U) {
284         for (const auto &[name, variable] : varMap) {
285             if (!variable->LexicalBound()) {
286                 continue;
287             }
288 
289             literals[variable->AsLocalVariable()->LexIdx()] = compiler::Literal(name);
290         }
291     } else {
292         std::vector<varbinder::Variable *> bindings(LexicalSlots());
293 
294         for (const auto &[name, variable] : varMap) {
295             (void)name;
296             if (!variable->LexicalBound()) {
297                 continue;
298             }
299 
300             bindings[variable->AsLocalVariable()->LexIdx()] = variable;
301         }
302 
303         uint32_t buffIndex = 0;
304         for (const auto *variable : bindings) {
305             if (variable == nullptr) {
306                 ASSERT(literals[buffIndex].GetString().empty());
307                 buffIndex++;
308                 continue;
309             }
310             if (variable->Declaration()->IsConstDecl()) {
311                 literals[buffIndex++] = compiler::Literal(true);
312             }
313             literals[buffIndex++] = compiler::Literal(variable->Name());
314         }
315     }
316 
317     evalBindings_ = compilerCtx->AddContextLiteral(std::move(literals));
318 }
319 
AddParam(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,VariableFlags flags)320 Variable *ParamScope::AddParam(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags)
321 {
322     ASSERT(newDecl->IsParameterDecl());
323 
324     if (currentVariable != nullptr) {
325         return nullptr;
326     }
327 
328     auto *param = allocator->New<LocalVariable>(newDecl, flags);
329 
330     params_.push_back(param);
331     InsertBinding(newDecl->Name(), param);
332     return param;
333 }
334 
AddParamDecl(ArenaAllocator * allocator,ir::AstNode * param)335 std::tuple<ParameterDecl *, ir::AstNode *, Variable *> ParamScope::AddParamDecl(ArenaAllocator *allocator,
336                                                                                 ir::AstNode *param)
337 {
338     const auto [name, pattern] = util::Helpers::ParamName(allocator, param, params_.size());
339 
340     auto *decl = NewDecl<ParameterDecl>(allocator, name);
341     auto *var = AddParam(allocator, FindLocal(name, varbinder::ResolveBindingOptions::BINDINGS), decl,
342                          VariableFlags::VAR | VariableFlags::LOCAL);
343 
344     if (var == nullptr) {
345         return {decl, param, nullptr};
346     }
347 
348     if (!pattern) {
349         decl->BindNode(param);
350         return {decl, nullptr, var};
351     }
352 
353     std::vector<ir::Identifier *> bindings = util::Helpers::CollectBindingNames(param);
354 
355     for (auto *binding : bindings) {
356         auto *varDecl = NewDecl<VarDecl>(allocator, binding->Name());
357         varDecl->BindNode(binding);
358 
359         if (FindLocal(varDecl->Name(), varbinder::ResolveBindingOptions::BINDINGS) != nullptr) {
360             return {decl, binding, nullptr};
361         }
362 
363         auto *paramVar = allocator->New<LocalVariable>(varDecl, VariableFlags::VAR | VariableFlags::LOCAL);
364         TryInsertBinding(varDecl->Name(), paramVar);
365     }
366 
367     return {decl, nullptr, var};
368 }
369 
BindName(ArenaAllocator * allocator,util::StringView name)370 void FunctionParamScope::BindName(ArenaAllocator *allocator, util::StringView name)
371 {
372     nameVar_ = AddDecl<ConstDecl, LocalVariable>(allocator, name, VariableFlags::INITIALIZED);
373     if (!functionScope_->InsertBinding(name, nameVar_).second) {
374         nameVar_ = nullptr;
375     }
376 }
377 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)378 Variable *FunctionParamScope::AddBinding([[maybe_unused]] ArenaAllocator *allocator,
379                                          [[maybe_unused]] Variable *currentVariable, [[maybe_unused]] Decl *newDecl,
380                                          [[maybe_unused]] ScriptExtension extension)
381 {
382     UNREACHABLE();
383 }
384 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)385 Variable *FunctionScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
386                                     [[maybe_unused]] ScriptExtension extension)
387 {
388     switch (newDecl->Type()) {
389         case DeclType::VAR: {
390             return AddVar<LocalVariable>(allocator, currentVariable, newDecl);
391         }
392         case DeclType::FUNC: {
393             return AddFunction<LocalVariable>(allocator, currentVariable, newDecl, extension);
394         }
395         case DeclType::ENUM: {
396             return InsertBinding(newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)).first->second;
397         }
398         case DeclType::ENUM_LITERAL: {
399             return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::ENUM_LITERAL);
400         }
401         case DeclType::INTERFACE: {
402             return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
403         }
404         default: {
405             return AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
406         }
407     }
408 }
409 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)410 Variable *GlobalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
411                                   [[maybe_unused]] ScriptExtension extension)
412 {
413     switch (newDecl->Type()) {
414         case DeclType::VAR: {
415             return AddVar<GlobalVariable>(allocator, currentVariable, newDecl);
416         }
417         case DeclType::FUNC: {
418             return AddFunction<GlobalVariable>(allocator, currentVariable, newDecl, extension);
419         }
420         case DeclType::ENUM: {
421             return InsertBinding(newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)).first->second;
422         }
423         case DeclType::ENUM_LITERAL: {
424             return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::ENUM_LITERAL);
425         }
426         case DeclType::INTERFACE: {
427             return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
428         }
429         default: {
430             return AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
431         }
432     }
433 }
434 
InsertBinding(const util::StringView & name,Variable * const var)435 Scope::InsertResult GlobalScope::InsertBinding(const util::StringView &name, Variable *const var)
436 {
437     return GlobalScope::InsertImpl(name, var, false, false);
438 }
439 
TryInsertBinding(const util::StringView & name,Variable * const var)440 Scope::InsertResult GlobalScope::TryInsertBinding(const util::StringView &name, Variable *const var)
441 {
442     const auto insRes = Scope::TryInsertBinding(name, var);
443     if (insRes.second) {
444         [[maybe_unused]] const bool insertSuccess = std::get<1>(foreignBindings_.try_emplace(name, var));
445         ASSERT(insertSuccess);
446     }
447 
448     return insRes;
449 }
450 
ReplaceBindings(const VariableMap bindings)451 void GlobalScope::ReplaceBindings([[maybe_unused]] const VariableMap bindings)
452 {
453     UNREACHABLE();
454 }
455 
EraseBinding(const util::StringView & name)456 Scope::VariableMap::size_type GlobalScope::EraseBinding(const util::StringView &name)
457 {
458     const auto erased = Scope::EraseBinding(name);
459     if (erased != 0) {
460         [[maybe_unused]] const auto erasedForeign = foreignBindings_.erase(name);
461         ASSERT(erasedForeign != 0);
462     }
463 
464     return erased;
465 }
466 
InsertForeignBinding(const util::StringView & name,Variable * const var)467 Scope::InsertResult GlobalScope::InsertForeignBinding(const util::StringView &name, Variable *const var)
468 {
469     return GlobalScope::InsertImpl(name, var, true, false);
470 }
471 
InsertImpl(const util::StringView & name,Variable * const var,const bool isForeign,const bool isDynamic)472 Scope::InsertResult GlobalScope::InsertImpl(const util::StringView &name, Variable *const var, const bool isForeign,
473                                             const bool isDynamic)
474 {
475     if (!isDynamic && isForeign && !var->Declaration()->Name().Is(compiler::Signatures::ETS_GLOBAL)) {
476         const auto *const node = var->Declaration()->Node();
477 
478         if (!(node->IsExported() || node->IsDefaultExported())) {
479             return Scope::InsertResult {Bindings().end(), false};
480         }
481     }
482 
483     const auto insRes = Scope::InsertBinding(name, var);
484     if (insRes.second) {
485         [[maybe_unused]] const bool insertSuccess = std::get<1>(foreignBindings_.emplace(name, isForeign));
486         ASSERT(insertSuccess);
487     }
488 
489     return insRes;
490 }
491 
IsForeignBinding(const util::StringView & name) const492 bool GlobalScope::IsForeignBinding(const util::StringView &name) const
493 {
494     // Asserts make sure that the passed in key comes from this scope
495     ASSERT(Bindings().find(name) != Bindings().end());
496     ASSERT(foreignBindings_.find(name) != foreignBindings_.end());
497 
498     return foreignBindings_.at(name);
499 }
500 
InsertDynamicBinding(const util::StringView & name,Variable * const var)501 Scope::InsertResult GlobalScope::InsertDynamicBinding(const util::StringView &name, Variable *const var)
502 {
503     return InsertImpl(name, var, true, true);
504 }
505 
506 // ModuleScope
507 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)508 Variable *ModuleScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
509                                   [[maybe_unused]] ScriptExtension extension)
510 {
511     switch (newDecl->Type()) {
512         case DeclType::VAR: {
513             return AddVar<LocalVariable>(allocator, currentVariable, newDecl);
514         }
515         case DeclType::FUNC: {
516             return AddFunction<LocalVariable>(allocator, currentVariable, newDecl, extension);
517         }
518         case DeclType::ENUM: {
519             return InsertBinding(newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)).first->second;
520         }
521         case DeclType::ENUM_LITERAL: {
522             return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::ENUM_LITERAL);
523         }
524         case DeclType::INTERFACE: {
525             return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
526         }
527         case DeclType::IMPORT: {
528             return AddImport(allocator, currentVariable, newDecl);
529         }
530         case DeclType::EXPORT: {
531             return allocator->New<LocalVariable>(newDecl, VariableFlags::NONE);
532         }
533         default: {
534             return AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
535         }
536     }
537 }
538 
AddImportDecl(ir::ImportDeclaration * importDecl,ImportDeclList && decls)539 void ModuleScope::AddImportDecl(ir::ImportDeclaration *importDecl, ImportDeclList &&decls)
540 {
541     auto res = imports_.emplace_back(importDecl, decls);
542 
543     for (auto &decl : res.second) {
544         decl->BindNode(importDecl);
545     }
546 }
547 
AddExportDecl(ir::AstNode * exportDecl,ExportDecl * decl)548 void ModuleScope::AddExportDecl(ir::AstNode *exportDecl, ExportDecl *decl)
549 {
550     decl->BindNode(exportDecl);
551 
552     ArenaVector<ExportDecl *> decls(allocator_->Adapter());
553     decls.push_back(decl);
554 
555     AddExportDecl(exportDecl, std::move(decls));
556 }
557 
AddExportDecl(ir::AstNode * exportDecl,ExportDeclList && decls)558 void ModuleScope::AddExportDecl(ir::AstNode *exportDecl, ExportDeclList &&decls)
559 {
560     auto res = exports_.emplace_back(exportDecl, decls);
561 
562     for (auto &decl : res.second) {
563         decl->BindNode(exportDecl);
564     }
565 }
566 
AddImport(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl)567 Variable *ModuleScope::AddImport(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)
568 {
569     if (currentVariable != nullptr && currentVariable->Declaration()->Type() != DeclType::VAR) {
570         return nullptr;
571     }
572 
573     if (newDecl->Node()->IsImportNamespaceSpecifier()) {
574         return InsertBinding(newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::READONLY))
575             .first->second;
576     }
577 
578     auto *variable = allocator->New<ModuleVariable>(newDecl, VariableFlags::NONE);
579     variable->ExoticName() = newDecl->AsImportDecl()->ImportName();
580     InsertBinding(newDecl->Name(), variable);
581     return variable;
582 }
583 
ExportAnalysis()584 bool ModuleScope::ExportAnalysis()
585 {
586     std::set<util::StringView> exportedNames;
587 
588     for (const auto &[exportDecl, decls] : exports_) {
589         if (exportDecl->IsExportAllDeclaration()) {
590             const auto *exportAllDecl = exportDecl->AsExportAllDeclaration();
591 
592             if (exportAllDecl->Exported() == nullptr) {
593                 continue;
594             }
595 
596             auto result = exportedNames.insert(exportAllDecl->Exported()->Name());
597             if (!result.second) {
598                 return false;
599             }
600 
601             continue;
602         }
603 
604         if (exportDecl->IsExportNamedDeclaration()) {
605             const auto *exportNamedDecl = exportDecl->AsExportNamedDeclaration();
606 
607             if (exportNamedDecl->Source() != nullptr) {
608                 continue;
609             }
610         }
611 
612         for (const auto *decl : decls) {
613             varbinder::Variable *variable = FindLocal(decl->LocalName(), varbinder::ResolveBindingOptions::BINDINGS);
614 
615             if (variable == nullptr) {
616                 continue;
617             }
618 
619             auto result = exportedNames.insert(decl->ExportName());
620             if (!result.second) {
621                 return false;
622             }
623 
624             if (!variable->IsModuleVariable()) {
625                 variable->AddFlag(VariableFlags::LOCAL_EXPORT);
626                 localExports_.insert({variable, decl->ExportName()});
627             }
628         }
629     }
630 
631     return true;
632 }
633 
634 // LocalScope
635 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)636 Variable *LocalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
637                                  [[maybe_unused]] ScriptExtension extension)
638 {
639     return AddLocal(allocator, currentVariable, newDecl, extension);
640 }
641 
FindLocal(const util::StringView & name,ResolveBindingOptions options) const642 Variable *ClassScope::FindLocal(const util::StringView &name, ResolveBindingOptions options) const
643 {
644     if ((options & ResolveBindingOptions::TYPE_ALIASES) != 0) {
645         auto found = typeAliasScope_->Bindings().find(name);
646         if (found != typeAliasScope_->Bindings().end()) {
647             return found->second;
648         }
649     }
650 
651     if ((options & ResolveBindingOptions::VARIABLES) != 0) {
652         auto found = instanceFieldScope_->Bindings().find(name);
653         if (found != instanceFieldScope_->Bindings().end()) {
654             return found->second;
655         }
656     }
657 
658     if ((options & ResolveBindingOptions::STATIC_VARIABLES) != 0) {
659         auto found = staticFieldScope_->Bindings().find(name);
660         if (found != staticFieldScope_->Bindings().end()) {
661             return found->second;
662         }
663     }
664 
665     if ((options & ResolveBindingOptions::DECLARATION) != 0) {
666         auto found = instanceDeclScope_->Bindings().find(name);
667         if (found != instanceDeclScope_->Bindings().end()) {
668             return found->second;
669         }
670     }
671 
672     if ((options & ResolveBindingOptions::STATIC_DECLARATION) != 0) {
673         auto found = staticDeclScope_->Bindings().find(name);
674         if (found != staticDeclScope_->Bindings().end()) {
675             return found->second;
676         }
677     }
678 
679     if ((options & ResolveBindingOptions::METHODS) != 0) {
680         auto found = instanceMethodScope_->Bindings().find(name);
681         if (found != instanceMethodScope_->Bindings().end()) {
682             return found->second;
683         }
684     }
685 
686     if ((options & ResolveBindingOptions::STATIC_METHODS) != 0) {
687         auto found = staticMethodScope_->Bindings().find(name);
688         if (found != staticMethodScope_->Bindings().end()) {
689             return found->second;
690         }
691     }
692 
693     return nullptr;
694 }
695 
SetBindingProps(Decl * newDecl,BindingProps * props,bool isStatic)696 void ClassScope::SetBindingProps(Decl *newDecl, BindingProps *props, bool isStatic)
697 {
698     switch (newDecl->Type()) {
699         case DeclType::CONST:
700         case DeclType::LET: {
701             props->SetBindingProps(VariableFlags::PROPERTY, newDecl->Node()->AsClassProperty()->Id(),
702                                    isStatic ? staticFieldScope_ : instanceFieldScope_);
703             break;
704         }
705         case DeclType::INTERFACE: {
706             props->SetBindingProps(VariableFlags::INTERFACE, newDecl->Node()->AsTSInterfaceDeclaration()->Id(),
707                                    isStatic ? staticDeclScope_ : instanceDeclScope_);
708             break;
709         }
710         case DeclType::CLASS: {
711             props->SetBindingProps(VariableFlags::CLASS, newDecl->Node()->AsClassDefinition()->Ident(),
712                                    isStatic ? staticDeclScope_ : instanceDeclScope_);
713             break;
714         }
715         case DeclType::ENUM_LITERAL: {
716             props->SetBindingProps(VariableFlags::ENUM_LITERAL, newDecl->Node()->AsTSEnumDeclaration()->Key(),
717                                    isStatic ? staticDeclScope_ : instanceDeclScope_);
718             break;
719         }
720         case DeclType::TYPE_ALIAS: {
721             props->SetBindingProps(VariableFlags::TYPE_ALIAS, newDecl->Node()->AsTSTypeAliasDeclaration()->Id(),
722                                    typeAliasScope_);
723             break;
724         }
725         default: {
726             UNREACHABLE();
727             break;
728         }
729     }
730 }
731 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)732 Variable *ClassScope::AddBinding(ArenaAllocator *allocator, [[maybe_unused]] Variable *currentVariable, Decl *newDecl,
733                                  [[maybe_unused]] ScriptExtension extension)
734 {
735     bool isStatic = newDecl->Node()->IsStatic();
736     BindingProps props;
737 
738     if (isStatic) {
739         props.SetFlagsType(VariableFlags::STATIC);
740     }
741 
742     SetBindingProps(newDecl, &props, isStatic);
743 
744     const auto *foundVar = FindLocal(newDecl->Name(), ResolveBindingOptions::ALL);
745     if (foundVar != nullptr) {
746         if (!newDecl->IsLetOrConstDecl()) {
747             return nullptr;
748         }
749 
750         foundVar = FindLocal(newDecl->Name(),
751                              ResolveBindingOptions::ALL ^ (isStatic ? ResolveBindingOptions::VARIABLES
752                                                                     : ResolveBindingOptions::STATIC_VARIABLES));
753         if (foundVar != nullptr) {
754             return nullptr;
755         }
756     }
757 
758     auto *var = props.GetTargetScope()->AddBinding(allocator, nullptr, newDecl, extension);
759     if (var == nullptr) {
760         return nullptr;
761     }
762 
763     if (auto node = newDecl->Node();
764         node->IsStatement() &&
765         (node->AsStatement()->IsMethodDefinition() || node->IsClassProperty() || node->IsClassStaticBlock()) &&
766         node->AsStatement()->AsClassElement()->Value() != nullptr) {
767         props.SetFlagsType(VariableFlags::INITIALIZED);
768     }
769 
770     var->SetScope(this);
771     var->AddFlag(props.GetFlags());
772 
773     if (props.GetIdent() != nullptr) {
774         props.GetIdent()->SetVariable(var);
775     }
776 
777     return var;
778 }
779 
ConvertToVariableScope(ArenaAllocator * allocator)780 void LoopDeclarationScope::ConvertToVariableScope(ArenaAllocator *allocator)
781 {
782     if (NeedLexEnv()) {
783         return;
784     }
785 
786     const auto &bindings = Bindings();
787     for (auto &[name, var] : bindings) {
788         if (!var->LexicalBound() || !var->Declaration()->IsLetOrConstDecl()) {
789             continue;
790         }
791 
792         slotIndex_++;
793         loopType_ = ScopeType::LOOP_DECL;
794         auto *copiedVar = var->AsLocalVariable()->Copy(allocator, var->Declaration());
795         copiedVar->AddFlag(VariableFlags::INITIALIZED | VariableFlags::PER_ITERATION);
796         var->AddFlag(VariableFlags::LOOP_DECL);
797         loopScope_->InsertBinding(name, copiedVar);
798     }
799 
800     if (loopType_ == ScopeType::LOOP_DECL) {
801         auto *parentVarScope = Parent()->EnclosingVariableScope();
802         slotIndex_ = std::max(slotIndex_, parentVarScope->LexicalSlots());
803         evalBindings_ = parentVarScope->EvalBindings();
804         initScope_ = allocator->New<LocalScope>(allocator, Parent());
805         initScope_->BindNode(Node());
806         initScope_->ReplaceBindings(bindings);
807     }
808 }
809 
ConvertToVariableScope(ArenaAllocator * allocator)810 void LoopScope::ConvertToVariableScope(ArenaAllocator *allocator)
811 {
812     declScope_->ConvertToVariableScope(allocator);
813 
814     if (loopType_ != ScopeType::LOCAL) {
815         return;
816     }
817 
818     for (const auto &[_, var] : Bindings()) {
819         (void)_;
820         if (var->LexicalBound() && var->Declaration()->IsLetDecl()) {
821             ASSERT(declScope_->NeedLexEnv());
822             loopType_ = ScopeType::LOOP;
823             break;
824         }
825     }
826 
827     if (loopType_ == ScopeType::LOOP) {
828         slotIndex_ = std::max(slotIndex_, declScope_->LexicalSlots());
829         evalBindings_ = declScope_->EvalBindings();
830     }
831 }
832 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)833 Variable *CatchParamScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
834                                       [[maybe_unused]] ScriptExtension extension)
835 {
836     return AddParam(allocator, currentVariable, newDecl, VariableFlags::INITIALIZED);
837 }
838 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)839 Variable *CatchScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
840                                  [[maybe_unused]] ScriptExtension extension)
841 {
842     if (!newDecl->IsVarDecl() &&
843         (paramScope_->FindLocal(newDecl->Name(), varbinder::ResolveBindingOptions::BINDINGS) != nullptr)) {
844         return nullptr;
845     }
846 
847     return AddLocal(allocator, currentVariable, newDecl, extension);
848 }
849 }  // namespace panda::es2panda::varbinder
850