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 : 2592714 : class value
159 : : {
160 : : public:
161 : 3450975 : 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 : 17803 : enum kind get_kind () const final override { return JSON_OBJECT; }
193 : : void print (pretty_printer *pp, bool formatted) const final override;
194 : : std::unique_ptr<value> clone () const final override;
195 : :
196 : 277 : object *dyn_cast_object () final override { return this; }
197 : :
198 : 471 : bool is_empty () const { return m_map.is_empty (); }
199 : :
200 : : void set (const char *key, value *v);
201 : :
202 : : /* Set the property KEY of this object, requiring V
203 : : to be of a specific json::value subclass.
204 : :
205 : : This can be used to enforce type-checking, making it easier
206 : : to comply with a schema, e.g.
207 : : obj->set<some_subclass> ("property_name", value)
208 : : leading to a compile-time error if VALUE is not of the
209 : : appropriate subclass. */
210 : : template <typename JsonType>
211 : 13879 : void set (const char *key, std::unique_ptr<JsonType> v)
212 : : {
213 : 13931 : set (key, v.release ());
214 : : }
215 : :
216 : : value *get (const char *key) const;
217 : :
218 : : void set_string (const char *key, const char *utf8_value);
219 : : void set_integer (const char *key, long v);
220 : : void set_float (const char *key, double v);
221 : :
222 : : /* Set to literal true/false. */
223 : : void set_bool (const char *key, bool v);
224 : :
225 : : /* Typesafe access to properties by name (such as from a schema). */
226 : : void set_string (const string_property &property, const char *utf8_value);
227 : : void set_integer (const integer_property &property, long value);
228 : : void set_bool (const bool_property &property, bool value);
229 : : void set_array_of_string (const array_of_string_property &property,
230 : : std::unique_ptr<json::array> value);
231 : : template <typename EnumType>
232 : : bool maybe_get_enum (const enum_property<EnumType> &property,
233 : : EnumType &out) const;
234 : : template <typename EnumType>
235 : : void set_enum (const enum_property<EnumType> &property,
236 : : EnumType value);
237 : :
238 : : static int compare (const json::object &obj_a, const json::object &obj_b);
239 : :
240 : 2435 : size_t get_num_keys () const { return m_keys.length (); }
241 : 1864 : const char *get_key (size_t i) const { return m_keys[i]; }
242 : :
243 : : std::unique_ptr<object> clone_as_object () const;
244 : :
245 : : private:
246 : : typedef hash_map <char *, value *,
247 : : simple_hashmap_traits<nofree_string_hash, value *> > map_t;
248 : : map_t m_map;
249 : :
250 : : /* Keep track of order in which keys were inserted. */
251 : : auto_vec <const char *> m_keys;
252 : : };
253 : :
254 : : /* Subclass of value for arrays. */
255 : :
256 : 616907 : class array : public value
257 : : {
258 : : public:
259 : : ~array ();
260 : :
261 : 776 : enum kind get_kind () const final override { return JSON_ARRAY; }
262 : : void print (pretty_printer *pp, bool formatted) const final override;
263 : : std::unique_ptr<value> clone () const final override;
264 : :
265 : 0 : array *dyn_cast_array () final override { return this; }
266 : :
267 : : void append (value *v);
268 : : void append_string (const char *utf8_value);
269 : :
270 : : /* Append V to this array, requiring V
271 : : to be a specific json::value subclass.
272 : :
273 : : This can be used to enforce type-checking, making it easier
274 : : to comply with a schema, e.g.
275 : : arr->append<some_subclass> (value)
276 : : leading to a compile-time error if VALUE is not of the
277 : : appropriate subclass. */
278 : : template <typename JsonType>
279 : 4123 : void append (std::unique_ptr<JsonType> v)
280 : : {
281 : 4123 : append (v.release ());
282 : : }
283 : :
284 : 1880 : size_t size () const { return m_elements.length (); }
285 : 916 : value *operator[] (size_t i) const { return m_elements[i]; }
286 : :
287 : : value **begin () { return m_elements.begin (); }
288 : : value **end () { return m_elements.end (); }
289 : : const value * const *begin () const { return m_elements.begin (); }
290 : : const value * const *end () const { return m_elements.end (); }
291 : 380 : size_t length () const { return m_elements.length (); }
292 : 325 : value *get (size_t idx) const { return m_elements[idx]; }
293 : :
294 : : private:
295 : : auto_vec<value *> m_elements;
296 : : };
297 : :
298 : : /* Subclass of value for floating-point numbers. */
299 : :
300 : 24 : class float_number : public value
301 : : {
302 : : public:
303 : 56 : float_number (double value) : m_value (value) {}
304 : :
305 : 84 : enum kind get_kind () const final override { return JSON_FLOAT; }
306 : : void print (pretty_printer *pp, bool formatted) const final override;
307 : : std::unique_ptr<value> clone () const final override;
308 : :
309 : 44 : double get () const { return m_value; }
310 : :
311 : : private:
312 : : double m_value;
313 : : };
314 : :
315 : : /* Subclass of value for integer-valued numbers. */
316 : :
317 : 28 : class integer_number : public value
318 : : {
319 : : public:
320 : 667741 : integer_number (long value) : m_value (value) {}
321 : :
322 : 2442 : enum kind get_kind () const final override { return JSON_INTEGER; }
323 : : void print (pretty_printer *pp, bool formatted) const final override;
324 : : std::unique_ptr<value> clone () const final override;
325 : :
326 : 0 : integer_number *dyn_cast_integer_number () final override { return this; }
327 : :
328 : 2321 : long get () const { return m_value; }
329 : :
330 : : private:
331 : : long m_value;
332 : : };
333 : :
334 : :
335 : : /* Subclass of value for strings. */
336 : :
337 : : class string : public value
338 : : {
339 : : public:
340 : : explicit string (const char *utf8);
341 : : string (const char *utf8, size_t len);
342 : 4165588 : ~string () { free (m_utf8); }
343 : :
344 : 21716 : enum kind get_kind () const final override { return JSON_STRING; }
345 : : void print (pretty_printer *pp, bool formatted) const final override;
346 : : std::unique_ptr<value> clone () const final override;
347 : 41 : string *dyn_cast_string () final override { return this; }
348 : :
349 : 11511 : const char *get_string () const { return m_utf8; }
350 : : size_t get_length () const { return m_len; }
351 : :
352 : : private:
353 : : char *m_utf8;
354 : : size_t m_len;
355 : : };
356 : :
357 : : /* Subclass of value for the three JSON literals "true", "false",
358 : : and "null". */
359 : :
360 : 28 : class literal : public value
361 : : {
362 : : public:
363 : 44 : literal (enum kind kind) : m_kind (kind) {}
364 : :
365 : : /* Construct literal for a boolean value. */
366 : 733 : literal (bool value): m_kind (value ? JSON_TRUE : JSON_FALSE) {}
367 : :
368 : 144 : enum kind get_kind () const final override { return m_kind; }
369 : : void print (pretty_printer *pp, bool formatted) const final override;
370 : : std::unique_ptr<value> clone () const final override;
371 : :
372 : : private:
373 : : enum kind m_kind;
374 : : };
375 : :
376 : :
377 : : template <typename EnumType>
378 : : inline bool
379 : 24 : object::maybe_get_enum (const enum_property<EnumType> &property,
380 : : EnumType &out) const
381 : : {
382 : 24 : if (value *jv = get (property.m_key.get ()))
383 : 20 : if (string *jstr = jv->dyn_cast_string ())
384 : : {
385 : 20 : if (enum_traits<EnumType>::maybe_get_value_from_string
386 : 20 : (jstr->get_string (), out))
387 : : return true;
388 : : }
389 : : return false;
390 : : }
391 : :
392 : : template <typename EnumType>
393 : : inline void
394 : 594 : object::set_enum (const enum_property<EnumType> &property,
395 : : EnumType value)
396 : : {
397 : : const char *str
398 : 594 : = json::enum_traits<EnumType>::get_string_for_value (value);
399 : 594 : set_string (property.m_key.get (), str);
400 : 594 : }
401 : :
402 : : } // namespace json
403 : :
404 : : template <>
405 : : template <>
406 : : inline bool
407 : : is_a_helper <json::value *>::test (json::value *)
408 : : {
409 : : return true;
410 : : }
411 : :
412 : : template <>
413 : : template <>
414 : : inline bool
415 : : is_a_helper <const json::value *>::test (const json::value *)
416 : : {
417 : : return true;
418 : : }
419 : :
420 : : template <>
421 : : template <>
422 : : inline bool
423 : : is_a_helper <json::object *>::test (json::value *jv)
424 : : {
425 : : return jv->get_kind () == json::JSON_OBJECT;
426 : : }
427 : :
428 : : template <>
429 : : template <>
430 : : inline bool
431 : : is_a_helper <const json::object *>::test (const json::value *jv)
432 : : {
433 : : return jv->get_kind () == json::JSON_OBJECT;
434 : : }
435 : :
436 : : template <>
437 : : template <>
438 : : inline bool
439 : 4 : is_a_helper <json::array *>::test (json::value *jv)
440 : : {
441 : 4 : return jv->get_kind () == json::JSON_ARRAY;
442 : : }
443 : :
444 : : template <>
445 : : template <>
446 : : inline bool
447 : 4 : is_a_helper <const json::array *>::test (const json::value *jv)
448 : : {
449 : 4 : return jv->get_kind () == json::JSON_ARRAY;
450 : : }
451 : :
452 : : template <>
453 : : template <>
454 : : inline bool
455 : : is_a_helper <json::float_number *>::test (json::value *jv)
456 : : {
457 : : return jv->get_kind () == json::JSON_FLOAT;
458 : : }
459 : :
460 : : template <>
461 : : template <>
462 : : inline bool
463 : 8 : is_a_helper <const json::float_number *>::test (const json::value *jv)
464 : : {
465 : 8 : return jv->get_kind () == json::JSON_FLOAT;
466 : : }
467 : :
468 : : template <>
469 : : template <>
470 : : inline bool
471 : 44 : is_a_helper <json::integer_number *>::test (json::value *jv)
472 : : {
473 : 44 : return jv->get_kind () == json::JSON_INTEGER;
474 : : }
475 : :
476 : : template <>
477 : : template <>
478 : : inline bool
479 : 12 : is_a_helper <const json::integer_number *>::test (const json::value *jv)
480 : : {
481 : 12 : return jv->get_kind () == json::JSON_INTEGER;
482 : : }
483 : :
484 : : template <>
485 : : template <>
486 : : inline bool
487 : 4 : is_a_helper <json::string *>::test (json::value *jv)
488 : : {
489 : 4 : return jv->get_kind () == json::JSON_STRING;
490 : : }
491 : :
492 : : template <>
493 : : template <>
494 : : inline bool
495 : 16 : is_a_helper <const json::string *>::test (const json::value *jv)
496 : : {
497 : 16 : return jv->get_kind () == json::JSON_STRING;
498 : : }
499 : :
500 : : #if CHECKING_P
501 : :
502 : : namespace selftest {
503 : :
504 : : class location;
505 : :
506 : : extern void assert_print_eq (const location &loc,
507 : : const json::value &jv,
508 : : bool formatted,
509 : : const char *expected_json);
510 : :
511 : : } // namespace selftest
512 : :
513 : : #endif /* #if CHECKING_P */
514 : :
515 : : #endif /* GCC_JSON_H */
|