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