• 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 #ifndef ES2PANDA_COMPILER_SCOPES_SCOPE_H
17 #define ES2PANDA_COMPILER_SCOPES_SCOPE_H
18 
19 #include <binder/declaration.h>
20 #include <binder/variable.h>
21 #include <parser/program/program.h>
22 #include <util/enumbitops.h>
23 #include <util/ustring.h>
24 
25 #include <map>
26 #include <unordered_map>
27 #include <vector>
28 
29 namespace panda::es2panda::compiler {
30 class IRNode;
31 }  // namespace panda::es2panda::compiler
32 
33 namespace panda::es2panda::binder {
34 
35 #define DECLARE_CLASSES(type, className) class className;
36 SCOPE_TYPES(DECLARE_CLASSES)
37 #undef DECLARE_CLASSES
38 
39 class Scope;
40 class VariableScope;
41 class Variable;
42 
43 using VariableMap = ArenaUnorderedMap<util::StringView, Variable *>;
44 
45 class TSBindings {
46 public:
TSBindings(ArenaAllocator * allocator)47     explicit TSBindings(ArenaAllocator *allocator) : allocator_(allocator) {}
48 
49     template <TSBindingType type>
AddTSVariable(const util::StringView & name,Variable * variable)50     bool AddTSVariable(const util::StringView &name, Variable *variable)
51     {
52         static_assert(type < TSBindingType::COUNT);
53         size_t index = GetIndex(type);
54         if (tsBindings_[index] == nullptr) {
55             tsBindings_[index] = allocator_->New<VariableMap>(allocator_->Adapter());
56         }
57         return tsBindings_[index]->insert({name, variable}).second;
58     }
59 
60     template <TSBindingType type>
FindTSVariable(const util::StringView & name)61     Variable *FindTSVariable(const util::StringView &name) const
62     {
63         static_assert(type < TSBindingType::COUNT);
64         size_t index = GetIndex(type);
65         if (tsBindings_[index] == nullptr) {
66             return nullptr;
67         }
68         auto res = tsBindings_[index]->find(name);
69         if (res == tsBindings_[index]->end()) {
70             return nullptr;
71         }
72         return res->second;
73     }
74 
InTSBindings(const util::StringView & name)75     bool InTSBindings(const util::StringView &name) const
76     {
77         for (size_t i = 0; i < GetIndex(TSBindingType::COUNT); i++) {
78             if (tsBindings_[i] && tsBindings_[i]->find(name) != tsBindings_[i]->end()) {
79                 return true;
80             }
81         }
82         return false;
83     }
84 
85 private:
GetIndex(TSBindingType type)86     size_t GetIndex(TSBindingType type) const
87     {
88         return static_cast<size_t>(type);
89     }
90 
91     ArenaAllocator *allocator_;
92     std::array<VariableMap *, static_cast<size_t>(TSBindingType::COUNT)> tsBindings_ {};
93 };
94 
95 class ExportBindings {
96 public:
ExportBindings(ArenaAllocator * allocator)97     explicit ExportBindings(ArenaAllocator *allocator)
98         : exportBindings_(allocator->Adapter()),
99           exportTSBindings_(allocator)
100     {
101     }
102 
FindExportVariable(const util::StringView & name)103     Variable *FindExportVariable(const util::StringView &name) const
104     {
105         auto res = exportBindings_.find(name);
106         if (res == exportBindings_.end()) {
107             return nullptr;
108         }
109         return res->second;
110     }
111 
AddExportVariable(const util::StringView & name,Variable * var)112     bool AddExportVariable(const util::StringView &name, Variable *var)
113     {
114         return exportBindings_.insert({name, var}).second;
115     }
116 
InExportBindings(const util::StringView & name)117     bool InExportBindings(const util::StringView &name) const
118     {
119         auto res = FindExportVariable(name);
120         return res != nullptr || exportTSBindings_.InTSBindings(name);
121     }
122 
123     template <TSBindingType type>
FindExportTSVariable(const util::StringView & name)124     Variable *FindExportTSVariable(const util::StringView &name) const
125     {
126         return exportTSBindings_.FindTSVariable<type>(name);
127     }
128 
129     template <TSBindingType type>
AddExportTSVariable(const util::StringView & name,Variable * var)130     bool AddExportTSVariable(const util::StringView &name, Variable *var)
131     {
132         return exportTSBindings_.AddTSVariable<type>(name, var);
133     }
134 
135 private:
136     VariableMap exportBindings_;
137     TSBindings exportTSBindings_;
138 };
139 
140 class ScopeFindResult {
141 public:
142     ScopeFindResult() = default;
ScopeFindResult(util::StringView n,Scope * s,uint32_t l,Variable * v)143     ScopeFindResult(util::StringView n, Scope *s, uint32_t l, Variable *v) : ScopeFindResult(n, s, l, l, v, false) {}
ScopeFindResult(Scope * s,uint32_t l,uint32_t ll,Variable * v)144     ScopeFindResult(Scope *s, uint32_t l, uint32_t ll, Variable *v) : scope(s), level(l), lexLevel(ll), variable(v) {}
ScopeFindResult(util::StringView n,Scope * s,uint32_t l,uint32_t ll,Variable * v,bool c)145     ScopeFindResult(util::StringView n, Scope *s, uint32_t l, uint32_t ll, Variable *v, bool c)
146         : name(n), scope(s), level(l), lexLevel(ll), variable(v), crossConcurrent(c)
147     {
148     }
149 
150     util::StringView name {};
151     Scope *scope {};
152     uint32_t level {};
153     uint32_t lexLevel {};
154     Variable *variable {};
155     bool crossConcurrent {false};
156 };
157 
158 class Scope {
159 public:
160     virtual ~Scope() = default;
161     NO_COPY_SEMANTIC(Scope);
162     NO_MOVE_SEMANTIC(Scope);
163 
164     virtual ScopeType Type() const = 0;
165 
166 #define DECLARE_CHECKS_CASTS(scopeType, className)        \
167     bool Is##className() const                            \
168     {                                                     \
169         return Type() == ScopeType::scopeType;            \
170     }                                                     \
171     className *As##className()                            \
172     {                                                     \
173         ASSERT(Is##className());                          \
174         return reinterpret_cast<className *>(this);       \
175     }                                                     \
176     const className *As##className() const                \
177     {                                                     \
178         ASSERT(Is##className());                          \
179         return reinterpret_cast<const className *>(this); \
180     }
SCOPE_TYPES(DECLARE_CHECKS_CASTS)181     SCOPE_TYPES(DECLARE_CHECKS_CASTS)
182 #undef DECLARE_CHECKS_CASTS
183 
184     bool IsVariableScope() const
185     {
186         return Type() > ScopeType::LOCAL;
187     }
188 
IsFunctionVariableScope()189     bool IsFunctionVariableScope() const
190     {
191         return Type() >= ScopeType::FUNCTION;
192     }
193 
AsFunctionVariableScope()194     FunctionScope *AsFunctionVariableScope()
195     {
196         ASSERT(IsFunctionVariableScope());
197         return reinterpret_cast<FunctionScope *>(this);
198     }
199 
AsFunctionVariableScope()200     const FunctionScope *AsFunctionVariableScope() const
201     {
202         ASSERT(IsFunctionVariableScope());
203         return reinterpret_cast<const FunctionScope *>(this);
204     }
205 
AsVariableScope()206     VariableScope *AsVariableScope()
207     {
208         ASSERT(IsVariableScope());
209         return reinterpret_cast<VariableScope *>(this);
210     }
211 
AsVariableScope()212     const VariableScope *AsVariableScope() const
213     {
214         ASSERT(IsVariableScope());
215         return reinterpret_cast<const VariableScope *>(this);
216     }
217 
218     VariableScope *EnclosingVariableScope();
219 
220     FunctionScope *EnclosingFunctionVariableScope();
221 
Decls()222     const ArenaVector<Decl *> &Decls() const
223     {
224         return decls_;
225     }
226 
Parent()227     Scope *Parent()
228     {
229         return parent_;
230     }
231 
Parent()232     const Scope *Parent() const
233     {
234         return parent_;
235     }
236 
SetParent(Scope * parent)237     void SetParent(Scope *parent)
238     {
239         parent_ = parent;
240     }
241 
ScopeStart()242     const compiler::IRNode *ScopeStart() const
243     {
244         return startIns_;
245     }
246 
ScopeEnd()247     const compiler::IRNode *ScopeEnd() const
248     {
249         return endIns_;
250     }
251 
SetScopeStart(const compiler::IRNode * ins)252     void SetScopeStart(const compiler::IRNode *ins)
253     {
254         startIns_ = ins;
255     }
256 
SetScopeEnd(const compiler::IRNode * ins)257     void SetScopeEnd(const compiler::IRNode *ins)
258     {
259         endIns_ = ins;
260     }
261 
Node()262     const ir::AstNode *Node() const
263     {
264         return node_;
265     }
266 
Node()267     ir::AstNode *Node()
268     {
269         return node_;
270     }
271 
BindNode(ir::AstNode * node)272     void BindNode(ir::AstNode *node)
273     {
274         node_ = node;
275     }
276 
AddDecl(ArenaAllocator * allocator,Decl * decl,ScriptExtension extension)277     bool AddDecl(ArenaAllocator *allocator, Decl *decl, [[maybe_unused]] ScriptExtension extension)
278     {
279         decls_.push_back(decl);
280         return AddBinding(allocator, FindLocal(decl->Name()), decl, extension);
281     }
282 
AddTsDecl(ArenaAllocator * allocator,Decl * decl,ScriptExtension extension)283     bool AddTsDecl(ArenaAllocator *allocator, Decl *decl, [[maybe_unused]] ScriptExtension extension)
284     {
285         decls_.push_back(decl);
286         return AddBinding(allocator, FindLocal(decl->Name(), ResolveBindingOptions::ALL), decl, extension);
287     }
288 
289     template <typename T, typename... Args>
290     T *NewDecl(ArenaAllocator *allocator, Args &&... args);
291 
292     template <typename DeclType, typename VariableType>
293     VariableType *AddDecl(ArenaAllocator *allocator, util::StringView name, VariableFlags flags);
294 
295     template <typename DeclType = binder::LetDecl, typename VariableType = binder::LocalVariable>
296     static VariableType *CreateVar(ArenaAllocator *allocator, util::StringView name, VariableFlags flags,
297                                    const ir::AstNode *node);
298 
299     template <typename T, typename... Args>
300     void PropagateBinding(ArenaAllocator *allocator, util::StringView name, Args &&... args);
301 
Bindings()302     VariableMap &Bindings()
303     {
304         return bindings_;
305     }
306 
Bindings()307     const VariableMap &Bindings() const
308     {
309         return bindings_;
310     }
311 
312     virtual bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
313                             [[maybe_unused]] ScriptExtension extension) = 0;
314 
315     Variable *FindLocal(const util::StringView &name,
316                         ResolveBindingOptions options = ResolveBindingOptions::BINDINGS) const;
317 
318     ScopeFindResult Find(const util::StringView &name,
319                          ResolveBindingOptions options = ResolveBindingOptions::BINDINGS) const;
320 
321     Decl *FindDecl(const util::StringView &name) const;
322 
323     bool HasVarDecl(const util::StringView &name) const;
324 
325     template <TSBindingType type>
FindLocalTSVariable(const util::StringView & name)326     Variable *FindLocalTSVariable(const util::StringView &name) const
327     {
328         return tsBindings_.FindTSVariable<type>(name);
329     }
330 
331     template <TSBindingType type>
AddLocalTSVariable(const util::StringView & name,Variable * var)332     void AddLocalTSVariable(const util::StringView &name, Variable *var)
333     {
334         tsBindings_.AddTSVariable<type>(name, var);
335     }
336 
InLocalTSBindings(const util::StringView & name)337     bool InLocalTSBindings(const util::StringView &name) const
338     {
339         return tsBindings_.InTSBindings(name);
340     }
341 
342 protected:
Scope(ArenaAllocator * allocator,Scope * parent)343     explicit Scope(ArenaAllocator *allocator, Scope *parent)
344         : parent_(parent), decls_(allocator->Adapter()), bindings_(allocator->Adapter()), tsBindings_(allocator)
345     {
346     }
347 
348     /**
349      * @return true - if the variable is shadowed
350      *         false - otherwise
351      */
352     using VariableVisitior = std::function<bool(const Variable *)>;
353 
354     /**
355      * @return true - if the variable is shadowed
356      *         false - otherwise
357      */
358     std::tuple<Scope *, bool> IterateShadowedVariables(const util::StringView &name, const VariableVisitior &visitor);
359 
360     bool AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
361                   [[maybe_unused]] ScriptExtension extension);
362 
363     Scope *parent_ {};
364     ArenaVector<Decl *> decls_;
365     VariableMap bindings_;
366     TSBindings tsBindings_;
367     ir::AstNode *node_ {};
368     const compiler::IRNode *startIns_ {};
369     const compiler::IRNode *endIns_ {};
370 };
371 
372 class VariableScope : public Scope {
373 public:
374     ~VariableScope() override = default;
375     NO_COPY_SEMANTIC(VariableScope);
376     NO_MOVE_SEMANTIC(VariableScope);
377 
AddFlag(VariableScopeFlags flag)378     void AddFlag(VariableScopeFlags flag)
379     {
380         flags_ |= flag;
381     }
382 
ClearFlag(VariableScopeFlags flag)383     void ClearFlag(VariableScopeFlags flag)
384     {
385         flags_ &= ~flag;
386     }
387 
HasFlag(VariableScopeFlags flag)388     bool HasFlag(VariableScopeFlags flag) const
389     {
390         return (flags_ & flag) != 0;
391     }
392 
NextSlot()393     uint32_t NextSlot()
394     {
395         return slotIndex_++;
396     }
397 
LexicalSlots()398     uint32_t LexicalSlots() const
399     {
400         return slotIndex_;
401     }
402 
NeedLexEnv()403     bool NeedLexEnv() const
404     {
405         return slotIndex_ != 0;
406     }
407 
AddLexicalVarNameAndType(uint32_t slot,util::StringView name,int type)408     void AddLexicalVarNameAndType(uint32_t slot, util::StringView name, int type)
409     {
410         lexicalVarNameAndTypes_.emplace(slot, std::pair<util::StringView, int>(name, type));
411     }
412 
GetLexicalVarNameAndTypes()413     ArenaMap<uint32_t, std::pair<util::StringView, int>> &GetLexicalVarNameAndTypes()
414     {
415         return lexicalVarNameAndTypes_;
416     }
417 
418 protected:
VariableScope(ArenaAllocator * allocator,Scope * parent)419     explicit VariableScope(ArenaAllocator *allocator, Scope *parent) : Scope(allocator, parent),
420                                                                        lexicalVarNameAndTypes_(allocator->Adapter()) {}
421 
422     inline VariableFlags DeclFlagToVariableFlag(DeclarationFlags declFlag);
423 
424     template <typename T>
425     bool AddVar(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl);
426 
427     template <typename T>
428     bool AddFunction(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
429                      [[maybe_unused]] ScriptExtension extension);
430 
431     template <typename T>
432     bool AddClass(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl);
433 
434     template <typename T>
435     bool AddTSBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags);
436 
437     template <typename T>
438     bool AddTSBinding(ArenaAllocator *allocator, Decl *newDecl, VariableFlags flags);
439 
440     template <typename T>
441     bool AddLexical(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl);
442 
443     VariableScopeFlags flags_ {};
444     uint32_t slotIndex_ {};
445     ArenaMap<uint32_t, std::pair<util::StringView, int>> lexicalVarNameAndTypes_; // for debuginfo and patchFix
446 };
447 
448 class ParamScope : public Scope {
449 public:
Type()450     ScopeType Type() const override
451     {
452         return ScopeType::PARAM;
453     }
454 
Params()455     ArenaVector<LocalVariable *> &Params()
456     {
457         return params_;
458     }
459 
Params()460     const ArenaVector<LocalVariable *> &Params() const
461     {
462         return params_;
463     }
464 
HasParam(util::StringView name)465     bool HasParam(util::StringView name) const
466     {
467         for (auto *param : params_) {
468             if (param->Name() == name) {
469                 return true;
470             }
471         }
472 
473         return false;
474     }
475 
476     std::tuple<ParameterDecl *, const ir::AstNode *> AddParamDecl(ArenaAllocator *allocator, const ir::AstNode *param);
477 
478 protected:
ParamScope(ArenaAllocator * allocator,Scope * parent)479     explicit ParamScope(ArenaAllocator *allocator, Scope *parent)
480         : Scope(allocator, parent), params_(allocator->Adapter())
481     {
482     }
483 
484     bool AddParam(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags);
485 
486     ArenaVector<LocalVariable *> params_;
487 };
488 
489 class FunctionScope;
490 
491 class FunctionParamScope : public ParamScope {
492 public:
FunctionParamScope(ArenaAllocator * allocator,Scope * parent)493     explicit FunctionParamScope(ArenaAllocator *allocator, Scope *parent) : ParamScope(allocator, parent) {}
494 
GetFunctionScope()495     FunctionScope *GetFunctionScope() const
496     {
497         return functionScope_;
498     }
499 
BindFunctionScope(FunctionScope * funcScope)500     void BindFunctionScope(FunctionScope *funcScope)
501     {
502         functionScope_ = funcScope;
503     }
504 
NameVar()505     LocalVariable *NameVar() const
506     {
507         return nameVar_;
508     }
509 
510     void BindName(ArenaAllocator *allocator, util::StringView name);
511 
Type()512     ScopeType Type() const override
513     {
514         return ScopeType::FUNCTION_PARAM;
515     }
516 
517     bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
518                     [[maybe_unused]] ScriptExtension extension) override;
519 
RemoveThisParam(const std::string_view & thisParam)520     void RemoveThisParam(const std::string_view &thisParam)
521     {
522         params_.erase(params_.begin());
523         bindings_.erase(thisParam);
524     }
525 
526     friend class FunctionScope;
527     template <typename E, typename T>
528     friend class ScopeWithParamScope;
529 
530 private:
531     FunctionScope *functionScope_ {};
532     LocalVariable *nameVar_ {};
533 };
534 
535 template <typename E, typename T>
536 class ScopeWithParamScope : public E {
537 public:
ScopeWithParamScope(ArenaAllocator * allocator,Scope * parent)538     explicit ScopeWithParamScope(ArenaAllocator *allocator, Scope *parent) : E(allocator, parent) {}
539 
BindParamScope(T * paramScope)540     void BindParamScope(T *paramScope)
541     {
542         AssignParamScope(paramScope);
543         this->bindings_ = paramScope->Bindings();
544     }
545 
AssignParamScope(T * paramScope)546     void AssignParamScope(T *paramScope)
547     {
548         ASSERT(this->parent_ == paramScope);
549         ASSERT(this->bindings_.empty());
550 
551         paramScope_ = paramScope;
552     }
553 
ParamScope()554     T *ParamScope()
555     {
556         return paramScope_;
557     }
558 
ParamScope()559     const T *ParamScope() const
560     {
561         return paramScope_;
562     }
563 
AddBindsFromParam()564     void AddBindsFromParam()
565     {
566         ASSERT(paramScope_);
567         this->bindings_.insert(paramScope_->Bindings().begin(), paramScope_->Bindings().end());
568     }
569 
570 protected:
571     T *paramScope_;
572 };
573 
574 class FunctionScope : public ScopeWithParamScope<VariableScope, FunctionParamScope> {
575 public:
FunctionScope(ArenaAllocator * allocator,Scope * parent)576     explicit FunctionScope(ArenaAllocator *allocator, Scope *parent) : ScopeWithParamScope(allocator, parent) {}
577 
Type()578     ScopeType Type() const override
579     {
580         return ScopeType::FUNCTION;
581     }
582 
BindName(util::StringView name,util::StringView internalName)583     void BindName(util::StringView name, util::StringView internalName)
584     {
585         name_ = name;
586         internalName_ = internalName;
587     }
588 
Name()589     const util::StringView &Name() const
590     {
591         return name_;
592     }
593 
InternalName()594     const util::StringView &InternalName() const
595     {
596         return internalName_;
597     }
598 
InFunctionScopes()599     bool InFunctionScopes() const
600     {
601         return inFunctionScopes_;
602     }
603 
SetInFunctionScopes()604     void SetInFunctionScopes()
605     {
606         inFunctionScopes_ = true;
607     }
608 
609     bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
610                     [[maybe_unused]] ScriptExtension extension) override;
611 
612 private:
613     util::StringView name_ {};
614     util::StringView internalName_ {};
615     bool inFunctionScopes_ {false};
616 };
617 
618 class LocalScope : public Scope {
619 public:
LocalScope(ArenaAllocator * allocator,Scope * parent)620     explicit LocalScope(ArenaAllocator *allocator, Scope *parent) : Scope(allocator, parent) {}
621 
Type()622     ScopeType Type() const override
623     {
624         return ScopeType::LOCAL;
625     }
626 
627     bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
628                     [[maybe_unused]] ScriptExtension extension) override;
629 };
630 
631 class CatchParamScope : public ParamScope {
632 public:
CatchParamScope(ArenaAllocator * allocator,Scope * parent)633     explicit CatchParamScope(ArenaAllocator *allocator, Scope *parent) : ParamScope(allocator, parent) {}
634 
Type()635     ScopeType Type() const override
636     {
637         return ScopeType::CATCH_PARAM;
638     }
639 
640     bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
641                     [[maybe_unused]] ScriptExtension extension) override;
642 
643     friend class CatchScope;
644 };
645 
646 class CatchScope : public ScopeWithParamScope<LocalScope, CatchParamScope> {
647 public:
CatchScope(ArenaAllocator * allocator,Scope * parent)648     explicit CatchScope(ArenaAllocator *allocator, Scope *parent) : ScopeWithParamScope(allocator, parent) {}
649 
Type()650     ScopeType Type() const override
651     {
652         return ScopeType::CATCH;
653     }
654 
655     bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
656                     [[maybe_unused]] ScriptExtension extension) override;
657 };
658 
659 class LoopScope : public VariableScope {
660 public:
LoopScope(ArenaAllocator * allocator,Scope * parent)661     explicit LoopScope(ArenaAllocator *allocator, Scope *parent) : VariableScope(allocator, parent) {}
662 
Type()663     ScopeType Type() const override
664     {
665         return loopType_;
666     }
667 
668     void InitVariable();
669 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)670     bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
671                     [[maybe_unused]] ScriptExtension extension) override
672     {
673         return AddLocal(allocator, currentVariable, newDecl, extension);
674     }
675 
676 protected:
677     ScopeType loopType_ {ScopeType::LOOP};
678 };
679 
680 class GlobalScope : public FunctionScope {
681 public:
GlobalScope(ArenaAllocator * allocator)682     explicit GlobalScope(ArenaAllocator *allocator) : FunctionScope(allocator, nullptr)
683     {
684         paramScope_ = allocator->New<FunctionParamScope>(allocator, this);
685     }
686 
Type()687     ScopeType Type() const override
688     {
689         return ScopeType::GLOBAL;
690     }
691 
692     bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
693                     [[maybe_unused]] ScriptExtension extension) override;
694 };
695 
696 class ModuleScope : public FunctionScope {
697 public:
ModuleScope(ArenaAllocator * allocator)698     explicit ModuleScope(ArenaAllocator *allocator) : FunctionScope(allocator, nullptr)
699     {
700         paramScope_ = allocator->New<FunctionParamScope>(allocator, this);
701     }
702 
Type()703     ScopeType Type() const override
704     {
705         return ScopeType::MODULE;
706     }
707 
708     void AssignIndexToModuleVariable(util::StringView name, uint32_t index);
709 
710     void ConvertLocalVariableToModuleVariable(ArenaAllocator *allocator, util::StringView localName);
711 
712     bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
713                     [[maybe_unused]] ScriptExtension extension) override;
714 };
715 
716 class TSModuleScope : public FunctionScope {
717 public:
TSModuleScope(ArenaAllocator * allocator,Scope * parent,ExportBindings * exportBindings)718     explicit TSModuleScope(ArenaAllocator *allocator, Scope *parent, ExportBindings *exportBindings)
719         : FunctionScope(allocator, nullptr), exportBindings_(exportBindings), variableNames_(allocator->Adapter())
720     {
721         paramScope_ = allocator->New<FunctionParamScope>(allocator, parent);
722         paramScope_->BindFunctionScope(this);
723         SetParent(paramScope_);
724     }
725 
Type()726     ScopeType Type() const override
727     {
728         return ScopeType::TSMODULE;
729     }
730 
731     template <TSBindingType type>
FindExportTSVariable(const util::StringView & name)732     Variable *FindExportTSVariable(const util::StringView &name) const
733     {
734         return exportBindings_->FindExportTSVariable<type>(name);
735     }
736 
737     template <TSBindingType type>
AddExportTSVariable(const util::StringView & name,Variable * var)738     bool AddExportTSVariable(const util::StringView &name, Variable *var)
739     {
740         return exportBindings_->AddExportTSVariable<type>(name, var);
741     }
742 
FindExportVariable(const util::StringView & name)743     Variable *FindExportVariable(const util::StringView &name) const
744     {
745         return exportBindings_->FindExportVariable(name);
746     }
747 
AddExportVariable(const util::StringView & name,Variable * var)748     bool AddExportVariable(const util::StringView &name, Variable *var)
749     {
750         return exportBindings_->AddExportVariable(name, var);
751     }
752 
AddExportVariable(const util::StringView & name)753     bool AddExportVariable(const util::StringView &name)
754     {
755         return exportBindings_->AddExportVariable(name, FindLocal(name));
756     }
757 
InExportBindings(const util::StringView & name)758     bool InExportBindings(const util::StringView &name) const
759     {
760         return exportBindings_->InExportBindings(name);
761     }
762 
AddDeclarationName(const util::StringView & name)763     void AddDeclarationName(const util::StringView &name)
764     {
765         variableNames_.insert(name);
766     }
767 
HasVariableName(const util::StringView & name)768     bool HasVariableName(const util::StringView &name) const
769     {
770         return variableNames_.find(name) != variableNames_.end();
771     }
772 
773 private:
774     ExportBindings *exportBindings_;
775     ArenaSet<util::StringView> variableNames_;
776 };
777 
778 class TSEnumScope : public FunctionScope {
779 public:
TSEnumScope(ArenaAllocator * allocator,Scope * parent,VariableMap * enumMemberBindings)780     explicit TSEnumScope(ArenaAllocator *allocator, Scope *parent, VariableMap *enumMemberBindings) : FunctionScope(
781         allocator, nullptr), enumMemberBindings_(enumMemberBindings), variableNames_(allocator->Adapter())
782     {
783         paramScope_ = allocator->New<FunctionParamScope>(allocator, parent);
784         paramScope_->BindFunctionScope(this);
785         SetParent(paramScope_);
786     }
787 
Type()788     ScopeType Type() const override
789     {
790         return ScopeType::TSENUM;
791     }
792 
FindEnumMemberVariable(const util::StringView & name)793     Variable *FindEnumMemberVariable(const util::StringView &name) const
794     {
795         auto res = enumMemberBindings_->find(name);
796         if (res == enumMemberBindings_->end()) {
797             return nullptr;
798         }
799         return res->second;
800     }
801 
AddDeclarationName(const util::StringView & name)802     void AddDeclarationName(const util::StringView &name)
803     {
804         variableNames_.insert(name);
805     }
806 
HasDeclarationName(const util::StringView & name)807     bool HasDeclarationName(const util::StringView &name) const
808     {
809         return variableNames_.find(name) != variableNames_.end();
810     }
811 
812     bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
813                     [[maybe_unused]] ScriptExtension extension) override;
814 
815 private:
816     VariableMap *enumMemberBindings_;
817     ArenaSet<util::StringView> variableNames_;
818 };
819 
DeclFlagToVariableFlag(DeclarationFlags declFlag)820 inline VariableFlags VariableScope::DeclFlagToVariableFlag(DeclarationFlags declFlag)
821 {
822     VariableFlags varFlag = VariableFlags::NONE;
823     if (declFlag & DeclarationFlags::EXPORT) {
824         varFlag = VariableFlags::LOCAL_EXPORT;
825     } else if (declFlag & DeclarationFlags::IMPORT) {
826         varFlag = VariableFlags::IMPORT;
827     }
828     return varFlag;
829 }
830 
831 template <typename T>
AddVar(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl)832 bool VariableScope::AddVar(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)
833 {
834     VariableFlags flags = VariableFlags::HOIST_VAR;
835     flags |= DeclFlagToVariableFlag(newDecl->Flags());
836 
837     if (!currentVariable) {
838         bindings_.insert({newDecl->Name(), allocator->New<T>(newDecl, flags)});
839         return true;
840     }
841 
842     switch (currentVariable->Declaration()->Type()) {
843         case DeclType::VAR: {
844             currentVariable->Reset(newDecl, flags);
845             break;
846         }
847         case DeclType::PARAM:
848         case DeclType::FUNC: {
849             break;
850         }
851         default: {
852             return false;
853         }
854     }
855 
856     return true;
857 }
858 
859 template <typename T>
AddFunction(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)860 bool VariableScope::AddFunction(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
861                                 [[maybe_unused]] ScriptExtension extension)
862 {
863     VariableFlags flags = (extension == ScriptExtension::JS) ? VariableFlags::HOIST_VAR : VariableFlags::HOIST;
864     flags |= DeclFlagToVariableFlag(newDecl->Flags());
865 
866     if (!currentVariable) {
867         bindings_.insert({newDecl->Name(), allocator->New<T>(newDecl, flags)});
868         return true;
869     }
870 
871     auto decl = currentVariable->Declaration();
872     if (decl->IsClassDecl() && decl->AsClassDecl()->IsDeclare()) {
873         newDecl->AsFunctionDecl()->SetDeclClass(decl->AsClassDecl());
874         bindings_[newDecl->Name()] = allocator->New<T>(newDecl, flags);
875         return true;
876     }
877 
878     if (extension != ScriptExtension::JS) {
879         return false;
880     }
881 
882     switch (currentVariable->Declaration()->Type()) {
883         case DeclType::VAR:
884         case DeclType::FUNC: {
885             currentVariable->Reset(newDecl, flags);
886             break;
887         }
888         default: {
889             return false;
890         }
891     }
892 
893     return true;
894 }
895 
896 template <typename T>
AddClass(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl)897 bool VariableScope::AddClass(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)
898 {
899     ASSERT(newDecl->IsClassDecl());
900 
901     VariableFlags flags = DeclFlagToVariableFlag(newDecl->Flags());
902 
903     if (!currentVariable) {
904         bindings_.insert({newDecl->Name(), allocator->New<T>(newDecl, flags)});
905         return true;
906     }
907 
908     auto decl = currentVariable->Declaration();
909     if (newDecl->AsClassDecl()->IsDeclare() && decl->IsFunctionDecl()) {
910         decl->AsFunctionDecl()->SetDeclClass(newDecl->AsClassDecl());
911         return true;
912     }
913 
914     return false;
915 }
916 
917 template <typename T>
AddTSBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,VariableFlags flags)918 bool VariableScope::AddTSBinding(ArenaAllocator *allocator, [[maybe_unused]] Variable *currentVariable, Decl *newDecl,
919                                  VariableFlags flags)
920 {
921     ASSERT(!currentVariable);
922     // TODO(xucheng): move the ts variables to tsBindings_
923     bindings_.insert({newDecl->Name(), allocator->New<T>(newDecl, flags)});
924     return true;
925 }
926 
927 template <typename T>
AddTSBinding(ArenaAllocator * allocator,Decl * newDecl,VariableFlags flags)928 bool VariableScope::AddTSBinding(ArenaAllocator *allocator, Decl *newDecl, VariableFlags flags)
929 {
930     switch (flags) {
931         case VariableFlags::NAMESPACE: {
932             return tsBindings_.AddTSVariable<TSBindingType::NAMESPACE>(
933                 newDecl->Name(), allocator->New<T>(newDecl, flags));
934         }
935         case VariableFlags::ENUM_LITERAL: {
936             return tsBindings_.AddTSVariable<TSBindingType::ENUMLITERAL>(
937                 newDecl->Name(), allocator->New<T>(newDecl, flags));
938         }
939         case VariableFlags::INTERFACE: {
940             return tsBindings_.AddTSVariable<TSBindingType::INTERFACE>(
941                 newDecl->Name(), allocator->New<T>(newDecl, flags));
942         }
943         case VariableFlags::IMPORT_EQUALS: {
944             return tsBindings_.AddTSVariable<TSBindingType::IMPORT_EQUALS>(
945                 newDecl->Name(), allocator->New<T>(newDecl, flags));
946         }
947         default: {
948             break;
949         }
950     }
951     return false;
952 }
953 
954 template <typename T>
AddLexical(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl)955 bool VariableScope::AddLexical(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)
956 {
957     VariableFlags flags = DeclFlagToVariableFlag(newDecl->Flags());
958 
959     if (currentVariable) {
960         return false;
961     }
962 
963     bindings_.insert({newDecl->Name(), allocator->New<T>(newDecl, flags)});
964     return true;
965 }
966 
967 template <typename T, typename... Args>
NewDecl(ArenaAllocator * allocator,Args &&...args)968 T *Scope::NewDecl(ArenaAllocator *allocator, Args &&... args)
969 {
970     T *decl = allocator->New<T>(std::forward<Args>(args)...);
971     decls_.push_back(decl);
972 
973     return decl;
974 }
975 
976 template <typename DeclType, typename VariableType>
AddDecl(ArenaAllocator * allocator,util::StringView name,VariableFlags flags)977 VariableType *Scope::AddDecl(ArenaAllocator *allocator, util::StringView name, VariableFlags flags)
978 {
979     if (FindLocal(name)) {
980         return nullptr;
981     }
982 
983     auto *decl = allocator->New<DeclType>(name);
984     auto *variable = allocator->New<VariableType>(decl, flags);
985 
986     decls_.push_back(decl);
987     bindings_.insert({decl->Name(), variable});
988 
989     return variable;
990 }
991 
992 template <typename DeclType, typename VariableType>
CreateVar(ArenaAllocator * allocator,util::StringView name,VariableFlags flags,const ir::AstNode * node)993 VariableType *Scope::CreateVar(ArenaAllocator *allocator, util::StringView name, VariableFlags flags,
994                                const ir::AstNode *node)
995 {
996     auto *decl = allocator->New<DeclType>(name);
997     auto *variable = allocator->New<VariableType>(decl, flags);
998     decl->BindNode(node);
999     return variable;
1000 }
1001 
1002 template <typename T, typename... Args>
PropagateBinding(ArenaAllocator * allocator,util::StringView name,Args &&...args)1003 void Scope::PropagateBinding(ArenaAllocator *allocator, util::StringView name, Args &&... args)
1004 {
1005     auto res = bindings_.find(name);
1006     if (res == bindings_.end()) {
1007         bindings_.insert({name, allocator->New<T>(std::forward<Args>(args)...)});
1008         return;
1009     }
1010 
1011     if (!res->second->Declaration()->IsParameterDecl()) {
1012         res->second->Reset(std::forward<Args>(args)...);
1013     }
1014 }
1015 
1016 }  // namespace panda::es2panda::binder
1017 
1018 #endif
1019