Branch data Line data Source code
1 : : /* JSON trees
2 : : Copyright (C) 2017-2025 Free Software Foundation, Inc.
3 : : Contributed by David Malcolm <dmalcolm@redhat.com>.
4 : :
5 : : This file is part of GCC.
6 : :
7 : : GCC is free software; you can redistribute it and/or modify it under
8 : : the terms of the GNU General Public License as published by the Free
9 : : Software Foundation; either version 3, or (at your option) any later
10 : : version.
11 : :
12 : : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 : : WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 : : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 : : for more details.
16 : :
17 : : You should have received a copy of the GNU General Public License
18 : : along with GCC; see the file COPYING3. If not see
19 : : <http://www.gnu.org/licenses/>. */
20 : :
21 : : #ifndef GCC_JSON_H
22 : : #define GCC_JSON_H
23 : :
24 : : #include "label-text.h"
25 : :
26 : : /* Implementation of JSON, a lightweight data-interchange format.
27 : :
28 : : See http://www.json.org/
29 : : and http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
30 : : and https://tools.ietf.org/html/rfc7159
31 : :
32 : : Supports parsing text into a DOM-like tree of json::value *, directly
33 : : creating such trees, and dumping json::value * to text. */
34 : :
35 : : /* TODO: `libcpp/mkdeps.cc` wants JSON writing support for p1689r5 output;
36 : : extract this code and move to libiberty. */
37 : :
38 : : namespace json
39 : : {
40 : :
41 : : /* Forward decls of json::value and its subclasses (using indentation
42 : : to denote inheritance. */
43 : :
44 : : class value;
45 : : class object;
46 : : class array;
47 : : class float_number;
48 : : class integer_number;
49 : : class string;
50 : : class literal;
51 : :
52 : : /* An enum for discriminating the subclasses of json::value. */
53 : :
54 : : enum kind
55 : : {
56 : : /* class json::object. */
57 : : JSON_OBJECT,
58 : :
59 : : /* class json::array. */
60 : : JSON_ARRAY,
61 : :
62 : : /* class json::integer_number. */
63 : : JSON_INTEGER,
64 : :
65 : : /* class json::float_number. */
66 : : JSON_FLOAT,
67 : :
68 : : /* class json::string. */
69 : : JSON_STRING,
70 : :
71 : : /* class json::literal uses these three values to identify the
72 : : particular literal. */
73 : : JSON_TRUE,
74 : : JSON_FALSE,
75 : : JSON_NULL
76 : : };
77 : :
78 : : namespace pointer { // json::pointer
79 : :
80 : : /* Implementation of JSON pointer (RFC 6901). */
81 : :
82 : : /* A token within a JSON pointer, expressing the parent of a particular
83 : : JSON value, and how it is descended from that parent.
84 : :
85 : : A JSON pointer can be built as a list of these tokens. */
86 : :
87 : : struct token
88 : : {
89 : : enum class kind
90 : : {
91 : : root_value,
92 : : object_member,
93 : : array_index
94 : : };
95 : :
96 : : token ();
97 : : token (json::object &parent, const char *member);
98 : : token (json::array &parent, size_t index);
99 : : token (const token &other) = delete;
100 : : token (token &&other) = delete;
101 : :
102 : : ~token ();
103 : :
104 : : token &
105 : : operator= (const token &other) = delete;
106 : :
107 : : token &
108 : : operator= (token &&other);
109 : :
110 : : json::value *m_parent;
111 : : union u
112 : : {
113 : : char *u_member;
114 : : size_t u_index;
115 : : } m_data;
116 : : enum kind m_kind;
117 : : };
118 : :
119 : : } // namespace json::pointer
120 : :
121 : : /* Typesafe way to work with properties in JSON objects. */
122 : :
123 : : template <typename Traits>
124 : 78 : struct property
125 : : {
126 : : explicit property (const char *key)
127 : : : m_key (label_text::borrow (key))
128 : : {}
129 : :
130 : 39 : explicit property (const char *key_prefix, const char *key)
131 : 39 : : m_key (label_text::take (concat (key_prefix, key, nullptr)))
132 : : {}
133 : :
134 : : label_text m_key;
135 : : };
136 : :
137 : : using string_property = property<string>;
138 : : using integer_property = property<integer_number>;
139 : : using bool_property = property<literal>;
140 : : using json_property = property<value>;
141 : : using array_of_string_property = property<array>;
142 : :
143 : : template <typename EnumType>
144 : : struct enum_traits
145 : : {
146 : : typedef EnumType enum_t;
147 : :
148 : : static enum_t get_unknown_value ();
149 : : static bool maybe_get_value_from_string (const char *, enum_t &out);
150 : : static const char *get_string_for_value (enum_t value);
151 : : };
152 : :
153 : : template <typename EnumType>
154 : : using enum_property = property<enum_traits<EnumType>>;
155 : :
156 : : /* Base class of JSON value. */
157 : :
158 : 2637713 : class value
159 : : {
160 : : public:
161 : 3365797 : virtual ~value () {}
162 : : virtual enum kind get_kind () const = 0;
163 : : virtual void print (pretty_printer *pp, bool formatted) const = 0;
164 : : virtual std::unique_ptr<value> clone () const = 0;
165 : :
166 : : void dump (FILE *, bool formatted) const;
167 : : void DEBUG_FUNCTION dump () const;
168 : :
169 : 0 : virtual object *dyn_cast_object () { return nullptr; }
170 : 0 : virtual array *dyn_cast_array () { return nullptr; }
171 : 0 : virtual integer_number *dyn_cast_integer_number () { return nullptr; }
172 : 0 : virtual string *dyn_cast_string () { return nullptr; }
173 : :
174 : : static int compare (const json::value &val_a, const json::value &val_b);
175 : :
176 : : const pointer::token &get_pointer_token () const { return m_pointer_token; }
177 : :
178 : : pointer::token m_pointer_token;
179 : : };
180 : :
181 : : /* Subclass of value for objects: a collection of key/value pairs
182 : : preserving the ordering in which keys were inserted.
183 : :
184 : : Preserving the order eliminates non-determinism in the output,
185 : : making it easier for the user to compare repeated invocations. */
186 : :
187 : : class object : public value
188 : : {
189 : : public:
190 : : ~object ();
191 : :
192 : : typedef hash_map <char *, value *,
193 : : simple_hashmap_traits<nofree_string_hash, value *> > map_t;
194 : :
195 : 18367 : enum kind get_kind () const final override { return JSON_OBJECT; }
196 : : void print (pretty_printer *pp, bool formatted) const final override;
197 : : std::unique_ptr<value> clone () const final override;
198 : :
199 : 303 : object *dyn_cast_object () final override { return this; }
200 : :
201 : 484 : bool is_empty () const { return m_map.is_empty (); }
202 : :
203 : : void set (const char *key, value *v);
204 : :
205 : : /* Set the property KEY of this object, requiring V
206 : : to be of a specific json::value subclass.
207 : :
208 : : This can be used to enforce type-checking, making it easier
209 : : to comply with a schema, e.g.
210 : : obj->set<some_subclass> ("property_name", value)
211 : : leading to a compile-time error if VALUE is not of the
212 : : appropriate subclass. */
213 : : template <typename JsonType>
214 : 15357 : void set (const char *key, std::unique_ptr<JsonType> v)
215 : : {
216 : 15419 : set (key, v.release ());
217 : : }
218 : :
219 : : value *get (const char *key) const;
220 : : const map_t &get_map () const { return m_map; }
221 : :
222 : : void set_string (const char *key, const char *utf8_value);
223 : : void set_integer (const char *key, long v);
224 : : void set_float (const char *key, double v);
225 : :
226 : : /* Set to literal true/false. */
227 : : void set_bool (const char *key, bool v);
228 : :
229 : : /* Typesafe access to properties by name (such as from a schema). */
230 : : void set_string (const string_property &property, const char *utf8_value);
231 : : void set_integer (const integer_property &property, long value);
232 : : void set_bool (const bool_property &property, bool value);
233 : : void set_array_of_string (const array_of_string_property &property,
234 : : std::unique_ptr<json::array> value);
235 : : template <typename EnumType>
236 : : bool maybe_get_enum (const enum_property<EnumType> &property,
237 : : EnumType &out) const;
238 : : template <typename EnumType>
239 : : void set_enum (const enum_property<EnumType> &property,
240 : : EnumType value);
241 : :
242 : : static int compare (const json::object &obj_a, const json::object &obj_b);
243 : :
244 : 2435 : size_t get_num_keys () const { return m_keys.length (); }
245 : 1864 : const char *get_key (size_t i) const { return m_keys[i]; }
246 : :
247 : : std::unique_ptr<object> clone_as_object () const;
248 : :
249 : : private:
250 : : map_t m_map;
251 : :
252 : : /* Keep track of order in which keys were inserted. */
253 : : auto_vec <const char *> m_keys;
254 : : };
255 : :
256 : : /* Subclass of value for arrays. */
257 : :
258 : 610435 : class array : public value
259 : : {
260 : : public:
261 : : ~array ();
262 : :
263 : 777 : enum kind get_kind () const final override { return JSON_ARRAY; }
264 : : void print (pretty_printer *pp, bool formatted) const final override;
265 : : std::unique_ptr<value> clone () const final override;
266 : :
267 : 0 : array *dyn_cast_array () final override { return this; }
268 : :
269 : : void append (value *v);
270 : : void append_string (const char *utf8_value);
271 : :
272 : : /* Append V to this array, requiring V
273 : : to be a specific json::value subclass.
274 : :
275 : : This can be used to enforce type-checking, making it easier
276 : : to comply with a schema, e.g.
277 : : arr->append<some_subclass> (value)
278 : : leading to a compile-time error if VALUE is not of the
279 : : appropriate subclass. */
280 : : template <typename JsonType>
281 : 4391 : void append (std::unique_ptr<JsonType> v)
282 : : {
283 : 4391 : append (v.release ());
284 : : }
285 : :
286 : 2090 : size_t size () const { return m_elements.length (); }
287 : 916 : value *operator[] (size_t i) const { return m_elements[i]; }
288 : :
289 : : value **begin () { return m_elements.begin (); }
290 : : value **end () { return m_elements.end (); }
291 : : const value * const *begin () const { return m_elements.begin (); }
292 : : const value * const *end () const { return m_elements.end (); }
293 : 416 : size_t length () const { return m_elements.length (); }
294 : 351 : value *get (size_t idx) const { return m_elements[idx]; }
295 : :
296 : : private:
297 : : auto_vec<value *> m_elements;
298 : : };
299 : :
300 : : /* Subclass of value for floating-point numbers. */
301 : :
302 : 24 : class float_number : public value
303 : : {
304 : : public:
305 : 56 : float_number (double value) : m_value (value) {}
306 : :
307 : 84 : enum kind get_kind () const final override { return JSON_FLOAT; }
308 : : void print (pretty_printer *pp, bool formatted) const final override;
309 : : std::unique_ptr<value> clone () const final override;
310 : :
311 : 44 : double get () const { return m_value; }
312 : :
313 : : private:
314 : : double m_value;
315 : : };
316 : :
317 : : /* Subclass of value for integer-valued numbers. */
318 : :
319 : 28 : class integer_number : public value
320 : : {
321 : : public:
322 : 656056 : integer_number (long value) : m_value (value) {}
323 : :
324 : 2467 : enum kind get_kind () const final override { return JSON_INTEGER; }
325 : : void print (pretty_printer *pp, bool formatted) const final override;
326 : : std::unique_ptr<value> clone () const final override;
327 : :
328 : 0 : integer_number *dyn_cast_integer_number () final override { return this; }
329 : :
330 : 2334 : long get () const { return m_value; }
331 : :
332 : : private:
333 : : long m_value;
334 : : };
335 : :
336 : :
337 : : /* Subclass of value for strings. */
338 : :
339 : : class string : public value
340 : : {
341 : : public:
342 : : explicit string (const char *utf8);
343 : : string (const char *utf8, size_t len);
344 : 4053102 : ~string () { free (m_utf8); }
345 : :
346 : 22926 : enum kind get_kind () const final override { return JSON_STRING; }
347 : : void print (pretty_printer *pp, bool formatted) const final override;
348 : : std::unique_ptr<value> clone () const final override;
349 : 41 : string *dyn_cast_string () final override { return this; }
350 : :
351 : 12116 : const char *get_string () const { return m_utf8; }
352 : : size_t get_length () const { return m_len; }
353 : :
354 : : private:
355 : : char *m_utf8;
356 : : size_t m_len;
357 : : };
358 : :
359 : : /* Subclass of value for the three JSON literals "true", "false",
360 : : and "null". */
361 : :
362 : 28 : class literal : public value
363 : : {
364 : : public:
365 : 44 : literal (enum kind kind) : m_kind (kind) {}
366 : :
367 : : /* Construct literal for a boolean value. */
368 : 743 : literal (bool value): m_kind (value ? JSON_TRUE : JSON_FALSE) {}
369 : :
370 : 144 : enum kind get_kind () const final override { return m_kind; }
371 : : void print (pretty_printer *pp, bool formatted) const final override;
372 : : std::unique_ptr<value> clone () const final override;
373 : :
374 : : private:
375 : : enum kind m_kind;
376 : : };
377 : :
378 : :
379 : : template <typename EnumType>
380 : : inline bool
381 : 24 : object::maybe_get_enum (const enum_property<EnumType> &property,
382 : : EnumType &out) const
383 : : {
384 : 24 : if (value *jv = get (property.m_key.get ()))
385 : 20 : if (string *jstr = jv->dyn_cast_string ())
386 : : {
387 : 20 : if (enum_traits<EnumType>::maybe_get_value_from_string
388 : 20 : (jstr->get_string (), out))
389 : : return true;
390 : : }
391 : : return false;
392 : : }
393 : :
394 : : template <typename EnumType>
395 : : inline void
396 : 594 : object::set_enum (const enum_property<EnumType> &property,
397 : : EnumType value)
398 : : {
399 : : const char *str
400 : 594 : = json::enum_traits<EnumType>::get_string_for_value (value);
401 : 594 : set_string (property.m_key.get (), str);
402 : 594 : }
403 : :
404 : : } // namespace json
405 : :
406 : : template <>
407 : : template <>
408 : : inline bool
409 : : is_a_helper <json::value *>::test (json::value *)
410 : : {
411 : : return true;
412 : : }
413 : :
414 : : template <>
415 : : template <>
416 : : inline bool
417 : : is_a_helper <const json::value *>::test (const json::value *)
418 : : {
419 : : return true;
420 : : }
421 : :
422 : : template <>
423 : : template <>
424 : : inline bool
425 : : is_a_helper <json::object *>::test (json::value *jv)
426 : : {
427 : : return jv->get_kind () == json::JSON_OBJECT;
428 : : }
429 : :
430 : : template <>
431 : : template <>
432 : : inline bool
433 : : is_a_helper <const json::object *>::test (const json::value *jv)
434 : : {
435 : : return jv->get_kind () == json::JSON_OBJECT;
436 : : }
437 : :
438 : : template <>
439 : : template <>
440 : : inline bool
441 : 4 : is_a_helper <json::array *>::test (json::value *jv)
442 : : {
443 : 4 : return jv->get_kind () == json::JSON_ARRAY;
444 : : }
445 : :
446 : : template <>
447 : : template <>
448 : : inline bool
449 : 4 : is_a_helper <const json::array *>::test (const json::value *jv)
450 : : {
451 : 4 : return jv->get_kind () == json::JSON_ARRAY;
452 : : }
453 : :
454 : : template <>
455 : : template <>
456 : : inline bool
457 : : is_a_helper <json::float_number *>::test (json::value *jv)
458 : : {
459 : : return jv->get_kind () == json::JSON_FLOAT;
460 : : }
461 : :
462 : : template <>
463 : : template <>
464 : : inline bool
465 : 8 : is_a_helper <const json::float_number *>::test (const json::value *jv)
466 : : {
467 : 8 : return jv->get_kind () == json::JSON_FLOAT;
468 : : }
469 : :
470 : : template <>
471 : : template <>
472 : : inline bool
473 : 44 : is_a_helper <json::integer_number *>::test (json::value *jv)
474 : : {
475 : 44 : return jv->get_kind () == json::JSON_INTEGER;
476 : : }
477 : :
478 : : template <>
479 : : template <>
480 : : inline bool
481 : 12 : is_a_helper <const json::integer_number *>::test (const json::value *jv)
482 : : {
483 : 12 : return jv->get_kind () == json::JSON_INTEGER;
484 : : }
485 : :
486 : : template <>
487 : : template <>
488 : : inline bool
489 : 4 : is_a_helper <json::string *>::test (json::value *jv)
490 : : {
491 : 4 : return jv->get_kind () == json::JSON_STRING;
492 : : }
493 : :
494 : : template <>
495 : : template <>
496 : : inline bool
497 : 16 : is_a_helper <const json::string *>::test (const json::value *jv)
498 : : {
499 : 16 : return jv->get_kind () == json::JSON_STRING;
500 : : }
501 : :
502 : : template <>
503 : : template <>
504 : : inline bool
505 : : is_a_helper<json::literal *>::test (json::value *jv)
506 : : {
507 : : return (jv->get_kind () == json::JSON_TRUE
508 : : || jv->get_kind () == json::JSON_FALSE
509 : : || jv->get_kind () == json::JSON_NULL);
510 : : }
511 : :
512 : : template <>
513 : : template <>
514 : : inline bool
515 : : is_a_helper<const json::literal *>::test (const json::value *jv)
516 : : {
517 : : return (jv->get_kind () == json::JSON_TRUE
518 : : || jv->get_kind () == json::JSON_FALSE
519 : : || jv->get_kind () == json::JSON_NULL);
520 : : }
521 : :
522 : : #if CHECKING_P
523 : :
524 : : namespace selftest {
525 : :
526 : : class location;
527 : :
528 : : extern void assert_print_eq (const location &loc,
529 : : const json::value &jv,
530 : : bool formatted,
531 : : const char *expected_json);
532 : :
533 : : } // namespace selftest
534 : :
535 : : #endif /* #if CHECKING_P */
536 : :
537 : : #endif /* GCC_JSON_H */
|