1/**
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#ifndef ES2PANDA_COMPILER_SCOPES_SCOPE_H
17#define ES2PANDA_COMPILER_SCOPES_SCOPE_H
18
19#include <binder/declaration.h>
20#include <binder/variable.h>
21#include <parser/program/program.h>
22#include <util/enumbitops.h>
23#include <util/ustring.h>
24
25#include <map>
26#include <unordered_map>
27#include <vector>
28
29namespace panda::es2panda::compiler {
30class IRNode;
31} // namespace panda::es2panda::compiler
32
33namespace panda::es2panda::ir {
34class ScriptFunction;
35class Statement;
36} // namespace panda::es2panda::ir
37
38namespace panda::es2panda::parser {
39class Program;
40} // namespace panda::es2panda::parser
41
42namespace panda::es2panda::binder {
43
44#define DECLARE_CLASSES(type, className) class className;
45SCOPE_TYPES(DECLARE_CLASSES)
46#undef DECLARE_CLASSES
47
48class Scope;
49class VariableScope;
50class Variable;
51
52using VariableMap = ArenaMap<util::StringView, Variable *>;
53
54class TSBindings {
55public:
56    explicit TSBindings(ArenaAllocator *allocator) : allocator_(allocator) {}
57
58    template <TSBindingType type>
59    bool AddTSVariable(const util::StringView &name, Variable *variable)
60    {
61        static_assert(type < TSBindingType::COUNT);
62        size_t index = GetIndex(type);
63        if (tsBindings_[index] == nullptr) {
64            tsBindings_[index] = allocator_->New<VariableMap>(allocator_->Adapter());
65        }
66        return tsBindings_[index]->insert({name, variable}).second;
67    }
68
69    template <TSBindingType type>
70    Variable *FindTSVariable(const util::StringView &name) const
71    {
72        static_assert(type < TSBindingType::COUNT);
73        size_t index = GetIndex(type);
74        if (tsBindings_[index] == nullptr) {
75            return nullptr;
76        }
77        auto res = tsBindings_[index]->find(name);
78        if (res == tsBindings_[index]->end()) {
79            return nullptr;
80        }
81        return res->second;
82    }
83
84    bool InTSBindings(const util::StringView &name) const
85    {
86        for (size_t i = 0; i < GetIndex(TSBindingType::COUNT); i++) {
87            if (tsBindings_[i] && tsBindings_[i]->find(name) != tsBindings_[i]->end()) {
88                return true;
89            }
90        }
91        return false;
92    }
93
94private:
95    size_t GetIndex(TSBindingType type) const
96    {
97        return static_cast<size_t>(type);
98    }
99
100    ArenaAllocator *allocator_;
101    std::array<VariableMap *, static_cast<size_t>(TSBindingType::COUNT)> tsBindings_ {};
102};
103
104class ExportBindings {
105public:
106    explicit ExportBindings(ArenaAllocator *allocator)
107        : exportBindings_(allocator->Adapter()),
108          exportTSBindings_(allocator)
109    {
110    }
111
112    Variable *FindExportVariable(const util::StringView &name) const
113    {
114        auto res = exportBindings_.find(name);
115        if (res == exportBindings_.end()) {
116            return nullptr;
117        }
118        return res->second;
119    }
120
121    bool AddExportVariable(const util::StringView &name, Variable *var)
122    {
123        return exportBindings_.insert({name, var}).second;
124    }
125
126    bool InExportBindings(const util::StringView &name) const
127    {
128        auto res = FindExportVariable(name);
129        return res != nullptr || exportTSBindings_.InTSBindings(name);
130    }
131
132    template <TSBindingType type>
133    Variable *FindExportTSVariable(const util::StringView &name) const
134    {
135        return exportTSBindings_.FindTSVariable<type>(name);
136    }
137
138    template <TSBindingType type>
139    bool AddExportTSVariable(const util::StringView &name, Variable *var)
140    {
141        return exportTSBindings_.AddTSVariable<type>(name, var);
142    }
143
144private:
145    VariableMap exportBindings_;
146    TSBindings exportTSBindings_;
147};
148
149class ScopeFindResult {
150public:
151    ScopeFindResult() = default;
152    ScopeFindResult(util::StringView n, Scope *s, uint32_t l, Variable *v)
153        : ScopeFindResult(n, s, l, l, l, v, nullptr)
154    {
155    }
156    ScopeFindResult(Scope *s, uint32_t l, uint32_t ll, Variable *v) : scope(s), level(l), lexLevel(ll), variable(v) {}
157    ScopeFindResult(util::StringView n, Scope *s, uint32_t l, uint32_t ll, uint32_t sl,
158                    Variable *v, ir::ScriptFunction *c)
159        : name(n), scope(s), level(l), lexLevel(ll), sendableLevel(sl), variable(v), concurrentFunc(c)
160    {
161    }
162
163    util::StringView name {};
164    Scope *scope {};
165    uint32_t level {};
166    uint32_t lexLevel {};
167    uint32_t sendableLevel {};
168    Variable *variable {};
169    ir::ScriptFunction *concurrentFunc {};
170};
171
172class Result {
173public:
174    uint32_t slot;
175    bool isMethod;
176    bool isStatic;
177    bool isGetter;
178    bool isSetter;
179    uint32_t validateMethodSlot;
180};
181
182class PrivateNameFindResult {
183public:
184    int32_t lexLevel;
185    Result result;
186};
187
188
189class Scope {
190public:
191    virtual ~Scope() = default;
192    NO_COPY_SEMANTIC(Scope);
193    NO_MOVE_SEMANTIC(Scope);
194
195    virtual ScopeType Type() const = 0;
196
197#define DECLARE_CHECKS_CASTS(scopeType, className)        \
198    bool Is##className() const                            \
199    {                                                     \
200        return Type() == ScopeType::scopeType;            \
201    }                                                     \
202    className *As##className()                            \
203    {                                                     \
204        ASSERT(Is##className());                          \
205        return reinterpret_cast<className *>(this);       \
206    }                                                     \
207    const className *As##className() const                \
208    {                                                     \
209        ASSERT(Is##className());                          \
210        return reinterpret_cast<const className *>(this); \
211    }
212    SCOPE_TYPES(DECLARE_CHECKS_CASTS)
213#undef DECLARE_CHECKS_CASTS
214
215    virtual bool IsVariableScope() const
216    {
217        return Type() > ScopeType::LOCAL;
218    }
219
220    bool IsFunctionVariableScope() const
221    {
222        return Type() >= ScopeType::FUNCTION;
223    }
224
225    FunctionScope *AsFunctionVariableScope()
226    {
227        ASSERT(IsFunctionVariableScope());
228        return reinterpret_cast<FunctionScope *>(this);
229    }
230
231    const FunctionScope *AsFunctionVariableScope() const
232    {
233        ASSERT(IsFunctionVariableScope());
234        return reinterpret_cast<const FunctionScope *>(this);
235    }
236
237    VariableScope *AsVariableScope()
238    {
239        ASSERT(IsVariableScope());
240        return reinterpret_cast<VariableScope *>(this);
241    }
242
243    const VariableScope *AsVariableScope() const
244    {
245        ASSERT(IsVariableScope());
246        return reinterpret_cast<const VariableScope *>(this);
247    }
248
249    VariableScope *EnclosingVariableScope();
250
251    FunctionScope *EnclosingFunctionVariableScope();
252
253    const ArenaVector<Decl *> &Decls() const
254    {
255        return decls_;
256    }
257
258    Scope *Parent()
259    {
260        return parent_;
261    }
262
263    const Scope *Parent() const
264    {
265        return parent_;
266    }
267
268    void SetParent(Scope *parent)
269    {
270        parent_ = parent;
271        SetTopScope();
272    }
273
274    const compiler::IRNode *ScopeStart() const
275    {
276        return startIns_;
277    }
278
279    const compiler::IRNode *ScopeEnd() const
280    {
281        return endIns_;
282    }
283
284    void SetScopeStart(const compiler::IRNode *ins)
285    {
286        startIns_ = ins;
287    }
288
289    void SetScopeEnd(const compiler::IRNode *ins)
290    {
291        endIns_ = ins;
292    }
293
294    const ir::AstNode *Node() const
295    {
296        return node_;
297    }
298
299    ir::AstNode *Node()
300    {
301        return node_;
302    }
303
304    void BindNode(ir::AstNode *node)
305    {
306        node_ = node;
307    }
308
309    bool AddDecl(ArenaAllocator *allocator, Decl *decl, [[maybe_unused]] ScriptExtension extension)
310    {
311        CHECK_NOT_NULL(decl);
312        decls_.push_back(decl);
313        return AddBinding(allocator, FindLocal(decl->Name()), decl, extension);
314    }
315
316    bool AddTsDecl(ArenaAllocator *allocator, Decl *decl, [[maybe_unused]] ScriptExtension extension)
317    {
318        decls_.push_back(decl);
319        return AddBinding(allocator, FindLocal(decl->Name(), ResolveBindingOptions::ALL), decl, extension);
320    }
321
322    virtual bool HasParamScope()
323    {
324        return false;
325    }
326
327    template <typename T, typename... Args>
328    T *NewDecl(ArenaAllocator *allocator, Args &&... args);
329
330    template <typename DeclType, typename VariableType>
331    VariableType *AddDecl(ArenaAllocator *allocator, util::StringView name, VariableFlags flags);
332
333    template <typename DeclType = binder::LetDecl, typename VariableType = binder::LocalVariable>
334    static VariableType *CreateVar(ArenaAllocator *allocator, util::StringView name, VariableFlags flags,
335                                   const ir::AstNode *node);
336
337    template <typename T, typename... Args>
338    void PropagateBinding(ArenaAllocator *allocator, util::StringView name, Args &&... args);
339
340    VariableMap &Bindings()
341    {
342        return bindings_;
343    }
344
345    const VariableMap &Bindings() const
346    {
347        return bindings_;
348    }
349
350    virtual bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
351                            [[maybe_unused]] ScriptExtension extension) = 0;
352
353    Variable *FindLocal(const util::StringView &name,
354                        ResolveBindingOptions options = ResolveBindingOptions::BINDINGS) const;
355
356    ScopeFindResult Find(const util::StringView &name,
357                         ResolveBindingOptions options = ResolveBindingOptions::BINDINGS) const;
358
359    std::pair<uint32_t, uint32_t> Find(const ir::Expression *expr, bool onlyLevel = false) const;
360
361    PrivateNameFindResult FindPrivateName(const util::StringView &name, bool isSetter = false) const;
362
363    Decl *FindDecl(const util::StringView &name) const;
364
365    bool HasVarDecl(const util::StringView &name) const;
366
367    void CalculateLevelInCorrespondingFunctionScope(const FunctionParamScope *scope, uint32_t &lexLevel,
368                                                    uint32_t &sendableLevel) const;
369
370    template <TSBindingType type>
371    Variable *FindLocalTSVariable(const util::StringView &name) const
372    {
373        return tsBindings_.FindTSVariable<type>(name);
374    }
375
376    template <TSBindingType type>
377    void AddLocalTSVariable(const util::StringView &name, Variable *var)
378    {
379        tsBindings_.AddTSVariable<type>(name, var);
380    }
381
382    bool InLocalTSBindings(const util::StringView &name) const
383    {
384        return tsBindings_.InTSBindings(name);
385    }
386
387    virtual const util::StringView &GetFullScopeName()
388    {
389        // Most scopes have no scopeName therefore their fullScopeNames should be got from their parents
390        if (parent_) {
391            return parent_->GetFullScopeName();
392        }
393        return fullScopeName_;
394    }
395
396    virtual uint32_t GetDuplicateScopeIndex(const util::StringView &childScopeName)
397    {
398        // Most sub class has no scope name, so as duplicate index, need to get from parent.
399        if (parent_) {
400            return parent_->GetDuplicateScopeIndex(childScopeName);
401        }
402
403        return 0;
404    }
405
406    virtual void SetSelfScopeName(const util::StringView &ident)
407    {
408        if (hasSelfScopeNameSet_) {
409            return;
410        }
411        hasSelfScopeNameSet_ = true;
412
413        if (!util::Helpers::IsSpecialScopeName(ident)) {
414            selfScopeName_ = ident;
415        }
416
417        Scope *parent = GetParentWithScopeName();
418        if (parent != nullptr) {
419            std::stringstream selfScopeName;
420            selfScopeName << GetScopeTag() << selfScopeName_;
421            scopeDuplicateIndex_ = parent->GetDuplicateScopeIndex(
422                util::UString(selfScopeName.str(), allocator_).View());
423        }
424    }
425
426    ArenaUnorderedMap<util::StringView, int32_t> &GetScopeNames()
427    {
428        return topScope_->scopeNames_;
429    }
430
431protected:
432    explicit Scope(ArenaAllocator *allocator, Scope *parent)
433        : parent_(parent),
434          decls_(allocator->Adapter()),
435          bindings_(allocator->Adapter()),
436          tsBindings_(allocator),
437          scopesIndex_(allocator->Adapter()),
438          scopeNames_(allocator->Adapter()),
439          allocator_(allocator)
440    {
441        SetTopScope();
442    }
443
444    /**
445     * @return true - if the variable is shadowed
446     *         false - otherwise
447     */
448    using VariableVisitior = std::function<bool(const Variable *)>;
449
450    /**
451     * @return true - if the variable is shadowed
452     *         false - otherwise
453     */
454    std::tuple<Scope *, bool> IterateShadowedVariables(const util::StringView &name, const VariableVisitior &visitor);
455
456    bool AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
457                  [[maybe_unused]] ScriptExtension extension);
458
459    void SetFullScopeNames();
460
461    void SetTopScope()
462    {
463        if (parent_) {
464            topScope_ = parent_->GetTopScope();
465        } else {
466            topScope_ = this;
467        }
468    }
469
470    void OptimizeSelfScopeName(std::stringstream &selfScopeStream);
471
472    virtual Scope *GetParentWithScopeName()
473    {
474        return parent_;
475    }
476
477    virtual util::StringView GetSelfScopeName()
478    {
479        if (hasSelfScopeNameSet_) {
480            return selfScopeName_;
481        }
482
483        std::stringstream scopeName;
484
485        if (scopeDuplicateIndex_ > 0) {
486            scopeName << util::Helpers::DUPLICATED_SEPERATOR <<
487                         std::hex << scopeDuplicateIndex_;
488        }
489
490        return util::UString(scopeName.str(), allocator_).View();
491    }
492
493    Scope *GetTopScope()
494    {
495        return topScope_;
496    }
497
498    Scope *parent_ {};
499    Scope *topScope_ {};
500    ArenaVector<Decl *> decls_;
501    VariableMap bindings_;
502    TSBindings tsBindings_;
503    ir::AstNode *node_ {};
504    const compiler::IRNode *startIns_ {};
505    const compiler::IRNode *endIns_ {};
506    ArenaUnorderedMap<util::StringView, uint32_t> scopesIndex_;
507    ArenaUnorderedMap<util::StringView, int32_t> scopeNames_;
508    util::StringView fullScopeName_ {};
509    ArenaAllocator *allocator_ {};
510    uint32_t scopeDuplicateIndex_ = 0;
511    util::StringView selfScopeName_ {};
512    bool hasSelfScopeNameSet_ { false };
513    bool hasFullScopeNameSet_ { false };
514
515private:
516    virtual util::StringView GetScopeTag()
517    {
518        return util::UString(util::Helpers::STRING_EMPTY.data(), allocator_).View();
519    }
520};
521
522class VariableScope : public Scope {
523public:
524    ~VariableScope() override = default;
525    NO_COPY_SEMANTIC(VariableScope);
526    NO_MOVE_SEMANTIC(VariableScope);
527
528    void AddFlag(VariableScopeFlags flag)
529    {
530        flags_ |= flag;
531    }
532
533    void ClearFlag(VariableScopeFlags flag)
534    {
535        flags_ &= ~flag;
536    }
537
538    bool HasFlag(VariableScopeFlags flag) const
539    {
540        return (flags_ & flag) != 0;
541    }
542
543    void RestoreFuncMain0LexEnv(uint32_t slotSize)
544    {
545        slotIndex_ = slotSize;
546    }
547
548    uint32_t NextSlot()
549    {
550        return slotIndex_++;
551    }
552
553    uint32_t NextSendableSlot()
554    {
555        return sendableSlotIndex_++;
556    }
557
558    uint32_t LexicalSlots() const
559    {
560        return slotIndex_;
561    }
562
563    uint32_t SendableSlots() const
564    {
565        return sendableSlotIndex_;
566    }
567
568    bool NeedLexEnv() const
569    {
570        return slotIndex_ != 0;
571    }
572
573    bool NeedSendableEnv() const
574    {
575        return sendableSlotIndex_ != 0;
576    }
577
578    void AddLexicalVarNameAndType(uint32_t slot, util::StringView name, int type)
579    {
580        lexicalVarNameAndTypes_.emplace(slot, std::pair<util::StringView, int>(name, type));
581    }
582
583    ArenaMap<uint32_t, std::pair<util::StringView, int>> &GetLexicalVarNameAndTypes()
584    {
585        return lexicalVarNameAndTypes_;
586    }
587
588protected:
589    explicit VariableScope(ArenaAllocator *allocator, Scope *parent) : Scope(allocator, parent),
590                                                                       lexicalVarNameAndTypes_(allocator->Adapter()) {}
591
592    inline VariableFlags DeclFlagToVariableFlag(DeclarationFlags declFlag);
593
594    template <typename T>
595    bool AddVar(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl);
596
597    template <typename T>
598    bool AddFunction(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
599                     [[maybe_unused]] ScriptExtension extension);
600
601    template <typename T>
602    bool AddClass(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl);
603
604    template <typename T>
605    bool AddTSBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags);
606
607    template <typename T>
608    bool AddTSBinding(ArenaAllocator *allocator, Decl *newDecl, VariableFlags flags);
609
610    template <typename T>
611    bool AddLexical(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl);
612
613    VariableScopeFlags flags_ {};
614    uint32_t slotIndex_ {};
615    uint32_t sendableSlotIndex_ {};
616    ArenaMap<uint32_t, std::pair<util::StringView, int>> lexicalVarNameAndTypes_; // for debuginfo and patchFix
617};
618
619class ParamScope : public Scope {
620public:
621    ScopeType Type() const override
622    {
623        return ScopeType::PARAM;
624    }
625
626    ArenaVector<LocalVariable *> &Params()
627    {
628        return params_;
629    }
630
631    const ArenaVector<LocalVariable *> &Params() const
632    {
633        return params_;
634    }
635
636    bool HasParam(util::StringView name) const
637    {
638        for (auto *param : params_) {
639            if (param->Name() == name) {
640                return true;
641            }
642        }
643
644        return false;
645    }
646
647    std::tuple<ParameterDecl *, const ir::AstNode *> AddParamDecl(ArenaAllocator *allocator, const ir::AstNode *param);
648
649protected:
650    explicit ParamScope(ArenaAllocator *allocator, Scope *parent)
651        : Scope(allocator, parent), params_(allocator->Adapter())
652    {
653    }
654
655    bool AddParam(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags);
656
657    ArenaVector<LocalVariable *> params_;
658};
659
660class FunctionScope;
661
662class FunctionParamScope : public ParamScope {
663public:
664    explicit FunctionParamScope(ArenaAllocator *allocator, Scope *parent) : ParamScope(allocator, parent) {}
665
666    FunctionScope *GetFunctionScope() const
667    {
668        return functionScope_;
669    }
670
671    void BindFunctionScope(FunctionScope *funcScope)
672    {
673        functionScope_ = funcScope;
674    }
675
676    LocalVariable *NameVar() const
677    {
678        return nameVar_;
679    }
680
681    void BindName(ArenaAllocator *allocator, util::StringView name);
682
683    ScopeType Type() const override
684    {
685        return ScopeType::FUNCTION_PARAM;
686    }
687
688    bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
689                    [[maybe_unused]] ScriptExtension extension) override;
690
691    void RemoveThisParam(const std::string_view &thisParam)
692    {
693        params_.erase(params_.begin());
694        bindings_.erase(thisParam);
695    }
696
697    const util::StringView &GetFullScopeName() override;
698    uint32_t GetDuplicateScopeIndex(const util::StringView &childScopeName) override;
699
700    friend class FunctionScope;
701    template <typename E, typename T>
702    friend class ScopeWithParamScope;
703
704private:
705    FunctionScope *functionScope_ {};
706    LocalVariable *nameVar_ {};
707};
708
709template <typename E, typename T>
710class ScopeWithParamScope : public E {
711public:
712    explicit ScopeWithParamScope(ArenaAllocator *allocator, Scope *parent) : E(allocator, parent) {}
713
714    void BindParamScope(T *paramScope)
715    {
716        CHECK_NOT_NULL(paramScope);
717        AssignParamScope(paramScope);
718        this->bindings_ = paramScope->Bindings();
719    }
720
721    void AssignParamScope(T *paramScope)
722    {
723        ASSERT(this->parent_ == paramScope);
724        ASSERT(this->bindings_.empty());
725
726        paramScope_ = paramScope;
727    }
728
729    T *ParamScope()
730    {
731        return paramScope_;
732    }
733
734    const T *ParamScope() const
735    {
736        return paramScope_;
737    }
738
739    void AddBindsFromParam()
740    {
741        ASSERT(paramScope_);
742        this->bindings_.insert(paramScope_->Bindings().begin(), paramScope_->Bindings().end());
743    }
744
745    bool HasParamScope() override
746    {
747        return true;
748    }
749
750protected:
751    T *paramScope_ {nullptr};
752};
753
754class FunctionScope : public ScopeWithParamScope<VariableScope, FunctionParamScope> {
755public:
756    explicit FunctionScope(ArenaAllocator *allocator, Scope *parent) : ScopeWithParamScope(allocator, parent) {}
757
758    ScopeType Type() const override
759    {
760        return ScopeType::FUNCTION;
761    }
762
763    virtual void BindNameWithScopeInfo(util::StringView name, util::StringView recordName);
764
765    void BindName(util::StringView name, util::StringView internalName)
766    {
767        name_ = name;
768        internalName_ = internalName;
769    }
770
771    const util::StringView &Name() const
772    {
773        return name_;
774    }
775
776    const util::StringView &InternalName() const
777    {
778        return internalName_;
779    }
780
781    bool InFunctionScopes() const
782    {
783        return inFunctionScopes_;
784    }
785
786    void SetInFunctionScopes()
787    {
788        inFunctionScopes_ = true;
789    }
790
791    bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
792                    [[maybe_unused]] ScriptExtension extension) override;
793
794    void SetSelfScopeName(const util::StringView &ident) override;
795
796    const util::StringView &GetFullScopeName() override
797    {
798        SetFullScopeNames();
799        return fullScopeName_;
800    }
801
802    uint32_t GetDuplicateScopeIndex(const util::StringView &childScopeName) override
803    {
804        auto it = scopesIndex_.find(childScopeName);
805        if (it == scopesIndex_.end()) {
806            scopesIndex_.insert({childScopeName, 0});
807            return 0;
808        } else {
809            return ++it->second;
810        }
811    }
812
813protected:
814    util::StringView GetSelfScopeName() override;
815
816    Scope *GetParentWithScopeName() override
817    {
818        Scope *parentScope = parent_;
819        // FunctionParamScope has the same scope name with functionScope
820        // But functionParamScope is the parent of functionScope, it should be skipped here.
821        if ((parentScope != nullptr) && (parentScope->IsFunctionParamScope())) {
822            parentScope = parentScope->Parent();
823        }
824
825        return parentScope;
826    }
827
828    util::StringView name_ {};
829    util::StringView internalName_ {};
830
831private:
832    util::StringView GetScopeTag() override;
833
834    bool inFunctionScopes_ {false};
835};
836
837class LocalScope : public Scope {
838public:
839    explicit LocalScope(ArenaAllocator *allocator, Scope *parent) : Scope(allocator, parent) {}
840
841    ScopeType Type() const override
842    {
843        return ScopeType::LOCAL;
844    }
845
846    bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
847                    [[maybe_unused]] ScriptExtension extension) override;
848};
849
850class ClassScope : public VariableScope {
851public:
852    explicit ClassScope(ArenaAllocator *allocator, Scope *parent)
853        : VariableScope(allocator, parent),
854          computedNames_(allocator->Adapter()),
855          privateNames_(allocator->Adapter()),
856          privateGetters_(allocator->Adapter()),
857          privateSetters_(allocator->Adapter())
858    {
859    }
860
861    ~ClassScope() override = default;
862
863    bool IsVariableScope() const override;
864
865    ScopeType Type() const override
866    {
867        return ScopeType::CLASS;
868    }
869
870    void AddClassVariable(const ir::Expression *key)
871    {
872        computedNames_.insert({key, slotIndex_++});
873    }
874
875    uint32_t GetSlot(const ir::Expression *key) const
876    {
877        ASSERT(computedNames_.find(key) != computedNames_.end());
878        return computedNames_.find(key)->second;
879    }
880
881    bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
882                    [[maybe_unused]] ScriptExtension extension) override
883    {
884        return AddLocal(allocator, currentVariable, newDecl, extension);
885    }
886
887    bool HasPrivateName(const util::StringView &name) const
888    {
889        return (privateNames_.count(name) + privateGetters_.count(name) + privateSetters_.count(name) != 0);
890    }
891
892    const util::StringView &GetFullScopeName() override
893    {
894        SetFullScopeNames();
895        return fullScopeName_;
896    }
897
898    uint32_t GetDuplicateScopeIndex(const util::StringView &childScopeName) override
899    {
900        auto it = scopesIndex_.find(childScopeName);
901        if (it == scopesIndex_.end()) {
902            scopesIndex_.insert({childScopeName, 0});
903            return 0;
904        } else {
905            return ++it->second;
906        }
907    }
908
909    Result GetPrivateProperty(const util::StringView &name, bool isSetter) const;
910    void AddPrivateName(std::vector<const ir::Statement *> privateProperties, uint32_t privateFieldCnt,
911                        uint32_t instancePrivateMethodCnt, uint32_t staticPrivateMethodCnt);
912    friend class ir::ClassDefinition;
913
914protected:
915    util::StringView GetSelfScopeName() override;
916
917private:
918    util::StringView GetScopeTag() override;
919
920    bool IsMethod(uint32_t slot) const
921    {
922        return slot >= instancePrivateMethodStartSlot_ && slot < privateMethodEndSlot_;
923    }
924
925    bool IsStaticMethod(uint32_t slot) const
926    {
927        return slot >= staticPrivateMethodStartSlot_;
928    }
929
930    ArenaUnorderedMap<const ir::Expression *, uint32_t> computedNames_;
931    ArenaUnorderedMap<util::StringView, uint32_t> privateNames_;
932    ArenaUnorderedMap<util::StringView, uint32_t> privateGetters_;
933    ArenaUnorderedMap<util::StringView, uint32_t> privateSetters_;
934    uint32_t privateFieldCnt_ {0};
935    uint32_t instancePrivateMethodStartSlot_ {0};
936    uint32_t staticPrivateMethodStartSlot_ {0};
937    uint32_t privateMethodEndSlot_ {0};
938    uint32_t instanceMethodValidation_ {0};
939    uint32_t staticMethodValidation_ {0};
940};
941
942class CatchParamScope : public ParamScope {
943public:
944    explicit CatchParamScope(ArenaAllocator *allocator, Scope *parent) : ParamScope(allocator, parent) {}
945
946    ScopeType Type() const override
947    {
948        return ScopeType::CATCH_PARAM;
949    }
950
951    bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
952                    [[maybe_unused]] ScriptExtension extension) override;
953
954    friend class CatchScope;
955};
956
957class CatchScope : public ScopeWithParamScope<LocalScope, CatchParamScope> {
958public:
959    explicit CatchScope(ArenaAllocator *allocator, Scope *parent) : ScopeWithParamScope(allocator, parent) {}
960
961    ScopeType Type() const override
962    {
963        return ScopeType::CATCH;
964    }
965
966    bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
967                    [[maybe_unused]] ScriptExtension extension) override;
968};
969
970class LoopScope : public VariableScope {
971public:
972    explicit LoopScope(ArenaAllocator *allocator, Scope *parent) : VariableScope(allocator, parent) {}
973
974    ScopeType Type() const override
975    {
976        return loopType_;
977    }
978
979    void InitVariable();
980
981    bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
982                    [[maybe_unused]] ScriptExtension extension) override
983    {
984        return AddLocal(allocator, currentVariable, newDecl, extension);
985    }
986
987protected:
988    ScopeType loopType_ {ScopeType::LOOP};
989};
990
991class StaticBlockScope : public VariableScope {
992public:
993    explicit StaticBlockScope(ArenaAllocator *allocator, Scope *parent) : VariableScope(allocator, parent) {}
994
995    ScopeType Type() const override
996    {
997        return staticBlockType_;
998    }
999
1000    bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
1001                    [[maybe_unused]] ScriptExtension extension) override
1002    {
1003        return AddLocal(allocator, currentVariable, newDecl, extension);
1004    }
1005
1006protected:
1007    ScopeType staticBlockType_ {ScopeType::STATIC_BLOCK};
1008};
1009
1010class GlobalScope : public FunctionScope {
1011public:
1012    explicit GlobalScope(ArenaAllocator *allocator) : FunctionScope(allocator, nullptr)
1013    {
1014        paramScope_ = allocator->New<FunctionParamScope>(allocator, this);
1015    }
1016
1017    ScopeType Type() const override
1018    {
1019        return ScopeType::GLOBAL;
1020    }
1021
1022    bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
1023                    [[maybe_unused]] ScriptExtension extension) override;
1024
1025    void SetSelfScopeName([[maybe_unused]] const util::StringView &ident) override;
1026
1027    void BindNameWithScopeInfo(util::StringView name, util::StringView recordName) override
1028    {
1029        // only func_main_0 will call BindNameWithScopeInfo() of GlobalScope
1030        name_ = name;
1031        std::stringstream internalName;
1032        internalName << recordName << name;
1033        internalName_ = util::UString(internalName.str(), allocator_).View();
1034    }
1035
1036    const util::StringView &GetFullScopeName() override
1037    {
1038        return fullScopeName_;
1039    }
1040};
1041
1042class ModuleScope : public FunctionScope {
1043public:
1044    explicit ModuleScope(ArenaAllocator *allocator, parser::Program *program) : FunctionScope(allocator, nullptr)
1045    {
1046        paramScope_ = allocator->New<FunctionParamScope>(allocator, this);
1047        program_ = program;
1048    }
1049
1050    ScopeType Type() const override
1051    {
1052        return ScopeType::MODULE;
1053    }
1054
1055    const parser::Program *Program() const
1056    {
1057        return program_;
1058    }
1059
1060    void AssignIndexToModuleVariable(util::StringView name, uint32_t index);
1061
1062    void ConvertLocalVariableToModuleVariable(ArenaAllocator *allocator, util::StringView localName);
1063
1064    bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
1065                    [[maybe_unused]] ScriptExtension extension) override;
1066
1067    void SetSelfScopeName([[maybe_unused]] const util::StringView &ident) override;
1068
1069    void BindNameWithScopeInfo(util::StringView name, util::StringView recordName) override
1070    {
1071        // only func_main_0 will call BindNameWithScopeInfo() of ModuleScope
1072        name_ = name;
1073        std::stringstream internalName;
1074        internalName << recordName << name;
1075        internalName_ = util::UString(internalName.str(), allocator_).View();
1076    }
1077
1078    const util::StringView &GetFullScopeName() override
1079    {
1080        return fullScopeName_;
1081    }
1082
1083private:
1084    parser::Program *program_ {nullptr};
1085};
1086
1087class TSModuleScope : public FunctionScope {
1088public:
1089    explicit TSModuleScope(ArenaAllocator *allocator, Scope *parent, ExportBindings *exportBindings)
1090        : FunctionScope(allocator, nullptr), exportBindings_(exportBindings), variableNames_(allocator->Adapter())
1091    {
1092        paramScope_ = allocator->New<FunctionParamScope>(allocator, parent);
1093        CHECK_NOT_NULL(paramScope_);
1094        paramScope_->BindFunctionScope(this);
1095        SetParent(paramScope_);
1096    }
1097
1098    ScopeType Type() const override
1099    {
1100        return ScopeType::TSMODULE;
1101    }
1102
1103    template <TSBindingType type>
1104    Variable *FindExportTSVariable(const util::StringView &name) const
1105    {
1106        return exportBindings_->FindExportTSVariable<type>(name);
1107    }
1108
1109    template <TSBindingType type>
1110    bool AddExportTSVariable(const util::StringView &name, Variable *var)
1111    {
1112        return exportBindings_->AddExportTSVariable<type>(name, var);
1113    }
1114
1115    Variable *FindExportVariable(const util::StringView &name) const
1116    {
1117        return exportBindings_->FindExportVariable(name);
1118    }
1119
1120    bool AddExportVariable(const util::StringView &name, Variable *var)
1121    {
1122        return exportBindings_->AddExportVariable(name, var);
1123    }
1124
1125    bool AddExportVariable(const util::StringView &name)
1126    {
1127        return exportBindings_->AddExportVariable(name, FindLocal(name));
1128    }
1129
1130    bool InExportBindings(const util::StringView &name) const
1131    {
1132        return exportBindings_->InExportBindings(name);
1133    }
1134
1135    void AddDeclarationName(const util::StringView &name)
1136    {
1137        variableNames_.insert(name);
1138    }
1139
1140    bool HasVariableName(const util::StringView &name) const
1141    {
1142        return variableNames_.find(name) != variableNames_.end();
1143    }
1144
1145protected:
1146    util::StringView GetSelfScopeName() override;
1147
1148private:
1149    util::StringView GetScopeTag() override;
1150
1151    ExportBindings *exportBindings_;
1152    ArenaSet<util::StringView> variableNames_;
1153};
1154
1155class TSEnumScope : public FunctionScope {
1156public:
1157    explicit TSEnumScope(ArenaAllocator *allocator, Scope *parent, VariableMap *enumMemberBindings) : FunctionScope(
1158        allocator, nullptr), enumMemberBindings_(enumMemberBindings), variableNames_(allocator->Adapter())
1159    {
1160        paramScope_ = allocator->New<FunctionParamScope>(allocator, parent);
1161        CHECK_NOT_NULL(paramScope_);
1162        paramScope_->BindFunctionScope(this);
1163        SetParent(paramScope_);
1164        scopeDuplicateIndex_ = parent->GetDuplicateScopeIndex(GetScopeTag());
1165    }
1166
1167    ScopeType Type() const override
1168    {
1169        return ScopeType::TSENUM;
1170    }
1171
1172    Variable *FindEnumMemberVariable(const util::StringView &name) const
1173    {
1174        auto res = enumMemberBindings_->find(name);
1175        if (res == enumMemberBindings_->end()) {
1176            return nullptr;
1177        }
1178        return res->second;
1179    }
1180
1181    void AddDeclarationName(const util::StringView &name)
1182    {
1183        variableNames_.insert(name);
1184    }
1185
1186    bool HasDeclarationName(const util::StringView &name) const
1187    {
1188        return variableNames_.find(name) != variableNames_.end();
1189    }
1190
1191    bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
1192                    [[maybe_unused]] ScriptExtension extension) override;
1193
1194    void SetSelfScopeName(const util::StringView &ident) override;
1195
1196protected:
1197    util::StringView GetSelfScopeName() override;
1198
1199private:
1200    util::StringView GetScopeTag() override;
1201
1202    VariableMap *enumMemberBindings_;
1203    ArenaSet<util::StringView> variableNames_;
1204};
1205
1206inline VariableFlags VariableScope::DeclFlagToVariableFlag(DeclarationFlags declFlag)
1207{
1208    VariableFlags varFlag = VariableFlags::NONE;
1209    if (declFlag & DeclarationFlags::EXPORT) {
1210        varFlag = VariableFlags::LOCAL_EXPORT;
1211    } else if (declFlag & DeclarationFlags::IMPORT) {
1212        varFlag = VariableFlags::IMPORT;
1213    }
1214    return varFlag;
1215}
1216
1217template <typename T>
1218bool VariableScope::AddVar(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)
1219{
1220    VariableFlags flags = VariableFlags::HOIST_VAR;
1221    flags |= DeclFlagToVariableFlag(newDecl->Flags());
1222
1223    if (!currentVariable) {
1224        bindings_.insert({newDecl->Name(), allocator->New<T>(newDecl, flags)});
1225        return true;
1226    }
1227
1228    switch (currentVariable->Declaration()->Type()) {
1229        case DeclType::VAR: {
1230            currentVariable->Reset(newDecl, flags);
1231            break;
1232        }
1233        case DeclType::PARAM:
1234        case DeclType::FUNC: {
1235            break;
1236        }
1237        default: {
1238            return false;
1239        }
1240    }
1241
1242    return true;
1243}
1244
1245template <typename T>
1246bool VariableScope::AddFunction(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
1247                                [[maybe_unused]] ScriptExtension extension)
1248{
1249    VariableFlags flags = (extension == ScriptExtension::JS) ? VariableFlags::HOIST_VAR : VariableFlags::HOIST;
1250    flags |= DeclFlagToVariableFlag(newDecl->Flags());
1251
1252    if (!currentVariable) {
1253        bindings_.insert({newDecl->Name(), allocator->New<T>(newDecl, flags)});
1254        return true;
1255    }
1256
1257    auto decl = currentVariable->Declaration();
1258    if (decl->IsClassDecl() && decl->AsClassDecl()->IsDeclare()) {
1259        newDecl->AsFunctionDecl()->SetDeclClass(decl->AsClassDecl());
1260        bindings_[newDecl->Name()] = allocator->New<T>(newDecl, flags);
1261        return true;
1262    }
1263
1264    if (extension != ScriptExtension::JS) {
1265        return false;
1266    }
1267
1268    switch (currentVariable->Declaration()->Type()) {
1269        case DeclType::VAR:
1270        case DeclType::FUNC: {
1271            currentVariable->Reset(newDecl, flags);
1272            break;
1273        }
1274        default: {
1275            return false;
1276        }
1277    }
1278
1279    return true;
1280}
1281
1282template <typename T>
1283bool VariableScope::AddClass(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)
1284{
1285    ASSERT(newDecl->IsClassDecl());
1286
1287    VariableFlags flags = DeclFlagToVariableFlag(newDecl->Flags());
1288
1289    if (!currentVariable) {
1290        bindings_.insert({newDecl->Name(), allocator->New<T>(newDecl, flags)});
1291        return true;
1292    }
1293
1294    auto decl = currentVariable->Declaration();
1295    if (newDecl->AsClassDecl()->IsDeclare() && decl->IsFunctionDecl()) {
1296        decl->AsFunctionDecl()->SetDeclClass(newDecl->AsClassDecl());
1297        return true;
1298    }
1299
1300    return false;
1301}
1302
1303template <typename T>
1304bool VariableScope::AddTSBinding(ArenaAllocator *allocator, [[maybe_unused]] Variable *currentVariable, Decl *newDecl,
1305                                 VariableFlags flags)
1306{
1307    ASSERT(!currentVariable);
1308    // TODO(xucheng): move the ts variables to tsBindings_
1309    bindings_.insert({newDecl->Name(), allocator->New<T>(newDecl, flags)});
1310    return true;
1311}
1312
1313template <typename T>
1314bool VariableScope::AddTSBinding(ArenaAllocator *allocator, Decl *newDecl, VariableFlags flags)
1315{
1316    switch (flags) {
1317        case VariableFlags::NAMESPACE: {
1318            return tsBindings_.AddTSVariable<TSBindingType::NAMESPACE>(
1319                newDecl->Name(), allocator->New<T>(newDecl, flags));
1320        }
1321        case VariableFlags::ENUM_LITERAL: {
1322            return tsBindings_.AddTSVariable<TSBindingType::ENUMLITERAL>(
1323                newDecl->Name(), allocator->New<T>(newDecl, flags));
1324        }
1325        case VariableFlags::INTERFACE: {
1326            return tsBindings_.AddTSVariable<TSBindingType::INTERFACE>(
1327                newDecl->Name(), allocator->New<T>(newDecl, flags));
1328        }
1329        case VariableFlags::IMPORT_EQUALS: {
1330            return tsBindings_.AddTSVariable<TSBindingType::IMPORT_EQUALS>(
1331                newDecl->Name(), allocator->New<T>(newDecl, flags));
1332        }
1333        default: {
1334            break;
1335        }
1336    }
1337    return false;
1338}
1339
1340template <typename T>
1341bool VariableScope::AddLexical(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)
1342{
1343    VariableFlags flags = DeclFlagToVariableFlag(newDecl->Flags());
1344
1345    if (currentVariable) {
1346        return false;
1347    }
1348
1349    bindings_.insert({newDecl->Name(), allocator->New<T>(newDecl, flags)});
1350    return true;
1351}
1352
1353template <typename T, typename... Args>
1354T *Scope::NewDecl(ArenaAllocator *allocator, Args &&... args)
1355{
1356    T *decl = allocator->New<T>(std::forward<Args>(args)...);
1357    decls_.push_back(decl);
1358
1359    return decl;
1360}
1361
1362template <typename DeclType, typename VariableType>
1363VariableType *Scope::AddDecl(ArenaAllocator *allocator, util::StringView name, VariableFlags flags)
1364{
1365    if (FindLocal(name)) {
1366        return nullptr;
1367    }
1368
1369    auto *decl = allocator->New<DeclType>(name);
1370    auto *variable = allocator->New<VariableType>(decl, flags);
1371    CHECK_NOT_NULL(decl);
1372    CHECK_NOT_NULL(variable);
1373
1374    decls_.push_back(decl);
1375    bindings_.insert({decl->Name(), variable});
1376
1377    return variable;
1378}
1379
1380template <typename DeclType, typename VariableType>
1381VariableType *Scope::CreateVar(ArenaAllocator *allocator, util::StringView name, VariableFlags flags,
1382                               const ir::AstNode *node)
1383{
1384    auto *decl = allocator->New<DeclType>(name);
1385    CHECK_NOT_NULL(decl);
1386    auto *variable = allocator->New<VariableType>(decl, flags);
1387    CHECK_NOT_NULL(variable);
1388    decl->BindNode(node);
1389    return variable;
1390}
1391
1392template <typename T, typename... Args>
1393void Scope::PropagateBinding(ArenaAllocator *allocator, util::StringView name, Args &&... args)
1394{
1395    auto res = bindings_.find(name);
1396    if (res == bindings_.end()) {
1397        bindings_.insert({name, allocator->New<T>(std::forward<Args>(args)...)});
1398        return;
1399    }
1400
1401    if (!res->second->Declaration()->IsParameterDecl()) {
1402        res->second->Reset(std::forward<Args>(args)...);
1403    }
1404}
1405
1406}  // namespace panda::es2panda::binder
1407
1408#endif
1409