1 /**
2 * Copyright (c) 2021-2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef ES2PANDA_COMPILER_SCOPES_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
23 namespace ark::es2panda::checker {
24 class Type;
25 enum class PropertyType;
26 // NOLINTBEGIN(readability-redundant-declaration)
27 bool IsTypeError(Type const *tp);
28 // NOLINTEND(readability-redundant-declaration)
29 } // namespace ark::es2panda::checker
30
31 namespace ark::es2panda::varbinder {
32 class Decl;
33 class Scope;
34 class VariableScope;
35
36 // CC-OFFNXT(G.PRE.09) code gen
37 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
38 #define DECLARE_CLASSES(type, className) class className; // CC-OFF(G.PRE.02) name part
VARIABLE_TYPES(DECLARE_CLASSES)39 VARIABLE_TYPES(DECLARE_CLASSES)
40 #undef DECLARE_CLASSES
41
42 class Variable {
43 public:
44 virtual ~Variable() = default;
45 NO_COPY_SEMANTIC(Variable);
46 NO_MOVE_SEMANTIC(Variable);
47
48 VariableType virtual Type() const = 0;
49
50 /* CC-OFFNXT(G.PRE.06) solid logic */
51 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
52 #define DECLARE_CHECKS_CASTS(variableType, className) \
53 bool Is##className() const \
54 { \
55 /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed*/ \
56 return Type() == VariableType::variableType; /* CC-OFF(G.PRE.02) name part */ \
57 } \
58 /* CC-OFFNXT(G.PRE.02) name part */ \
59 className *As##className() \
60 { \
61 ES2PANDA_ASSERT(Is##className()); \
62 /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed*/ \
63 return reinterpret_cast<className *>(this); /* CC-OFF(G.PRE.02) name part */ \
64 } \
65 const className *As##className() const \
66 { \
67 ES2PANDA_ASSERT(Is##className()); \
68 /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed*/ \
69 return reinterpret_cast<const className *>(this); \
70 }
71 VARIABLE_TYPES(DECLARE_CHECKS_CASTS)
72 #undef DECLARE_CHECKS_CASTS
73
74 [[nodiscard]] const Decl *Declaration() const noexcept
75 {
76 return decl_;
77 }
78
79 [[nodiscard]] Decl *Declaration() noexcept
80 {
81 return decl_;
82 }
83
84 [[nodiscard]] VariableFlags Flags() const noexcept
85 {
86 return flags_;
87 }
88
89 [[nodiscard]] checker::Type *TsType() const
90 {
91 return tsType_;
92 }
93
94 [[nodiscard]] Scope *GetScope() const noexcept
95 {
96 return scope_;
97 }
98
99 checker::Type *SetTsType(checker::Type *tsType) noexcept
100 {
101 return (tsType_ = tsType);
102 }
103
104 void SetScope(varbinder::Scope *scope) noexcept
105 {
106 scope_ = scope;
107 }
108
109 void AddFlag(VariableFlags flag) noexcept
110 {
111 flags_ |= flag;
112 }
113
114 [[nodiscard]] bool HasFlag(VariableFlags flag) const noexcept
115 {
116 return (flags_ & flag) != 0;
117 }
118
119 void RemoveFlag(VariableFlags flag) noexcept
120 {
121 flags_ &= ~flag;
122 }
123
124 void Reset(Decl *decl, VariableFlags flags) noexcept
125 {
126 decl_ = decl;
127 flags_ = flags;
128 }
129
130 [[nodiscard]] bool LexicalBound() const noexcept
131 {
132 return HasFlag(VariableFlags::LEXICAL_BOUND);
133 }
134
135 [[nodiscard]] const util::StringView &Name() const;
136 virtual void SetLexical(Scope *scope) = 0;
137
138 protected:
139 explicit Variable(Decl *decl, VariableFlags flags) : decl_(decl), flags_(flags) {}
140 explicit Variable(VariableFlags flags) : flags_(flags) {}
141
142 // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
143 Decl *decl_ {};
144 VariableFlags flags_ {};
145 // NOLINTEND(misc-non-private-member-variables-in-classes)
146
147 private:
148 checker::Type *tsType_ {};
149 Scope *scope_ {};
150 };
151
152 class LocalVariable : public Variable {
153 public:
154 explicit LocalVariable(Decl *decl, VariableFlags flags);
155 explicit LocalVariable(VariableFlags flags);
156
Type()157 VariableType Type() const override
158 {
159 return VariableType::LOCAL;
160 }
161
BindVReg(compiler::VReg vreg)162 void BindVReg(compiler::VReg vreg)
163 {
164 ES2PANDA_ASSERT(!LexicalBound());
165 vreg_ = vreg;
166 }
167
BindLexEnvSlot(uint32_t slot)168 void BindLexEnvSlot(uint32_t slot)
169 {
170 ES2PANDA_ASSERT(!LexicalBound());
171 AddFlag(VariableFlags::LEXICAL_BOUND);
172 vreg_.SetIndex(slot);
173 }
174
Vreg()175 compiler::VReg Vreg() const
176 {
177 return vreg_;
178 }
179
Vreg()180 compiler::VReg &Vreg()
181 {
182 return vreg_;
183 }
184
LexIdx()185 uint32_t LexIdx() const
186 {
187 ES2PANDA_ASSERT(LexicalBound());
188 return vreg_.GetIndex();
189 }
190
191 void SetLexical([[maybe_unused]] Scope *scope) override;
192 LocalVariable *Copy(ArenaAllocator *allocator, Decl *decl) const;
193
194 private:
195 compiler::VReg vreg_ {};
196 };
197
198 class GlobalVariable : public Variable {
199 public:
GlobalVariable(Decl * decl,VariableFlags flags)200 explicit GlobalVariable(Decl *decl, VariableFlags flags) : Variable(decl, flags) {}
201
Type()202 VariableType Type() const override
203 {
204 return VariableType::GLOBAL;
205 }
206
207 void SetLexical([[maybe_unused]] Scope *scope) override;
208 };
209
210 class ModuleVariable : public Variable {
211 public:
ModuleVariable(Decl * decl,VariableFlags flags)212 explicit ModuleVariable(Decl *decl, VariableFlags flags) : Variable(decl, flags) {}
213
Type()214 VariableType Type() const override
215 {
216 return VariableType::MODULE;
217 }
218
ModuleReg()219 compiler::VReg &ModuleReg()
220 {
221 return moduleReg_;
222 }
223
ModuleReg()224 compiler::VReg ModuleReg() const
225 {
226 return moduleReg_;
227 }
228
ExoticName()229 const util::StringView &ExoticName() const
230 {
231 return exoticName_;
232 }
233
ExoticName()234 util::StringView &ExoticName()
235 {
236 return exoticName_;
237 }
238
239 void SetLexical([[maybe_unused]] Scope *scope) override;
240
241 private:
242 compiler::VReg moduleReg_ {};
243 util::StringView exoticName_ {};
244 };
245
246 class EnumVariable : public Variable {
247 public:
248 explicit EnumVariable(Decl *decl, bool backReference = false)
Variable(decl,VariableFlags::NONE)249 : Variable(decl, VariableFlags::NONE), backReference_(backReference)
250 {
251 }
252
Type()253 VariableType Type() const override
254 {
255 return VariableType::ENUM;
256 }
257
SetValue(EnumMemberResult value)258 void SetValue(EnumMemberResult value)
259 {
260 value_ = value;
261 }
262
Value()263 const EnumMemberResult &Value() const
264 {
265 return value_;
266 }
267
BackReference()268 bool BackReference() const
269 {
270 return backReference_;
271 }
272
SetBackReference()273 void SetBackReference()
274 {
275 backReference_ = true;
276 }
277
278 void ResetDecl(Decl *decl);
279
280 void SetLexical([[maybe_unused]] Scope *scope) override;
281
282 private:
283 EnumMemberResult value_ {};
284 bool backReference_ {};
285 };
286 } // namespace ark::es2panda::varbinder
287 #endif
288