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