P4C
The P4 Compiler
Loading...
Searching...
No Matches
json_generator.h
1/*
2Copyright 2013-present Barefoot Networks, Inc.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17#ifndef IR_JSON_GENERATOR_H_
18#define IR_JSON_GENERATOR_H_
19
20#include <optional>
21#include <string>
22#include <string_view>
23#include <unordered_set>
24#include <variant>
25
26#include "ir/node.h"
27#include "lib/bitvec.h"
28#include "lib/cstring.h"
29#include "lib/indent.h"
30#include "lib/ltbitmatrix.h"
31#include "lib/match.h"
32#include "lib/ordered_map.h"
33#include "lib/ordered_set.h"
34#include "lib/safe_vector.h"
35#include "lib/string_map.h"
36
37namespace P4 {
38
39class JSONGenerator {
40 std::unordered_set<int> node_refs;
41 std::ostream &out;
42 bool dumpSourceInfo;
43
44 template <typename T>
45 class has_toJSON {
46 typedef char small;
47 typedef struct {
48 char c[2];
49 } big;
50
51 template <typename C>
52 static small test(decltype(&C::toJSON));
53 template <typename C>
54 static big test(...);
55
56 public:
57 static const bool value = sizeof(test<T>(0)) == sizeof(char);
58 };
59
60 indent_t indent;
61 enum output_state_t {
62 TOP,
63 VEC_START,
64 VEC_MID,
65 OBJ_START,
66 OBJ_AFTERTAG,
67 OBJ_MID,
68 OBJ_END
69 } output_state = TOP;
70
71 enum state_restore_kind { NONE, OBJECT, VECTOR };
72 class state_restore_t {
73 output_state_t prev_state;
74 JSONGenerator &gen;
75 state_restore_kind kind;
76 friend class JSONGenerator;
77
78 state_restore_t(JSONGenerator &gen, state_restore_kind kind)
79 : prev_state(gen.output_state), gen(gen), kind(kind) {}
80 state_restore_t(const state_restore_t &) = delete;
81 state_restore_t(state_restore_t &&a) : prev_state(a.prev_state), gen(a.gen), kind(a.kind) {
82 a.kind = NONE;
83 }
84
85 public:
86 ~state_restore_t() {
87 if (kind == OBJECT) gen.end_object(*this);
88 if (kind == VECTOR) gen.end_vector(*this);
89 }
90 };
91
92 public:
93 explicit JSONGenerator(std::ostream &out, bool dumpSourceInfo = false)
94 : out(out), dumpSourceInfo(dumpSourceInfo) {}
95
96 state_restore_t begin_vector() {
97 if (output_state == OBJ_START) output_state = OBJ_END;
98 BUG_CHECK(output_state != VEC_START, "invalid json output state in begin_vector");
99 state_restore_t rv(*this, VECTOR);
100 output_state = VEC_START;
101 out << '[';
102 ++indent;
103 return rv;
104 }
105
106 void end_vector(state_restore_t &prev) {
107 BUG_CHECK(prev.kind == VECTOR, "invalid previous state in end_vector");
108 prev.kind = NONE;
109 --indent;
110 if (output_state == VEC_MID)
111 out << std::endl << indent;
112 else if (output_state != VEC_START)
113 BUG("invalid json output state in end_vector");
114 out << ']';
115 if ((output_state = prev.prev_state) == OBJ_AFTERTAG) output_state = OBJ_MID;
116 }
117
118 state_restore_t begin_object() {
119 BUG_CHECK(output_state != OBJ_START && output_state != OBJ_MID && output_state != OBJ_END,
120 "invalid json output state in begin_object");
121 state_restore_t rv(*this, OBJECT);
122 output_state = OBJ_START;
123 return rv;
124 }
125
126 void end_object(state_restore_t &prev) {
127 BUG_CHECK(prev.kind == OBJECT, "invalid previous state in end_object");
128 prev.kind = NONE;
129 switch (output_state) {
130 case OBJ_START:
131 out << "{}";
132 break;
133 case OBJ_MID:
134 out << std::endl << --indent << '}';
135 break;
136 case OBJ_END:
137 break;
138 default:
139 BUG("invalid json output state in end_object");
140 break;
141 }
142 if ((output_state = prev.prev_state) == OBJ_AFTERTAG) output_state = OBJ_MID;
143 }
144
145 template <typename T>
146 void emit(const T &val) {
147 switch (output_state) {
148 case VEC_MID:
149 out << ',';
150 /* fall through */
151 case VEC_START:
152 out << std::endl << indent;
153 output_state = VEC_MID;
154 break;
155 case OBJ_AFTERTAG:
156 output_state = OBJ_MID;
157 break;
158 case TOP:
159 break;
160 case OBJ_START:
161 output_state = OBJ_END;
162 break;
163 case OBJ_MID:
164 case OBJ_END:
165 BUG("invalid json output state for emit(obj)");
166 }
167 generate(val);
168 if (output_state == TOP) out << std::endl;
169 }
170
171 void emit_tag(std::string_view tag) {
172 switch (output_state) {
173 case OBJ_START:
174 out << '{' << std::endl << ++indent;
175 break;
176 case OBJ_MID:
177 out << ',' << std::endl << indent;
178 break;
179 case TOP:
180 case VEC_START:
181 case VEC_MID:
182 case OBJ_AFTERTAG:
183 case OBJ_END:
184 BUG("invalid json output state for emit_tag");
185 }
186 out << '\"' << cstring(tag).escapeJson() << "\" : ";
187 output_state = OBJ_AFTERTAG;
188 }
189
190 template <typename T>
191 void emit(std::string_view tag, const T &val) {
192 emit_tag(tag);
193 generate(val);
194 output_state = OBJ_MID;
195 }
196
197 private:
198 template <typename T>
199 void generate(const safe_vector<T> &v) {
200 auto t = begin_vector();
201 for (auto &el : v) emit(el);
202 end_vector(t);
203 }
204
205 template <typename T>
206 void generate(const std::vector<T> &v) {
207 auto t = begin_vector();
208 for (auto &el : v) emit(el);
209 end_vector(t);
210 }
211
212 template <typename T, typename U>
213 void generate(const std::pair<T, U> &v) {
214 auto t = begin_object();
215 toJSON(v);
216 end_object(t);
217 }
218
219 public:
220 template <typename T, typename U>
221 void toJSON(const std::pair<T, U> &v) {
222 emit("first", v.first);
223 emit("second", v.second);
224 }
225
226 private:
227 template <typename T>
228 void generate(const std::optional<T> &v) {
229 auto t = begin_object();
230 emit("valid", !!v);
231 if (v) emit("value", *v);
232 end_object(t);
233 }
234
235 template <typename T>
236 void generate(const std::set<T> &v) {
237 auto t = begin_vector();
238 for (auto &el : v) emit(el);
239 end_vector(t);
240 }
241
242 template <typename T>
243 void generate(const ordered_set<T> &v) {
244 auto t = begin_vector();
245 for (auto &el : v) emit(el);
246 end_vector(t);
247 }
248
249 template <typename K, typename V>
250 void generate(const std::map<K, V> &v) {
251 auto t = begin_vector();
252 for (auto &el : v) emit(el);
253 end_vector(t);
254 }
255
256 template <typename K, typename V>
257 void generate(const ordered_map<K, V> &v) {
258 auto t = begin_vector();
259 for (auto &el : v) emit(el);
260 end_vector(t);
261 }
262
263 template <typename V>
264 void generate(const string_map<V> &v) {
265 auto t = begin_object();
266 for (auto &el : v) emit(el.first, el.second);
267 end_object(t);
268 }
269
270 template <class... Types>
271 void generate(const std::variant<Types...> &v) {
272 auto t = begin_object();
273 emit("variant_index", v.index());
274 std::visit([this](auto &value) { this->emit("value", value); }, v);
275 end_object(t);
276 }
277
278 void generate(bool v) { out << (v ? "true" : "false"); }
279 template <typename T>
280 std::enable_if_t<std::is_integral_v<T>> generate(T v) {
281 out << std::to_string(v);
282 }
283 void generate(double v) { out << std::to_string(v); }
284 template <typename T>
285 std::enable_if_t<std::is_same_v<T, big_int>> generate(const T &v) {
286 out << v;
287 }
288
289 void generate(cstring v) {
290 if (v) {
291 out << "\"" << v.escapeJson() << "\"";
292 } else {
293 out << "null";
294 }
295 }
296 template <typename T>
297 std::enable_if_t<std::is_same_v<T, LTBitMatrix> || std::is_enum_v<T>> generate(T v) {
298 out << "\"" << v << "\"";
299 }
300
301 void generate(const bitvec &v) { out << "\"" << v << "\""; }
302
303 void generate(const match_t &v) {
304 auto t = begin_object();
305 emit("word0", v.word0);
306 emit("word1", v.word1);
307 end_object(t);
308 }
309
310 template <typename T>
311 std::enable_if_t<has_toJSON<T>::value && !std::is_base_of_v<IR::Node, T>> generate(const T &v) {
312 auto t = begin_object();
313 v.toJSON(*this);
314 end_object(t);
315 }
316
317 void generate(const IR::Node &v) {
318 auto t = begin_object();
319 if (node_refs.find(v.id) != node_refs.end()) {
320 emit("Node_ID", v.id);
321 } else {
322 node_refs.insert(v.id);
323 v.toJSON(*this);
324 if (dumpSourceInfo) {
325 v.sourceInfoToJSON(*this);
326 }
327 }
328 end_object(t);
329 }
330
331 template <typename T>
332 std::enable_if_t<std::is_pointer_v<T> && has_toJSON<std::remove_pointer_t<T>>::value> generate(
333 T v) {
334 if (v)
335 generate(*v);
336 else
337 out << "null";
338 }
339
340 template <typename T, size_t N>
341 void generate(const T (&v)[N]) {
342 auto t = begin_vector();
343 for (auto &el : v) emit(el);
344 end_vector(t);
345 }
346};
347
348} // namespace P4
349
350#endif /* IR_JSON_GENERATOR_H_ */
Definition node.h:94
Definition bitvec.h:120
Definition cstring.h:85
cstring escapeJson() const
Definition cstring.cpp:272
Definition indent.h:26
Definition ordered_map.h:32
Definition ordered_set.h:32
Definition safe_vector.h:27
Definition string_map.h:41
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
Definition match.h:36