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