]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/json.cc
check undefine_p for one more vr
[thirdparty/gcc.git] / gcc / json.cc
1 /* JSON trees
2 Copyright (C) 2017-2023 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 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "json.h"
25 #include "pretty-print.h"
26 #include "math.h"
27 #include "selftest.h"
28
29 using namespace json;
30
31 /* class json::value. */
32
33 /* Dump this json::value tree to OUTF.
34
35 No formatting is done.
36
37 The key/value pairs of json::objects are printed in the order
38 in which the keys were originally inserted. */
39
40 void
41 value::dump (FILE *outf) const
42 {
43 pretty_printer pp;
44 pp_buffer (&pp)->stream = outf;
45 print (&pp);
46 pp_flush (&pp);
47 }
48
49 /* class json::object, a subclass of json::value, representing
50 an ordered collection of key/value pairs. */
51
52 /* json:object's dtor. */
53
54 object::~object ()
55 {
56 for (map_t::iterator it = m_map.begin (); it != m_map.end (); ++it)
57 {
58 free (const_cast <char *>((*it).first));
59 delete ((*it).second);
60 }
61 }
62
63 /* Implementation of json::value::print for json::object. */
64
65 void
66 object::print (pretty_printer *pp) const
67 {
68 pp_character (pp, '{');
69
70 /* Iterate in the order that the keys were inserted. */
71 unsigned i;
72 const char *key;
73 FOR_EACH_VEC_ELT (m_keys, i, key)
74 {
75 if (i > 0)
76 pp_string (pp, ", ");
77 map_t &mut_map = const_cast<map_t &> (m_map);
78 value *value = *mut_map.get (key);
79 pp_doublequote (pp);
80 pp_string (pp, key); // FIXME: escaping?
81 pp_doublequote (pp);
82 pp_string (pp, ": ");
83 value->print (pp);
84 }
85 pp_character (pp, '}');
86 }
87
88 /* Set the json::value * for KEY, taking ownership of V
89 (and taking a copy of KEY if necessary). */
90
91 void
92 object::set (const char *key, value *v)
93 {
94 gcc_assert (key);
95 gcc_assert (v);
96
97 value **ptr = m_map.get (key);
98 if (ptr)
99 {
100 /* If the key is already present, delete the existing value
101 and overwrite it. */
102 delete *ptr;
103 *ptr = v;
104 }
105 else
106 {
107 /* If the key wasn't already present, take a copy of the key,
108 and store the value. */
109 char *owned_key = xstrdup (key);
110 m_map.put (owned_key, v);
111 m_keys.safe_push (owned_key);
112 }
113 }
114
115 /* Get the json::value * for KEY.
116
117 The object retains ownership of the value. */
118
119 value *
120 object::get (const char *key) const
121 {
122 gcc_assert (key);
123
124 value **ptr = const_cast <map_t &> (m_map).get (key);
125 if (ptr)
126 return *ptr;
127 else
128 return NULL;
129 }
130
131 /* class json::array, a subclass of json::value, representing
132 an ordered collection of values. */
133
134 /* json::array's dtor. */
135
136 array::~array ()
137 {
138 unsigned i;
139 value *v;
140 FOR_EACH_VEC_ELT (m_elements, i, v)
141 delete v;
142 }
143
144 /* Implementation of json::value::print for json::array. */
145
146 void
147 array::print (pretty_printer *pp) const
148 {
149 pp_character (pp, '[');
150 unsigned i;
151 value *v;
152 FOR_EACH_VEC_ELT (m_elements, i, v)
153 {
154 if (i)
155 pp_string (pp, ", ");
156 v->print (pp);
157 }
158 pp_character (pp, ']');
159 }
160
161 /* Append non-NULL value V to a json::array, taking ownership of V. */
162
163 void
164 array::append (value *v)
165 {
166 gcc_assert (v);
167 m_elements.safe_push (v);
168 }
169
170 /* class json::float_number, a subclass of json::value, wrapping a double. */
171
172 /* Implementation of json::value::print for json::float_number. */
173
174 void
175 float_number::print (pretty_printer *pp) const
176 {
177 char tmp[1024];
178 snprintf (tmp, sizeof (tmp), "%g", m_value);
179 pp_string (pp, tmp);
180 }
181
182 /* class json::integer_number, a subclass of json::value, wrapping a long. */
183
184 /* Implementation of json::value::print for json::integer_number. */
185
186 void
187 integer_number::print (pretty_printer *pp) const
188 {
189 char tmp[1024];
190 snprintf (tmp, sizeof (tmp), "%ld", m_value);
191 pp_string (pp, tmp);
192 }
193
194
195 /* class json::string, a subclass of json::value. */
196
197 /* json::string's ctor. */
198
199 string::string (const char *utf8)
200 {
201 gcc_assert (utf8);
202 m_utf8 = xstrdup (utf8);
203 m_len = strlen (utf8);
204 }
205
206 string::string (const char *utf8, size_t len)
207 {
208 gcc_assert (utf8);
209 m_utf8 = XNEWVEC (char, len);
210 m_len = len;
211 memcpy (m_utf8, utf8, len);
212 }
213
214 /* Implementation of json::value::print for json::string. */
215
216 void
217 string::print (pretty_printer *pp) const
218 {
219 pp_character (pp, '"');
220 for (size_t i = 0; i != m_len; ++i)
221 {
222 char ch = m_utf8[i];
223 switch (ch)
224 {
225 case '"':
226 pp_string (pp, "\\\"");
227 break;
228 case '\\':
229 pp_string (pp, "\\\\");
230 break;
231 case '\b':
232 pp_string (pp, "\\b");
233 break;
234 case '\f':
235 pp_string (pp, "\\f");
236 break;
237 case '\n':
238 pp_string (pp, "\\n");
239 break;
240 case '\r':
241 pp_string (pp, "\\r");
242 break;
243 case '\t':
244 pp_string (pp, "\\t");
245 break;
246 case '\0':
247 pp_string (pp, "\\0");
248 break;
249 default:
250 pp_character (pp, ch);
251 }
252 }
253 pp_character (pp, '"');
254 }
255
256 /* class json::literal, a subclass of json::value. */
257
258 /* Implementation of json::value::print for json::literal. */
259
260 void
261 literal::print (pretty_printer *pp) const
262 {
263 switch (m_kind)
264 {
265 case JSON_TRUE:
266 pp_string (pp, "true");
267 break;
268 case JSON_FALSE:
269 pp_string (pp, "false");
270 break;
271 case JSON_NULL:
272 pp_string (pp, "null");
273 break;
274 default:
275 gcc_unreachable ();
276 }
277 }
278
279 \f
280 #if CHECKING_P
281
282 namespace selftest {
283
284 /* Selftests. */
285
286 /* Verify that JV->print () prints EXPECTED_JSON. */
287
288 static void
289 assert_print_eq (const json::value &jv, const char *expected_json)
290 {
291 pretty_printer pp;
292 jv.print (&pp);
293 ASSERT_STREQ (expected_json, pp_formatted_text (&pp));
294 }
295
296 /* Verify that object::get works as expected. */
297
298 static void
299 test_object_get ()
300 {
301 object obj;
302 value *val = new json::string ("value");
303 obj.set ("foo", val);
304 ASSERT_EQ (obj.get ("foo"), val);
305 ASSERT_EQ (obj.get ("not-present"), NULL);
306 }
307
308 /* Verify that JSON objects are written correctly. */
309
310 static void
311 test_writing_objects ()
312 {
313 object obj;
314 obj.set ("foo", new json::string ("bar"));
315 obj.set ("baz", new json::string ("quux"));
316 /* This test relies on json::object writing out key/value pairs
317 in key-insertion order. */
318 assert_print_eq (obj, "{\"foo\": \"bar\", \"baz\": \"quux\"}");
319 }
320
321 /* Verify that JSON arrays are written correctly. */
322
323 static void
324 test_writing_arrays ()
325 {
326 array arr;
327 assert_print_eq (arr, "[]");
328
329 arr.append (new json::string ("foo"));
330 assert_print_eq (arr, "[\"foo\"]");
331
332 arr.append (new json::string ("bar"));
333 assert_print_eq (arr, "[\"foo\", \"bar\"]");
334 }
335
336 /* Verify that JSON numbers are written correctly. */
337
338 static void
339 test_writing_float_numbers ()
340 {
341 assert_print_eq (float_number (0), "0");
342 assert_print_eq (float_number (42), "42");
343 assert_print_eq (float_number (-100), "-100");
344 assert_print_eq (float_number (123456789), "1.23457e+08");
345 }
346
347 static void
348 test_writing_integer_numbers ()
349 {
350 assert_print_eq (integer_number (0), "0");
351 assert_print_eq (integer_number (42), "42");
352 assert_print_eq (integer_number (-100), "-100");
353 assert_print_eq (integer_number (123456789), "123456789");
354 assert_print_eq (integer_number (-123456789), "-123456789");
355 }
356
357 /* Verify that JSON strings are written correctly. */
358
359 static void
360 test_writing_strings ()
361 {
362 string foo ("foo");
363 assert_print_eq (foo, "\"foo\"");
364
365 string contains_quotes ("before \"quoted\" after");
366 assert_print_eq (contains_quotes, "\"before \\\"quoted\\\" after\"");
367
368 const char data[] = {'a', 'b', 'c', 'd', '\0', 'e', 'f'};
369 string not_terminated (data, 3);
370 assert_print_eq (not_terminated, "\"abc\"");
371 string embedded_null (data, sizeof data);
372 assert_print_eq (embedded_null, "\"abcd\\0ef\"");
373 }
374
375 /* Verify that JSON literals are written correctly. */
376
377 static void
378 test_writing_literals ()
379 {
380 assert_print_eq (literal (JSON_TRUE), "true");
381 assert_print_eq (literal (JSON_FALSE), "false");
382 assert_print_eq (literal (JSON_NULL), "null");
383
384 assert_print_eq (literal (true), "true");
385 assert_print_eq (literal (false), "false");
386 }
387
388 /* Run all of the selftests within this file. */
389
390 void
391 json_cc_tests ()
392 {
393 test_object_get ();
394 test_writing_objects ();
395 test_writing_arrays ();
396 test_writing_float_numbers ();
397 test_writing_integer_numbers ();
398 test_writing_strings ();
399 test_writing_literals ();
400 }
401
402 } // namespace selftest
403
404 #endif /* #if CHECKING_P */