• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021 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 <binder/tsBinding.h>
19 #include <ir/base/scriptFunction.h>
20 #include <ir/base/classDefinition.h>
21 
22 namespace panda::es2panda::binder {
23 
EnclosingVariableScope()24 VariableScope *Scope::EnclosingVariableScope()
25 {
26     Scope *iter = this;
27 
28     while (iter) {
29         if (iter->IsVariableScope()) {
30             return iter->AsVariableScope();
31         }
32 
33         iter = iter->Parent();
34     }
35 
36     return nullptr;
37 }
38 
EnclosingFunctionVariableScope()39 FunctionScope *Scope::EnclosingFunctionVariableScope()
40 {
41     Scope *iter = this;
42     while (iter) {
43         if (iter->IsFunctionVariableScope()) {
44             return iter->AsFunctionVariableScope();
45         }
46 
47         iter = iter->Parent();
48     }
49 
50     return nullptr;
51 }
52 
FindLocal(const util::StringView & name,ResolveBindingOptions options) const53 Variable *Scope::FindLocal(const util::StringView &name, ResolveBindingOptions options) const
54 {
55     if (options & ResolveBindingOptions::INTERFACES) {
56         const std::string &interfaceName = binder::TSBinding::ToTSBinding(name);
57 
58         auto res = bindings_.find(util::StringView{interfaceName});
59         if (res != bindings_.end()) {
60             return res->second;
61         }
62 
63         if (!(options & ResolveBindingOptions::BINDINGS)) {
64             return nullptr;
65         }
66     }
67 
68     auto res = bindings_.find(name);
69     if (res == bindings_.end()) {
70         return nullptr;
71     }
72 
73     return res->second;
74 }
75 
CalculateLevelInCorrespondingFunctionScope(const FunctionParamScope * scope,uint32_t & lexLevel,uint32_t & sendableLevel) const76 void Scope::CalculateLevelInCorrespondingFunctionScope(const FunctionParamScope *scope, uint32_t &lexLevel,
77                                                        uint32_t &sendableLevel) const
78 {
79     auto *funcVariableScope = scope->GetFunctionScope();
80     // we may only have function param scope without function scope in TS here
81     if (funcVariableScope == nullptr) {
82         return;
83     }
84 
85     if (funcVariableScope->NeedLexEnv()) {
86         lexLevel++;
87     }
88 
89     if (funcVariableScope->NeedSendableEnv()) {
90         sendableLevel++;
91     }
92 }
93 
Find(const util::StringView & name,ResolveBindingOptions options) const94 ScopeFindResult Scope::Find(const util::StringView &name, ResolveBindingOptions options) const
95 {
96     uint32_t level = 0;
97     uint32_t lexLevel = 0;
98     uint32_t sendableLevel = 0;
99     const auto *iter = this;
100     ir::ScriptFunction *concurrentFunc = nullptr;
101     // If the first scope is functionParamScope, it means its corresponding functionScope is not
102     // iterated. so by default we set prevScopeNotFunctionScope as true so under such case,
103     // functionScopeNotIterated will be true.
104     bool prevScopeNotFunctionScope = true;
105     bool lexical = false;
106 
107     while (iter != nullptr) {
108         bool functionScopeNotIterated = iter->IsFunctionParamScope() && prevScopeNotFunctionScope;
109         Variable *v = iter->FindLocal(name, options);
110 
111         if (v != nullptr) {
112             return {name, const_cast<Scope *>(iter), level, lexLevel, sendableLevel, v, concurrentFunc};
113         }
114 
115         if (iter->IsFunctionVariableScope() && !lexical) {
116             lexical = true;
117         }
118 
119         if (iter->IsFunctionScope() && !concurrentFunc) {
120             if (iter->Node()->AsScriptFunction()->IsConcurrent()) {
121                 concurrentFunc = const_cast<ir::ScriptFunction *>(iter->Node()->AsScriptFunction());
122             }
123         }
124 
125         if (iter->IsVariableScope()) {
126             if (lexical) {
127                 level++;
128             }
129 
130             if (iter->AsVariableScope()->NeedLexEnv()) {
131                 lexLevel++;
132             }
133 
134             if (iter->AsVariableScope()->NeedSendableEnv()) {
135                 sendableLevel++;
136             }
137         } else if (functionScopeNotIterated) {
138             level++;
139             CalculateLevelInCorrespondingFunctionScope(iter->AsFunctionParamScope(), lexLevel, sendableLevel);
140         }
141 
142         prevScopeNotFunctionScope = !iter->IsFunctionVariableScope();
143         iter = iter->Parent();
144     }
145 
146     return {name, nullptr, 0, 0, 0, nullptr, concurrentFunc};
147 }
148 
Find(const ir::Expression * expr,bool onlyLevel) const149 std::pair<uint32_t, uint32_t> Scope::Find(const ir::Expression *expr, bool onlyLevel) const
150 {
151     uint32_t lexLevel = 0;
152     const auto *iter = this;
153 
154     while (iter != nullptr) {
155         if (iter->Type() == ScopeType::CLASS) {
156             if (onlyLevel) {
157                 return {lexLevel, 0};
158             }
159             return {lexLevel, iter->AsClassScope()->GetSlot(expr)};
160         }
161 
162         if (iter->IsVariableScope()) {
163             if (iter->AsVariableScope()->NeedLexEnv()) {
164                 lexLevel++;
165             }
166         }
167         iter = iter->Parent();
168     }
169 
170     UNREACHABLE();
171 }
172 
IsVariableScope() const173 bool ClassScope::IsVariableScope() const
174 {
175     // sendable class does not need a lexical env, handle it's scope as a non-variable scope
176     return !node_->AsClassDefinition()->IsSendable();
177 }
178 
GetPrivateProperty(const util::StringView & name,bool isSetter) const179 Result ClassScope::GetPrivateProperty(const util::StringView &name, bool isSetter) const
180 {
181     if (name.Is("#method")) {
182         return {instanceMethodValidation_, false, false, false, false, 0};
183     }
184 
185     uint32_t slot{0};
186     bool setter{false};
187     bool getter{false};
188 
189     if (privateNames_.find(name) != privateNames_.end()) {
190         slot = privateNames_.find(name)->second;
191     } else {
192         auto accessor = isSetter ? privateSetters_ : privateGetters_;
193         auto unexpectedAccessor = isSetter ? privateGetters_ : privateSetters_;
194 
195         if (accessor.find(name) != accessor.end()) {
196             setter = isSetter;
197             getter = !setter;
198             slot = accessor.find(name)->second;
199         } else {
200             getter = isSetter;
201             setter = !getter;
202             slot = unexpectedAccessor.find(name)->second;
203         }
204     }
205 
206     uint32_t validateMethodSlot{0};
207 
208     if (IsMethod(slot)) {
209         validateMethodSlot = IsStaticMethod(slot) ? staticMethodValidation_ : instanceMethodValidation_;
210     }
211 
212     return {slot, IsMethod(slot), IsStaticMethod(slot), getter, setter, validateMethodSlot};
213 }
214 
AddPrivateName(std::vector<const ir::Statement * > privateProperties,uint32_t privateFieldCnt,uint32_t instancePrivateMethodCnt,uint32_t staticPrivateMethodCnt)215 void ClassScope::AddPrivateName(std::vector<const ir::Statement *> privateProperties, uint32_t privateFieldCnt,
216                                 uint32_t instancePrivateMethodCnt, uint32_t staticPrivateMethodCnt)
217 {
218     privateFieldCnt_ = privateFieldCnt;
219     instancePrivateMethodStartSlot_ = slotIndex_ + privateFieldCnt_;
220     staticPrivateMethodStartSlot_ = instancePrivateMethodStartSlot_ + instancePrivateMethodCnt;
221     uint32_t instancePrivateMethodSlot = instancePrivateMethodStartSlot_;
222     uint32_t staticPrivateMethodSlot = staticPrivateMethodStartSlot_;
223     for (const auto *stmt : privateProperties) {
224         if (stmt->IsClassProperty()) {
225             privateNames_[stmt->AsClassProperty()->Key()->AsPrivateIdentifier()->Name()] = slotIndex_++;
226             continue;
227         }
228         ASSERT(stmt->IsMethodDefinition());
229         auto *methodDef = stmt->AsMethodDefinition();
230         uint32_t *start = methodDef->IsStatic() ? &staticPrivateMethodSlot : &instancePrivateMethodSlot;
231         auto name = methodDef->Key()->AsPrivateIdentifier()->Name();
232         switch (methodDef->Kind()) {
233             case ir::MethodDefinitionKind::GET: {
234                 privateGetters_[name] =  (*start)++;
235                 continue;
236             }
237             case ir::MethodDefinitionKind::SET: {
238                 privateSetters_[name] =  (*start)++;
239                 continue;
240             }
241             default: {
242                 privateNames_[name]=  (*start)++;
243                 continue;
244             }
245         }
246     }
247     slotIndex_ = staticPrivateMethodSlot;
248     privateMethodEndSlot_ = slotIndex_;
249     if (instancePrivateMethodCnt != 0) {
250         instanceMethodValidation_ = slotIndex_++;
251     }
252 
253     if (staticPrivateMethodCnt != 0) {
254         staticMethodValidation_ = slotIndex_++;
255     }
256 }
257 
GetSelfScopeName()258 util::StringView ClassScope::GetSelfScopeName()
259 {
260     if (hasSelfScopeNameSet_) {
261         return selfScopeName_;
262     }
263 
264     std::stringstream scopeName;
265 
266     if (node_ && node_->IsClassDefinition() && node_->AsClassDefinition()->Ident()) {
267         util::StringView selfName = node_->AsClassDefinition()->Ident()->Name();
268         scopeName << selfName;
269         return util::UString(scopeName.str(), allocator_).View();
270     }
271     // To get the name for anonymous class
272     if (node_ && node_->Parent() && node_->Parent()->Parent()) {
273         scopeName << util::Helpers::GetName(allocator_, node_->Parent()->Parent());
274         return util::UString(scopeName.str(), allocator_).View();
275     }
276 
277     return util::UString(scopeName.str(), allocator_).View();
278 }
279 
GetScopeTag()280 util::StringView ClassScope::GetScopeTag()
281 {
282     return util::UString(util::Helpers::CLASS_SCOPE_TAG.data(), allocator_).View();
283 }
284 
FindPrivateName(const util::StringView & name,bool isSetter) const285 PrivateNameFindResult Scope::FindPrivateName(const util::StringView &name, bool isSetter) const
286 {
287     uint32_t lexLevel = 0;
288     const auto *iter = this;
289 
290     while (iter != nullptr) {
291         if (iter->Type() == ScopeType::CLASS) {
292             const auto *classScope = iter->AsClassScope();
293             if (name.Is("#method") || classScope->HasPrivateName(name)) {
294                 return {lexLevel, classScope->GetPrivateProperty(name, isSetter)};
295             }
296         }
297 
298         if (iter->IsVariableScope()) {
299             if (iter->AsVariableScope()->NeedLexEnv()) {
300                 lexLevel++;
301             }
302         }
303         iter = iter->Parent();
304     }
305 
306     UNREACHABLE();
307 }
308 
FindDecl(const util::StringView & name) const309 Decl *Scope::FindDecl(const util::StringView &name) const
310 {
311     for (auto *it : decls_) {
312         if (it->Name() == name) {
313             return it;
314         }
315     }
316 
317     return nullptr;
318 }
319 
HasVarDecl(const util::StringView & name) const320 bool Scope::HasVarDecl(const util::StringView &name) const
321 {
322     for (auto *it : decls_) {
323         if (it->Name() == name && it->IsVarDecl()) {
324             return true;
325         }
326     }
327 
328     return false;
329 }
330 
IterateShadowedVariables(const util::StringView & name,const VariableVisitior & visitor)331 std::tuple<Scope *, bool> Scope::IterateShadowedVariables(const util::StringView &name, const VariableVisitior &visitor)
332 {
333     auto *iter = this;
334 
335     while (true) {
336         auto *v = iter->FindLocal(name);
337 
338         if (v && visitor(v)) {
339             return {iter, true};
340         }
341 
342         if (iter->IsFunctionVariableScope()) {
343             break;
344         }
345 
346         iter = iter->Parent();
347     }
348 
349     return {iter, false};
350 }
351 
SetFullScopeNames()352 void Scope::SetFullScopeNames()
353 {
354     if (hasFullScopeNameSet_) {
355         return;
356     }
357     hasFullScopeNameSet_ = true;
358     if (!hasSelfScopeNameSet_) {
359         SetSelfScopeName(GetSelfScopeName());
360     }
361 
362     std::stringstream selfScopeStream;
363     OptimizeSelfScopeName(selfScopeStream);
364     std::stringstream fullScopeName;
365     Scope *parent = GetParentWithScopeName();
366     if (parent) {
367         fullScopeName << parent->GetFullScopeName() <<
368                          GetScopeTag() <<
369                          selfScopeStream.str();
370         if (scopeDuplicateIndex_ > 0) {
371             fullScopeName << util::Helpers::DUPLICATED_SEPERATOR <<
372                              std::hex << scopeDuplicateIndex_;
373         }
374     }
375 
376     fullScopeName_ = util::UString(fullScopeName.str(), allocator_).View();
377 }
378 
OptimizeSelfScopeName(std::stringstream & selfScopeStream)379 void Scope::OptimizeSelfScopeName(std::stringstream &selfScopeStream)
380 {
381     bool useIndex = false;
382     auto it = topScope_->scopeNames_.find(selfScopeName_);
383     if (it == topScope_->scopeNames_.end()) {
384         std::stringstream indexScopeName;
385         indexScopeName << util::Helpers::INDEX_NAME_SPICIFIER << std::hex << topScope_->scopeNames_.size();
386         if (selfScopeName_.Length() > indexScopeName.str().length()) {
387             topScope_->scopeNames_.insert(
388                 {selfScopeName_, (int32_t)topScope_->scopeNames_.size()}
389             );
390             selfScopeStream << indexScopeName.str();
391             useIndex = true;
392         }
393     } else {
394         selfScopeStream << util::Helpers::INDEX_NAME_SPICIFIER << std::hex << it->second;
395         useIndex = true;
396     }
397 
398     if (!useIndex) {
399         selfScopeStream << selfScopeName_;
400     }
401 }
402 
AddLocal(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)403 bool Scope::AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
404                      [[maybe_unused]] ScriptExtension extension)
405 {
406     VariableFlags flags = VariableFlags::NONE;
407     switch (newDecl->Type()) {
408         case DeclType::VAR: {
409             auto [scope, shadowed] = IterateShadowedVariables(
410                 newDecl->Name(), [](const Variable *v) { return !v->HasFlag(VariableFlags::VAR); });
411 
412             if (shadowed) {
413                 return false;
414             }
415 
416             VariableFlags varFlags = VariableFlags::HOIST_VAR;
417             if (scope->IsGlobalScope()) {
418                 scope->Bindings().insert({newDecl->Name(), allocator->New<GlobalVariable>(newDecl, varFlags)});
419             } else {
420                 scope->PropagateBinding<LocalVariable>(allocator, newDecl->Name(), newDecl, varFlags);
421             }
422 
423             return true;
424         }
425         case DeclType::ENUM_LITERAL: {
426             return tsBindings_.AddTSVariable<TSBindingType::ENUMLITERAL>(
427                 newDecl->Name(), allocator->New<EnumLiteralVariable>(newDecl, VariableFlags::ENUM_LITERAL));
428         }
429         case DeclType::INTERFACE: {
430             bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::INTERFACE)});
431             return true;
432         }
433         case DeclType::FUNC: {
434             flags = VariableFlags::HOIST;
435             [[fallthrough]];
436         }
437         default: {
438             if (currentVariable) {
439                 return false;
440             }
441 
442             if (HasVarDecl(newDecl->Name())) {
443                 return false;
444             }
445 
446             bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, flags)});
447             return true;
448         }
449     }
450 }
451 
AddParam(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,VariableFlags flags)452 bool ParamScope::AddParam(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags)
453 {
454     CHECK_NOT_NULL(newDecl);
455     ASSERT(newDecl->IsParameterDecl());
456 
457     if (currentVariable) {
458         return false;
459     }
460 
461     auto *param = allocator->New<LocalVariable>(newDecl, flags);
462 
463     params_.push_back(param);
464     bindings_.insert({newDecl->Name(), param});
465     return true;
466 }
467 
AddParamDecl(ArenaAllocator * allocator,const ir::AstNode * param)468 std::tuple<ParameterDecl *, const ir::AstNode *> ParamScope::AddParamDecl(ArenaAllocator *allocator,
469                                                                           const ir::AstNode *param)
470 {
471     const auto [name, pattern] = util::Helpers::ParamName(allocator, param, params_.size());
472 
473     auto *decl = NewDecl<ParameterDecl>(allocator, name);
474     CHECK_NOT_NULL(decl);
475 
476     if (!AddParam(allocator, FindLocal(name), decl, VariableFlags::VAR)) {
477         return {decl, param};
478     }
479 
480     if (!pattern) {
481         decl->BindNode(param);
482         return {decl, nullptr};
483     }
484 
485     std::vector<const ir::Identifier *> bindings = util::Helpers::CollectBindingNames(param);
486 
487     for (const auto *binding : bindings) {
488         auto *varDecl = NewDecl<VarDecl>(allocator, binding->Name());
489         CHECK_NOT_NULL(varDecl);
490         varDecl->BindNode(binding);
491 
492         if (FindLocal(varDecl->Name())) {
493             return {decl, binding};
494         }
495 
496         auto *paramVar = allocator->New<LocalVariable>(varDecl, VariableFlags::VAR);
497         bindings_.insert({varDecl->Name(), paramVar});
498     }
499 
500     return {decl, nullptr};
501 }
502 
BindName(ArenaAllocator * allocator,util::StringView name)503 void FunctionParamScope::BindName(ArenaAllocator *allocator, util::StringView name)
504 {
505     nameVar_ = AddDecl<ConstDecl, LocalVariable>(allocator, name, VariableFlags::INITIALIZED);
506     functionScope_->Bindings().insert({name, nameVar_});
507 }
508 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)509 bool FunctionParamScope::AddBinding([[maybe_unused]] ArenaAllocator *allocator,
510                                     [[maybe_unused]] Variable *currentVariable, [[maybe_unused]] Decl *newDecl,
511                                     [[maybe_unused]] ScriptExtension extension)
512 {
513     UNREACHABLE();
514 }
515 
GetFullScopeName()516 const util::StringView &FunctionParamScope::GetFullScopeName()
517 {
518     if (functionScope_) {
519         return functionScope_->GetFullScopeName();
520     }
521 
522     // FunctionParam should have the same name with FunctionScope
523     // Get scope name from parent in case the functionScope_ is nullptr
524     if (parent_) {
525         return parent_->GetFullScopeName();
526     }
527 
528     return fullScopeName_;
529 }
530 
GetDuplicateScopeIndex(const util::StringView & childScopeName)531 uint32_t FunctionParamScope::GetDuplicateScopeIndex(const util::StringView &childScopeName)
532 {
533     if (functionScope_) {
534         return functionScope_->GetDuplicateScopeIndex(childScopeName);
535     }
536 
537     if (parent_) {
538         return parent_->GetDuplicateScopeIndex(childScopeName);
539     }
540 
541     return 0;
542 }
543 
BindNameWithScopeInfo(util::StringView name,util::StringView recordName)544 void FunctionScope::BindNameWithScopeInfo(util::StringView name, util::StringView recordName)
545 {
546     name_ = name;
547     std::stringstream internalName;
548     internalName << recordName << util::Helpers::FUNC_NAME_SEPARATOR;
549 
550     Scope *parent = GetParentWithScopeName();
551     if (parent != nullptr) {
552         internalName << parent->GetFullScopeName();
553     }
554     internalName << GetScopeTag() << util::Helpers::FUNC_NAME_SEPARATOR << GetSelfScopeName();
555     if (scopeDuplicateIndex_ > 0) {
556         internalName << util::Helpers::DUPLICATED_SEPERATOR <<
557                         std::hex << scopeDuplicateIndex_;
558     }
559     internalName_ = util::UString(internalName.str(), allocator_).View();
560 }
561 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)562 bool FunctionScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
563                                [[maybe_unused]] ScriptExtension extension)
564 {
565     switch (newDecl->Type()) {
566         case DeclType::VAR: {
567             return AddVar<LocalVariable>(allocator, currentVariable, newDecl);
568         }
569         case DeclType::FUNC: {
570             return AddFunction<LocalVariable>(allocator, currentVariable, newDecl, extension);
571         }
572         case DeclType::CLASS: {
573             return AddClass<LocalVariable>(allocator, currentVariable, newDecl);
574         }
575         case DeclType::ENUM_LITERAL: {
576             return AddTSBinding<EnumLiteralVariable>(allocator, newDecl, VariableFlags::ENUM_LITERAL);
577         }
578         case DeclType::NAMESPACE: {
579             return AddTSBinding<NamespaceVariable>(allocator, newDecl, VariableFlags::NAMESPACE);
580         }
581         case DeclType::IMPORT_EQUALS: {
582             return AddTSBinding<ImportEqualsVariable>(allocator, newDecl, VariableFlags::IMPORT_EQUALS);
583         }
584         case DeclType::INTERFACE: {
585             return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
586         }
587         default: {
588             return AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
589         }
590     }
591 }
592 
SetSelfScopeName(const util::StringView & ident)593 void FunctionScope::SetSelfScopeName(const util::StringView &ident)
594 {
595     Scope::SetSelfScopeName(ident);
596     paramScope_->selfScopeName_ = selfScopeName_;
597     paramScope_->hasSelfScopeNameSet_ = true;
598     hasSelfScopeNameSet_ = true;
599 }
600 
GetScopeTag()601 util::StringView FunctionScope::GetScopeTag()
602 {
603     if (IsFunctionScope() && (node_->IsScriptFunction() && node_->AsScriptFunction()->IsConstructor())) {
604         return util::UString(util::Helpers::CTOR_TAG.data(), allocator_).View();
605     }
606     if (parent_ && parent_->Parent() && parent_->Parent()->IsClassScope()) {
607         bool hasNodeParent = node_ && node_->Parent() && node_->Parent()->Parent();
608         const ir::AstNode *nodeParent = hasNodeParent ? node_->Parent()->Parent() : nullptr;
609         if (nodeParent && nodeParent->IsMethodDefinition() && nodeParent->AsMethodDefinition()->IsStatic()) {
610             return util::UString(util::Helpers::STATIC_METHOD_TAG.data(), allocator_).View();
611         }
612         return util::UString(util::Helpers::METHOD_TAG.data(), allocator_).View();
613     }
614     return util::UString(util::Helpers::FUNCTION_TAG.data(), allocator_).View();
615 }
616 
GetSelfScopeName()617 util::StringView FunctionScope::GetSelfScopeName()
618 {
619     if (hasSelfScopeNameSet_) {
620         return selfScopeName_;
621     }
622 
623     if (node_ && node_->IsScriptFunction()) {
624         auto selfName = util::Helpers::FunctionName(allocator_, node_->AsScriptFunction());
625         if (!util::Helpers::IsSpecialScopeName(selfName)) {
626             return selfName;
627         }
628     }
629     return util::UString(util::Helpers::STRING_EMPTY.data(), allocator_).View();
630 }
631 
GetSelfScopeName()632 util::StringView TSModuleScope::GetSelfScopeName()
633 {
634     if (hasSelfScopeNameSet_) {
635         return selfScopeName_;
636     }
637     throw Error(ErrorType::GENERIC, "namespace or module name should be set in Binder::ResolveReference()");
638 }
639 
GetScopeTag()640 util::StringView TSModuleScope::GetScopeTag()
641 {
642     return util::UString(util::Helpers::NAMESPACE_TAG.data(), allocator_).View();
643 }
644 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)645 bool TSEnumScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
646                              [[maybe_unused]] ScriptExtension extension)
647 {
648     ASSERT(newDecl->Type() == DeclType::ENUM);
649     return enumMemberBindings_->insert({newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)}).second;
650 }
651 
SetSelfScopeName(const util::StringView & ident)652 void TSEnumScope::SetSelfScopeName(const util::StringView &ident)
653 {
654     if (!hasSelfScopeNameSet_) {
655         FunctionScope::SetSelfScopeName(GetSelfScopeName());
656     }
657 }
658 
GetSelfScopeName()659 util::StringView TSEnumScope::GetSelfScopeName()
660 {
661     if (hasSelfScopeNameSet_) {
662         return selfScopeName_;
663     }
664 
665     std::stringstream scopeName;
666     if (node_ && node_->IsScriptFunction()) {
667         auto scriptFunction = node_->AsScriptFunction();
668         if (scriptFunction->Params().size() > 0 && scriptFunction->Params()[0]->IsIdentifier()) {
669             scopeName << scriptFunction->Params()[0]->AsIdentifier()->Name();
670         }
671     }
672     return util::UString(scopeName.str(), allocator_).View();
673 }
674 
GetScopeTag()675 util::StringView TSEnumScope::GetScopeTag()
676 {
677     return util::UString(util::Helpers::ENUM_TAG.data(), allocator_).View();
678 }
679 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)680 bool GlobalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
681                              [[maybe_unused]] ScriptExtension extension)
682 {
683     switch (newDecl->Type()) {
684         case DeclType::VAR: {
685             return AddVar<GlobalVariable>(allocator, currentVariable, newDecl);
686         }
687         case DeclType::FUNC: {
688             return AddFunction<GlobalVariable>(allocator, currentVariable, newDecl, extension);
689         }
690         case DeclType::CLASS: {
691             return AddClass<LocalVariable>(allocator, currentVariable, newDecl);
692         }
693         case DeclType::ENUM_LITERAL: {
694             return AddTSBinding<EnumLiteralVariable>(allocator, newDecl, VariableFlags::ENUM_LITERAL);
695         }
696         case DeclType::NAMESPACE: {
697             return AddTSBinding<NamespaceVariable>(allocator, newDecl, VariableFlags::NAMESPACE);
698         }
699         case DeclType::IMPORT_EQUALS: {
700             return AddTSBinding<ImportEqualsVariable>(allocator, newDecl, VariableFlags::IMPORT_EQUALS);
701         }
702         case DeclType::INTERFACE: {
703             return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
704         }
705         default: {
706             return AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
707         }
708     }
709 
710     return true;
711 }
712 
SetSelfScopeName(const util::StringView & ident)713 void GlobalScope::SetSelfScopeName([[maybe_unused]] const util::StringView &ident)
714 {
715     hasSelfScopeNameSet_ = true;
716 }
717 
718 // ModuleScope
719 
ConvertLocalVariableToModuleVariable(ArenaAllocator * allocator,util::StringView localName)720 void ModuleScope::ConvertLocalVariableToModuleVariable(ArenaAllocator *allocator, util::StringView localName)
721 {
722     auto res = bindings_.find(localName);
723     // Since the module's exported [localName] has been validated before,
724     // [localName] must have a binding now.
725     ASSERT(res != bindings_.end());
726     if (!res->second->IsModuleVariable()) {
727         auto *decl = res->second->Declaration();
728         decl->AddFlag(DeclarationFlags::EXPORT);
729         VariableFlags flags = res->second->Flags();
730         res->second = allocator->New<ModuleVariable>(decl, flags | VariableFlags::LOCAL_EXPORT);
731     }
732 }
733 
AssignIndexToModuleVariable(util::StringView name,uint32_t index)734 void ModuleScope::AssignIndexToModuleVariable(util::StringView name, uint32_t index)
735 {
736     auto *moduleVar = FindLocal(name);
737     CHECK_NOT_NULL(moduleVar);
738     ASSERT(moduleVar->IsModuleVariable());
739     moduleVar->AsModuleVariable()->AssignIndex(index);
740 }
741 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)742 bool ModuleScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
743                              [[maybe_unused]] ScriptExtension extension)
744 {
745     switch (newDecl->Type()) {
746         case DeclType::VAR: {
747             auto [scope, shadowed] = IterateShadowedVariables(
748                 newDecl->Name(), [](const Variable *v) { return !v->HasFlag(VariableFlags::VAR); });
749 
750             if (shadowed) {
751                 return false;
752             }
753             return newDecl->IsImportOrExportDecl() ?
754                    AddVar<ModuleVariable>(allocator, currentVariable, newDecl) :
755                    AddVar<LocalVariable>(allocator, currentVariable, newDecl);
756         }
757         case DeclType::FUNC: {
758             if (currentVariable) {
759                 auto decl = currentVariable->Declaration();
760                 if (!decl->IsClassDecl() || !decl->AsClassDecl()->IsDeclare()) {
761                     return false;
762                 }
763             }
764             return newDecl->IsImportOrExportDecl() ?
765                    AddFunction<ModuleVariable>(allocator, currentVariable, newDecl, extension) :
766                    AddFunction<LocalVariable>(allocator, currentVariable, newDecl, extension);
767         }
768         case DeclType::CLASS: {
769             return newDecl->IsImportOrExportDecl() ?
770                    AddClass<ModuleVariable>(allocator, currentVariable, newDecl) :
771                    AddClass<LocalVariable>(allocator, currentVariable, newDecl);
772         }
773         case DeclType::ENUM_LITERAL: {
774             return AddTSBinding<EnumLiteralVariable>(allocator, newDecl, VariableFlags::ENUM_LITERAL);
775         }
776         case DeclType::NAMESPACE: {
777             return AddTSBinding<NamespaceVariable>(allocator, newDecl, VariableFlags::NAMESPACE);
778         }
779         case DeclType::IMPORT_EQUALS: {
780             return AddTSBinding<ImportEqualsVariable>(allocator, newDecl, VariableFlags::IMPORT_EQUALS);
781         }
782         case DeclType::INTERFACE: {
783             return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
784         }
785         default: {
786             if (currentVariable) {
787                 return false;
788             }
789             return newDecl->IsImportOrExportDecl() ?
790                    AddLexical<ModuleVariable>(allocator, currentVariable, newDecl) :
791                    AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
792         }
793     }
794 }
795 
SetSelfScopeName(const util::StringView & ident)796 void ModuleScope::SetSelfScopeName([[maybe_unused]] const util::StringView &ident)
797 {
798     hasSelfScopeNameSet_ = true;
799 }
800 
801 // LocalScope
802 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)803 bool LocalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
804                             [[maybe_unused]] ScriptExtension extension)
805 {
806     return AddLocal(allocator, currentVariable, newDecl, extension);
807 }
808 
InitVariable()809 void LoopScope::InitVariable()
810 {
811     for (const auto &[name, var] : bindings_) {
812         if (!var->Declaration()->IsLetOrConstOrClassDecl()) {
813             continue;
814         }
815 
816         var->AddFlag(VariableFlags::INITIALIZED);
817         if (var->LexicalBound()) {
818             var->AddFlag(VariableFlags::PER_ITERATION);
819         }
820     }
821 }
822 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)823 bool CatchParamScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
824                                  [[maybe_unused]] ScriptExtension extension)
825 {
826     return AddParam(allocator, currentVariable, newDecl, VariableFlags::INITIALIZED);
827 }
828 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)829 bool CatchScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
830                             [[maybe_unused]] ScriptExtension extension)
831 {
832     if (!newDecl->IsVarDecl() && paramScope_->FindLocal(newDecl->Name())) {
833         return false;
834     }
835 
836     return AddLocal(allocator, currentVariable, newDecl, extension);
837 }
838 }  // namespace panda::es2panda::binder
839