Branch data Line data Source code
1 : : /* JSON trees
2 : : Copyright (C) 2017-2024 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 : : /* Base class of JSON value. */
77 : :
78 : 2692022 : class value
79 : : {
80 : : public:
81 : 2832856 : virtual ~value () {}
82 : : virtual enum kind get_kind () const = 0;
83 : : virtual void print (pretty_printer *pp, bool formatted) const = 0;
84 : :
85 : : void dump (FILE *, bool formatted) const;
86 : : void DEBUG_FUNCTION dump () const;
87 : : };
88 : :
89 : : /* Subclass of value for objects: a collection of key/value pairs
90 : : preserving the ordering in which keys were inserted.
91 : :
92 : : Preserving the order eliminates non-determinism in the output,
93 : : making it easier for the user to compare repeated invocations. */
94 : :
95 : : class object : public value
96 : : {
97 : : public:
98 : : ~object ();
99 : :
100 : 7596 : enum kind get_kind () const final override { return JSON_OBJECT; }
101 : : void print (pretty_printer *pp, bool formatted) const final override;
102 : :
103 : 444 : bool is_empty () const { return m_map.is_empty (); }
104 : :
105 : : void set (const char *key, value *v);
106 : :
107 : : /* Set the property KEY of this object, requiring V
108 : : to be of a specific json::value subclass.
109 : :
110 : : This can be used to enforce type-checking, making it easier
111 : : to comply with a schema, e.g.
112 : : obj->set<some_subclass> ("property_name", value)
113 : : leading to a compile-time error if VALUE is not of the
114 : : appropriate subclass. */
115 : : template <typename JsonType>
116 : 9920 : void set (const char *key, std::unique_ptr<JsonType> v)
117 : : {
118 : 9920 : set (key, v.release ());
119 : : }
120 : :
121 : : value *get (const char *key) const;
122 : :
123 : : void set_string (const char *key, const char *utf8_value);
124 : : void set_integer (const char *key, long v);
125 : : void set_float (const char *key, double v);
126 : :
127 : : /* Set to literal true/false. */
128 : : void set_bool (const char *key, bool v);
129 : :
130 : : private:
131 : : typedef hash_map <char *, value *,
132 : : simple_hashmap_traits<nofree_string_hash, value *> > map_t;
133 : : map_t m_map;
134 : :
135 : : /* Keep track of order in which keys were inserted. */
136 : : auto_vec <const char *> m_keys;
137 : : };
138 : :
139 : : /* Subclass of value for arrays. */
140 : :
141 : 611471 : class array : public value
142 : : {
143 : : public:
144 : : ~array ();
145 : :
146 : 640 : enum kind get_kind () const final override { return JSON_ARRAY; }
147 : : void print (pretty_printer *pp, bool formatted) const final override;
148 : :
149 : : void append (value *v);
150 : : void append_string (const char *utf8_value);
151 : :
152 : : /* Append V to this array, requiring V
153 : : to be a specific json::value subclass.
154 : :
155 : : This can be used to enforce type-checking, making it easier
156 : : to comply with a schema, e.g.
157 : : arr->append<some_subclass> (value)
158 : : leading to a compile-time error if VALUE is not of the
159 : : appropriate subclass. */
160 : : template <typename JsonType>
161 : 2293 : void append (std::unique_ptr<JsonType> v)
162 : : {
163 : 2293 : append (v.release ());
164 : : }
165 : :
166 : 812 : size_t size () const { return m_elements.length (); }
167 : 872 : value *operator[] (size_t i) const { return m_elements[i]; }
168 : :
169 : : value **begin () { return m_elements.begin (); }
170 : : value **end () { return m_elements.end (); }
171 : : const value * const *begin () const { return m_elements.begin (); }
172 : : const value * const *end () const { return m_elements.end (); }
173 : 8 : size_t length () const { return m_elements.length (); }
174 : 48 : value *get (size_t idx) const { return m_elements[idx]; }
175 : :
176 : : private:
177 : : auto_vec<value *> m_elements;
178 : : };
179 : :
180 : : /* Subclass of value for floating-point numbers. */
181 : :
182 : 4 : class float_number : public value
183 : : {
184 : : public:
185 : 32 : float_number (double value) : m_value (value) {}
186 : :
187 : 20 : enum kind get_kind () const final override { return JSON_FLOAT; }
188 : : void print (pretty_printer *pp, bool formatted) const final override;
189 : :
190 : 12 : double get () const { return m_value; }
191 : :
192 : : private:
193 : : double m_value;
194 : : };
195 : :
196 : : /* Subclass of value for integer-valued numbers. */
197 : :
198 : 4 : class integer_number : public value
199 : : {
200 : : public:
201 : 672525 : integer_number (long value) : m_value (value) {}
202 : :
203 : 2296 : enum kind get_kind () const final override { return JSON_INTEGER; }
204 : : void print (pretty_printer *pp, bool formatted) const final override;
205 : :
206 : 2244 : long get () const { return m_value; }
207 : :
208 : : private:
209 : : long m_value;
210 : : };
211 : :
212 : :
213 : : /* Subclass of value for strings. */
214 : :
215 : : class string : public value
216 : : {
217 : : public:
218 : : explicit string (const char *utf8);
219 : : string (const char *utf8, size_t len);
220 : 2077490 : ~string () { free (m_utf8); }
221 : :
222 : 1312 : enum kind get_kind () const final override { return JSON_STRING; }
223 : : void print (pretty_printer *pp, bool formatted) const final override;
224 : :
225 : 1268 : const char *get_string () const { return m_utf8; }
226 : : size_t get_length () const { return m_len; }
227 : :
228 : : private:
229 : : char *m_utf8;
230 : : size_t m_len;
231 : : };
232 : :
233 : : /* Subclass of value for the three JSON literals "true", "false",
234 : : and "null". */
235 : :
236 : 4 : class literal : public value
237 : : {
238 : : public:
239 : 20 : literal (enum kind kind) : m_kind (kind) {}
240 : :
241 : : /* Construct literal for a boolean value. */
242 : 824 : literal (bool value): m_kind (value ? JSON_TRUE : JSON_FALSE) {}
243 : :
244 : 16 : enum kind get_kind () const final override { return m_kind; }
245 : : void print (pretty_printer *pp, bool formatted) const final override;
246 : :
247 : : private:
248 : : enum kind m_kind;
249 : : };
250 : :
251 : : } // namespace json
252 : :
253 : : template <>
254 : : template <>
255 : : inline bool
256 : : is_a_helper <json::value *>::test (json::value *)
257 : : {
258 : : return true;
259 : : }
260 : :
261 : : template <>
262 : : template <>
263 : : inline bool
264 : : is_a_helper <const json::value *>::test (const json::value *)
265 : : {
266 : : return true;
267 : : }
268 : :
269 : : template <>
270 : : template <>
271 : : inline bool
272 : : is_a_helper <json::object *>::test (json::value *jv)
273 : : {
274 : : return jv->get_kind () == json::JSON_OBJECT;
275 : : }
276 : :
277 : : template <>
278 : : template <>
279 : : inline bool
280 : : is_a_helper <const json::object *>::test (const json::value *jv)
281 : : {
282 : : return jv->get_kind () == json::JSON_OBJECT;
283 : : }
284 : :
285 : : template <>
286 : : template <>
287 : : inline bool
288 : 4 : is_a_helper <json::array *>::test (json::value *jv)
289 : : {
290 : 4 : return jv->get_kind () == json::JSON_ARRAY;
291 : : }
292 : :
293 : : template <>
294 : : template <>
295 : : inline bool
296 : 4 : is_a_helper <const json::array *>::test (const json::value *jv)
297 : : {
298 : 4 : return jv->get_kind () == json::JSON_ARRAY;
299 : : }
300 : :
301 : : template <>
302 : : template <>
303 : : inline bool
304 : : is_a_helper <json::float_number *>::test (json::value *jv)
305 : : {
306 : : return jv->get_kind () == json::JSON_FLOAT;
307 : : }
308 : :
309 : : template <>
310 : : template <>
311 : : inline bool
312 : 8 : is_a_helper <const json::float_number *>::test (const json::value *jv)
313 : : {
314 : 8 : return jv->get_kind () == json::JSON_FLOAT;
315 : : }
316 : :
317 : : template <>
318 : : template <>
319 : : inline bool
320 : 44 : is_a_helper <json::integer_number *>::test (json::value *jv)
321 : : {
322 : 44 : return jv->get_kind () == json::JSON_INTEGER;
323 : : }
324 : :
325 : : template <>
326 : : template <>
327 : : inline bool
328 : 12 : is_a_helper <const json::integer_number *>::test (const json::value *jv)
329 : : {
330 : 12 : return jv->get_kind () == json::JSON_INTEGER;
331 : : }
332 : :
333 : : template <>
334 : : template <>
335 : : inline bool
336 : 4 : is_a_helper <json::string *>::test (json::value *jv)
337 : : {
338 : 4 : return jv->get_kind () == json::JSON_STRING;
339 : : }
340 : :
341 : : template <>
342 : : template <>
343 : : inline bool
344 : 16 : is_a_helper <const json::string *>::test (const json::value *jv)
345 : : {
346 : 16 : return jv->get_kind () == json::JSON_STRING;
347 : : }
348 : :
349 : : #if CHECKING_P
350 : :
351 : : namespace selftest {
352 : :
353 : : class location;
354 : :
355 : : extern void assert_print_eq (const location &loc,
356 : : const json::value &jv,
357 : : bool formatted,
358 : : const char *expected_json);
359 : :
360 : : } // namespace selftest
361 : :
362 : : #endif /* #if CHECKING_P */
363 : :
364 : : #endif /* GCC_JSON_H */
|