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 "astDump.h"
17
18#include "ir/astNode.h"
19#include "util/helpers.h"
20
21#include <cmath>
22#include <iostream>
23
24namespace ark::es2panda::ir {
25AstDumper::AstDumper(const ir::AstNode *node, util::StringView sourceCode) : index_(sourceCode)
26{
27    isSrcEmpty_ = sourceCode.Empty();
28    SerializeObject(node);
29}
30
31void AstDumper::Add(std::initializer_list<AstDumper::Property> props)
32{
33    AddList<std::initializer_list<AstDumper::Property>>(props);
34}
35
36void AstDumper::Add(const AstDumper::Property &prop)
37{
38    Serialize(prop);
39}
40
41const char *AstDumper::ModifierToString(ModifierFlags flags)
42{
43    if ((flags & ModifierFlags::INTERNAL) != 0) {
44        return "internal";
45    }
46
47    if ((flags & ModifierFlags::PRIVATE) != 0) {
48        return "private";
49    }
50
51    if ((flags & ModifierFlags::PROTECTED) != 0) {
52        return "protected";
53    }
54
55    if ((flags & ModifierFlags::PUBLIC) != 0) {
56        return "public";
57    }
58
59    return nullptr;
60}
61
62const char *AstDumper::TypeOperatorToString(TSOperatorType operatorType)
63{
64    if (operatorType == TSOperatorType::KEYOF) {
65        return "keyof";
66    }
67
68    if (operatorType == TSOperatorType::READONLY) {
69        return "readonly";
70    }
71
72    if (operatorType == TSOperatorType::UNIQUE) {
73        return "unique";
74    }
75
76    return nullptr;
77}
78
79void AstDumper::Serialize(const AstDumper::Property &prop)
80{
81    SerializePropKey(prop.Key());
82    const auto &value = prop.Value();
83
84    if (std::holds_alternative<const char *>(value)) {
85        SerializeString(std::get<const char *>(value));
86    } else if (std::holds_alternative<util::StringView>(value)) {
87        SerializeString(std::get<util::StringView>(value));
88    } else if (std::holds_alternative<bool>(value)) {
89        SerializeBoolean(std::get<bool>(value));
90    } else if (std::holds_alternative<lexer::Number>(value)) {
91        SerializeNumber(std::get<lexer::Number>(value));
92    } else if (std::holds_alternative<char16_t>(value)) {
93        SerializeChar16(std::get<char16_t>(value));
94    } else if (std::holds_alternative<const ir::AstNode *>(value)) {
95        SerializeObject(std::get<const ir::AstNode *>(value));
96    } else if (std::holds_alternative<std::vector<const ir::AstNode *>>(value)) {
97        SerializeArray(std::get<std::vector<const ir::AstNode *>>(value));
98    } else if (std::holds_alternative<lexer::TokenType>(value)) {
99        SerializeToken(std::get<lexer::TokenType>(value));
100    } else if (std::holds_alternative<std::initializer_list<Property>>(value)) {
101        SerializePropList(std::get<std::initializer_list<Property>>(value));
102    } else if (std::holds_alternative<Property::Constant>(value)) {
103        SerializeConstant(std::get<Property::Constant>(value));
104    }
105}
106
107void AstDumper::SerializeToken(lexer::TokenType token)
108{
109    ss_ << "\"" << lexer::TokenToString(token) << "\"";
110}
111
112void AstDumper::SerializePropKey(const char *str)
113{
114    ss_ << std::endl;
115    Indent();
116    SerializeString(str);
117    ss_ << ": ";
118}
119
120void AstDumper::SerializeString(const char *str)
121{
122    ss_ << "\"" << str << "\"";
123}
124
125void AstDumper::SerializeString(const util::StringView &str)
126{
127    ss_ << "\"" << str.Utf8() << "\"";
128}
129
130void AstDumper::SerializeNumber(size_t number)
131{
132    ss_ << number;
133}
134
135void AstDumper::SerializeNumber(lexer::Number number)
136{
137    if (number.IsInt()) {
138        ss_ << number.GetInt();
139    } else if (number.IsLong()) {
140        ss_ << number.GetLong();
141    } else if (number.IsFloat()) {
142        if (std::isinf(number.GetFloat())) {
143            ss_ << "\"Infinity\"";
144        } else {
145            ss_ << number.GetFloat();
146        }
147    } else {
148        if (std::isinf(number.GetDouble())) {
149            ss_ << "\"Infinity\"";
150        } else {
151            ss_ << number.GetDouble();
152        }
153    }
154}
155
156void AstDumper::SerializeChar16(char16_t c16)
157{
158    SerializeString(util::Helpers::UTF16toUTF8(c16).c_str());
159}
160
161void AstDumper::SerializeBoolean(bool boolean)
162{
163    ss_ << (boolean ? "true" : "false");
164}
165
166void AstDumper::SerializeConstant(Property::Constant constant)
167{
168    switch (constant) {
169        case Property::Constant::PROP_NULL: {
170            ss_ << "null";
171            break;
172        }
173        case Property::Constant::PROP_UNDEFINED: {
174            ss_ << "undefined";
175            break;
176        }
177        case Property::Constant::EMPTY_ARRAY: {
178            ss_ << "[]";
179            break;
180        }
181        default: {
182            UNREACHABLE();
183        }
184    }
185}
186
187void AstDumper::SerializePropList(std::initializer_list<AstDumper::Property> props)
188{
189    Wrap([this, &props]() -> void {
190        // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
191        for (const auto *it = props.begin(); it != props.end(); ++it) {
192            Serialize(*it);
193            if (std::next(it) != props.end()) {
194                ss_ << ',';
195            }
196        }
197    });
198}
199
200void AstDumper::SerializeArray(std::vector<const ir::AstNode *> array)
201{
202    Wrap(
203        [this, &array]() -> void {
204            for (auto it = array.begin(); it != array.end(); ++it) {
205                ss_ << std::endl;
206                Indent();
207
208                SerializeObject(*it);
209
210                if (std::next(it) != array.end()) {
211                    ss_ << ',';
212                }
213            }
214        },
215        '[', ']');
216}
217
218void AstDumper::SerializeObject(const ir::AstNode *object)
219{
220    Wrap([this, object]() -> void {
221        object->Dump(this);
222        if (!isSrcEmpty_) {
223            SerializeLoc(object->Range());
224        }
225    });
226}
227
228void AstDumper::Wrap(const WrapperCb &cb, char delimStart, char delimEnd)
229{
230    ss_ << delimStart;
231    indent_++;
232
233    cb();
234    ss_ << std::endl;
235    indent_--;
236    Indent();
237    ss_ << delimEnd;
238}
239
240void AstDumper::SerializeLoc(const lexer::SourceRange &loc)
241{
242    ss_ << ',';
243    SerializePropKey("loc");
244
245    Wrap([this, &loc]() -> void {
246        SerializePropKey("start");
247        SerializeSourcePosition(loc.start);
248        ss_ << ',';
249        SerializePropKey("end");
250        SerializeSourcePosition(loc.end);
251    });
252}
253
254void AstDumper::SerializeSourcePosition(const lexer::SourcePosition &pos)
255{
256    lexer::SourceLocation loc = index_.GetLocation(pos);
257
258    Wrap([this, &loc]() -> void {
259        SerializePropKey("line");
260        SerializeNumber(loc.line);
261        ss_ << ',';
262        SerializePropKey("column");
263        SerializeNumber(loc.col);
264    });
265}
266
267void AstDumper::Indent()
268{
269    for (int32_t i = 0; i < indent_; i++) {
270        ss_ << "  ";
271    }
272}
273}  // namespace ark::es2panda::ir
274