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_VARIABLE_H
17#define ES2PANDA_COMPILER_SCOPES_VARIABLE_H
18
19#include "varbinder/enumMemberResult.h"
20#include "varbinder/variableFlags.h"
21#include "ir/irnode.h"
22#include "macros.h"
23#include "util/ustring.h"
24
25#include <limits>
26
27namespace ark::es2panda::checker {
28class Type;
29enum class PropertyType;
30// NOLINTBEGIN(readability-redundant-declaration)
31bool IsTypeError(Type const *tp);
32[[noreturn]] void ThrowEmptyError();
33// NOLINTEND(readability-redundant-declaration)
34}  // namespace ark::es2panda::checker
35
36namespace ark::es2panda::varbinder {
37class Decl;
38class Scope;
39class VariableScope;
40
41// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
42#define DECLARE_CLASSES(type, className) class className;
43VARIABLE_TYPES(DECLARE_CLASSES)
44#undef DECLARE_CLASSES
45
46class Variable {
47public:
48    virtual ~Variable() = default;
49    NO_COPY_SEMANTIC(Variable);
50    NO_MOVE_SEMANTIC(Variable);
51
52    VariableType virtual Type() const = 0;
53
54// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
55#define DECLARE_CHECKS_CASTS(variableType, className)     \
56    bool Is##className() const                            \
57    {                                                     \
58        return Type() == VariableType::variableType;      \
59    }                                                     \
60    className *As##className()                            \
61    {                                                     \
62        ASSERT(Is##className());                          \
63        return reinterpret_cast<className *>(this);       \
64    }                                                     \
65    const className *As##className() const                \
66    {                                                     \
67        ASSERT(Is##className());                          \
68        return reinterpret_cast<const className *>(this); \
69    }
70    VARIABLE_TYPES(DECLARE_CHECKS_CASTS)
71#undef DECLARE_CHECKS_CASTS
72
73    [[nodiscard]] const Decl *Declaration() const noexcept
74    {
75        return decl_;
76    }
77
78    [[nodiscard]] Decl *Declaration() noexcept
79    {
80        return decl_;
81    }
82
83    [[nodiscard]] VariableFlags Flags() const noexcept
84    {
85        return flags_;
86    }
87
88    [[nodiscard]] checker::Type *TsType() const
89    {
90        if (UNLIKELY(IsTypeError(tsType_))) {
91            checker::ThrowEmptyError();
92        }
93        return tsType_;
94    }
95
96    [[nodiscard]] checker::Type *TsTypeOrError() const noexcept
97    {
98        return tsType_;
99    }
100
101    [[nodiscard]] Scope *GetScope() const noexcept
102    {
103        return scope_;
104    }
105
106    void SetTsType(checker::Type *tsType) noexcept
107    {
108        tsType_ = tsType;
109    }
110
111    void SetScope(varbinder::Scope *scope) noexcept
112    {
113        scope_ = scope;
114    }
115
116    void AddFlag(VariableFlags flag) noexcept
117    {
118        flags_ |= flag;
119    }
120
121    [[nodiscard]] bool HasFlag(VariableFlags flag) const noexcept
122    {
123        return (flags_ & flag) != 0;
124    }
125
126    void RemoveFlag(VariableFlags flag) noexcept
127    {
128        flags_ &= ~flag;
129    }
130
131    void Reset(Decl *decl, VariableFlags flags) noexcept
132    {
133        decl_ = decl;
134        flags_ = flags;
135    }
136
137    [[nodiscard]] bool LexicalBound() const noexcept
138    {
139        return HasFlag(VariableFlags::LEXICAL_BOUND);
140    }
141
142    [[nodiscard]] const util::StringView &Name() const;
143    virtual void SetLexical(Scope *scope) = 0;
144
145protected:
146    explicit Variable(Decl *decl, VariableFlags flags) : decl_(decl), flags_(flags) {}
147    explicit Variable(VariableFlags flags) : flags_(flags) {}
148
149    // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
150    Decl *decl_ {};
151    VariableFlags flags_ {};
152    // NOLINTEND(misc-non-private-member-variables-in-classes)
153
154private:
155    checker::Type *tsType_ {};
156    Scope *scope_ {};
157};
158
159class LocalVariable : public Variable {
160public:
161    explicit LocalVariable(Decl *decl, VariableFlags flags);
162    explicit LocalVariable(VariableFlags flags);
163
164    VariableType Type() const override
165    {
166        return VariableType::LOCAL;
167    }
168
169    void BindVReg(compiler::VReg vreg)
170    {
171        ASSERT(!LexicalBound());
172        vreg_ = vreg;
173    }
174
175    void BindLexEnvSlot(uint32_t slot)
176    {
177        ASSERT(!LexicalBound());
178        AddFlag(VariableFlags::LEXICAL_BOUND);
179        vreg_.SetIndex(slot);
180    }
181
182    compiler::VReg Vreg() const
183    {
184        return vreg_;
185    }
186
187    compiler::VReg &Vreg()
188    {
189        return vreg_;
190    }
191
192    uint32_t LexIdx() const
193    {
194        ASSERT(LexicalBound());
195        return vreg_.GetIndex();
196    }
197
198    void SetLexical([[maybe_unused]] Scope *scope) override;
199    LocalVariable *Copy(ArenaAllocator *allocator, Decl *decl) const;
200
201private:
202    compiler::VReg vreg_ {};
203};
204
205class GlobalVariable : public Variable {
206public:
207    explicit GlobalVariable(Decl *decl, VariableFlags flags) : Variable(decl, flags) {}
208
209    VariableType Type() const override
210    {
211        return VariableType::GLOBAL;
212    }
213
214    void SetLexical([[maybe_unused]] Scope *scope) override;
215};
216
217class ModuleVariable : public Variable {
218public:
219    explicit ModuleVariable(Decl *decl, VariableFlags flags) : Variable(decl, flags) {}
220
221    VariableType Type() const override
222    {
223        return VariableType::MODULE;
224    }
225
226    compiler::VReg &ModuleReg()
227    {
228        return moduleReg_;
229    }
230
231    compiler::VReg ModuleReg() const
232    {
233        return moduleReg_;
234    }
235
236    const util::StringView &ExoticName() const
237    {
238        return exoticName_;
239    }
240
241    util::StringView &ExoticName()
242    {
243        return exoticName_;
244    }
245
246    void SetLexical([[maybe_unused]] Scope *scope) override;
247
248private:
249    compiler::VReg moduleReg_ {};
250    util::StringView exoticName_ {};
251};
252
253class EnumVariable : public Variable {
254public:
255    explicit EnumVariable(Decl *decl, bool backReference = false)
256        : Variable(decl, VariableFlags::NONE), backReference_(backReference)
257    {
258    }
259
260    VariableType Type() const override
261    {
262        return VariableType::ENUM;
263    }
264
265    void SetValue(EnumMemberResult value)
266    {
267        value_ = value;
268    }
269
270    const EnumMemberResult &Value() const
271    {
272        return value_;
273    }
274
275    bool BackReference() const
276    {
277        return backReference_;
278    }
279
280    void SetBackReference()
281    {
282        backReference_ = true;
283    }
284
285    void ResetDecl(Decl *decl);
286
287    void SetLexical([[maybe_unused]] Scope *scope) override;
288
289private:
290    EnumMemberResult value_ {};
291    bool backReference_ {};
292};
293}  // namespace ark::es2panda::varbinder
294#endif
295