P4C
The P4 Compiler
Loading...
Searching...
No Matches
json_loader.h
1/*
2 * SPDX-FileCopyrightText: 2013 Barefoot Networks, Inc.
3 * Copyright 2013-present Barefoot Networks, Inc.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8#ifndef IR_JSON_LOADER_H_
9#define IR_JSON_LOADER_H_
10
11#include <map>
12#include <optional>
13#include <string>
14#include <string_view>
15#include <unordered_map>
16#include <utility>
17#include <variant>
18
19#include "ir.h"
20#include "json_parser.h"
21#include "lib/bitvec.h"
22#include "lib/cstring.h"
23#include "lib/ltbitmatrix.h"
24#include "lib/match.h"
25#include "lib/null.h"
26#include "lib/ordered_map.h"
27#include "lib/ordered_set.h"
28#include "lib/safe_vector.h"
29
30namespace P4 {
31
32class JSONLoader {
33 template <typename T>
34 class has_fromJSON {
35 typedef char small;
36 typedef struct {
37 char c[2];
38 } big;
39
40 template <typename C>
41 static small test(decltype(&C::fromJSON));
42 template <typename C>
43 static big test(...);
44
45 public:
46 static const bool value = sizeof(test<T>(0)) == sizeof(char);
47 };
48
49 std::unordered_map<int, IR::Node *> &node_refs;
50 std::unique_ptr<JsonData> json_root;
51 const JsonData *json = nullptr;
52 JsonData::LocationInfo *locinfo = nullptr;
53 bool (*errfn)(const JSONLoader &, std::string_view msg) = nullptr;
54
55 JSONLoader(const JsonData *json, std::unordered_map<int, IR::Node *> &refs,
57 : node_refs(refs), json(json), locinfo(locinfo) {}
58
59 public:
60 explicit JSONLoader(std::istream &in, JsonData::LocationInfo *li = nullptr)
61 : node_refs(*(new std::unordered_map<int, IR::Node *>())), locinfo(li) {
62 in >> json_root;
63 json = json_root.get();
64 }
65
66 JSONLoader(const JSONLoader &unpacker, std::string_view field)
67 : node_refs(unpacker.node_refs), json(nullptr), locinfo(unpacker.locinfo) {
68 if (!unpacker) return;
69 if (auto *obj = unpacker.json->to<JsonObject>()) {
70 if (auto it = obj->find(field); it != obj->end()) {
71 json = it->second.get();
72 }
73 }
74 }
75
76 explicit operator bool() const { return json != nullptr; }
77 template <typename T>
78 [[nodiscard]] bool is() const {
79 return json && json->is<T>();
80 }
81 template <typename T>
82 [[nodiscard]] const T &as() const {
83 return json->as<T>();
84 }
85
86 std::string locdesc(const JsonData &d) const {
87 if (!locinfo) return "";
88 return locinfo->desc(d);
89 }
90 std::string locdesc() const {
91 if (!json) return "";
92 return locdesc(*json);
93 }
94 bool error(std::string_view msg) const {
95 if ((!errfn || errfn(*this, msg)) && JsonData::strict) throw JsonData::error(msg, json);
96 return false;
97 }
98
99 private:
100 const IR::Node *get_node(NodeFactoryFn factory = nullptr) {
101 if (!json || !json->is<JsonObject>()) return nullptr; // invalid json exception?
102 int id;
103 auto success = load("Node_ID", id) || error("missing field Node_ID");
104 if (!success) return nullptr;
105 if (id >= 0) {
106 if (node_refs.find(id) == node_refs.end()) {
107 if (!factory) {
108 cstring type;
109 auto success = load("Node_Type", type) || error("missing field Node_Type");
110 if (!success) return nullptr;
111 factory = get(IR::unpacker_table, type);
112 }
113 if (factory) {
114 auto *node = factory(*this)->to<IR::Node>();
115 CHECK_NULL(node);
116 node_refs[id] = node;
117 // Creating JsonObject from source_info read from jsonFile
118 // and setting SourceInfo for each node
119 // when "--fromJSON" flag is used
120 node_refs[id]->sourceInfoFromJSON(*this);
121 } else {
122 return nullptr;
123 } // invalid json exception?
124 }
125 return node_refs[id];
126 }
127 return nullptr; // invalid json exception?
128 }
129
130 template <typename T>
131 void unpack_json(safe_vector<T> &v) {
132 T temp;
133 v.clear();
134 for (auto &e : as<JsonVector>()) {
135 load(e, temp);
136 v.push_back(temp);
137 }
138 }
139
140 template <typename T>
141 void unpack_json(std::set<T> &v) {
142 T temp;
143 v.clear();
144 for (auto &e : as<JsonVector>()) {
145 load(e, temp);
146 v.insert(temp);
147 }
148 }
149
150 template <typename T>
151 void unpack_json(ordered_set<T> &v) {
152 T temp;
153 v.clear();
154 for (auto &e : as<JsonVector>()) {
155 load(e, temp);
156 v.insert(temp);
157 }
158 }
159
160 template <typename T>
161 void unpack_json(IR::Vector<T> &v) {
162 v = get_node(NodeFactoryFn(&IR::Vector<T>::fromJSON))->as<IR::Vector<T>>();
163 }
164 template <typename T>
165 void unpack_json(const IR::Vector<T> *&v) {
166 v = get_node(NodeFactoryFn(&IR::Vector<T>::fromJSON))->checkedTo<IR::Vector<T>>();
167 }
168 template <typename T>
169 void unpack_json(IR::IndexedVector<T> &v) {
170 v = get_node(NodeFactoryFn(&IR::IndexedVector<T>::fromJSON))->as<IR::IndexedVector<T>>();
171 }
172 template <typename T>
173 void unpack_json(const IR::IndexedVector<T> *&v) {
174 v = get_node(NodeFactoryFn(&IR::IndexedVector<T>::fromJSON))
175 ->checkedTo<IR::IndexedVector<T>>();
176 }
177 template <class T, template <class K, class V, class COMP, class ALLOC> class MAP, class COMP,
178 class ALLOC>
179 void unpack_json(IR::NameMap<T, MAP, COMP, ALLOC> &m) {
180 m = get_node(NodeFactoryFn(&IR::NameMap<T, MAP, COMP, ALLOC>::fromJSON))
182 }
183 template <class T, template <class K, class V, class COMP, class ALLOC> class MAP, class COMP,
184 class ALLOC>
185 void unpack_json(const IR::NameMap<T, MAP, COMP, ALLOC> *&m) {
186 m = get_node(NodeFactoryFn(&IR::NameMap<T, MAP, COMP, ALLOC>::fromJSON))
188 }
189
190 template <typename K, typename V>
191 void unpack_json(std::map<K, V> &v) {
192 std::pair<K, V> temp;
193 v.clear();
194 if (is<JsonVector>()) {
195 for (auto &e : as<JsonVector>()) {
196 load(e, temp);
197 v.insert(temp);
198 }
199 } else {
200 for (auto &e : as<JsonObject>()) {
201 load(JsonString(e.first), temp.first);
202 load(e.second, temp.second);
203 v.insert(temp);
204 }
205 }
206 }
207 template <typename K, typename V>
208 void unpack_json(ordered_map<K, V> &v) {
209 std::pair<K, V> temp;
210 v.clear();
211 if (is<JsonVector>()) {
212 for (auto &e : as<JsonVector>()) {
213 load(e, temp);
214 v.insert(temp);
215 }
216 } else {
217 for (auto &e : as<JsonObject>()) {
218 load(JsonString(e.first), temp.first);
219 load(e.second, temp.second);
220 v.insert(temp);
221 }
222 }
223 }
224 template <typename V>
225 void unpack_json(string_map<V> &v) {
226 std::pair<cstring, V> temp;
227 v.clear();
228 for (auto &e : as<JsonObject>()) {
229 temp.first = e.first;
230 load(e.second, temp.second);
231 v.insert(temp);
232 }
233 }
234
235 template <typename K, typename V>
236 void unpack_json(std::multimap<K, V> &v) {
237 std::pair<K, V> temp;
238 v.clear();
239 if (is<JsonVector>()) {
240 for (auto &e : as<JsonVector>()) {
241 load(e, temp);
242 v.insert(temp);
243 }
244 } else {
245 for (auto &e : as<JsonObject>()) {
246 load(JsonString(e.first), temp.first);
247 load(e.second, temp.second);
248 v.insert(temp);
249 }
250 }
251 }
252
253 template <typename T>
254 void unpack_json(std::vector<T> &v) {
255 T temp;
256 v.clear();
257 for (auto &e : as<JsonVector>()) {
258 load(e, temp);
259 v.push_back(temp);
260 }
261 }
262
263 template <typename T, typename U>
264 void unpack_json(std::pair<T, U> &v) {
265 load("first", v.first) || error("missing field first");
266 load("second", v.second) || error("missing field second");
267 }
268
269 template <typename T>
270 void unpack_json(std::optional<T> &v) {
271 bool isValid = false;
272 load("valid", isValid) || error("missing field valid");
273 if (!isValid) {
274 v = std::nullopt;
275 return;
276 }
277 T value;
278 auto success = load("value", value) || error("missing field value");
279 if (!success) {
280 v = std::nullopt;
281 return;
282 }
283 v = std::move(value);
284 }
285
286 template <int N, class Variant>
287 std::enable_if_t<N == std::variant_size_v<Variant>> unpack_variant(int /*target*/,
288 Variant & /*variant*/) {
289 BUG("Error traversing variant during load");
290 }
291
292 template <int N, class Variant>
293 std::enable_if_t<(N < std::variant_size_v<Variant>)> unpack_variant(int target,
294 Variant &variant) {
295 if (N == target) {
296 variant.template emplace<N>();
297 load("value", std::get<N>(variant)) || error("missing field value");
298 } else
299 unpack_variant<N + 1>(target, variant);
300 }
301
302 template <class... Types>
303 void unpack_json(std::variant<Types...> &v) {
304 int index = -1;
305 load("variant_index", index) || error("missing field variant_index");
306 unpack_variant<0>(index, v);
307 }
308
309 void unpack_json(bool &v) { v = as<JsonBoolean>(); }
310
311 template <typename T>
312 std::enable_if_t<std::is_integral_v<T>> unpack_json(T &v) {
313 v = as<JsonNumber>();
314 }
315 void unpack_json(big_int &v) { v = as<JsonNumber>().val; }
316 void unpack_json(std::string &v) {
317 if (is<JsonString>()) v = as<JsonString>();
318 }
319 void unpack_json(cstring &v) {
320 if (is<JsonString>())
321 v = cstring(as<JsonString>());
322 else if (is<JsonNull>())
323 v = cstring();
324 }
325 void unpack_json(IR::ID &v) {
326 if (!json->is<JsonNull>()) v.name = as<JsonString>();
327 }
328
329 void unpack_json(LTBitMatrix &m) {
330 if (auto *s = json->to<JsonString>()) s->c_str() >> m;
331 }
332
333 void unpack_json(bitvec &v) {
334 if (auto *s = json->to<JsonString>()) s->c_str() >> v;
335 }
336
337 template <typename T>
338 std::enable_if_t<std::is_enum_v<T>> unpack_json(T &v) {
339 if (auto *s = json->to<JsonString>()) *s >> v;
340 }
341
342 void unpack_json(match_t &v) {
343 if (auto *s = json->to<JsonString>()) s->c_str() >> v;
344 }
345
346 template <typename T>
347 std::enable_if_t<has_fromJSON<T>::value && !std::is_base_of_v<IR::INode, T> &&
348 std::is_pointer_v<decltype(T::fromJSON(std::declval<JSONLoader &>()))>>
349 unpack_json(T *&v) {
350 v = T::fromJSON(*this);
351 }
352
353 template <typename T>
354 std::enable_if_t<has_fromJSON<T>::value && !std::is_base_of_v<IR::INode, T> &&
355 std::is_pointer_v<decltype(T::fromJSON(std::declval<JSONLoader &>()))>>
356 unpack_json(T &v) {
357 v = *(T::fromJSON(*this));
358 }
359
360 template <typename T>
361 std::enable_if_t<has_fromJSON<T>::value && !std::is_base_of<IR::INode, T>::value &&
362 !std::is_pointer_v<decltype(T::fromJSON(std::declval<JSONLoader &>()))>>
363 unpack_json(T &v) {
364 v = T::fromJSON(*this);
365 }
366
367 template <typename T>
368 std::enable_if_t<has_fromJSON<T>::value && !std::is_base_of<IR::INode, T>::value &&
369 !std::is_pointer_v<decltype(T::fromJSON(std::declval<JSONLoader &>()))>>
370 unpack_json(T *&v) {
371 v = new T(T::fromJSON(*this));
372 }
373
374 template <typename T>
375 std::enable_if_t<std::is_base_of_v<IR::INode, T>> unpack_json(T &v) {
376 v = get_node()->as<T>();
377 }
378 template <typename T>
379 std::enable_if_t<std::is_base_of_v<IR::INode, T>> unpack_json(const T *&v) {
380 v = get_node()->checkedTo<T>();
381 }
382
383 template <typename T, size_t N>
384 void unpack_json(T (&v)[N]) {
385 if (auto *j = json->to<JsonVector>()) {
386 for (size_t i = 0; i < N && i < j->size(); ++i) {
387 load(j->at(i), v[i]);
388 }
389 }
390 }
391
392 public:
393 template <typename T>
394 void load(const JsonData &json, T &v) {
395 JSONLoader(&json, node_refs, locinfo).unpack_json(v);
396 }
397
398 template <typename T>
399 void load(const std::unique_ptr<JsonData> &json, T &v) {
400 JSONLoader(json.get(), node_refs, locinfo).unpack_json(v);
401 }
402
403 template <typename T>
404 bool load(std::string_view field, T *&v) {
405 if (auto loader = JSONLoader(*this, field)) {
406 loader.unpack_json(v);
407 return true;
408 } else {
409 v = nullptr;
410 return false;
411 }
412 }
413
414 template <typename T>
415 bool load(std::string_view field, T &v) {
416 if (auto loader = JSONLoader(*this, field)) {
417 loader.unpack_json(v);
418 return true;
419 }
420 return false;
421 }
422
423 template <typename T>
424 JSONLoader &operator>>(T &v) {
425 unpack_json(v);
426 return *this;
427 }
428};
429
430template <class T>
431IR::Vector<T>::Vector(JSONLoader &json) : VectorBase(json) {
432 json.load("vec", vec) || json.error("missing field vec");
433}
434template <class T>
435IR::Node *IR::Vector<T>::fromJSON(JSONLoader &json) {
436 return new Vector<T>(json);
437}
438template <class T>
439IR::IndexedVector<T>::IndexedVector(JSONLoader &json) : Vector<T>(json) {
440 json.load("declarations", declarations) || json.error("missing field declarations");
441}
442template <class T>
443IR::Node *IR::IndexedVector<T>::fromJSON(JSONLoader &json) {
444 return new IndexedVector<T>(json);
445}
446template <class T, template <class K, class V, class COMP, class ALLOC> class MAP /*= std::map */,
447 class COMP /*= std::less<cstring>*/,
448 class ALLOC /*= std::allocator<std::pair<cstring, const T*>>*/>
449IR::NameMap<T, MAP, COMP, ALLOC>::NameMap(JSONLoader &json) : Node(json) {
450 json.load("symbols", symbols) || json.error("missing field symbols");
451}
452template <class T, template <class K, class V, class COMP, class ALLOC> class MAP /*= std::map */,
453 class COMP /*= std::less<cstring>*/,
454 class ALLOC /*= std::allocator<std::pair<cstring, const T*>>*/>
455IR::Node *IR::NameMap<T, MAP, COMP, ALLOC>::fromJSON(JSONLoader &json) {
456 return new IR::NameMap<T, MAP, COMP, ALLOC>(json);
457}
458
459} // namespace P4
460
461#endif /* IR_JSON_LOADER_H_ */
const T & as() const
Tries to convert the class to type T. A BUG occurs if the cast fails.
Definition castable.h:33
Definition indexed_vector.h:31
Definition namemap.h:38
Definition node.h:53
Definition ir/vector.h:59
Definition json_loader.h:32
Definition json_parser.h:41
Definition json_parser.h:17
Definition json_parser.h:112
Definition json_parser.h:101
Definition json_parser.h:77
Definition json_parser.h:90
Definition ltbitmatrix.h:25
Definition bitvec.h:120
Definition cstring.h:85
Definition ordered_map.h:32
Definition ordered_set.h:32
Definition safe_vector.h:18
Definition string_map.h:41
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:13
Definition bson.cpp:69
Definition id.h:28
Definition json_parser.h:32
T * to() noexcept
Definition rtti.h:226
Definition match.h:36