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