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