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