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#ifndef ES2PANDA_IR_ASTDUMP_H
17#define ES2PANDA_IR_ASTDUMP_H
18
19#include <ir/astNode.h>
20#include <lexer/token/sourceLocation.h>
21#include <lexer/token/tokenType.h>
22#include <util/ustring.h>
23
24#include <sstream>
25#include <variant>
26
27namespace panda::es2panda::ir {
28
29class AstDumper {
30public:
31    class Nullable {
32    public:
33        explicit Nullable(const ir::AstNode *node) : node_(node) {}
34
35        const ir::AstNode *Node() const
36        {
37            return node_;
38        }
39
40    private:
41        const ir::AstNode *node_;
42    };
43
44    class Optional {
45    public:
46        using Val = std::variant<const char *, const ir::AstNode *, bool>;
47        explicit Optional(const ir::AstNode *node) : value_(node) {}
48        explicit Optional(const char *string) : value_(const_cast<char *>(string)) {}
49        explicit Optional(bool boolean) : value_(boolean) {}
50
51        const Val &Value() const
52        {
53            return value_;
54        }
55
56    private:
57        Val value_;
58    };
59
60    class Property {
61    public:
62        class Ignore {
63        public:
64            Ignore() = default;
65        };
66
67        enum class Constant {
68            PROP_NULL,
69            EMPTY_ARRAY,
70        };
71
72        using Val =
73            std::variant<const char *, lexer::TokenType, std::initializer_list<Property>, util::StringView, bool,
74                         double, const ir::AstNode *, std::vector<const ir::AstNode *>, Constant, Nullable, Ignore>;
75
76        Property(const char *key, const char *string) : key_(key), value_(string) {}
77        Property(const char *key, util::StringView str) : key_(key), value_(str) {}
78        Property(const char *key, bool boolean) : key_(key), value_(boolean) {}
79        Property(const char *key, double number) : key_(key), value_(number) {}
80        Property(const char *key, lexer::TokenType token) : key_(key), value_(token) {}
81        Property(const char *key, std::initializer_list<Property> props) : key_(key), value_(props) {}
82        Property(const char *key, const ir::AstNode *node) : key_(key), value_(const_cast<ir::AstNode *>(node)) {}
83
84        Property(const char *key, Constant constant) : key_(key), value_(constant) {}
85        Property(const char *key, Nullable nullable) : key_(key)
86        {
87            if (nullable.Node()) {
88                value_ = nullable.Node();
89            } else {
90                value_ = Property::Constant::PROP_NULL;
91            }
92        }
93
94        Property(const char *key, Optional optional) : key_(key)
95        {
96            const auto &value = optional.Value();
97            if (std::holds_alternative<const ir::AstNode *>(value) && std::get<const ir::AstNode *>(value)) {
98                value_ = std::get<const ir::AstNode *>(value);
99                return;
100            }
101
102            if (std::holds_alternative<const char *>(value) && std::get<const char *>(value)) {
103                value_ = std::get<const char *>(value);
104                return;
105            }
106
107            if (std::holds_alternative<bool>(value) && std::get<bool>(value)) {
108                value_ = std::get<bool>(value);
109                return;
110            }
111
112            value_ = Ignore();
113        }
114
115        template <typename T>
116        Property(const char *key, const ArenaVector<T> &array) : key_(key)
117        {
118            if (array.empty()) {
119                value_ = Constant::EMPTY_ARRAY;
120                return;
121            }
122
123            std::vector<const ir::AstNode *> nodes;
124            nodes.reserve(array.size());
125
126            for (auto &it : array) {
127                nodes.push_back(it);
128            }
129
130            value_ = std::move(nodes);
131        }
132
133        const char *Key() const
134        {
135            return key_;
136        }
137
138        const Val &Value() const
139        {
140            return value_;
141        }
142
143    private:
144        const char *key_;
145        Val value_ {false};
146    };
147
148    explicit AstDumper(const BlockStatement *program, util::StringView sourceCode);
149    explicit AstDumper(const ir::AstNode *node);
150
151    void SerializeNode(const ir::AstNode *node);
152
153    void Add(std::initializer_list<Property> props);
154    void Add(const AstDumper::Property &prop);
155
156    static const char *ModifierToString(ModifierFlags flags);
157    static const char *TypeOperatorToString(TSOperatorType operatorType);
158
159    std::string Str() const
160    {
161        return ss_.str();
162    }
163
164private:
165    using WrapperCb = std::function<void()>;
166
167    template <typename T>
168    void AddList(T props)
169    {
170        for (auto it = props.begin(); it != props.end();) {
171            Serialize(*it);
172
173            do {
174                if (++it == props.end()) {
175                    return;
176                }
177            } while (std::holds_alternative<Property::Ignore>((*it).Value()));
178
179            ss_ << ',';
180        }
181    }
182
183    void Indent();
184
185    void Serialize(const AstDumper::Property &prop);
186    void SerializePropKey(const char *str);
187    void SerializeString(const char *str);
188    void SerializeString(const util::StringView &str);
189    void SerializeNumber(size_t number);
190    void SerializeNumber(double number);
191    void SerializeBoolean(bool boolean);
192    void SerializeObject(const ir::AstNode *object);
193    void SerializeToken(lexer::TokenType token);
194    void SerializePropList(std::initializer_list<AstDumper::Property> props);
195    void SerializeConstant(Property::Constant constant);
196    void Wrap(const WrapperCb &cb, char delimStart = '{', char delimEnd = '}');
197
198    void SerializeLoc(const lexer::SourceRange &loc);
199    void SerializeSourcePosition(const lexer::SourcePosition &pos);
200
201    void SerializeArray(std::vector<const ir::AstNode *> array);
202
203    lexer::LineIndex index_;
204    std::stringstream ss_;
205    int32_t indent_;
206    bool dumpNodeOnly_ = false;
207};
208}  // namespace panda::es2panda::ir
209
210#endif  // ASTDUMP_H
211