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_VARBINDER_RECORDTABLE_H
17#define ES2PANDA_VARBINDER_RECORDTABLE_H
18
19#include "macros.h"
20#include "utils/arena_containers.h"
21#include "util/ustring.h"
22#include "util/enumbitops.h"
23
24namespace ark::es2panda::parser {
25class Program;
26}  // namespace ark::es2panda::parser
27
28namespace ark::es2panda::checker {
29class Signature;
30}  // namespace ark::es2panda::checker
31
32namespace ark::es2panda::ir {
33class ClassDefinition;
34class TSInterfaceDeclaration;
35class Identifier;
36}  // namespace ark::es2panda::ir
37
38namespace ark::es2panda::varbinder {
39class FunctionScope;
40class BoundContext;
41
42using ENUMBITOPS_OPERATORS;
43
44enum class RecordTableFlags : uint32_t {
45    NONE = 0U,
46    EXTERNAL = 1U << 0U,
47};
48
49}  // namespace ark::es2panda::varbinder
50
51template <>
52struct enumbitops::IsAllowedType<ark::es2panda::varbinder::RecordTableFlags> : std::true_type {
53};
54
55namespace ark::es2panda::varbinder {
56
57class RecordTable {
58public:
59    explicit RecordTable(ArenaAllocator *allocator, parser::Program *program, RecordTableFlags flags)
60        : classDefinitions_(allocator->Adapter()),
61          interfaceDeclarations_(allocator->Adapter()),
62          signatures_(allocator->Adapter()),
63          program_(program),
64          flags_(flags)
65    {
66    }
67
68    NO_COPY_SEMANTIC(RecordTable);
69    NO_MOVE_SEMANTIC(RecordTable);
70
71    ~RecordTable() = default;
72
73    bool IsExternal() const
74    {
75        return (flags_ & RecordTableFlags::EXTERNAL) != 0;
76    }
77
78    ArenaSet<ir::ClassDefinition *> &ClassDefinitions()
79    {
80        return classDefinitions_;
81    }
82
83    const ArenaSet<ir::ClassDefinition *> &ClassDefinitions() const
84    {
85        return classDefinitions_;
86    }
87
88    ArenaSet<ir::TSInterfaceDeclaration *> &InterfaceDeclarations()
89    {
90        return interfaceDeclarations_;
91    }
92
93    const ArenaSet<ir::TSInterfaceDeclaration *> &InterfaceDeclarations() const
94    {
95        return interfaceDeclarations_;
96    }
97
98    ArenaVector<FunctionScope *> &Signatures()
99    {
100        return signatures_;
101    }
102
103    const ArenaVector<FunctionScope *> &Signatures() const
104    {
105        return signatures_;
106    }
107
108    void SetClassDefinition(ir::ClassDefinition *classDefinition)
109    {
110        record_ = classDefinition;
111    }
112
113    ir::ClassDefinition *ClassDefinition()
114    {
115        return std::holds_alternative<ir::ClassDefinition *>(record_) ? std::get<ir::ClassDefinition *>(record_)
116                                                                      : nullptr;
117    }
118
119    const ir::ClassDefinition *ClassDefinition() const
120    {
121        return std::holds_alternative<ir::ClassDefinition *>(record_) ? std::get<ir::ClassDefinition *>(record_)
122                                                                      : nullptr;
123    }
124
125    void SetInterfaceDeclaration(ir::TSInterfaceDeclaration *interfaceDeclaration)
126    {
127        record_ = interfaceDeclaration;
128    }
129
130    ir::TSInterfaceDeclaration *InterfaceDeclaration()
131    {
132        return std::holds_alternative<ir::TSInterfaceDeclaration *>(record_)
133                   ? std::get<ir::TSInterfaceDeclaration *>(record_)
134                   : nullptr;
135    }
136
137    const ir::TSInterfaceDeclaration *InterfaceDeclaration() const
138    {
139        return std::holds_alternative<ir::TSInterfaceDeclaration *>(record_)
140                   ? std::get<ir::TSInterfaceDeclaration *>(record_)
141                   : nullptr;
142    }
143
144    void SetProgram(parser::Program *program)
145    {
146        program_ = program;
147    }
148
149    parser::Program *Program()
150    {
151        return program_;
152    }
153
154    const parser::Program *Program() const
155    {
156        return program_;
157    }
158
159    util::StringView RecordName() const;
160
161private:
162    friend class BoundContext;
163    using RecordHolder = std::variant<ir::ClassDefinition *, ir::TSInterfaceDeclaration *, std::nullptr_t>;
164
165    ArenaSet<ir::ClassDefinition *> classDefinitions_;
166    ArenaSet<ir::TSInterfaceDeclaration *> interfaceDeclarations_;
167    ArenaVector<varbinder::FunctionScope *> signatures_;
168    RecordHolder record_ {nullptr};
169    parser::Program *program_ {};
170    BoundContext *boundCtx_ {};
171    RecordTableFlags flags_ {};
172};
173
174class BoundContext {
175public:
176    explicit BoundContext(RecordTable *recordTable, ir::ClassDefinition *classDef, bool force = false);
177    explicit BoundContext(RecordTable *recordTable, ir::TSInterfaceDeclaration *interfaceDecl, bool force = false);
178    ~BoundContext();
179
180    NO_COPY_SEMANTIC(BoundContext);
181    NO_MOVE_SEMANTIC(BoundContext);
182
183    void *operator new(size_t) = delete;
184    void *operator new[](size_t) = delete;
185
186    util::StringView FormRecordName() const;
187
188private:
189    BoundContext *prev_;
190    RecordTable *recordTable_;
191    RecordTable::RecordHolder currentRecord_ {nullptr};
192    RecordTable::RecordHolder savedRecord_ {nullptr};
193    ir::Identifier *recordIdent_ {nullptr};
194};
195
196}  // namespace ark::es2panda::varbinder
197
198#endif  // ES2PANDA_VARBINDER_RECORDTABLE_H
199