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 : : /* Implementation of JSON, a lightweight data-interchange format.
25 : :
26 : : See http://www.json.org/
27 : : and http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
28 : : and https://tools.ietf.org/html/rfc7159
29 : :
30 : : Supports parsing text into a DOM-like tree of json::value *, directly
31 : : creating such trees, and dumping json::value * to text. */
32 : :
33 : : /* TODO: `libcpp/mkdeps.cc` wants JSON writing support for p1689r5 output;
34 : : extract this code and move to libiberty. */
35 : :
36 : : namespace json
37 : : {
38 : :
39 : : /* Forward decls of json::value and its subclasses (using indentation
40 : : to denote inheritance. */
41 : :
42 : : class value;
43 : : class object;
44 : : class array;
45 : : class float_number;
46 : : class integer_number;
47 : : class string;
48 : : class literal;
49 : :
50 : : /* An enum for discriminating the subclasses of json::value. */
51 : :
52 : : enum kind
53 : : {
54 : : /* class json::object. */
55 : : JSON_OBJECT,
56 : :
57 : : /* class json::array. */
58 : : JSON_ARRAY,
59 : :
60 : : /* class json::integer_number. */
61 : : JSON_INTEGER,
62 : :
63 : : /* class json::float_number. */
64 : : JSON_FLOAT,
65 : :
66 : : /* class json::string. */
67 : : JSON_STRING,
68 : :
69 : : /* class json::literal uses these three values to identify the
70 : : particular literal. */
71 : : JSON_TRUE,
72 : : JSON_FALSE,
73 : : JSON_NULL
74 : : };
75 : :
76 : : namespace pointer { // json::pointer
77 : :
78 : : /* Implementation of JSON pointer (RFC 6901). */
79 : :
80 : : /* A token within a JSON pointer, expressing the parent of a particular
81 : : JSON value, and how it is descended from that parent.
82 : :
83 : : A JSON pointer can be built as a list of these tokens. */
84 : :
85 : : struct token
86 : : {
87 : : enum class kind
88 : : {
89 : : root_value,
90 : : object_member,
91 : : array_index
92 : : };
93 : :
94 : : token ();
95 : : token (json::object &parent, const char *member);
96 : : token (json::array &parent, size_t index);
97 : : token (const token &other) = delete;
98 : : token (token &&other) = delete;
99 : :
100 : : ~token ();
101 : :
102 : : token &
103 : : operator= (const token &other) = delete;
104 : :
105 : : token &
106 : : operator= (token &&other);
107 : :
108 : : json::value *m_parent;
109 : : union u
110 : : {
111 : : char *u_member;
112 : : size_t u_index;
113 : : } m_data;
114 : : enum kind m_kind;
115 : : };
116 : :
117 : : } // namespace json::pointer
118 : :
119 : : /* Base class of JSON value. */
120 : :
121 : 2726707 : class value
122 : : {
123 : : public:
124 : 3490697 : virtual ~value () {}
125 : : virtual enum kind get_kind () const = 0;
126 : : virtual void print (pretty_printer *pp, bool formatted) const = 0;
127 : :
128 : : void dump (FILE *, bool formatted) const;
129 : : void DEBUG_FUNCTION dump () const;
130 : :
131 : 0 : virtual object *dyn_cast_object () { return nullptr; }
132 : :
133 : : static int compare (const json::value &val_a, const json::value &val_b);
134 : :
135 : : const pointer::token &get_pointer_token () const { return m_pointer_token; }
136 : :
137 : : pointer::token m_pointer_token;
138 : : };
139 : :
140 : : /* Subclass of value for objects: a collection of key/value pairs
141 : : preserving the ordering in which keys were inserted.
142 : :
143 : : Preserving the order eliminates non-determinism in the output,
144 : : making it easier for the user to compare repeated invocations. */
145 : :
146 : : class object : public value
147 : : {
148 : : public:
149 : : ~object ();
150 : :
151 : 17354 : enum kind get_kind () const final override { return JSON_OBJECT; }
152 : : void print (pretty_printer *pp, bool formatted) const final override;
153 : :
154 : 271 : object *dyn_cast_object () final override { return this; }
155 : :
156 : 462 : bool is_empty () const { return m_map.is_empty (); }
157 : :
158 : : void set (const char *key, value *v);
159 : :
160 : : /* Set the property KEY of this object, requiring V
161 : : to be of a specific json::value subclass.
162 : :
163 : : This can be used to enforce type-checking, making it easier
164 : : to comply with a schema, e.g.
165 : : obj->set<some_subclass> ("property_name", value)
166 : : leading to a compile-time error if VALUE is not of the
167 : : appropriate subclass. */
168 : : template <typename JsonType>
169 : 10101 : void set (const char *key, std::unique_ptr<JsonType> v)
170 : : {
171 : 10147 : set (key, v.release ());
172 : : }
173 : :
174 : : value *get (const char *key) const;
175 : :
176 : : void set_string (const char *key, const char *utf8_value);
177 : : void set_integer (const char *key, long v);
178 : : void set_float (const char *key, double v);
179 : :
180 : : /* Set to literal true/false. */
181 : : void set_bool (const char *key, bool v);
182 : :
183 : : static int compare (const json::object &obj_a, const json::object &obj_b);
184 : :
185 : : private:
186 : : typedef hash_map <char *, value *,
187 : : simple_hashmap_traits<nofree_string_hash, value *> > map_t;
188 : : map_t m_map;
189 : :
190 : : /* Keep track of order in which keys were inserted. */
191 : : auto_vec <const char *> m_keys;
192 : : };
193 : :
194 : : /* Subclass of value for arrays. */
195 : :
196 : 621044 : class array : public value
197 : : {
198 : : public:
199 : : ~array ();
200 : :
201 : 760 : enum kind get_kind () const final override { return JSON_ARRAY; }
202 : : void print (pretty_printer *pp, bool formatted) const final override;
203 : :
204 : : void append (value *v);
205 : : void append_string (const char *utf8_value);
206 : :
207 : : /* Append V to this array, requiring V
208 : : to be a specific json::value subclass.
209 : :
210 : : This can be used to enforce type-checking, making it easier
211 : : to comply with a schema, e.g.
212 : : arr->append<some_subclass> (value)
213 : : leading to a compile-time error if VALUE is not of the
214 : : appropriate subclass. */
215 : : template <typename JsonType>
216 : 2651 : void append (std::unique_ptr<JsonType> v)
217 : : {
218 : 2651 : append (v.release ());
219 : : }
220 : :
221 : 1761 : size_t size () const { return m_elements.length (); }
222 : 908 : value *operator[] (size_t i) const { return m_elements[i]; }
223 : :
224 : : value **begin () { return m_elements.begin (); }
225 : : value **end () { return m_elements.end (); }
226 : : const value * const *begin () const { return m_elements.begin (); }
227 : : const value * const *end () const { return m_elements.end (); }
228 : 369 : size_t length () const { return m_elements.length (); }
229 : 319 : value *get (size_t idx) const { return m_elements[idx]; }
230 : :
231 : : private:
232 : : auto_vec<value *> m_elements;
233 : : };
234 : :
235 : : /* Subclass of value for floating-point numbers. */
236 : :
237 : 20 : class float_number : public value
238 : : {
239 : : public:
240 : 48 : float_number (double value) : m_value (value) {}
241 : :
242 : 68 : enum kind get_kind () const final override { return JSON_FLOAT; }
243 : : void print (pretty_printer *pp, bool formatted) const final override;
244 : :
245 : 36 : double get () const { return m_value; }
246 : :
247 : : private:
248 : : double m_value;
249 : : };
250 : :
251 : : /* Subclass of value for integer-valued numbers. */
252 : :
253 : 24 : class integer_number : public value
254 : : {
255 : : public:
256 : 679904 : integer_number (long value) : m_value (value) {}
257 : :
258 : 2426 : enum kind get_kind () const final override { return JSON_INTEGER; }
259 : : void print (pretty_printer *pp, bool formatted) const final override;
260 : :
261 : 2313 : long get () const { return m_value; }
262 : :
263 : : private:
264 : : long m_value;
265 : : };
266 : :
267 : :
268 : : /* Subclass of value for strings. */
269 : :
270 : : class string : public value
271 : : {
272 : : public:
273 : : explicit string (const char *utf8);
274 : : string (const char *utf8, size_t len);
275 : 4209864 : ~string () { free (m_utf8); }
276 : :
277 : 20488 : enum kind get_kind () const final override { return JSON_STRING; }
278 : : void print (pretty_printer *pp, bool formatted) const final override;
279 : :
280 : 10860 : const char *get_string () const { return m_utf8; }
281 : : size_t get_length () const { return m_len; }
282 : :
283 : : private:
284 : : char *m_utf8;
285 : : size_t m_len;
286 : : };
287 : :
288 : : /* Subclass of value for the three JSON literals "true", "false",
289 : : and "null". */
290 : :
291 : 24 : class literal : public value
292 : : {
293 : : public:
294 : 36 : literal (enum kind kind) : m_kind (kind) {}
295 : :
296 : : /* Construct literal for a boolean value. */
297 : 850 : literal (bool value): m_kind (value ? JSON_TRUE : JSON_FALSE) {}
298 : :
299 : 128 : enum kind get_kind () const final override { return m_kind; }
300 : : void print (pretty_printer *pp, bool formatted) const final override;
301 : :
302 : : private:
303 : : enum kind m_kind;
304 : : };
305 : :
306 : : } // namespace json
307 : :
308 : : template <>
309 : : template <>
310 : : inline bool
311 : : is_a_helper <json::value *>::test (json::value *)
312 : : {
313 : : return true;
314 : : }
315 : :
316 : : template <>
317 : : template <>
318 : : inline bool
319 : : is_a_helper <const json::value *>::test (const json::value *)
320 : : {
321 : : return true;
322 : : }
323 : :
324 : : template <>
325 : : template <>
326 : : inline bool
327 : : is_a_helper <json::object *>::test (json::value *jv)
328 : : {
329 : : return jv->get_kind () == json::JSON_OBJECT;
330 : : }
331 : :
332 : : template <>
333 : : template <>
334 : : inline bool
335 : : is_a_helper <const json::object *>::test (const json::value *jv)
336 : : {
337 : : return jv->get_kind () == json::JSON_OBJECT;
338 : : }
339 : :
340 : : template <>
341 : : template <>
342 : : inline bool
343 : 4 : is_a_helper <json::array *>::test (json::value *jv)
344 : : {
345 : 4 : return jv->get_kind () == json::JSON_ARRAY;
346 : : }
347 : :
348 : : template <>
349 : : template <>
350 : : inline bool
351 : 4 : is_a_helper <const json::array *>::test (const json::value *jv)
352 : : {
353 : 4 : return jv->get_kind () == json::JSON_ARRAY;
354 : : }
355 : :
356 : : template <>
357 : : template <>
358 : : inline bool
359 : : is_a_helper <json::float_number *>::test (json::value *jv)
360 : : {
361 : : return jv->get_kind () == json::JSON_FLOAT;
362 : : }
363 : :
364 : : template <>
365 : : template <>
366 : : inline bool
367 : 8 : is_a_helper <const json::float_number *>::test (const json::value *jv)
368 : : {
369 : 8 : return jv->get_kind () == json::JSON_FLOAT;
370 : : }
371 : :
372 : : template <>
373 : : template <>
374 : : inline bool
375 : 44 : is_a_helper <json::integer_number *>::test (json::value *jv)
376 : : {
377 : 44 : return jv->get_kind () == json::JSON_INTEGER;
378 : : }
379 : :
380 : : template <>
381 : : template <>
382 : : inline bool
383 : 12 : is_a_helper <const json::integer_number *>::test (const json::value *jv)
384 : : {
385 : 12 : return jv->get_kind () == json::JSON_INTEGER;
386 : : }
387 : :
388 : : template <>
389 : : template <>
390 : : inline bool
391 : 4 : is_a_helper <json::string *>::test (json::value *jv)
392 : : {
393 : 4 : return jv->get_kind () == json::JSON_STRING;
394 : : }
395 : :
396 : : template <>
397 : : template <>
398 : : inline bool
399 : 16 : is_a_helper <const json::string *>::test (const json::value *jv)
400 : : {
401 : 16 : return jv->get_kind () == json::JSON_STRING;
402 : : }
403 : :
404 : : #if CHECKING_P
405 : :
406 : : namespace selftest {
407 : :
408 : : class location;
409 : :
410 : : extern void assert_print_eq (const location &loc,
411 : : const json::value &jv,
412 : : bool formatted,
413 : : const char *expected_json);
414 : :
415 : : } // namespace selftest
416 : :
417 : : #endif /* #if CHECKING_P */
418 : :
419 : : #endif /* GCC_JSON_H */
|