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_VARIABLE_H
17#define ES2PANDA_COMPILER_SCOPES_VARIABLE_H
18
19#include <binder/enumMemberResult.h>
20#include <binder/variableFlags.h>
21#include <ir/irnode.h>
22#include <macros.h>
23#include <util/patchFix.h>
24#include <util/ustring.h>
25
26#include <limits>
27
28namespace panda::es2panda::checker {
29class Type;
30}  // namespace panda::es2panda::checker
31
32namespace panda::es2panda::binder {
33
34class Decl;
35class Scope;
36class VariableScope;
37class ExportBindings;
38class Variable;
39
40using VariableMap = ArenaMap<util::StringView, Variable *>;
41
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    virtual VariableType Type() const = 0;
53
54#define DECLARE_CHECKS_CASTS(variableType, className)     \
55    bool Is##className() const                            \
56    {                                                     \
57        return Type() == VariableType::variableType;      \
58    }                                                     \
59    className *As##className()                            \
60    {                                                     \
61        ASSERT(Is##className());                          \
62        return reinterpret_cast<className *>(this);       \
63    }                                                     \
64    const className *As##className() const                \
65    {                                                     \
66        ASSERT(Is##className());                          \
67        return reinterpret_cast<const className *>(this); \
68    }
69    VARIABLE_TYPES(DECLARE_CHECKS_CASTS)
70#undef DECLARE_CHECKS_CASTS
71
72    Decl *Declaration() const
73    {
74        return decl_;
75    }
76
77    VariableFlags Flags() const
78    {
79        return flags_;
80    }
81
82    checker::Type *TsType() const
83    {
84        return tsType_;
85    }
86
87    void SetTsType(checker::Type *tsType)
88    {
89        tsType_ = tsType;
90    }
91
92    void AddFlag(VariableFlags flag)
93    {
94        flags_ |= flag;
95    }
96
97    bool HasFlag(VariableFlags flag) const
98    {
99        return (flags_ & flag) != 0;
100    }
101
102    void RemoveFlag(VariableFlags flag)
103    {
104        flags_ &= ~flag;
105    }
106
107    void Reset(Decl *decl, VariableFlags flags)
108    {
109        decl_ = decl;
110        flags_ = flags;
111    }
112
113    bool LexicalBound() const
114    {
115        return HasFlag(VariableFlags::LEXICAL_BOUND);
116    }
117
118    bool InSendableEnv() const
119    {
120        return HasFlag(VariableFlags::IN_SENDABLE_ENV);
121    }
122
123    const util::StringView &Name() const;
124    virtual void SetLexical(Scope *scope, util::PatchFix *patchFixHelper = nullptr) = 0;
125
126protected:
127    explicit Variable(Decl *decl, VariableFlags flags) : decl_(decl), flags_(flags) {}
128
129    Decl *decl_;
130    VariableFlags flags_ {};
131    checker::Type *tsType_ {};
132};
133
134class LocalVariable : public Variable {
135public:
136    explicit LocalVariable(Decl *decl, VariableFlags flags);
137
138    VariableType Type() const override
139    {
140        return VariableType::LOCAL;
141    }
142
143    void BindVReg(compiler::VReg vreg)
144    {
145        ASSERT(!LexicalBound());
146        vreg_ = vreg;
147    }
148
149    void BindLexEnvSlot(uint32_t slot)
150    {
151        ASSERT(!LexicalBound());
152        AddFlag(VariableFlags::LEXICAL_BOUND);
153        vreg_ = slot;
154    }
155
156    compiler::VReg Vreg() const
157    {
158        return vreg_;
159    }
160
161    uint32_t LexIdx() const
162    {
163        ASSERT(LexicalBound());
164        return vreg_;
165    }
166
167    void SetLexical([[maybe_unused]] Scope *scope, [[maybe_unused]] util::PatchFix *patchFixHelper = nullptr) override;
168    LocalVariable *Copy(ArenaAllocator *allocator, Decl *decl) const;
169
170private:
171    uint32_t vreg_ {};
172};
173
174class GlobalVariable : public Variable {
175public:
176    explicit GlobalVariable(Decl *decl, VariableFlags flags) : Variable(decl, flags) {}
177
178    VariableType Type() const override
179    {
180        return VariableType::GLOBAL;
181    }
182
183    void SetLexical([[maybe_unused]] Scope *scope, [[maybe_unused]] util::PatchFix *patchFixHelper = nullptr) override;
184};
185
186class ModuleVariable : public Variable {
187public:
188    explicit ModuleVariable(Decl *decl, VariableFlags flags) : Variable(decl, flags) {}
189
190    VariableType Type() const override
191    {
192        return VariableType::MODULE;
193    }
194
195    void SetLexical([[maybe_unused]] Scope *scope, [[maybe_unused]] util::PatchFix *patchFixHelper = nullptr) override;
196
197    void AssignIndex(uint32_t index)
198    {
199        index_ = index;
200    }
201
202    uint32_t Index() const
203    {
204        return index_;
205    }
206
207private:
208    uint32_t index_ {0};
209};
210
211class EnumVariable : public Variable {
212public:
213    explicit EnumVariable(Decl *decl, bool backReference = false)
214        : Variable(decl, VariableFlags::NONE), backReference_(backReference)
215    {
216    }
217
218    VariableType Type() const override
219    {
220        return VariableType::ENUM;
221    }
222
223    void SetValue(EnumMemberResult value)
224    {
225        value_ = value;
226    }
227
228    const EnumMemberResult &Value() const
229    {
230        return value_;
231    }
232
233    bool BackReference() const
234    {
235        return backReference_;
236    }
237
238    void SetBackReference()
239    {
240        backReference_ = true;
241    }
242
243    bool IsVisited() const
244    {
245        return isVisited_;
246    }
247
248    void SetVisited()
249    {
250        isVisited_ = true;
251    }
252
253    bool StringInit() const
254    {
255        return isStringInit_;
256    }
257
258    void SetStringInit()
259    {
260        isStringInit_ = true;
261    }
262
263    void ResetDecl(Decl *decl);
264
265    void SetLexical([[maybe_unused]] Scope *scope, [[maybe_unused]] util::PatchFix *patchFixHelper = nullptr) override;
266
267private:
268    EnumMemberResult value_ {false};
269    bool backReference_ {};
270    bool isVisited_ {false};
271    bool isStringInit_ {false};
272};
273
274class NamespaceVariable : public Variable {
275public:
276    explicit NamespaceVariable(Decl *decl, VariableFlags flags) : Variable(decl, flags) {}
277
278    VariableType Type() const override
279    {
280        return VariableType::NAMESPACE;
281    }
282
283    void SetLexical([[maybe_unused]] Scope *scope, [[maybe_unused]] util::PatchFix *patchFixHelper = nullptr) override;
284
285    ExportBindings *GetExportBindings()
286    {
287        return exportBindings_;
288    }
289
290    const ExportBindings *GetExportBindings() const
291    {
292        return exportBindings_;
293    }
294
295    void SetExportBindings(ExportBindings *exportBindings)
296    {
297        exportBindings_ = exportBindings;
298    }
299
300private:
301    ExportBindings *exportBindings_ {nullptr};
302};
303
304class EnumLiteralVariable : public Variable {
305public:
306    explicit EnumLiteralVariable(Decl *decl, VariableFlags flags) : Variable(decl, flags) {}
307
308    VariableType Type() const override
309    {
310        return VariableType::ENUMLITERAL;
311    }
312
313    void SetLexical([[maybe_unused]] Scope *scope, [[maybe_unused]] util::PatchFix *patchFixHelper = nullptr) override;
314
315    VariableMap *GetEnumMembers() const
316    {
317        return enumMemberBindings_;
318    }
319
320    Variable *FindEnumMemberVariable(const util::StringView &name) const
321    {
322        auto res = enumMemberBindings_->find(name);
323        if (res == enumMemberBindings_->end()) {
324            return nullptr;
325        }
326        return res->second;
327    }
328
329    void SetEnumMembers(VariableMap *enumMemberBindings)
330    {
331        enumMemberBindings_ = enumMemberBindings;
332    }
333
334private:
335    VariableMap *enumMemberBindings_ {nullptr};
336};
337
338class ImportEqualsVariable : public Variable {
339public:
340    explicit ImportEqualsVariable(Decl *decl, VariableFlags flags) : Variable(decl, flags) {}
341
342    VariableType Type() const override
343    {
344        return VariableType::IMPORT_EQUALS;
345    }
346
347    void SetLexical([[maybe_unused]] Scope *scope, [[maybe_unused]] util::PatchFix *patchFixHelper = nullptr) override;
348
349    Scope *GetScope()
350    {
351        return scope_;
352    }
353
354    void SetScope(Scope *scope)
355    {
356        scope_ = scope;
357    }
358
359private:
360    Scope *scope_ {nullptr};
361};
362
363}  // namespace panda::es2panda::binder
364#endif
365