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 #include "astNode.h"
17 #include "ir/astDump.h"
18 #include "ir/srcDump.h"
19 #include "ir/typed.h"
20
21 namespace ark::es2panda::ir {
22
AstNode(AstNode const & other)23 AstNode::AstNode(AstNode const &other)
24 {
25 range_ = other.range_;
26 type_ = other.type_;
27 if (other.variable_ != nullptr) {
28 variable_ = other.variable_;
29 }
30 flags_ = other.flags_;
31 astNodeFlags_ = other.astNodeFlags_;
32 // boxing_unboxing_flags_ {}; leave default value!
33 }
34
IsExported() const35 [[nodiscard]] bool AstNode::IsExported() const noexcept
36 {
37 if (UNLIKELY(IsClassDefinition())) {
38 return parent_->IsExported();
39 }
40
41 return (flags_ & ModifierFlags::EXPORT) != 0;
42 }
43
IsDefaultExported() const44 [[nodiscard]] bool AstNode::IsDefaultExported() const noexcept
45 {
46 if (UNLIKELY(IsClassDefinition())) {
47 return parent_->IsDefaultExported();
48 }
49
50 return (flags_ & ModifierFlags::DEFAULT_EXPORT) != 0;
51 }
52
IsExportedType() const53 [[nodiscard]] bool AstNode::IsExportedType() const noexcept
54 {
55 if (UNLIKELY(IsClassDefinition())) {
56 return this->parent_->IsExportedType();
57 }
58
59 return (flags_ & ModifierFlags::EXPORT_TYPE) != 0;
60 }
61
HasExportAlias() const62 [[nodiscard]] bool AstNode::HasExportAlias() const noexcept
63 {
64 if (UNLIKELY(IsClassDefinition())) {
65 return parent_->HasExportAlias();
66 }
67
68 return (astNodeFlags_ & AstNodeFlags::HAS_EXPORT_ALIAS) != 0;
69 }
70
IsScopeBearer() const71 bool AstNode::IsScopeBearer() const noexcept
72 {
73 return false;
74 }
75
Scope() const76 varbinder::Scope *AstNode::Scope() const noexcept
77 {
78 ES2PANDA_UNREACHABLE();
79 }
80
ClearScope()81 void AstNode::ClearScope() noexcept
82 {
83 ES2PANDA_UNREACHABLE();
84 }
85
AsClassElement()86 ir::ClassElement *AstNode::AsClassElement()
87 {
88 ES2PANDA_ASSERT(IsMethodDefinition() || IsClassProperty() || IsClassStaticBlock());
89 return reinterpret_cast<ir::ClassElement *>(this);
90 }
91
AsClassElement() const92 const ir::ClassElement *AstNode::AsClassElement() const
93 {
94 ES2PANDA_ASSERT(IsMethodDefinition() || IsClassProperty() || IsClassStaticBlock());
95 return reinterpret_cast<const ir::ClassElement *>(this);
96 }
97
98 template <typename R, typename T>
GetTopStatementImpl(T * self)99 static R GetTopStatementImpl(T *self)
100 {
101 auto iter = self;
102
103 while (iter->Parent()) {
104 iter = iter->Parent();
105 }
106
107 return reinterpret_cast<R>(iter);
108 }
109
GetTopStatement()110 ir::BlockStatement *AstNode::GetTopStatement()
111 {
112 return GetTopStatementImpl<ir::BlockStatement *>(this);
113 }
114
GetTopStatement() const115 const ir::BlockStatement *AstNode::GetTopStatement() const
116 {
117 return GetTopStatementImpl<const ir::BlockStatement *>(this);
118 }
119
Clone(ArenaAllocator * const allocator,AstNode * const parent)120 AstNode *AstNode::Clone([[maybe_unused]] ArenaAllocator *const allocator, [[maybe_unused]] AstNode *const parent)
121 {
122 ES2PANDA_UNREACHABLE();
123 }
124
TransformChildrenRecursively(const NodeTransformer & cb,std::string_view transformationName)125 void AstNode::TransformChildrenRecursively(const NodeTransformer &cb, std::string_view transformationName)
126 { // post-order, but use when you don't care about the order
127 TransformChildrenRecursivelyPostorder(cb, transformationName);
128 }
129
TransformChildrenRecursivelyPreorder(const NodeTransformer & cb,std::string_view transformationName)130 void AstNode::TransformChildrenRecursivelyPreorder(const NodeTransformer &cb, std::string_view transformationName)
131 {
132 TransformChildren(
133 [=](AstNode *child) {
134 auto *res = cb(child);
135 res->TransformChildrenRecursivelyPreorder(cb, transformationName);
136 return res;
137 },
138 transformationName);
139 }
140
TransformChildrenRecursivelyPostorder(const NodeTransformer & cb,std::string_view transformationName)141 void AstNode::TransformChildrenRecursivelyPostorder(const NodeTransformer &cb, std::string_view transformationName)
142 {
143 TransformChildren(
144 [=](AstNode *child) {
145 child->TransformChildrenRecursivelyPostorder(cb, transformationName);
146 return cb(child);
147 },
148 transformationName);
149 }
150
IterateRecursively(const NodeTraverser & cb) const151 void AstNode::IterateRecursively(const NodeTraverser &cb) const
152 { // pre-order, use when you don't care
153 IterateRecursivelyPreorder(cb);
154 }
155
IterateRecursivelyPreorder(const NodeTraverser & cb) const156 void AstNode::IterateRecursivelyPreorder(const NodeTraverser &cb) const
157 {
158 Iterate([=](AstNode *child) {
159 cb(child);
160 child->IterateRecursivelyPreorder(cb);
161 });
162 }
163
IterateRecursivelyPostorder(const NodeTraverser & cb) const164 void AstNode::IterateRecursivelyPostorder(const NodeTraverser &cb) const
165 {
166 Iterate([=](AstNode *child) {
167 child->IterateRecursivelyPostorder(cb);
168 cb(child);
169 });
170 }
171
AnyChildHelper(bool * found,const NodePredicate & cb,AstNode * ast)172 void AnyChildHelper(bool *found, const NodePredicate &cb, AstNode *ast)
173 {
174 if (*found) {
175 return;
176 }
177
178 if (cb(ast)) {
179 *found = true;
180 return;
181 }
182
183 ast->Iterate([=](AstNode *child) { AnyChildHelper(found, cb, child); });
184 }
185
IsAnyChild(const NodePredicate & cb) const186 bool AstNode::IsAnyChild(const NodePredicate &cb) const
187 {
188 bool found = false;
189 Iterate([&found, cb](AstNode *child) { AnyChildHelper(&found, cb, child); });
190 return found;
191 }
192
FindChildHelper(AstNode * & found,const NodePredicate & cb,AstNode * ast)193 void FindChildHelper(AstNode *&found, const NodePredicate &cb, AstNode *ast)
194 {
195 if (found != nullptr) {
196 return;
197 }
198
199 if (cb(ast)) {
200 found = ast;
201 return;
202 }
203
204 ast->Iterate([&found, cb](AstNode *child) { FindChildHelper(found, cb, child); });
205 }
206
FindChild(const NodePredicate & cb) const207 AstNode *AstNode::FindChild(const NodePredicate &cb) const
208 {
209 AstNode *found = nullptr;
210 Iterate([&found, cb](AstNode *child) { FindChildHelper(found, cb, child); });
211 return found;
212 }
213
EnclosingScope(const ir::AstNode * expr)214 varbinder::Scope *AstNode::EnclosingScope(const ir::AstNode *expr) noexcept
215 {
216 while (expr != nullptr && !expr->IsScopeBearer()) {
217 expr = expr->Parent();
218 }
219 return expr != nullptr ? expr->Scope() : nullptr;
220 }
221
DumpJSON() const222 std::string AstNode::DumpJSON() const
223 {
224 ir::AstDumper dumper {this};
225 return dumper.Str();
226 }
227
DumpEtsSrc() const228 std::string AstNode::DumpEtsSrc() const
229 {
230 ir::SrcDumper dumper {this};
231 return dumper.Str();
232 }
233
DumpDecl() const234 std::string AstNode::DumpDecl() const
235 {
236 ir::SrcDumper dumper {this, true};
237 dumper.Run();
238 return dumper.Str();
239 }
240
IsolatedDumpDecl() const241 std::string AstNode::IsolatedDumpDecl() const
242 {
243 ir::SrcDumper dumper {this, true, true};
244 dumper.Run();
245 return dumper.Str();
246 }
247
SetOriginalNode(AstNode * originalNode)248 void AstNode::SetOriginalNode(AstNode *originalNode) noexcept
249 {
250 originalNode_ = originalNode;
251 }
252
OriginalNode() const253 AstNode *AstNode::OriginalNode() const noexcept
254 {
255 return originalNode_;
256 }
257
SetTransformedNode(std::string_view const transformationName,AstNode * transformedNode)258 void AstNode::SetTransformedNode(std::string_view const transformationName, AstNode *transformedNode)
259 {
260 transformedNode->SetOriginalNode(this);
261 transformedNode_ = std::make_optional(std::make_pair(transformationName, transformedNode));
262 }
263
CleanUp()264 void AstNode::CleanUp()
265 {
266 SetVariable(nullptr);
267 if (IsScopeBearer()) {
268 ClearScope();
269 }
270 if (IsTyped()) {
271 this->AsTyped()->SetTsType(nullptr);
272 }
273 }
274
IsReadonly() const275 bool AstNode::IsReadonly() const noexcept
276 {
277 return (flags_ & ModifierFlags::READONLY) != 0;
278 }
279
280 // NOTE: For readonly parameter type
IsReadonlyType() const281 bool AstNode::IsReadonlyType() const noexcept
282 {
283 return (flags_ & ModifierFlags::READONLY_PARAMETER) != 0;
284 }
285
IsOptionalDeclaration() const286 bool AstNode::IsOptionalDeclaration() const noexcept
287 {
288 return (flags_ & ModifierFlags::OPTIONAL) != 0;
289 }
290
IsDefinite() const291 bool AstNode::IsDefinite() const noexcept
292 {
293 return (flags_ & ModifierFlags::DEFINITE) != 0;
294 }
295
IsConstructor() const296 bool AstNode::IsConstructor() const noexcept
297 {
298 return (flags_ & ModifierFlags::CONSTRUCTOR) != 0;
299 }
300
IsOverride() const301 bool AstNode::IsOverride() const noexcept
302 {
303 return (flags_ & ModifierFlags::OVERRIDE) != 0;
304 }
305
ShallowClone(ArenaAllocator * allocator)306 AstNode *AstNode::ShallowClone(ArenaAllocator *allocator)
307 {
308 auto clone = Construct(allocator);
309 CopyTo(clone);
310 return clone;
311 }
312
CopyTo(AstNode * other) const313 void AstNode::CopyTo(AstNode *other) const
314 {
315 ES2PANDA_ASSERT(other->type_ == type_);
316
317 other->parent_ = parent_;
318 other->range_ = range_;
319 other->flags_ = flags_;
320 other->astNodeFlags_ = astNodeFlags_;
321 other->boxingUnboxingFlags_ = boxingUnboxingFlags_;
322 other->variable_ = variable_;
323 other->originalNode_ = originalNode_;
324 other->transformedNode_ = transformedNode_;
325 }
326
Construct(ArenaAllocator * allocator)327 AstNode *AstNode::Construct([[maybe_unused]] ArenaAllocator *allocator)
328 {
329 ES2PANDA_UNREACHABLE();
330 }
331 } // namespace ark::es2panda::ir
332