]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/json.cc
aarch64: Avoid using mismatched ZERO ZA sizes
[thirdparty/gcc.git] / gcc / json.cc
CommitLineData
4a4412b9 1/* JSON trees
a945c346 2 Copyright (C) 2017-2024 Free Software Foundation, Inc.
4a4412b9
DM
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along 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
29using namespace json;
30
30d9a3a6
DM
31/* Print a JSON string to PP, escaping '"', control characters,
32 and embedded null bytes.
33 The string is required to be UTF-8 encoded. */
34
35static void
36print_escaped_json_string (pretty_printer *pp,
37 const char *utf8_str,
38 size_t len)
39{
40 pp_character (pp, '"');
41 for (size_t i = 0; i != len; ++i)
42 {
43 char ch = utf8_str[i];
44 switch (ch)
45 {
46 case '"':
47 pp_string (pp, "\\\"");
48 break;
49 case '\\':
50 pp_string (pp, "\\\\");
51 break;
52 case '\b':
53 pp_string (pp, "\\b");
54 break;
55 case '\f':
56 pp_string (pp, "\\f");
57 break;
58 case '\n':
59 pp_string (pp, "\\n");
60 break;
61 case '\r':
62 pp_string (pp, "\\r");
63 break;
64 case '\t':
65 pp_string (pp, "\\t");
66 break;
67 case '\0':
68 pp_string (pp, "\\0");
69 break;
70 default:
71 pp_character (pp, ch);
72 }
73 }
74 pp_character (pp, '"');
75}
76
4a4412b9
DM
77/* class json::value. */
78
79/* Dump this json::value tree to OUTF.
7f1e15f7 80
7f1e15f7
DM
81 The key/value pairs of json::objects are printed in the order
82 in which the keys were originally inserted. */
4a4412b9
DM
83
84void
3bd8241a 85value::dump (FILE *outf, bool formatted) const
4a4412b9
DM
86{
87 pretty_printer pp;
88 pp_buffer (&pp)->stream = outf;
3bd8241a 89 print (&pp, formatted);
4a4412b9
DM
90 pp_flush (&pp);
91}
92
93/* class json::object, a subclass of json::value, representing
7f1e15f7 94 an ordered collection of key/value pairs. */
4a4412b9
DM
95
96/* json:object's dtor. */
97
98object::~object ()
99{
100 for (map_t::iterator it = m_map.begin (); it != m_map.end (); ++it)
101 {
102 free (const_cast <char *>((*it).first));
103 delete ((*it).second);
104 }
105}
106
107/* Implementation of json::value::print for json::object. */
108
109void
3bd8241a 110object::print (pretty_printer *pp, bool formatted) const
4a4412b9 111{
4a4412b9 112 pp_character (pp, '{');
3bd8241a
DM
113 if (formatted)
114 pp_indentation (pp) += 1;
7f1e15f7
DM
115
116 /* Iterate in the order that the keys were inserted. */
117 unsigned i;
118 const char *key;
119 FOR_EACH_VEC_ELT (m_keys, i, key)
4a4412b9 120 {
7f1e15f7 121 if (i > 0)
3bd8241a
DM
122 {
123 pp_string (pp, ",");
124 if (formatted)
125 {
126 pp_newline (pp);
127 pp_indent (pp);
128 }
129 else
130 pp_space (pp);
131 }
7f1e15f7
DM
132 map_t &mut_map = const_cast<map_t &> (m_map);
133 value *value = *mut_map.get (key);
30d9a3a6 134 print_escaped_json_string (pp, key, strlen (key));
ca23341b 135 pp_string (pp, ": ");
3bd8241a
DM
136 const int indent = strlen (key) + 4;
137 if (formatted)
138 pp_indentation (pp) += indent;
139 value->print (pp, formatted);
140 if (formatted)
141 pp_indentation (pp) -= indent;
4a4412b9 142 }
3bd8241a
DM
143 if (formatted)
144 pp_indentation (pp) -= 1;
4a4412b9
DM
145 pp_character (pp, '}');
146}
147
dad2580c 148/* Set the json::value * for KEY, taking ownership of V
4a4412b9
DM
149 (and taking a copy of KEY if necessary). */
150
151void
152object::set (const char *key, value *v)
153{
dad2580c
DM
154 gcc_assert (key);
155 gcc_assert (v);
156
4a4412b9
DM
157 value **ptr = m_map.get (key);
158 if (ptr)
159 {
160 /* If the key is already present, delete the existing value
161 and overwrite it. */
162 delete *ptr;
163 *ptr = v;
164 }
165 else
7f1e15f7
DM
166 {
167 /* If the key wasn't already present, take a copy of the key,
168 and store the value. */
169 char *owned_key = xstrdup (key);
170 m_map.put (owned_key, v);
171 m_keys.safe_push (owned_key);
172 }
4a4412b9
DM
173}
174
30d3ba51
DM
175/* Get the json::value * for KEY.
176
177 The object retains ownership of the value. */
178
179value *
180object::get (const char *key) const
181{
182 gcc_assert (key);
183
184 value **ptr = const_cast <map_t &> (m_map).get (key);
185 if (ptr)
186 return *ptr;
187 else
188 return NULL;
189}
190
070944fd
DM
191/* Set value of KEY within this object to a JSON
192 string value based on UTF8_VALUE. */
193
194void
195object::set_string (const char *key, const char *utf8_value)
196{
197 set (key, new json::string (utf8_value));
198}
199
200/* Set value of KEY within this object to a JSON
201 integer value based on V. */
202
203void
204object::set_integer (const char *key, long v)
205{
206 set (key, new json::integer_number (v));
207}
208
209/* Set value of KEY within this object to a JSON
210 floating point value based on V. */
211
212void
213object::set_float (const char *key, double v)
214{
215 set (key, new json::float_number (v));
216}
217
218/* Set value of KEY within this object to the JSON
219 literal true or false, based on V. */
220
221void
222object::set_bool (const char *key, bool v)
223{
224 set (key, new json::literal (v));
225}
226
4a4412b9
DM
227/* class json::array, a subclass of json::value, representing
228 an ordered collection of values. */
229
230/* json::array's dtor. */
231
232array::~array ()
233{
234 unsigned i;
235 value *v;
236 FOR_EACH_VEC_ELT (m_elements, i, v)
237 delete v;
238}
239
240/* Implementation of json::value::print for json::array. */
241
242void
3bd8241a 243array::print (pretty_printer *pp, bool formatted) const
4a4412b9
DM
244{
245 pp_character (pp, '[');
3bd8241a
DM
246 if (formatted)
247 pp_indentation (pp) += 1;
4a4412b9
DM
248 unsigned i;
249 value *v;
250 FOR_EACH_VEC_ELT (m_elements, i, v)
251 {
252 if (i)
3bd8241a
DM
253 {
254 pp_string (pp, ",");
255 if (formatted)
256 {
257 pp_newline (pp);
258 pp_indent (pp);
259 }
260 else
261 pp_space (pp);
262 }
263 v->print (pp, formatted);
4a4412b9 264 }
3bd8241a
DM
265 if (formatted)
266 pp_indentation (pp) -= 1;
4a4412b9
DM
267 pp_character (pp, ']');
268}
269
dad2580c
DM
270/* Append non-NULL value V to a json::array, taking ownership of V. */
271
272void
273array::append (value *v)
274{
275 gcc_assert (v);
276 m_elements.safe_push (v);
277}
278
07622278 279/* class json::float_number, a subclass of json::value, wrapping a double. */
4a4412b9 280
07622278 281/* Implementation of json::value::print for json::float_number. */
4a4412b9
DM
282
283void
3bd8241a
DM
284float_number::print (pretty_printer *pp,
285 bool formatted ATTRIBUTE_UNUSED) const
4a4412b9
DM
286{
287 char tmp[1024];
288 snprintf (tmp, sizeof (tmp), "%g", m_value);
289 pp_string (pp, tmp);
290}
291
07622278
ML
292/* class json::integer_number, a subclass of json::value, wrapping a long. */
293
294/* Implementation of json::value::print for json::integer_number. */
295
296void
3bd8241a
DM
297integer_number::print (pretty_printer *pp,
298 bool formatted ATTRIBUTE_UNUSED) const
07622278
ML
299{
300 char tmp[1024];
301 snprintf (tmp, sizeof (tmp), "%ld", m_value);
302 pp_string (pp, tmp);
303}
304
305
4a4412b9
DM
306/* class json::string, a subclass of json::value. */
307
dad2580c
DM
308/* json::string's ctor. */
309
310string::string (const char *utf8)
311{
312 gcc_assert (utf8);
313 m_utf8 = xstrdup (utf8);
ee08aa9a
LH
314 m_len = strlen (utf8);
315}
316
317string::string (const char *utf8, size_t len)
318{
319 gcc_assert (utf8);
320 m_utf8 = XNEWVEC (char, len);
321 m_len = len;
322 memcpy (m_utf8, utf8, len);
dad2580c
DM
323}
324
325/* Implementation of json::value::print for json::string. */
326
4a4412b9 327void
3bd8241a
DM
328string::print (pretty_printer *pp,
329 bool formatted ATTRIBUTE_UNUSED) const
4a4412b9 330{
30d9a3a6 331 print_escaped_json_string (pp, m_utf8, m_len);
4a4412b9
DM
332}
333
334/* class json::literal, a subclass of json::value. */
335
336/* Implementation of json::value::print for json::literal. */
337
338void
3bd8241a
DM
339literal::print (pretty_printer *pp,
340 bool formatted ATTRIBUTE_UNUSED) const
4a4412b9
DM
341{
342 switch (m_kind)
343 {
344 case JSON_TRUE:
345 pp_string (pp, "true");
346 break;
347 case JSON_FALSE:
348 pp_string (pp, "false");
349 break;
350 case JSON_NULL:
351 pp_string (pp, "null");
352 break;
353 default:
354 gcc_unreachable ();
355 }
356}
357
358\f
359#if CHECKING_P
360
361namespace selftest {
362
363/* Selftests. */
364
365/* Verify that JV->print () prints EXPECTED_JSON. */
366
367static void
3bd8241a
DM
368assert_print_eq (const location &loc,
369 const json::value &jv,
370 bool formatted,
371 const char *expected_json)
4a4412b9
DM
372{
373 pretty_printer pp;
3bd8241a 374 jv.print (&pp, formatted);
2220263f 375 ASSERT_STREQ_AT (loc, expected_json, pp_formatted_text (&pp));
4a4412b9
DM
376}
377
3bd8241a
DM
378#define ASSERT_PRINT_EQ(JV, FORMATTED, EXPECTED_JSON) \
379 assert_print_eq (SELFTEST_LOCATION, JV, FORMATTED, EXPECTED_JSON)
2220263f 380
30d3ba51
DM
381/* Verify that object::get works as expected. */
382
383static void
384test_object_get ()
385{
386 object obj;
387 value *val = new json::string ("value");
388 obj.set ("foo", val);
389 ASSERT_EQ (obj.get ("foo"), val);
390 ASSERT_EQ (obj.get ("not-present"), NULL);
391}
392
7f1e15f7 393/* Verify that JSON objects are written correctly. */
4a4412b9
DM
394
395static void
396test_writing_objects ()
397{
398 object obj;
070944fd
DM
399 obj.set_string ("foo", "bar");
400 obj.set_string ("baz", "quux");
30d9a3a6
DM
401 obj.set_string ("\"\\\b\f\n\r\t", "value for awkward key");
402
7f1e15f7
DM
403 /* This test relies on json::object writing out key/value pairs
404 in key-insertion order. */
3bd8241a
DM
405 ASSERT_PRINT_EQ (obj, true,
406 "{\"foo\": \"bar\",\n"
30d9a3a6
DM
407 " \"baz\": \"quux\",\n"
408 " \"\\\"\\\\\\b\\f\\n\\r\\t\": \"value for awkward key\"}");
3bd8241a 409 ASSERT_PRINT_EQ (obj, false,
30d9a3a6
DM
410 "{\"foo\": \"bar\", \"baz\": \"quux\""
411 ", \"\\\"\\\\\\b\\f\\n\\r\\t\": \"value for awkward key\"}");
4a4412b9
DM
412}
413
414/* Verify that JSON arrays are written correctly. */
415
416static void
417test_writing_arrays ()
418{
419 array arr;
3bd8241a 420 ASSERT_PRINT_EQ (arr, true, "[]");
4a4412b9
DM
421
422 arr.append (new json::string ("foo"));
3bd8241a 423 ASSERT_PRINT_EQ (arr, true, "[\"foo\"]");
4a4412b9
DM
424
425 arr.append (new json::string ("bar"));
3bd8241a
DM
426 ASSERT_PRINT_EQ (arr, true,
427 "[\"foo\",\n"
428 " \"bar\"]");
429 ASSERT_PRINT_EQ (arr, false,
430 "[\"foo\", \"bar\"]");
4a4412b9
DM
431}
432
433/* Verify that JSON numbers are written correctly. */
434
435static void
07622278
ML
436test_writing_float_numbers ()
437{
3bd8241a
DM
438 ASSERT_PRINT_EQ (float_number (0), true, "0");
439 ASSERT_PRINT_EQ (float_number (42), true, "42");
440 ASSERT_PRINT_EQ (float_number (-100), true, "-100");
441 ASSERT_PRINT_EQ (float_number (123456789), true, "1.23457e+08");
07622278
ML
442}
443
444static void
445test_writing_integer_numbers ()
4a4412b9 446{
3bd8241a
DM
447 ASSERT_PRINT_EQ (integer_number (0), true, "0");
448 ASSERT_PRINT_EQ (integer_number (42), true, "42");
449 ASSERT_PRINT_EQ (integer_number (-100), true, "-100");
450 ASSERT_PRINT_EQ (integer_number (123456789), true, "123456789");
451 ASSERT_PRINT_EQ (integer_number (-123456789), true, "-123456789");
4a4412b9
DM
452}
453
454/* Verify that JSON strings are written correctly. */
455
456static void
457test_writing_strings ()
458{
459 string foo ("foo");
3bd8241a 460 ASSERT_PRINT_EQ (foo, true, "\"foo\"");
4a4412b9
DM
461
462 string contains_quotes ("before \"quoted\" after");
3bd8241a 463 ASSERT_PRINT_EQ (contains_quotes, true, "\"before \\\"quoted\\\" after\"");
ee08aa9a
LH
464
465 const char data[] = {'a', 'b', 'c', 'd', '\0', 'e', 'f'};
466 string not_terminated (data, 3);
3bd8241a 467 ASSERT_PRINT_EQ (not_terminated, true, "\"abc\"");
ee08aa9a 468 string embedded_null (data, sizeof data);
3bd8241a 469 ASSERT_PRINT_EQ (embedded_null, true, "\"abcd\\0ef\"");
4a4412b9
DM
470}
471
9ed31860 472/* Verify that JSON literals are written correctly. */
4a4412b9
DM
473
474static void
475test_writing_literals ()
476{
3bd8241a
DM
477 ASSERT_PRINT_EQ (literal (JSON_TRUE), true, "true");
478 ASSERT_PRINT_EQ (literal (JSON_FALSE), true, "false");
479 ASSERT_PRINT_EQ (literal (JSON_NULL), true, "null");
c8fda30f 480
3bd8241a
DM
481 ASSERT_PRINT_EQ (literal (true), true, "true");
482 ASSERT_PRINT_EQ (literal (false), true, "false");
483}
484
485/* Verify that nested values are formatted correctly when written. */
486
487static void
488test_formatting ()
489{
490 object obj;
491 object *child = new object;
492 object *grandchild = new object;
493
494 obj.set_string ("str", "bar");
495 obj.set ("child", child);
496 obj.set_integer ("int", 42);
497
498 child->set ("grandchild", grandchild);
499 child->set_integer ("int", 1776);
500
501 array *arr = new array;
502 for (int i = 0; i < 3; i++)
503 arr->append (new integer_number (i));
504 grandchild->set ("arr", arr);
505 grandchild->set_integer ("int", 1066);
506
507 /* This test relies on json::object writing out key/value pairs
508 in key-insertion order. */
509 ASSERT_PRINT_EQ (obj, true,
510 ("{\"str\": \"bar\",\n"
511 " \"child\": {\"grandchild\": {\"arr\": [0,\n"
512 " 1,\n"
513 " 2],\n"
514 " \"int\": 1066},\n"
515 " \"int\": 1776},\n"
516 " \"int\": 42}"));
517 ASSERT_PRINT_EQ (obj, false,
518 ("{\"str\": \"bar\", \"child\": {\"grandchild\":"
519 " {\"arr\": [0, 1, 2], \"int\": 1066},"
520 " \"int\": 1776}, \"int\": 42}"));
4a4412b9
DM
521}
522
523/* Run all of the selftests within this file. */
524
525void
526json_cc_tests ()
527{
30d3ba51 528 test_object_get ();
4a4412b9
DM
529 test_writing_objects ();
530 test_writing_arrays ();
07622278
ML
531 test_writing_float_numbers ();
532 test_writing_integer_numbers ();
4a4412b9
DM
533 test_writing_strings ();
534 test_writing_literals ();
3bd8241a 535 test_formatting ();
4a4412b9
DM
536}
537
538} // namespace selftest
539
540#endif /* #if CHECKING_P */