• 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 
ScopeStart()237     const compiler::IRNode *ScopeStart() const
238     {
239         return startIns_;
240     }
241 
ScopeEnd()242     const compiler::IRNode *ScopeEnd() const
243     {
244         return endIns_;
245     }
246 
SetScopeStart(const compiler::IRNode * ins)247     void SetScopeStart(const compiler::IRNode *ins)
248     {
249         startIns_ = ins;
250     }
251 
SetScopeEnd(const compiler::IRNode * ins)252     void SetScopeEnd(const compiler::IRNode *ins)
253     {
254         endIns_ = ins;
255     }
256 
Node()257     const ir::AstNode *Node() const
258     {
259         return node_;
260     }
261 
BindNode(const ir::AstNode * node)262     void BindNode(const ir::AstNode *node)
263     {
264         node_ = node;
265     }
266 
AddDecl(ArenaAllocator * allocator,Decl * decl,ScriptExtension extension)267     bool AddDecl(ArenaAllocator *allocator, Decl *decl, [[maybe_unused]] ScriptExtension extension)
268     {
269         decls_.push_back(decl);
270         return AddBinding(allocator, FindLocal(decl->Name()), decl, extension);
271     }
272 
AddTsDecl(ArenaAllocator * allocator,Decl * decl,ScriptExtension extension)273     bool AddTsDecl(ArenaAllocator *allocator, Decl *decl, [[maybe_unused]] ScriptExtension extension)
274     {
275         decls_.push_back(decl);
276         return AddBinding(allocator, FindLocal(decl->Name(), ResolveBindingOptions::ALL), decl, extension);
277     }
278 
279     template <typename T, typename... Args>
280     T *NewDecl(ArenaAllocator *allocator, Args &&... args);
281 
282     template <typename DeclType, typename VariableType>
283     VariableType *AddDecl(ArenaAllocator *allocator, util::StringView name, VariableFlags flags);
284 
285     template <typename DeclType = binder::LetDecl, typename VariableType = binder::LocalVariable>
286     static VariableType *CreateVar(ArenaAllocator *allocator, util::StringView name, VariableFlags flags,
287                                    const ir::AstNode *node);
288 
289     template <typename T, typename... Args>
290     void PropagateBinding(ArenaAllocator *allocator, util::StringView name, Args &&... args);
291 
Bindings()292     VariableMap &Bindings()
293     {
294         return bindings_;
295     }
296 
Bindings()297     const VariableMap &Bindings() const
298     {
299         return bindings_;
300     }
301 
302     virtual bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
303                             [[maybe_unused]] ScriptExtension extension) = 0;
304 
305     Variable *FindLocal(const util::StringView &name,
306                         ResolveBindingOptions options = ResolveBindingOptions::BINDINGS) const;
307 
308     ScopeFindResult Find(const util::StringView &name,
309                          ResolveBindingOptions options = ResolveBindingOptions::BINDINGS) const;
310 
311     Decl *FindDecl(const util::StringView &name) const;
312 
313     bool HasVarDecl(const util::StringView &name) const;
314 
315     template <TSBindingType type>
FindLocalTSVariable(const util::StringView & name)316     Variable *FindLocalTSVariable(const util::StringView &name) const
317     {
318         return tsBindings_.FindTSVariable<type>(name);
319     }
320 
321     template <TSBindingType type>
AddLocalTSVariable(const util::StringView & name,Variable * var)322     void AddLocalTSVariable(const util::StringView &name, Variable *var)
323     {
324         tsBindings_.AddTSVariable<type>(name, var);
325     }
326 
InLocalTSBindings(const util::StringView & name)327     bool InLocalTSBindings(const util::StringView &name) const
328     {
329         return tsBindings_.InTSBindings(name);
330     }
331 
332 protected:
Scope(ArenaAllocator * allocator,Scope * parent)333     explicit Scope(ArenaAllocator *allocator, Scope *parent)
334         : parent_(parent), decls_(allocator->Adapter()), bindings_(allocator->Adapter()), tsBindings_(allocator)
335     {
336     }
337 
338     /**
339      * @return true - if the variable is shadowed
340      *         false - otherwise
341      */
342     using VariableVisitior = std::function<bool(const Variable *)>;
343 
344     /**
345      * @return true - if the variable is shadowed
346      *         false - otherwise
347      */
348     std::tuple<Scope *, bool> IterateShadowedVariables(const util::StringView &name, const VariableVisitior &visitor);
349 
350     bool AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
351                   [[maybe_unused]] ScriptExtension extension);
352 
SetParent(Scope * parent)353     void SetParent(Scope *parent)
354     {
355         parent_ = parent;
356     }
357 
358     Scope *parent_ {};
359     ArenaVector<Decl *> decls_;
360     VariableMap bindings_;
361     TSBindings tsBindings_;
362     const ir::AstNode *node_ {};
363     const compiler::IRNode *startIns_ {};
364     const compiler::IRNode *endIns_ {};
365 };
366 
367 class VariableScope : public Scope {
368 public:
369     ~VariableScope() override = default;
370     NO_COPY_SEMANTIC(VariableScope);
371     NO_MOVE_SEMANTIC(VariableScope);
372 
AddFlag(VariableScopeFlags flag)373     void AddFlag(VariableScopeFlags flag)
374     {
375         flags_ |= flag;
376     }
377 
ClearFlag(VariableScopeFlags flag)378     void ClearFlag(VariableScopeFlags flag)
379     {
380         flags_ &= ~flag;
381     }
382 
HasFlag(VariableScopeFlags flag)383     bool HasFlag(VariableScopeFlags flag) const
384     {
385         return (flags_ & flag) != 0;
386     }
387 
NextSlot()388     uint32_t NextSlot()
389     {
390         return slotIndex_++;
391     }
392 
LexicalSlots()393     uint32_t LexicalSlots() const
394     {
395         return slotIndex_;
396     }
397 
NeedLexEnv()398     bool NeedLexEnv() const
399     {
400         return slotIndex_ != 0;
401     }
402 
AddLexicalVarNameAndType(uint32_t slot,util::StringView name,int type)403     void AddLexicalVarNameAndType(uint32_t slot, util::StringView name, int type)
404     {
405         lexicalVarNameAndTypes_.emplace(slot, std::pair<util::StringView, int>(name, type));
406     }
407 
GetLexicalVarNameAndTypes()408     ArenaMap<uint32_t, std::pair<util::StringView, int>> &GetLexicalVarNameAndTypes()
409     {
410         return lexicalVarNameAndTypes_;
411     }
412 
413 protected:
VariableScope(ArenaAllocator * allocator,Scope * parent)414     explicit VariableScope(ArenaAllocator *allocator, Scope *parent) : Scope(allocator, parent),
415                                                                        lexicalVarNameAndTypes_(allocator->Adapter()) {}
416 
417     inline VariableFlags DeclFlagToVariableFlag(DeclarationFlags declFlag);
418 
419     template <typename T>
420     bool AddVar(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl);
421 
422     template <typename T>
423     bool AddFunction(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
424                      [[maybe_unused]] ScriptExtension extension);
425 
426     template <typename T>
427     bool AddTSBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags);
428 
429     template <typename T>
430     bool AddTSBinding(ArenaAllocator *allocator, Decl *newDecl, VariableFlags flags);
431 
432     template <typename T>
433     bool AddLexical(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl);
434 
435     VariableScopeFlags flags_ {};
436     uint32_t slotIndex_ {};
437     ArenaMap<uint32_t, std::pair<util::StringView, int>> lexicalVarNameAndTypes_; // for debuginfo and hotfix
438 };
439 
440 class ParamScope : public Scope {
441 public:
Type()442     ScopeType Type() const override
443     {
444         return ScopeType::PARAM;
445     }
446 
Params()447     ArenaVector<LocalVariable *> &Params()
448     {
449         return params_;
450     }
451 
Params()452     const ArenaVector<LocalVariable *> &Params() const
453     {
454         return params_;
455     }
456 
HasParam(util::StringView name)457     bool HasParam(util::StringView name) const
458     {
459         for (auto *param : params_) {
460             if (param->Name() == name) {
461                 return true;
462             }
463         }
464 
465         return false;
466     }
467 
468     std::tuple<ParameterDecl *, const ir::AstNode *> AddParamDecl(ArenaAllocator *allocator, const ir::AstNode *param);
469 
470 protected:
ParamScope(ArenaAllocator * allocator,Scope * parent)471     explicit ParamScope(ArenaAllocator *allocator, Scope *parent)
472         : Scope(allocator, parent), params_(allocator->Adapter())
473     {
474     }
475 
476     bool AddParam(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags);
477 
478     ArenaVector<LocalVariable *> params_;
479 };
480 
481 class FunctionScope;
482 
483 class FunctionParamScope : public ParamScope {
484 public:
FunctionParamScope(ArenaAllocator * allocator,Scope * parent)485     explicit FunctionParamScope(ArenaAllocator *allocator, Scope *parent) : ParamScope(allocator, parent) {}
486 
GetFunctionScope()487     FunctionScope *GetFunctionScope() const
488     {
489         return functionScope_;
490     }
491 
BindFunctionScope(FunctionScope * funcScope)492     void BindFunctionScope(FunctionScope *funcScope)
493     {
494         functionScope_ = funcScope;
495     }
496 
NameVar()497     LocalVariable *NameVar() const
498     {
499         return nameVar_;
500     }
501 
502     void BindName(ArenaAllocator *allocator, util::StringView name);
503 
Type()504     ScopeType Type() const override
505     {
506         return ScopeType::FUNCTION_PARAM;
507     }
508 
509     bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
510                     [[maybe_unused]] ScriptExtension extension) override;
511 
RemoveThisParam()512     void RemoveThisParam()
513     {
514         params_.erase(params_.begin());
515     }
516 
517     friend class FunctionScope;
518     template <typename E, typename T>
519     friend class ScopeWithParamScope;
520 
521 private:
522     FunctionScope *functionScope_ {};
523     LocalVariable *nameVar_ {};
524 };
525 
526 template <typename E, typename T>
527 class ScopeWithParamScope : public E {
528 public:
ScopeWithParamScope(ArenaAllocator * allocator,Scope * parent)529     explicit ScopeWithParamScope(ArenaAllocator *allocator, Scope *parent) : E(allocator, parent) {}
530 
BindParamScope(T * paramScope)531     void BindParamScope(T *paramScope)
532     {
533         AssignParamScope(paramScope);
534         this->bindings_ = paramScope->Bindings();
535     }
536 
AssignParamScope(T * paramScope)537     void AssignParamScope(T *paramScope)
538     {
539         ASSERT(this->parent_ == paramScope);
540         ASSERT(this->bindings_.empty());
541 
542         paramScope_ = paramScope;
543     }
544 
ParamScope()545     T *ParamScope()
546     {
547         return paramScope_;
548     }
549 
ParamScope()550     const T *ParamScope() const
551     {
552         return paramScope_;
553     }
554 
AddBindsFromParam()555     void AddBindsFromParam()
556     {
557         ASSERT(paramScope_);
558         this->bindings_.insert(paramScope_->Bindings().begin(), paramScope_->Bindings().end());
559     }
560 
561 protected:
562     T *paramScope_;
563 };
564 
565 class FunctionScope : public ScopeWithParamScope<VariableScope, FunctionParamScope> {
566 public:
FunctionScope(ArenaAllocator * allocator,Scope * parent)567     explicit FunctionScope(ArenaAllocator *allocator, Scope *parent) : ScopeWithParamScope(allocator, parent) {}
568 
Type()569     ScopeType Type() const override
570     {
571         return ScopeType::FUNCTION;
572     }
573 
BindName(util::StringView name,util::StringView internalName)574     void BindName(util::StringView name, util::StringView internalName)
575     {
576         name_ = name;
577         internalName_ = internalName;
578     }
579 
Name()580     const util::StringView &Name() const
581     {
582         return name_;
583     }
584 
InternalName()585     const util::StringView &InternalName() const
586     {
587         return internalName_;
588     }
589 
590     bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
591                     [[maybe_unused]] ScriptExtension extension) override;
592 
593 private:
594     util::StringView name_ {};
595     util::StringView internalName_ {};
596 };
597 
598 class LocalScope : public Scope {
599 public:
LocalScope(ArenaAllocator * allocator,Scope * parent)600     explicit LocalScope(ArenaAllocator *allocator, Scope *parent) : Scope(allocator, parent) {}
601 
Type()602     ScopeType Type() const override
603     {
604         return ScopeType::LOCAL;
605     }
606 
607     bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
608                     [[maybe_unused]] ScriptExtension extension) override;
609 };
610 
611 class CatchParamScope : public ParamScope {
612 public:
CatchParamScope(ArenaAllocator * allocator,Scope * parent)613     explicit CatchParamScope(ArenaAllocator *allocator, Scope *parent) : ParamScope(allocator, parent) {}
614 
Type()615     ScopeType Type() const override
616     {
617         return ScopeType::CATCH_PARAM;
618     }
619 
620     bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
621                     [[maybe_unused]] ScriptExtension extension) override;
622 
623     friend class CatchScope;
624 };
625 
626 class CatchScope : public ScopeWithParamScope<LocalScope, CatchParamScope> {
627 public:
CatchScope(ArenaAllocator * allocator,Scope * parent)628     explicit CatchScope(ArenaAllocator *allocator, Scope *parent) : ScopeWithParamScope(allocator, parent) {}
629 
Type()630     ScopeType Type() const override
631     {
632         return ScopeType::CATCH;
633     }
634 
635     bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
636                     [[maybe_unused]] ScriptExtension extension) override;
637 };
638 
639 class LoopScope : public VariableScope {
640 public:
LoopScope(ArenaAllocator * allocator,Scope * parent)641     explicit LoopScope(ArenaAllocator *allocator, Scope *parent) : VariableScope(allocator, parent) {}
642 
Type()643     ScopeType Type() const override
644     {
645         return loopType_;
646     }
647 
648     void InitVariable();
649 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)650     bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
651                     [[maybe_unused]] ScriptExtension extension) override
652     {
653         return AddLocal(allocator, currentVariable, newDecl, extension);
654     }
655 
656 protected:
657     ScopeType loopType_ {ScopeType::LOOP};
658 };
659 
660 class GlobalScope : public FunctionScope {
661 public:
GlobalScope(ArenaAllocator * allocator)662     explicit GlobalScope(ArenaAllocator *allocator) : FunctionScope(allocator, nullptr)
663     {
664         paramScope_ = allocator->New<FunctionParamScope>(allocator, this);
665     }
666 
Type()667     ScopeType Type() const override
668     {
669         return ScopeType::GLOBAL;
670     }
671 
672     bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
673                     [[maybe_unused]] ScriptExtension extension) override;
674 };
675 
676 class ModuleScope : public FunctionScope {
677 public:
ModuleScope(ArenaAllocator * allocator)678     explicit ModuleScope(ArenaAllocator *allocator) : FunctionScope(allocator, nullptr)
679     {
680         paramScope_ = allocator->New<FunctionParamScope>(allocator, this);
681     }
682 
Type()683     ScopeType Type() const override
684     {
685         return ScopeType::MODULE;
686     }
687 
688     void AssignIndexToModuleVariable(util::StringView name, uint32_t index);
689 
690     void ConvertLocalVariableToModuleVariable(ArenaAllocator *allocator, util::StringView localName);
691 
692     bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
693                     [[maybe_unused]] ScriptExtension extension) override;
694 };
695 
696 class TSModuleScope : public FunctionScope {
697 public:
TSModuleScope(ArenaAllocator * allocator,Scope * parent,ExportBindings * exportBindings)698     explicit TSModuleScope(ArenaAllocator *allocator, Scope *parent, ExportBindings *exportBindings)
699         : FunctionScope(allocator, nullptr), exportBindings_(exportBindings), variableNames_(allocator->Adapter())
700     {
701         paramScope_ = allocator->New<FunctionParamScope>(allocator, parent);
702         paramScope_->BindFunctionScope(this);
703         SetParent(paramScope_);
704     }
705 
Type()706     ScopeType Type() const override
707     {
708         return ScopeType::TSMODULE;
709     }
710 
711     template <TSBindingType type>
FindExportTSVariable(const util::StringView & name)712     Variable *FindExportTSVariable(const util::StringView &name) const
713     {
714         return exportBindings_->FindExportTSVariable<type>(name);
715     }
716 
717     template <TSBindingType type>
AddExportTSVariable(const util::StringView & name,Variable * var)718     bool AddExportTSVariable(const util::StringView &name, Variable *var)
719     {
720         return exportBindings_->AddExportTSVariable<type>(name, var);
721     }
722 
FindExportVariable(const util::StringView & name)723     Variable *FindExportVariable(const util::StringView &name) const
724     {
725         return exportBindings_->FindExportVariable(name);
726     }
727 
AddExportVariable(const util::StringView & name,Variable * var)728     bool AddExportVariable(const util::StringView &name, Variable *var)
729     {
730         return exportBindings_->AddExportVariable(name, var);
731     }
732 
AddExportVariable(const util::StringView & name)733     bool AddExportVariable(const util::StringView &name)
734     {
735         return exportBindings_->AddExportVariable(name, FindLocal(name));
736     }
737 
InExportBindings(const util::StringView & name)738     bool InExportBindings(const util::StringView &name) const
739     {
740         return exportBindings_->InExportBindings(name);
741     }
742 
AddDeclarationName(const util::StringView & name)743     void AddDeclarationName(const util::StringView &name)
744     {
745         variableNames_.insert(name);
746     }
747 
HasVariableName(const util::StringView & name)748     bool HasVariableName(const util::StringView &name) const
749     {
750         return variableNames_.find(name) != variableNames_.end();
751     }
752 
753 private:
754     ExportBindings *exportBindings_;
755     ArenaSet<util::StringView> variableNames_;
756 };
757 
DeclFlagToVariableFlag(DeclarationFlags declFlag)758 inline VariableFlags VariableScope::DeclFlagToVariableFlag(DeclarationFlags declFlag)
759 {
760     VariableFlags varFlag = VariableFlags::NONE;
761     if (declFlag & DeclarationFlags::EXPORT) {
762         varFlag = VariableFlags::LOCAL_EXPORT;
763     } else if (declFlag & DeclarationFlags::IMPORT) {
764         varFlag = VariableFlags::IMPORT;
765     }
766     return varFlag;
767 }
768 
769 template <typename T>
AddVar(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl)770 bool VariableScope::AddVar(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)
771 {
772     VariableFlags flags = VariableFlags::HOIST_VAR;
773     flags |= DeclFlagToVariableFlag(newDecl->Flags());
774 
775     if (!currentVariable) {
776         bindings_.insert({newDecl->Name(), allocator->New<T>(newDecl, flags)});
777         return true;
778     }
779 
780     switch (currentVariable->Declaration()->Type()) {
781         case DeclType::VAR: {
782             currentVariable->Reset(newDecl, flags);
783             break;
784         }
785         case DeclType::PARAM:
786         case DeclType::FUNC: {
787             break;
788         }
789         default: {
790             return false;
791         }
792     }
793 
794     return true;
795 }
796 
797 template <typename T>
AddFunction(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)798 bool VariableScope::AddFunction(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
799                                 [[maybe_unused]] ScriptExtension extension)
800 {
801     VariableFlags flags = (extension == ScriptExtension::JS) ? VariableFlags::HOIST_VAR : VariableFlags::HOIST;
802     flags |= DeclFlagToVariableFlag(newDecl->Flags());
803 
804     if (!currentVariable) {
805         bindings_.insert({newDecl->Name(), allocator->New<T>(newDecl, flags)});
806         return true;
807     }
808 
809     if (extension != ScriptExtension::JS) {
810         return false;
811     }
812 
813     switch (currentVariable->Declaration()->Type()) {
814         case DeclType::VAR:
815         case DeclType::FUNC: {
816             currentVariable->Reset(newDecl, flags);
817             break;
818         }
819         default: {
820             return false;
821         }
822     }
823 
824     return true;
825 }
826 
827 template <typename T>
AddTSBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,VariableFlags flags)828 bool VariableScope::AddTSBinding(ArenaAllocator *allocator, [[maybe_unused]] Variable *currentVariable, Decl *newDecl,
829                                  VariableFlags flags)
830 {
831     ASSERT(!currentVariable);
832     // TODO(xucheng): move the ts variables to tsBindings_
833     bindings_.insert({newDecl->Name(), allocator->New<T>(newDecl, flags)});
834     return true;
835 }
836 
837 template <typename T>
AddTSBinding(ArenaAllocator * allocator,Decl * newDecl,VariableFlags flags)838 bool VariableScope::AddTSBinding(ArenaAllocator *allocator, Decl *newDecl, VariableFlags flags)
839 {
840     switch (flags) {
841         case VariableFlags::NAMESPACE: {
842             return tsBindings_.AddTSVariable<TSBindingType::NAMESPACE>(
843                 newDecl->Name(), allocator->New<T>(newDecl, flags));
844         }
845         case VariableFlags::ENUM_LITERAL: {
846             return tsBindings_.AddTSVariable<TSBindingType::ENUM>(
847                 newDecl->Name(), allocator->New<T>(newDecl, flags));
848         }
849         case VariableFlags::INTERFACE: {
850             return tsBindings_.AddTSVariable<TSBindingType::INTERFACE>(
851                 newDecl->Name(), allocator->New<T>(newDecl, flags));
852         }
853         case VariableFlags::IMPORT_EQUALS: {
854             return tsBindings_.AddTSVariable<TSBindingType::IMPORT_EQUALS>(
855                 newDecl->Name(), allocator->New<T>(newDecl, flags));
856         }
857         default: {
858             break;
859         }
860     }
861     return false;
862 }
863 
864 template <typename T>
AddLexical(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl)865 bool VariableScope::AddLexical(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)
866 {
867     VariableFlags flags = DeclFlagToVariableFlag(newDecl->Flags());
868 
869     if (currentVariable) {
870         return false;
871     }
872 
873     bindings_.insert({newDecl->Name(), allocator->New<T>(newDecl, flags)});
874     return true;
875 }
876 
877 template <typename T, typename... Args>
NewDecl(ArenaAllocator * allocator,Args &&...args)878 T *Scope::NewDecl(ArenaAllocator *allocator, Args &&... args)
879 {
880     T *decl = allocator->New<T>(std::forward<Args>(args)...);
881     decls_.push_back(decl);
882 
883     return decl;
884 }
885 
886 template <typename DeclType, typename VariableType>
AddDecl(ArenaAllocator * allocator,util::StringView name,VariableFlags flags)887 VariableType *Scope::AddDecl(ArenaAllocator *allocator, util::StringView name, VariableFlags flags)
888 {
889     if (FindLocal(name)) {
890         return nullptr;
891     }
892 
893     auto *decl = allocator->New<DeclType>(name);
894     auto *variable = allocator->New<VariableType>(decl, flags);
895 
896     decls_.push_back(decl);
897     bindings_.insert({decl->Name(), variable});
898 
899     return variable;
900 }
901 
902 template <typename DeclType, typename VariableType>
CreateVar(ArenaAllocator * allocator,util::StringView name,VariableFlags flags,const ir::AstNode * node)903 VariableType *Scope::CreateVar(ArenaAllocator *allocator, util::StringView name, VariableFlags flags,
904                                const ir::AstNode *node)
905 {
906     auto *decl = allocator->New<DeclType>(name);
907     auto *variable = allocator->New<VariableType>(decl, flags);
908     decl->BindNode(node);
909     return variable;
910 }
911 
912 template <typename T, typename... Args>
PropagateBinding(ArenaAllocator * allocator,util::StringView name,Args &&...args)913 void Scope::PropagateBinding(ArenaAllocator *allocator, util::StringView name, Args &&... args)
914 {
915     auto res = bindings_.find(name);
916     if (res == bindings_.end()) {
917         bindings_.insert({name, allocator->New<T>(std::forward<Args>(args)...)});
918         return;
919     }
920 
921     if (!res->second->Declaration()->IsParameterDecl()) {
922         res->second->Reset(std::forward<Args>(args)...);
923     }
924 }
925 
926 }  // namespace panda::es2panda::binder
927 
928 #endif
929