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