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