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