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     }
99     SCOPE_TYPES(DECLARE_CHECKS_CASTS)
100 #undef DECLARE_CHECKS_CASTS
101 
IsVariableScope() const102     bool IsVariableScope() const
103     {
104         return Type() > ScopeType::LOCAL;
105     }
106 
IsFunctionVariableScope() const107     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() const118     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() const130     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) const153     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() const163     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() const178     const Scope *Parent() const
179     {
180         return parent_;
181     }
182 
ScopeStart() const183     const compiler::IRNode *ScopeStart() const
184     {
185         return startIns_;
186     }
187 
ScopeEnd() const188     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() const208     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, [[maybe_unused]] 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, [[maybe_unused]] 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() const250     const VariableMap &Bindings() const
251     {
252         return bindings_;
253     }
254 
OrderedBindings(ArenaAllocator *allocator) const255     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() const382     uint32_t LexicalSlots() const
383     {
384         return slotIndex_;
385     }
386 
NeedLexEnv() const387     bool NeedLexEnv() const
388     {
389         return slotIndex_ != 0;
390     }
391 
EvalBindings() const392     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:
423     ScopeType Type() const override
424     {
425         return ScopeType::PARAM;
426     }
427 
Params()428     ArenaVector<LocalVariable *> &Params()
429     {
430         return params_;
431     }
432 
Params() const433     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() const458     FunctionScope *GetFunctionScope() const
459     {
460         return functionScope_;
461     }
462 
BindFunctionScope(FunctionScope *funcScope)463     void BindFunctionScope(FunctionScope *funcScope)
464     {
465         functionScope_ = funcScope;
466     }
467 
NameVar() const468     LocalVariable *NameVar() const
469     {
470         return nameVar_;
471     }
472 
473     void BindName(ArenaAllocator *allocator, util::StringView name);
474 
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() const516     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 
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() const558     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 
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() const595     const util::StringView &Name() const
596     {
597         return name_;
598     }
599 
InternalName() const600     const util::StringView &InternalName() const
601     {
602         return internalName_;
603     }
604 
TypeAliasScope() const605     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 
634     ScopeType Type() const override
635     {
636         return ScopeType::CLASS;
637     }
638 
StaticDeclScope()639     LocalScope *StaticDeclScope()
640     {
641         return staticDeclScope_;
642     }
643 
StaticDeclScope() const644     const LocalScope *StaticDeclScope() const
645     {
646         return staticDeclScope_;
647     }
648 
StaticFieldScope()649     LocalScope *StaticFieldScope()
650     {
651         return staticFieldScope_;
652     }
653 
StaticFieldScope() const654     const LocalScope *StaticFieldScope() const
655     {
656         return staticFieldScope_;
657     }
658 
StaticMethodScope()659     LocalScope *StaticMethodScope()
660     {
661         return staticMethodScope_;
662     }
663 
StaticMethodScope() const664     const LocalScope *StaticMethodScope() const
665     {
666         return staticMethodScope_;
667     }
668 
InstanceFieldScope()669     LocalScope *InstanceFieldScope()
670     {
671         return instanceFieldScope_;
672     }
673 
InstanceFieldScope() const674     const LocalScope *InstanceFieldScope() const
675     {
676         return instanceFieldScope_;
677     }
678 
InstanceMethodScope()679     LocalScope *InstanceMethodScope()
680     {
681         return instanceMethodScope_;
682     }
683 
InstanceMethodScope() const684     const LocalScope *InstanceMethodScope() const
685     {
686         return instanceMethodScope_;
687     }
688 
InstanceDeclScope()689     LocalScope *InstanceDeclScope()
690     {
691         return instanceDeclScope_;
692     }
693 
InstanceDeclScope() const694     const LocalScope *InstanceDeclScope() const
695     {
696         return instanceDeclScope_;
697     }
698 
GetAndIncrementAnonymousClassIdx() const699     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() const723         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 
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 
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 
788     ScopeType Type() const override
789     {
790         return loopType_;
791     }
792 
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     {
821         // NOTE(kkonkuznetsov): currently LoopScope type has ScopeType::LOCAL
822         // therefore it does not respond to IsLoopScope() because it checks for type.
823         // This LOOP_SCOPE flag can be used to check that scope is actually a loop scope.
824         AddFlag(ScopeFlags::LOOP_SCOPE);
825     }
826 
DeclScope()827     LoopDeclarationScope *DeclScope()
828     {
829         return declScope_;
830     }
831 
BindDecls(LoopDeclarationScope *declScope)832     void BindDecls(LoopDeclarationScope *declScope)
833     {
834         declScope_ = declScope;
835         declScope_->loopScope_ = this;
836     }
837 
838     ScopeType Type() const override
839     {
840         return loopType_;
841     }
842 
843     void ConvertToVariableScope(ArenaAllocator *allocator);
844 
845     Variable *AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
846                          [[maybe_unused]] ScriptExtension extension) override
847     {
848         return AddLocal(allocator, currentVariable, newDecl, extension);
849     }
850 
851 protected:
852     // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
853     LoopDeclarationScope *declScope_ {};
854     ScopeType loopType_ {ScopeType::LOCAL};
855     // NOLINTEND(misc-non-private-member-variables-in-classes)
856 };
857 
858 class GlobalScope : public FunctionScope {
859 public:
GlobalScope(ArenaAllocator *allocator)860     explicit GlobalScope(ArenaAllocator *allocator)
861         : FunctionScope(allocator, nullptr), foreignBindings_(allocator->Adapter())
862     {
863         auto *paramScope = allocator->New<FunctionParamScope>(allocator, this);
864         paramScope_ = paramScope;
865         paramScope_->BindFunctionScope(this);
866     }
867 
868     ScopeType Type() const override
869     {
870         return ScopeType::GLOBAL;
871     }
872 
873     Variable *AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
874                          [[maybe_unused]] ScriptExtension extension) override;
875 
876     InsertResult InsertBinding(const util::StringView &name, Variable *var) override;
877     InsertResult TryInsertBinding(const util::StringView &name, Variable *var) override;
878     void MergeBindings(VariableMap const &bindings) override;
879     VariableMap::size_type EraseBinding(const util::StringView &name) override;
880 
881     InsertResult InsertForeignBinding(const util::StringView &name, Variable *var);
882     [[nodiscard]] bool IsForeignBinding(const util::StringView &name) const;
883 
884     InsertResult InsertDynamicBinding(const util::StringView &name, Variable *var);
885 
886 private:
887     InsertResult InsertImpl(const util::StringView &name, Variable *var, bool isForeign, bool isDynamic);
888 
889     ArenaUnorderedMap<util::StringView, bool> foreignBindings_;
890 };
891 
892 class ModuleScope : public GlobalScope {
893 public:
894     template <typename K, typename V>
895     using ModuleEntry = ArenaVector<std::pair<K, V>>;
896     using ImportDeclList = ArenaVector<ImportDecl *>;
897     using ExportDeclList = ArenaVector<ExportDecl *>;
898     using LocalExportNameMap = ArenaMultiMap<varbinder::Variable *, util::StringView>;
899 
ModuleScope(ArenaAllocator *allocator)900     explicit ModuleScope(ArenaAllocator *allocator)
901         : GlobalScope(allocator),
902           allocator_(allocator),
903           imports_(allocator_->Adapter()),
904           exports_(allocator_->Adapter()),
905           localExports_(allocator_->Adapter())
906     {
907     }
908 
909     ScopeType Type() const override
910     {
911         return ScopeType::MODULE;
912     }
913 
Imports() const914     const ModuleEntry<ir::ImportDeclaration *, ImportDeclList> &Imports() const
915     {
916         return imports_;
917     }
918 
Exports() const919     const ModuleEntry<ir::AstNode *, ExportDeclList> &Exports() const
920     {
921         return exports_;
922     }
923 
LocalExports() const924     const LocalExportNameMap &LocalExports() const
925     {
926         return localExports_;
927     }
928 
929     void AddImportDecl(ir::ImportDeclaration *importDecl, ImportDeclList &&decls);
930 
931     void AddExportDecl(ir::AstNode *exportDecl, ExportDecl *decl);
932 
933     void AddExportDecl(ir::AstNode *exportDecl, ExportDeclList &&decls);
934 
935     Variable *AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
936                          [[maybe_unused]] ScriptExtension extension) override;
937 
938     bool ExportAnalysis();
939 
940 private:
941     Variable *AddImport(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl);
942 
943     ArenaAllocator *allocator_;
944     ModuleEntry<ir::ImportDeclaration *, ImportDeclList> imports_;
945     ModuleEntry<ir::AstNode *, ExportDeclList> exports_;
946     LocalExportNameMap localExports_;
947 };
948 
949 template <typename T>
AddVar(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)950 Variable *VariableScope::AddVar(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)
951 {
952     if (!currentVariable) {
953         return InsertBinding(newDecl->Name(), allocator->New<T>(newDecl, VariableFlags::HOIST_VAR)).first->second;
954     }
955 
956     switch (currentVariable->Declaration()->Type()) {
957         case DeclType::VAR: {
958             currentVariable->Reset(newDecl, VariableFlags::HOIST_VAR);
959             [[fallthrough]];
960         }
961         case DeclType::PARAM:
962         case DeclType::FUNC: {
963             return currentVariable;
964         }
965         default: {
966             return nullptr;
967         }
968     }
969 }
970 
971 template <typename T>
AddFunction(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)972 Variable *VariableScope::AddFunction(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
973                                      [[maybe_unused]] ScriptExtension extension)
974 {
975     VariableFlags flags = (extension == ScriptExtension::JS) ? VariableFlags::HOIST_VAR : VariableFlags::HOIST;
976 
977     if (!currentVariable) {
978         return InsertBinding(newDecl->Name(), allocator->New<T>(newDecl, flags)).first->second;
979     }
980 
981     if (extension != ScriptExtension::JS || IsModuleScope()) {
982         return nullptr;
983     }
984 
985     switch (currentVariable->Declaration()->Type()) {
986         case DeclType::VAR:
987         case DeclType::FUNC: {
988             currentVariable->Reset(newDecl, VariableFlags::HOIST_VAR);
989             return currentVariable;
990         }
991         default: {
992             return nullptr;
993         }
994     }
995 }
996 
997 template <typename T>
AddTSBinding(ArenaAllocator *allocator, [[maybe_unused]] Variable *currentVariable, Decl *newDecl, VariableFlags flags)998 Variable *VariableScope::AddTSBinding(ArenaAllocator *allocator, [[maybe_unused]] Variable *currentVariable,
999                                       Decl *newDecl, VariableFlags flags)
1000 {
1001     ASSERT(!currentVariable);
1002     return InsertBinding(newDecl->Name(), allocator->New<T>(newDecl, flags)).first->second;
1003 }
1004 
1005 template <typename T>
AddLexical(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)1006 Variable *VariableScope::AddLexical(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)
1007 {
1008     if (currentVariable) {
1009         return nullptr;
1010     }
1011 
1012     return InsertBinding(newDecl->Name(), allocator->New<T>(newDecl, VariableFlags::NONE)).first->second;
1013 }
1014 
1015 template <typename T, typename... Args>
NewDecl(ArenaAllocator *allocator, Args &&...args)1016 T *Scope::NewDecl(ArenaAllocator *allocator, Args &&...args)
1017 {
1018     T *decl = allocator->New<T>(std::forward<Args>(args)...);
1019     decls_.push_back(decl);
1020 
1021     return decl;
1022 }
1023 
1024 template <typename DeclType, typename VariableType>
AddDecl(ArenaAllocator *allocator, util::StringView name, VariableFlags flags)1025 VariableType *Scope::AddDecl(ArenaAllocator *allocator, util::StringView name, VariableFlags flags)
1026 {
1027     if (FindLocal(name, varbinder::ResolveBindingOptions::BINDINGS)) {
1028         return nullptr;
1029     }
1030 
1031     auto *decl = allocator->New<DeclType>(name);
1032     auto *variable = allocator->New<VariableType>(decl, flags);
1033 
1034     decls_.push_back(decl);
1035     bindings_.insert({decl->Name(), variable});
1036     variable->SetScope(this);
1037 
1038     return variable;
1039 }
1040 
1041 template <typename DeclType, typename VariableType>
CreateVar(ArenaAllocator *allocator, util::StringView name, VariableFlags flags, ir::AstNode *node)1042 VariableType *Scope::CreateVar(ArenaAllocator *allocator, util::StringView name, VariableFlags flags, ir::AstNode *node)
1043 {
1044     auto *decl = allocator->New<DeclType>(name);
1045     auto *variable = allocator->New<VariableType>(decl, flags);
1046     decl->BindNode(node);
1047     return variable;
1048 }
1049 
1050 template <typename T, typename... Args>
PropagateBinding(ArenaAllocator *allocator, util::StringView name, Args &&...args)1051 Variable *Scope::PropagateBinding(ArenaAllocator *allocator, util::StringView name, Args &&...args)
1052 {
1053     auto res = bindings_.find(name);
1054     if (res == bindings_.end()) {
1055         return bindings_.insert({name, allocator->New<T>(std::forward<Args>(args)...)}).first->second;
1056     }
1057 
1058     res->second->Reset(std::forward<Args>(args)...);
1059     return res->second;
1060 }
1061 }  // namespace ark::es2panda::varbinder
1062 
1063 #endif
1064