• 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     bool HasLexEnvInCorrespondingFunctionScope(const FunctionParamScope *scope) const;
326 
327     template <TSBindingType type>
FindLocalTSVariable(const util::StringView & name)328     Variable *FindLocalTSVariable(const util::StringView &name) const
329     {
330         return tsBindings_.FindTSVariable<type>(name);
331     }
332 
333     template <TSBindingType type>
AddLocalTSVariable(const util::StringView & name,Variable * var)334     void AddLocalTSVariable(const util::StringView &name, Variable *var)
335     {
336         tsBindings_.AddTSVariable<type>(name, var);
337     }
338 
InLocalTSBindings(const util::StringView & name)339     bool InLocalTSBindings(const util::StringView &name) const
340     {
341         return tsBindings_.InTSBindings(name);
342     }
343 
344 protected:
Scope(ArenaAllocator * allocator,Scope * parent)345     explicit Scope(ArenaAllocator *allocator, Scope *parent)
346         : parent_(parent), decls_(allocator->Adapter()), bindings_(allocator->Adapter()), tsBindings_(allocator)
347     {
348     }
349 
350     /**
351      * @return true - if the variable is shadowed
352      *         false - otherwise
353      */
354     using VariableVisitior = std::function<bool(const Variable *)>;
355 
356     /**
357      * @return true - if the variable is shadowed
358      *         false - otherwise
359      */
360     std::tuple<Scope *, bool> IterateShadowedVariables(const util::StringView &name, const VariableVisitior &visitor);
361 
362     bool AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
363                   [[maybe_unused]] ScriptExtension extension);
364 
365     Scope *parent_ {};
366     ArenaVector<Decl *> decls_;
367     VariableMap bindings_;
368     TSBindings tsBindings_;
369     ir::AstNode *node_ {};
370     const compiler::IRNode *startIns_ {};
371     const compiler::IRNode *endIns_ {};
372 };
373 
374 class VariableScope : public Scope {
375 public:
376     ~VariableScope() override = default;
377     NO_COPY_SEMANTIC(VariableScope);
378     NO_MOVE_SEMANTIC(VariableScope);
379 
AddFlag(VariableScopeFlags flag)380     void AddFlag(VariableScopeFlags flag)
381     {
382         flags_ |= flag;
383     }
384 
ClearFlag(VariableScopeFlags flag)385     void ClearFlag(VariableScopeFlags flag)
386     {
387         flags_ &= ~flag;
388     }
389 
HasFlag(VariableScopeFlags flag)390     bool HasFlag(VariableScopeFlags flag) const
391     {
392         return (flags_ & flag) != 0;
393     }
394 
NextSlot()395     uint32_t NextSlot()
396     {
397         return slotIndex_++;
398     }
399 
LexicalSlots()400     uint32_t LexicalSlots() const
401     {
402         return slotIndex_;
403     }
404 
NeedLexEnv()405     bool NeedLexEnv() const
406     {
407         return slotIndex_ != 0;
408     }
409 
AddLexicalVarNameAndType(uint32_t slot,util::StringView name,int type)410     void AddLexicalVarNameAndType(uint32_t slot, util::StringView name, int type)
411     {
412         lexicalVarNameAndTypes_.emplace(slot, std::pair<util::StringView, int>(name, type));
413     }
414 
GetLexicalVarNameAndTypes()415     ArenaMap<uint32_t, std::pair<util::StringView, int>> &GetLexicalVarNameAndTypes()
416     {
417         return lexicalVarNameAndTypes_;
418     }
419 
420 protected:
VariableScope(ArenaAllocator * allocator,Scope * parent)421     explicit VariableScope(ArenaAllocator *allocator, Scope *parent) : Scope(allocator, parent),
422                                                                        lexicalVarNameAndTypes_(allocator->Adapter()) {}
423 
424     inline VariableFlags DeclFlagToVariableFlag(DeclarationFlags declFlag);
425 
426     template <typename T>
427     bool AddVar(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl);
428 
429     template <typename T>
430     bool AddFunction(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
431                      [[maybe_unused]] ScriptExtension extension);
432 
433     template <typename T>
434     bool AddClass(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl);
435 
436     template <typename T>
437     bool AddTSBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags);
438 
439     template <typename T>
440     bool AddTSBinding(ArenaAllocator *allocator, Decl *newDecl, VariableFlags flags);
441 
442     template <typename T>
443     bool AddLexical(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl);
444 
445     VariableScopeFlags flags_ {};
446     uint32_t slotIndex_ {};
447     ArenaMap<uint32_t, std::pair<util::StringView, int>> lexicalVarNameAndTypes_; // for debuginfo and patchFix
448 };
449 
450 class ParamScope : public Scope {
451 public:
Type()452     ScopeType Type() const override
453     {
454         return ScopeType::PARAM;
455     }
456 
Params()457     ArenaVector<LocalVariable *> &Params()
458     {
459         return params_;
460     }
461 
Params()462     const ArenaVector<LocalVariable *> &Params() const
463     {
464         return params_;
465     }
466 
HasParam(util::StringView name)467     bool HasParam(util::StringView name) const
468     {
469         for (auto *param : params_) {
470             if (param->Name() == name) {
471                 return true;
472             }
473         }
474 
475         return false;
476     }
477 
478     std::tuple<ParameterDecl *, const ir::AstNode *> AddParamDecl(ArenaAllocator *allocator, const ir::AstNode *param);
479 
480 protected:
ParamScope(ArenaAllocator * allocator,Scope * parent)481     explicit ParamScope(ArenaAllocator *allocator, Scope *parent)
482         : Scope(allocator, parent), params_(allocator->Adapter())
483     {
484     }
485 
486     bool AddParam(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags);
487 
488     ArenaVector<LocalVariable *> params_;
489 };
490 
491 class FunctionScope;
492 
493 class FunctionParamScope : public ParamScope {
494 public:
FunctionParamScope(ArenaAllocator * allocator,Scope * parent)495     explicit FunctionParamScope(ArenaAllocator *allocator, Scope *parent) : ParamScope(allocator, parent) {}
496 
GetFunctionScope()497     FunctionScope *GetFunctionScope() const
498     {
499         return functionScope_;
500     }
501 
BindFunctionScope(FunctionScope * funcScope)502     void BindFunctionScope(FunctionScope *funcScope)
503     {
504         functionScope_ = funcScope;
505     }
506 
NameVar()507     LocalVariable *NameVar() const
508     {
509         return nameVar_;
510     }
511 
512     void BindName(ArenaAllocator *allocator, util::StringView name);
513 
Type()514     ScopeType Type() const override
515     {
516         return ScopeType::FUNCTION_PARAM;
517     }
518 
519     bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
520                     [[maybe_unused]] ScriptExtension extension) override;
521 
RemoveThisParam(const std::string_view & thisParam)522     void RemoveThisParam(const std::string_view &thisParam)
523     {
524         params_.erase(params_.begin());
525         bindings_.erase(thisParam);
526     }
527 
528     friend class FunctionScope;
529     template <typename E, typename T>
530     friend class ScopeWithParamScope;
531 
532 private:
533     FunctionScope *functionScope_ {};
534     LocalVariable *nameVar_ {};
535 };
536 
537 template <typename E, typename T>
538 class ScopeWithParamScope : public E {
539 public:
ScopeWithParamScope(ArenaAllocator * allocator,Scope * parent)540     explicit ScopeWithParamScope(ArenaAllocator *allocator, Scope *parent) : E(allocator, parent) {}
541 
BindParamScope(T * paramScope)542     void BindParamScope(T *paramScope)
543     {
544         AssignParamScope(paramScope);
545         this->bindings_ = paramScope->Bindings();
546     }
547 
AssignParamScope(T * paramScope)548     void AssignParamScope(T *paramScope)
549     {
550         ASSERT(this->parent_ == paramScope);
551         ASSERT(this->bindings_.empty());
552 
553         paramScope_ = paramScope;
554     }
555 
ParamScope()556     T *ParamScope()
557     {
558         return paramScope_;
559     }
560 
ParamScope()561     const T *ParamScope() const
562     {
563         return paramScope_;
564     }
565 
AddBindsFromParam()566     void AddBindsFromParam()
567     {
568         ASSERT(paramScope_);
569         this->bindings_.insert(paramScope_->Bindings().begin(), paramScope_->Bindings().end());
570     }
571 
572 protected:
573     T *paramScope_;
574 };
575 
576 class FunctionScope : public ScopeWithParamScope<VariableScope, FunctionParamScope> {
577 public:
FunctionScope(ArenaAllocator * allocator,Scope * parent)578     explicit FunctionScope(ArenaAllocator *allocator, Scope *parent) : ScopeWithParamScope(allocator, parent) {}
579 
Type()580     ScopeType Type() const override
581     {
582         return ScopeType::FUNCTION;
583     }
584 
BindName(util::StringView name,util::StringView internalName)585     void BindName(util::StringView name, util::StringView internalName)
586     {
587         name_ = name;
588         internalName_ = internalName;
589     }
590 
Name()591     const util::StringView &Name() const
592     {
593         return name_;
594     }
595 
InternalName()596     const util::StringView &InternalName() const
597     {
598         return internalName_;
599     }
600 
InFunctionScopes()601     bool InFunctionScopes() const
602     {
603         return inFunctionScopes_;
604     }
605 
SetInFunctionScopes()606     void SetInFunctionScopes()
607     {
608         inFunctionScopes_ = true;
609     }
610 
611     bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
612                     [[maybe_unused]] ScriptExtension extension) override;
613 
614 private:
615     util::StringView name_ {};
616     util::StringView internalName_ {};
617     bool inFunctionScopes_ {false};
618 };
619 
620 class LocalScope : public Scope {
621 public:
LocalScope(ArenaAllocator * allocator,Scope * parent)622     explicit LocalScope(ArenaAllocator *allocator, Scope *parent) : Scope(allocator, parent) {}
623 
Type()624     ScopeType Type() const override
625     {
626         return ScopeType::LOCAL;
627     }
628 
629     bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
630                     [[maybe_unused]] ScriptExtension extension) override;
631 };
632 
633 class CatchParamScope : public ParamScope {
634 public:
CatchParamScope(ArenaAllocator * allocator,Scope * parent)635     explicit CatchParamScope(ArenaAllocator *allocator, Scope *parent) : ParamScope(allocator, parent) {}
636 
Type()637     ScopeType Type() const override
638     {
639         return ScopeType::CATCH_PARAM;
640     }
641 
642     bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
643                     [[maybe_unused]] ScriptExtension extension) override;
644 
645     friend class CatchScope;
646 };
647 
648 class CatchScope : public ScopeWithParamScope<LocalScope, CatchParamScope> {
649 public:
CatchScope(ArenaAllocator * allocator,Scope * parent)650     explicit CatchScope(ArenaAllocator *allocator, Scope *parent) : ScopeWithParamScope(allocator, parent) {}
651 
Type()652     ScopeType Type() const override
653     {
654         return ScopeType::CATCH;
655     }
656 
657     bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
658                     [[maybe_unused]] ScriptExtension extension) override;
659 };
660 
661 class LoopScope : public VariableScope {
662 public:
LoopScope(ArenaAllocator * allocator,Scope * parent)663     explicit LoopScope(ArenaAllocator *allocator, Scope *parent) : VariableScope(allocator, parent) {}
664 
Type()665     ScopeType Type() const override
666     {
667         return loopType_;
668     }
669 
670     void InitVariable();
671 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)672     bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
673                     [[maybe_unused]] ScriptExtension extension) override
674     {
675         return AddLocal(allocator, currentVariable, newDecl, extension);
676     }
677 
678 protected:
679     ScopeType loopType_ {ScopeType::LOOP};
680 };
681 
682 class GlobalScope : public FunctionScope {
683 public:
GlobalScope(ArenaAllocator * allocator)684     explicit GlobalScope(ArenaAllocator *allocator) : FunctionScope(allocator, nullptr)
685     {
686         paramScope_ = allocator->New<FunctionParamScope>(allocator, this);
687     }
688 
Type()689     ScopeType Type() const override
690     {
691         return ScopeType::GLOBAL;
692     }
693 
694     bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
695                     [[maybe_unused]] ScriptExtension extension) override;
696 };
697 
698 class ModuleScope : public FunctionScope {
699 public:
ModuleScope(ArenaAllocator * allocator)700     explicit ModuleScope(ArenaAllocator *allocator) : FunctionScope(allocator, nullptr)
701     {
702         paramScope_ = allocator->New<FunctionParamScope>(allocator, this);
703     }
704 
Type()705     ScopeType Type() const override
706     {
707         return ScopeType::MODULE;
708     }
709 
710     void AssignIndexToModuleVariable(util::StringView name, uint32_t index);
711 
712     void ConvertLocalVariableToModuleVariable(ArenaAllocator *allocator, util::StringView localName);
713 
714     bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
715                     [[maybe_unused]] ScriptExtension extension) override;
716 };
717 
718 class TSModuleScope : public FunctionScope {
719 public:
TSModuleScope(ArenaAllocator * allocator,Scope * parent,ExportBindings * exportBindings)720     explicit TSModuleScope(ArenaAllocator *allocator, Scope *parent, ExportBindings *exportBindings)
721         : FunctionScope(allocator, nullptr), exportBindings_(exportBindings), variableNames_(allocator->Adapter())
722     {
723         paramScope_ = allocator->New<FunctionParamScope>(allocator, parent);
724         paramScope_->BindFunctionScope(this);
725         SetParent(paramScope_);
726     }
727 
Type()728     ScopeType Type() const override
729     {
730         return ScopeType::TSMODULE;
731     }
732 
733     template <TSBindingType type>
FindExportTSVariable(const util::StringView & name)734     Variable *FindExportTSVariable(const util::StringView &name) const
735     {
736         return exportBindings_->FindExportTSVariable<type>(name);
737     }
738 
739     template <TSBindingType type>
AddExportTSVariable(const util::StringView & name,Variable * var)740     bool AddExportTSVariable(const util::StringView &name, Variable *var)
741     {
742         return exportBindings_->AddExportTSVariable<type>(name, var);
743     }
744 
FindExportVariable(const util::StringView & name)745     Variable *FindExportVariable(const util::StringView &name) const
746     {
747         return exportBindings_->FindExportVariable(name);
748     }
749 
AddExportVariable(const util::StringView & name,Variable * var)750     bool AddExportVariable(const util::StringView &name, Variable *var)
751     {
752         return exportBindings_->AddExportVariable(name, var);
753     }
754 
AddExportVariable(const util::StringView & name)755     bool AddExportVariable(const util::StringView &name)
756     {
757         return exportBindings_->AddExportVariable(name, FindLocal(name));
758     }
759 
InExportBindings(const util::StringView & name)760     bool InExportBindings(const util::StringView &name) const
761     {
762         return exportBindings_->InExportBindings(name);
763     }
764 
AddDeclarationName(const util::StringView & name)765     void AddDeclarationName(const util::StringView &name)
766     {
767         variableNames_.insert(name);
768     }
769 
HasVariableName(const util::StringView & name)770     bool HasVariableName(const util::StringView &name) const
771     {
772         return variableNames_.find(name) != variableNames_.end();
773     }
774 
775 private:
776     ExportBindings *exportBindings_;
777     ArenaSet<util::StringView> variableNames_;
778 };
779 
780 class TSEnumScope : public FunctionScope {
781 public:
TSEnumScope(ArenaAllocator * allocator,Scope * parent,VariableMap * enumMemberBindings)782     explicit TSEnumScope(ArenaAllocator *allocator, Scope *parent, VariableMap *enumMemberBindings) : FunctionScope(
783         allocator, nullptr), enumMemberBindings_(enumMemberBindings), variableNames_(allocator->Adapter())
784     {
785         paramScope_ = allocator->New<FunctionParamScope>(allocator, parent);
786         paramScope_->BindFunctionScope(this);
787         SetParent(paramScope_);
788     }
789 
Type()790     ScopeType Type() const override
791     {
792         return ScopeType::TSENUM;
793     }
794 
FindEnumMemberVariable(const util::StringView & name)795     Variable *FindEnumMemberVariable(const util::StringView &name) const
796     {
797         auto res = enumMemberBindings_->find(name);
798         if (res == enumMemberBindings_->end()) {
799             return nullptr;
800         }
801         return res->second;
802     }
803 
AddDeclarationName(const util::StringView & name)804     void AddDeclarationName(const util::StringView &name)
805     {
806         variableNames_.insert(name);
807     }
808 
HasDeclarationName(const util::StringView & name)809     bool HasDeclarationName(const util::StringView &name) const
810     {
811         return variableNames_.find(name) != variableNames_.end();
812     }
813 
814     bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
815                     [[maybe_unused]] ScriptExtension extension) override;
816 
817 private:
818     VariableMap *enumMemberBindings_;
819     ArenaSet<util::StringView> variableNames_;
820 };
821 
DeclFlagToVariableFlag(DeclarationFlags declFlag)822 inline VariableFlags VariableScope::DeclFlagToVariableFlag(DeclarationFlags declFlag)
823 {
824     VariableFlags varFlag = VariableFlags::NONE;
825     if (declFlag & DeclarationFlags::EXPORT) {
826         varFlag = VariableFlags::LOCAL_EXPORT;
827     } else if (declFlag & DeclarationFlags::IMPORT) {
828         varFlag = VariableFlags::IMPORT;
829     }
830     return varFlag;
831 }
832 
833 template <typename T>
AddVar(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl)834 bool VariableScope::AddVar(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)
835 {
836     VariableFlags flags = VariableFlags::HOIST_VAR;
837     flags |= DeclFlagToVariableFlag(newDecl->Flags());
838 
839     if (!currentVariable) {
840         bindings_.insert({newDecl->Name(), allocator->New<T>(newDecl, flags)});
841         return true;
842     }
843 
844     switch (currentVariable->Declaration()->Type()) {
845         case DeclType::VAR: {
846             currentVariable->Reset(newDecl, flags);
847             break;
848         }
849         case DeclType::PARAM:
850         case DeclType::FUNC: {
851             break;
852         }
853         default: {
854             return false;
855         }
856     }
857 
858     return true;
859 }
860 
861 template <typename T>
AddFunction(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)862 bool VariableScope::AddFunction(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
863                                 [[maybe_unused]] ScriptExtension extension)
864 {
865     VariableFlags flags = (extension == ScriptExtension::JS) ? VariableFlags::HOIST_VAR : VariableFlags::HOIST;
866     flags |= DeclFlagToVariableFlag(newDecl->Flags());
867 
868     if (!currentVariable) {
869         bindings_.insert({newDecl->Name(), allocator->New<T>(newDecl, flags)});
870         return true;
871     }
872 
873     auto decl = currentVariable->Declaration();
874     if (decl->IsClassDecl() && decl->AsClassDecl()->IsDeclare()) {
875         newDecl->AsFunctionDecl()->SetDeclClass(decl->AsClassDecl());
876         bindings_[newDecl->Name()] = allocator->New<T>(newDecl, flags);
877         return true;
878     }
879 
880     if (extension != ScriptExtension::JS) {
881         return false;
882     }
883 
884     switch (currentVariable->Declaration()->Type()) {
885         case DeclType::VAR:
886         case DeclType::FUNC: {
887             currentVariable->Reset(newDecl, flags);
888             break;
889         }
890         default: {
891             return false;
892         }
893     }
894 
895     return true;
896 }
897 
898 template <typename T>
AddClass(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl)899 bool VariableScope::AddClass(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)
900 {
901     ASSERT(newDecl->IsClassDecl());
902 
903     VariableFlags flags = DeclFlagToVariableFlag(newDecl->Flags());
904 
905     if (!currentVariable) {
906         bindings_.insert({newDecl->Name(), allocator->New<T>(newDecl, flags)});
907         return true;
908     }
909 
910     auto decl = currentVariable->Declaration();
911     if (newDecl->AsClassDecl()->IsDeclare() && decl->IsFunctionDecl()) {
912         decl->AsFunctionDecl()->SetDeclClass(newDecl->AsClassDecl());
913         return true;
914     }
915 
916     return false;
917 }
918 
919 template <typename T>
AddTSBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,VariableFlags flags)920 bool VariableScope::AddTSBinding(ArenaAllocator *allocator, [[maybe_unused]] Variable *currentVariable, Decl *newDecl,
921                                  VariableFlags flags)
922 {
923     ASSERT(!currentVariable);
924     // TODO(xucheng): move the ts variables to tsBindings_
925     bindings_.insert({newDecl->Name(), allocator->New<T>(newDecl, flags)});
926     return true;
927 }
928 
929 template <typename T>
AddTSBinding(ArenaAllocator * allocator,Decl * newDecl,VariableFlags flags)930 bool VariableScope::AddTSBinding(ArenaAllocator *allocator, Decl *newDecl, VariableFlags flags)
931 {
932     switch (flags) {
933         case VariableFlags::NAMESPACE: {
934             return tsBindings_.AddTSVariable<TSBindingType::NAMESPACE>(
935                 newDecl->Name(), allocator->New<T>(newDecl, flags));
936         }
937         case VariableFlags::ENUM_LITERAL: {
938             return tsBindings_.AddTSVariable<TSBindingType::ENUMLITERAL>(
939                 newDecl->Name(), allocator->New<T>(newDecl, flags));
940         }
941         case VariableFlags::INTERFACE: {
942             return tsBindings_.AddTSVariable<TSBindingType::INTERFACE>(
943                 newDecl->Name(), allocator->New<T>(newDecl, flags));
944         }
945         case VariableFlags::IMPORT_EQUALS: {
946             return tsBindings_.AddTSVariable<TSBindingType::IMPORT_EQUALS>(
947                 newDecl->Name(), allocator->New<T>(newDecl, flags));
948         }
949         default: {
950             break;
951         }
952     }
953     return false;
954 }
955 
956 template <typename T>
AddLexical(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl)957 bool VariableScope::AddLexical(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)
958 {
959     VariableFlags flags = DeclFlagToVariableFlag(newDecl->Flags());
960 
961     if (currentVariable) {
962         return false;
963     }
964 
965     bindings_.insert({newDecl->Name(), allocator->New<T>(newDecl, flags)});
966     return true;
967 }
968 
969 template <typename T, typename... Args>
NewDecl(ArenaAllocator * allocator,Args &&...args)970 T *Scope::NewDecl(ArenaAllocator *allocator, Args &&... args)
971 {
972     T *decl = allocator->New<T>(std::forward<Args>(args)...);
973     decls_.push_back(decl);
974 
975     return decl;
976 }
977 
978 template <typename DeclType, typename VariableType>
AddDecl(ArenaAllocator * allocator,util::StringView name,VariableFlags flags)979 VariableType *Scope::AddDecl(ArenaAllocator *allocator, util::StringView name, VariableFlags flags)
980 {
981     if (FindLocal(name)) {
982         return nullptr;
983     }
984 
985     auto *decl = allocator->New<DeclType>(name);
986     auto *variable = allocator->New<VariableType>(decl, flags);
987 
988     decls_.push_back(decl);
989     bindings_.insert({decl->Name(), variable});
990 
991     return variable;
992 }
993 
994 template <typename DeclType, typename VariableType>
CreateVar(ArenaAllocator * allocator,util::StringView name,VariableFlags flags,const ir::AstNode * node)995 VariableType *Scope::CreateVar(ArenaAllocator *allocator, util::StringView name, VariableFlags flags,
996                                const ir::AstNode *node)
997 {
998     auto *decl = allocator->New<DeclType>(name);
999     auto *variable = allocator->New<VariableType>(decl, flags);
1000     decl->BindNode(node);
1001     return variable;
1002 }
1003 
1004 template <typename T, typename... Args>
PropagateBinding(ArenaAllocator * allocator,util::StringView name,Args &&...args)1005 void Scope::PropagateBinding(ArenaAllocator *allocator, util::StringView name, Args &&... args)
1006 {
1007     auto res = bindings_.find(name);
1008     if (res == bindings_.end()) {
1009         bindings_.insert({name, allocator->New<T>(std::forward<Args>(args)...)});
1010         return;
1011     }
1012 
1013     if (!res->second->Declaration()->IsParameterDecl()) {
1014         res->second->Reset(std::forward<Args>(args)...);
1015     }
1016 }
1017 
1018 }  // namespace panda::es2panda::binder
1019 
1020 #endif
1021