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
61 JSONLoader(const JsonData *json, std::unordered_map<int, IR::Node *> &refs)
62 : node_refs(refs), json(json) {}
63
64 public:
65 explicit JSONLoader(std::istream &in)
66 : node_refs(*(new std::unordered_map<int, IR::Node *>())) {
67 in >> json_root;
68 json = json_root.get();
69 }
70
71 JSONLoader(const JSONLoader &unpacker, std::string_view field)
72 : node_refs(unpacker.node_refs), json(nullptr) {
73 if (!unpacker) return;
74 if (auto *obj = unpacker.json->to<JsonObject>()) {
75 if (auto it = obj->find(field); it != obj->end()) {
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
91 private:
92 const IR::Node *get_node() {
93 if (!json || !json->is<JsonObject>()) return nullptr; // invalid json exception?
94 int id;
95 auto success = load("Node_ID", id);
96 if (!success) {
97 return nullptr;
98 }
99 if (id >= 0) {
100 if (node_refs.find(id) == node_refs.end()) {
101 cstring type;
102 auto success = load("Node_Type", type);
103 if (!success) {
104 return nullptr;
105 }
106 if (auto fn = get(IR::unpacker_table, type)) {
107 node_refs[id] = fn(*this);
108 // Creating JsonObject from source_info read from jsonFile
109 // and setting SourceInfo for each node
110 // when "--fromJSON" flag is used
111 node_refs[id]->sourceInfoFromJSON(*this);
112 } else {
113 return nullptr;
114 } // invalid json exception?
115 }
116 return node_refs[id];
117 }
118 return nullptr; // invalid json exception?
119 }
120
121 template <typename T>
122 void unpack_json(safe_vector<T> &v) {
123 T temp;
124 v.clear();
125 for (auto &e : as<JsonVector>()) {
126 load(e, temp);
127 v.push_back(temp);
128 }
129 }
130
131 template <typename T>
132 void unpack_json(std::set<T> &v) {
133 T temp;
134 v.clear();
135 for (auto &e : as<JsonVector>()) {
136 load(e, temp);
137 v.insert(temp);
138 }
139 }
140
141 template <typename T>
142 void unpack_json(ordered_set<T> &v) {
143 T temp;
144 v.clear();
145 for (auto &e : as<JsonVector>()) {
146 load(e, temp);
147 v.insert(temp);
148 }
149 }
150
151 template <typename T>
152 void unpack_json(IR::Vector<T> &v) {
153 v = *IR::Vector<T>::fromJSON(*this);
154 }
155 template <typename T>
156 void unpack_json(const IR::Vector<T> *&v) {
157 v = IR::Vector<T>::fromJSON(*this);
158 }
159 template <typename T>
160 void unpack_json(IR::IndexedVector<T> &v) {
161 v = *IR::IndexedVector<T>::fromJSON(*this);
162 }
163 template <typename T>
164 void unpack_json(const IR::IndexedVector<T> *&v) {
165 v = IR::IndexedVector<T>::fromJSON(*this);
166 }
167 template <class T, template <class K, class V, class COMP, class ALLOC> class MAP, class COMP,
168 class ALLOC>
169 void unpack_json(IR::NameMap<T, MAP, COMP, ALLOC> &m) {
170 m = *IR::NameMap<T, MAP, COMP, ALLOC>::fromJSON(*this);
171 }
172 template <class T, template <class K, class V, class COMP, class ALLOC> class MAP, class COMP,
173 class ALLOC>
174 void unpack_json(const IR::NameMap<T, MAP, COMP, ALLOC> *&m) {
175 m = IR::NameMap<T, MAP, COMP, ALLOC>::fromJSON(*this);
176 }
177
178 template <typename K, typename V>
179 void unpack_json(std::map<K, V> &v) {
180 std::pair<K, V> temp;
181 v.clear();
182 if (is<JsonVector>()) {
183 for (auto &e : as<JsonVector>()) {
184 load(e, temp);
185 v.insert(temp);
186 }
187 } else {
188 for (auto &e : as<JsonObject>()) {
189 load(JsonString(e.first), temp.first);
190 load(e.second, temp.second);
191 v.insert(temp);
192 }
193 }
194 }
195 template <typename K, typename V>
196 void unpack_json(ordered_map<K, V> &v) {
197 std::pair<K, V> temp;
198 v.clear();
199 if (is<JsonVector>()) {
200 for (auto &e : as<JsonVector>()) {
201 load(e, temp);
202 v.insert(temp);
203 }
204 } else {
205 for (auto &e : as<JsonObject>()) {
206 load(JsonString(e.first), temp.first);
207 load(e.second, temp.second);
208 v.insert(temp);
209 }
210 }
211 }
212 template <typename V>
213 void unpack_json(string_map<V> &v) {
214 std::pair<cstring, V> temp;
215 v.clear();
216 for (auto &e : as<JsonObject>()) {
217 temp.first = e.first;
218 load(e.second, temp.second);
219 v.insert(temp);
220 }
221 }
222
223 template <typename K, typename V>
224 void unpack_json(std::multimap<K, V> &v) {
225 std::pair<K, V> temp;
226 v.clear();
227 if (is<JsonVector>()) {
228 for (auto &e : as<JsonVector>()) {
229 load(e, temp);
230 v.insert(temp);
231 }
232 } else {
233 for (auto &e : as<JsonObject>()) {
234 load(JsonString(e.first), temp.first);
235 load(e.second, temp.second);
236 v.insert(temp);
237 }
238 }
239 }
240
241 template <typename T>
242 void unpack_json(std::vector<T> &v) {
243 T temp;
244 v.clear();
245 for (auto &e : as<JsonVector>()) {
246 load(e, temp);
247 v.push_back(temp);
248 }
249 }
250
251 template <typename T, typename U>
252 void unpack_json(std::pair<T, U> &v) {
253 load("first", v.first);
254 load("second", v.second);
255 }
256
257 template <typename T>
258 void unpack_json(std::optional<T> &v) {
259 bool isValid = false;
260 load("valid", isValid);
261 if (!isValid) {
262 v = std::nullopt;
263 return;
264 }
265 T value;
266 auto success = load("value", value);
267 if (!success) {
268 v = std::nullopt;
269 return;
270 }
271 v = std::move(value);
272 }
273
274 template <int N, class Variant>
275 std::enable_if_t<N == std::variant_size_v<Variant>> unpack_variant(int /*target*/,
276 Variant & /*variant*/) {
277 BUG("Error traversing variant during load");
278 }
279
280 template <int N, class Variant>
281 std::enable_if_t<(N < std::variant_size_v<Variant>)> unpack_variant(int target,
282 Variant &variant) {
283 if (N == target) {
284 variant.template emplace<N>();
285 load("value", std::get<N>(variant));
286 } else
287 unpack_variant<N + 1>(target, variant);
288 }
289
290 template <class... Types>
291 void unpack_json(std::variant<Types...> &v) {
292 int index = -1;
293 load("variant_index", index);
294 unpack_variant<0>(index, v);
295 }
296
297 void unpack_json(bool &v) { v = as<JsonBoolean>(); }
298
299 template <typename T>
300 std::enable_if_t<std::is_integral_v<T>> unpack_json(T &v) {
301 v = as<JsonNumber>();
302 }
303 void unpack_json(big_int &v) { v = as<JsonNumber>().val; }
304 void unpack_json(std::string &v) {
305 if (is<JsonString>()) v = as<JsonString>();
306 }
307 void unpack_json(cstring &v) {
308 if (is<JsonString>())
309 v = cstring(as<JsonString>());
310 else if (is<JsonNull>())
311 v = cstring();
312 }
313 void unpack_json(IR::ID &v) {
314 if (!json->is<JsonNull>()) v.name = as<JsonString>();
315 }
316
317 void unpack_json(LTBitMatrix &m) {
318 if (auto *s = json->to<JsonString>()) s->c_str() >> m;
319 }
320
321 void unpack_json(bitvec &v) {
322 if (auto *s = json->to<JsonString>()) s->c_str() >> v;
323 }
324
325 template <typename T>
326 std::enable_if_t<std::is_enum_v<T>> unpack_json(T &v) {
327 if (auto *s = json->to<JsonString>()) *s >> v;
328 }
329
330 void unpack_json(match_t &v) {
331 if (auto *s = json->to<JsonString>()) s->c_str() >> v;
332 }
333
334 void unpack_json(UnparsedConstant *&v) {
335 cstring text("");
336 unsigned skip = 0;
337 unsigned base = 0;
338 bool hasWidth = false;
339
340 load("text", text);
341 load("skip", skip);
342 load("base", base);
343 load("hasWidth", hasWidth);
344
345 v = new UnparsedConstant({text, skip, base, hasWidth});
346 }
347
348 template <typename T>
349 std::enable_if_t<has_fromJSON<T>::value && !std::is_base_of_v<IR::Node, T> &&
350 std::is_pointer_v<decltype(T::fromJSON(std::declval<JSONLoader &>()))>>
351 unpack_json(T *&v) {
352 v = T::fromJSON(*this);
353 }
354
355 template <typename T>
356 std::enable_if_t<has_fromJSON<T>::value && !std::is_base_of_v<IR::Node, 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<IR::Node, T>::value &&
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<std::is_base_of_v<IR::INode, T>> unpack_json(T &v) {
371 v = get_node()->as<T>();
372 }
373 template <typename T>
374 std::enable_if_t<std::is_base_of_v<IR::INode, T>> unpack_json(const T *&v) {
375 v = get_node()->checkedTo<T>();
376 }
377
378 template <typename T, size_t N>
379 void unpack_json(T (&v)[N]) {
380 if (auto *j = json->to<JsonVector>()) {
381 for (size_t i = 0; i < N && i < j->size(); ++i) {
382 load(j->at(i), v[i]);
383 }
384 }
385 }
386
387 public:
388 template <typename T>
389 void load(const JsonData &json, T &v) {
390 JSONLoader(&json, node_refs).unpack_json(v);
391 }
392
393 template <typename T>
394 void load(const std::unique_ptr<JsonData> &json, T &v) {
395 JSONLoader(json.get(), node_refs).unpack_json(v);
396 }
397
398 template <typename T>
399 bool load(std::string_view field, T *&v) {
400 if (auto loader = JSONLoader(*this, field)) {
401 loader.unpack_json(v);
402 return true;
403 } else {
404 v = nullptr;
405 return false;
406 }
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 }
415 return false;
416 }
417
418 template <typename T>
419 JSONLoader &operator>>(T &v) {
420 unpack_json(v);
421 return *this;
422 }
423};
424
425template <class T>
426IR::Vector<T>::Vector(JSONLoader &json) : VectorBase(json) {
427 json.load("vec", vec);
428}
429template <class T>
430IR::Vector<T> *IR::Vector<T>::fromJSON(JSONLoader &json) {
431 return new Vector<T>(json);
432}
433template <class T>
434IR::IndexedVector<T>::IndexedVector(JSONLoader &json) : Vector<T>(json) {
435 json.load("declarations", declarations);
436}
437template <class T>
438IR::IndexedVector<T> *IR::IndexedVector<T>::fromJSON(JSONLoader &json) {
439 return new IndexedVector<T>(json);
440}
441template <class T, template <class K, class V, class COMP, class ALLOC> class MAP /*= std::map */,
442 class COMP /*= std::less<cstring>*/,
443 class ALLOC /*= std::allocator<std::pair<cstring, const T*>>*/>
444IR::NameMap<T, MAP, COMP, ALLOC>::NameMap(JSONLoader &json) : Node(json) {
445 json.load("symbols", symbols);
446}
447template <class T, template <class K, class V, class COMP, class ALLOC> class MAP /*= std::map */,
448 class COMP /*= std::less<cstring>*/,
449 class ALLOC /*= std::allocator<std::pair<cstring, const T*>>*/>
450IR::NameMap<T, MAP, COMP, ALLOC> *IR::NameMap<T, MAP, COMP, ALLOC>::fromJSON(JSONLoader &json) {
451 return new IR::NameMap<T, MAP, COMP, ALLOC>(json);
452}
453
454} // namespace P4
455
456#endif /* IR_JSON_LOADER_H_ */
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:17
Definition json_parser.h:84
Definition json_parser.h:73
Definition json_parser.h:49
Definition json_parser.h:62
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 constantParsing.h:65
Definition bson.cpp:69
Definition id.h:28
T * to() noexcept
Definition rtti.h:226
Definition match.h:36