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