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#include "astNode.h"
17#include "ir/astDump.h"
18#include "ir/srcDump.h"
19
20namespace ark::es2panda::ir {
21
22AstNode::AstNode(AstNode const &other)
23{
24    range_ = other.range_;
25    type_ = other.type_;
26    if (other.variable_ != nullptr) {
27        variable_ = other.variable_;
28    }
29    flags_ = other.flags_;
30    astNodeFlags_ = other.astNodeFlags_;
31    // boxing_unboxing_flags_ {};  leave default value!
32}
33
34[[nodiscard]] bool AstNode::IsExported() const noexcept
35{
36    if (UNLIKELY(IsClassDefinition())) {
37        return parent_->IsExported();
38    }
39
40    return (flags_ & ModifierFlags::EXPORT) != 0;
41}
42
43[[nodiscard]] bool AstNode::IsDefaultExported() const noexcept
44{
45    if (UNLIKELY(IsClassDefinition())) {
46        return parent_->IsDefaultExported();
47    }
48
49    return (flags_ & ModifierFlags::DEFAULT_EXPORT) != 0;
50}
51
52[[nodiscard]] bool AstNode::IsExportedType() const noexcept
53{
54    if (UNLIKELY(IsClassDefinition())) {
55        return this->parent_->IsExportedType();
56    }
57
58    return (flags_ & ModifierFlags::EXPORT_TYPE) != 0;
59}
60
61[[nodiscard]] bool AstNode::HasExportAlias() const noexcept
62{
63    if (UNLIKELY(IsClassDefinition())) {
64        return parent_->HasExportAlias();
65    }
66
67    return (astNodeFlags_ & AstNodeFlags::HAS_EXPORT_ALIAS) != 0;
68}
69
70bool AstNode::IsScopeBearer() const noexcept
71{
72    return false;
73}
74
75varbinder::Scope *AstNode::Scope() const noexcept
76{
77    UNREACHABLE();
78}
79
80void AstNode::ClearScope() noexcept
81{
82    UNREACHABLE();
83}
84
85ir::ClassElement *AstNode::AsClassElement()
86{
87    ASSERT(IsMethodDefinition() || IsClassProperty() || IsClassStaticBlock());
88    return reinterpret_cast<ir::ClassElement *>(this);
89}
90
91const ir::ClassElement *AstNode::AsClassElement() const
92{
93    ASSERT(IsMethodDefinition() || IsClassProperty() || IsClassStaticBlock());
94    return reinterpret_cast<const ir::ClassElement *>(this);
95}
96
97template <typename R, typename T>
98static R GetTopStatementImpl(T *self)
99{
100    auto iter = self;
101
102    while (iter->Parent()) {
103        iter = iter->Parent();
104    }
105
106    return reinterpret_cast<R>(iter);
107}
108
109ir::BlockStatement *AstNode::GetTopStatement()
110{
111    return GetTopStatementImpl<ir::BlockStatement *>(this);
112}
113
114const ir::BlockStatement *AstNode::GetTopStatement() const
115{
116    return GetTopStatementImpl<const ir::BlockStatement *>(this);
117}
118
119AstNode *AstNode::Clone([[maybe_unused]] ArenaAllocator *const allocator, [[maybe_unused]] AstNode *const parent)
120{
121    UNREACHABLE();
122}
123
124void AstNode::TransformChildrenRecursively(const NodeTransformer &cb, std::string_view transformationName)
125{  // post-order, but use when you don't care about the order
126    TransformChildrenRecursivelyPostorder(cb, transformationName);
127}
128
129void AstNode::TransformChildrenRecursivelyPreorder(const NodeTransformer &cb, std::string_view transformationName)
130{
131    TransformChildren(
132        [=](AstNode *child) {
133            auto *res = cb(child);
134            res->TransformChildrenRecursivelyPreorder(cb, transformationName);
135            return res;
136        },
137        transformationName);
138}
139
140void AstNode::TransformChildrenRecursivelyPostorder(const NodeTransformer &cb, std::string_view transformationName)
141{
142    TransformChildren(
143        [=](AstNode *child) {
144            child->TransformChildrenRecursivelyPostorder(cb, transformationName);
145            return cb(child);
146        },
147        transformationName);
148}
149
150void AstNode::IterateRecursively(const NodeTraverser &cb) const
151{  // pre-order, use when you don't care
152    IterateRecursivelyPreorder(cb);
153}
154
155void AstNode::IterateRecursivelyPreorder(const NodeTraverser &cb) const
156{
157    Iterate([=](AstNode *child) {
158        cb(child);
159        child->IterateRecursivelyPreorder(cb);
160    });
161}
162
163void AstNode::IterateRecursivelyPostorder(const NodeTraverser &cb) const
164{
165    Iterate([=](AstNode *child) {
166        child->IterateRecursivelyPostorder(cb);
167        cb(child);
168    });
169}
170
171void AnyChildHelper(bool *found, const NodePredicate &cb, AstNode *ast)
172{
173    if (*found) {
174        return;
175    }
176
177    if (cb(ast)) {
178        *found = true;
179        return;
180    }
181
182    ast->Iterate([=](AstNode *child) { AnyChildHelper(found, cb, child); });
183}
184
185bool AstNode::IsAnyChild(const NodePredicate &cb) const
186{
187    bool found = false;
188    Iterate([&found, cb](AstNode *child) { AnyChildHelper(&found, cb, child); });
189    return found;
190}
191
192void FindChildHelper(AstNode *&found, const NodePredicate &cb, AstNode *ast)
193{
194    if (found != nullptr) {
195        return;
196    }
197
198    if (cb(ast)) {
199        found = ast;
200        return;
201    }
202
203    ast->Iterate([&found, cb](AstNode *child) { FindChildHelper(found, cb, child); });
204}
205
206AstNode *AstNode::FindChild(const NodePredicate &cb) const
207{
208    AstNode *found = nullptr;
209    Iterate([&found, cb](AstNode *child) { FindChildHelper(found, cb, child); });
210    return found;
211}
212
213varbinder::Scope *AstNode::EnclosingScope(const ir::AstNode *expr)
214{
215    while (expr != nullptr && !expr->IsScopeBearer()) {
216        expr = expr->Parent();
217    }
218    return expr != nullptr ? expr->Scope() : nullptr;
219}
220
221std::string AstNode::DumpJSON() const
222{
223    ir::AstDumper dumper {this};
224    return dumper.Str();
225}
226
227std::string AstNode::DumpEtsSrc() const
228{
229    ir::SrcDumper dumper {this};
230    return dumper.Str();
231}
232
233void AstNode::SetOriginalNode(AstNode *originalNode)
234{
235    originalNode_ = originalNode;
236}
237
238void AstNode::SetTransformedNode(std::string_view const transformationName, AstNode *transformedNode)
239{
240    ASSERT(!transformedNode_.has_value());
241    transformedNode->SetOriginalNode(this);
242    transformedNode_ = std::make_optional(std::make_pair(transformationName, transformedNode));
243}
244}  // namespace ark::es2panda::ir
245