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 #ifndef ES2PANDA_IR_AST_DUMP_H
17 #define ES2PANDA_IR_AST_DUMP_H
18 
19 #include "ir/astNode.h"
20 #include "lexer/token/sourceLocation.h"
21 #include "lexer/token/tokenType.h"
22 #include "lexer/token/number.h"
23 #include "util/ustring.h"
24 
25 #include <sstream>
26 #include <variant>
27 
28 namespace ark::es2panda::ir {
29 class AstDumper {
30 public:
31     class Nullish {
32     public:
Nullish(const ir::AstNode *node)33         explicit Nullish(const ir::AstNode *node) : node_(node) {}
34 
Node() const35         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 AstNode *, bool, std::vector<const AstNode *>>;
Optional(const ir::AstNode *node)47         explicit Optional(const ir::AstNode *node) : value_(node) {}
Optional(const char *string)48         explicit Optional(const char *string) : value_(const_cast<char *>(string)) {}
Optional(bool boolean)49         explicit Optional(bool boolean) : value_(boolean) {}
50 
51         template <typename T>
Optional(const ArenaVector<T> &array)52         explicit Optional(const ArenaVector<T> &array)
53         {
54             std::vector<const AstNode *> nodes;
55             nodes.reserve(array.size());
56 
57             for (auto &it : array) {
58                 nodes.push_back(it);
59             }
60 
61             value_ = std::move(nodes);
62         }
63 
Value() const64         const Val &Value() const
65         {
66             return value_;
67         }
68 
69     private:
70         Val value_;
71     };
72 
73     class Property {
74     public:
75         class Ignore {
76         public:
77             Ignore() = default;
78         };
79 
80         enum class Constant {
81             PROP_NULL,
82             PROP_UNDEFINED,
83             EMPTY_ARRAY,
84         };
85 
86         using Val = std::variant<const char *, lexer::TokenType, std::initializer_list<Property>, util::StringView,
87                                  bool, char16_t, lexer::Number, const ir::AstNode *, std::vector<const ir::AstNode *>,
88                                  Constant, Nullish, Ignore>;
89 
Property(const char *key, const char *string)90         Property(const char *key, const char *string) : key_(key), value_(string) {}
Property(const char *key, util::StringView str)91         Property(const char *key, util::StringView str) : key_(key), value_(str) {}
Property(const char *key, bool boolean)92         Property(const char *key, bool boolean) : key_(key), value_(boolean) {}
Property(const char *key, char16_t c16)93         Property(const char *key, char16_t c16) : key_(key), value_(c16) {}
Property(const char *key, lexer::Number number)94         Property(const char *key, lexer::Number number) : key_(key), value_(number) {}
Property(const char *key, lexer::TokenType token)95         Property(const char *key, lexer::TokenType token) : key_(key), value_(token) {}
Property(const char *key, std::initializer_list<Property> props)96         Property(const char *key, std::initializer_list<Property> props) : key_(key), value_(props) {}
Property(const char *key, const ir::AstNode *node)97         Property(const char *key, const ir::AstNode *node) : key_(key), value_(const_cast<ir::AstNode *>(node)) {}
98 
Property(const char *key, Constant constant)99         Property(const char *key, Constant constant) : key_(key), value_(constant) {}
Property(const char *key, Nullish nullish)100         Property(const char *key, Nullish nullish) : key_(key)
101         {
102             if (nullish.Node() != nullptr) {
103                 value_ = nullish.Node();
104             } else {
105                 value_ = Property::Constant::PROP_NULL;
106             }
107         }
108 
Property(const char *key, const Optional &optional)109         Property(const char *key, const Optional &optional) : key_(key)
110         {
111             const auto &value = optional.Value();
112             if (std::holds_alternative<const ir::AstNode *>(value) &&
113                 (std::get<const ir::AstNode *>(value) != nullptr)) {
114                 value_ = std::get<const ir::AstNode *>(value);
115                 return;
116             }
117 
118             if (std::holds_alternative<const char *>(value) && (std::get<const char *>(value) != nullptr)) {
119                 value_ = std::get<const char *>(value);
120                 return;
121             }
122 
123             if (std::holds_alternative<bool>(value) && std::get<bool>(value)) {
124                 value_ = std::get<bool>(value);
125                 return;
126             }
127 
128             if (std::holds_alternative<std::vector<const AstNode *>>(value)) {
129                 const auto &array = std::get<std::vector<const AstNode *>>(value);
130                 if (!array.empty()) {
131                     value_ = array;
132                     return;
133                 }
134             }
135 
136             value_ = Ignore();
137         }
138 
139         template <typename T>
Property(const char *key, const ArenaVector<T> &array)140         Property(const char *key, const ArenaVector<T> &array) : key_(key)
141         {
142             if (array.empty()) {
143                 value_ = Constant::EMPTY_ARRAY;
144                 return;
145             }
146 
147             std::vector<const ir::AstNode *> nodes;
148             nodes.reserve(array.size());
149 
150             for (auto &it : array) {
151                 nodes.push_back(it);
152             }
153 
154             value_ = std::move(nodes);
155         }
156 
157         template <typename T>
Property(const char *key, const ArenaVector<T> &array, const std::function<bool(AstNode *)> &filter)158         Property(const char *key, const ArenaVector<T> &array, const std::function<bool(AstNode *)> &filter) : key_(key)
159         {
160             std::vector<const ir::AstNode *> nodes;
161             nodes.reserve(array.size());
162 
163             for (auto &it : array) {
164                 if (filter(it)) {
165                     nodes.push_back(it);
166                 }
167             }
168 
169             if (nodes.empty()) {
170                 value_ = Constant::EMPTY_ARRAY;
171                 return;
172             }
173 
174             value_ = std::move(nodes);
175         }
176 
Key() const177         const char *Key() const
178         {
179             return key_;
180         }
181 
Value() const182         const Val &Value() const
183         {
184             return value_;
185         }
186 
187     private:
188         const char *key_;
189         Val value_ {};
190     };
191 
192     explicit AstDumper(const ir::AstNode *node, util::StringView sourceCode = "");
193 
194     void Add(std::initializer_list<Property> props);
195     void Add(const AstDumper::Property &prop);
196 
197     static const char *ModifierToString(ModifierFlags flags);
198     static const char *TypeOperatorToString(TSOperatorType operatorType);
199 
Str() const200     std::string Str() const
201     {
202         return ss_.str();
203     }
204 
205 private:
206     using WrapperCb = std::function<void()>;
207 
208     template <typename T>
AddList(T props)209     void AddList(T props)
210     {
211         for (auto it = props.begin(); it != props.end();) {
212             Serialize(*it);
213 
214             do {
215                 if (++it == props.end()) {
216                     return;
217                 }
218             } while (std::holds_alternative<Property::Ignore>((*it).Value()));
219 
220             ss_ << ',';
221         }
222     }
223 
224     void Indent();
225 
226     void Serialize(const AstDumper::Property &prop);
227     void SerializePropKey(const char *str);
228     void SerializeString(const char *str);
229     void SerializeString(const util::StringView &str);
230     void SerializeNumber(size_t number);
231     void SerializeNumber(lexer::Number number);
232     void SerializeChar16(char16_t c16);
233     void SerializeBoolean(bool boolean);
234     void SerializeObject(const ir::AstNode *object);
235     void SerializeToken(lexer::TokenType token);
236     void SerializePropList(std::initializer_list<AstDumper::Property> props);
237     void SerializeConstant(Property::Constant constant);
238     void Wrap(const WrapperCb &cb, char delimStart = '{', char delimEnd = '}');
239 
240     void SerializeLoc(const lexer::SourceRange &loc);
241     void SerializeSourcePosition(const lexer::SourcePosition &pos);
242 
243     void SerializeArray(std::vector<const ir::AstNode *> array);
244 
245     const lexer::LineIndex index_;
246     std::stringstream ss_;
247     int32_t indent_ {};
248     bool isSrcEmpty_ = false;
249 };
250 }  // namespace ark::es2panda::ir
251 
252 #endif  // AST_DUMP_H
253