d: Merge upstream dmd, druntime 2bbf64907c, phobos b64bfbf91
[official-gcc.git] / gcc / json.cc
blob90ddd7ab3b156d3ccbb2e36de19af01a17b41131
1 /* JSON trees
2 Copyright (C) 2017-2023 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
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.
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.
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/>. */
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"
29 using namespace json;
31 /* class json::value. */
33 /* Dump this json::value tree to OUTF.
35 The key/value pairs of json::objects are printed in the order
36 in which the keys were originally inserted. */
38 void
39 value::dump (FILE *outf, bool formatted) const
41 pretty_printer pp;
42 pp_buffer (&pp)->stream = outf;
43 print (&pp, formatted);
44 pp_flush (&pp);
47 /* class json::object, a subclass of json::value, representing
48 an ordered collection of key/value pairs. */
50 /* json:object's dtor. */
52 object::~object ()
54 for (map_t::iterator it = m_map.begin (); it != m_map.end (); ++it)
56 free (const_cast <char *>((*it).first));
57 delete ((*it).second);
61 /* Implementation of json::value::print for json::object. */
63 void
64 object::print (pretty_printer *pp, bool formatted) const
66 pp_character (pp, '{');
67 if (formatted)
68 pp_indentation (pp) += 1;
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)
75 if (i > 0)
77 pp_string (pp, ",");
78 if (formatted)
80 pp_newline (pp);
81 pp_indent (pp);
83 else
84 pp_space (pp);
86 map_t &mut_map = const_cast<map_t &> (m_map);
87 value *value = *mut_map.get (key);
88 pp_doublequote (pp);
89 pp_string (pp, key); // FIXME: escaping?
90 pp_doublequote (pp);
91 pp_string (pp, ": ");
92 const int indent = strlen (key) + 4;
93 if (formatted)
94 pp_indentation (pp) += indent;
95 value->print (pp, formatted);
96 if (formatted)
97 pp_indentation (pp) -= indent;
99 if (formatted)
100 pp_indentation (pp) -= 1;
101 pp_character (pp, '}');
104 /* Set the json::value * for KEY, taking ownership of V
105 (and taking a copy of KEY if necessary). */
107 void
108 object::set (const char *key, value *v)
110 gcc_assert (key);
111 gcc_assert (v);
113 value **ptr = m_map.get (key);
114 if (ptr)
116 /* If the key is already present, delete the existing value
117 and overwrite it. */
118 delete *ptr;
119 *ptr = v;
121 else
123 /* If the key wasn't already present, take a copy of the key,
124 and store the value. */
125 char *owned_key = xstrdup (key);
126 m_map.put (owned_key, v);
127 m_keys.safe_push (owned_key);
131 /* Get the json::value * for KEY.
133 The object retains ownership of the value. */
135 value *
136 object::get (const char *key) const
138 gcc_assert (key);
140 value **ptr = const_cast <map_t &> (m_map).get (key);
141 if (ptr)
142 return *ptr;
143 else
144 return NULL;
147 /* Set value of KEY within this object to a JSON
148 string value based on UTF8_VALUE. */
150 void
151 object::set_string (const char *key, const char *utf8_value)
153 set (key, new json::string (utf8_value));
156 /* Set value of KEY within this object to a JSON
157 integer value based on V. */
159 void
160 object::set_integer (const char *key, long v)
162 set (key, new json::integer_number (v));
165 /* Set value of KEY within this object to a JSON
166 floating point value based on V. */
168 void
169 object::set_float (const char *key, double v)
171 set (key, new json::float_number (v));
174 /* Set value of KEY within this object to the JSON
175 literal true or false, based on V. */
177 void
178 object::set_bool (const char *key, bool v)
180 set (key, new json::literal (v));
183 /* class json::array, a subclass of json::value, representing
184 an ordered collection of values. */
186 /* json::array's dtor. */
188 array::~array ()
190 unsigned i;
191 value *v;
192 FOR_EACH_VEC_ELT (m_elements, i, v)
193 delete v;
196 /* Implementation of json::value::print for json::array. */
198 void
199 array::print (pretty_printer *pp, bool formatted) const
201 pp_character (pp, '[');
202 if (formatted)
203 pp_indentation (pp) += 1;
204 unsigned i;
205 value *v;
206 FOR_EACH_VEC_ELT (m_elements, i, v)
208 if (i)
210 pp_string (pp, ",");
211 if (formatted)
213 pp_newline (pp);
214 pp_indent (pp);
216 else
217 pp_space (pp);
219 v->print (pp, formatted);
221 if (formatted)
222 pp_indentation (pp) -= 1;
223 pp_character (pp, ']');
226 /* Append non-NULL value V to a json::array, taking ownership of V. */
228 void
229 array::append (value *v)
231 gcc_assert (v);
232 m_elements.safe_push (v);
235 /* class json::float_number, a subclass of json::value, wrapping a double. */
237 /* Implementation of json::value::print for json::float_number. */
239 void
240 float_number::print (pretty_printer *pp,
241 bool formatted ATTRIBUTE_UNUSED) const
243 char tmp[1024];
244 snprintf (tmp, sizeof (tmp), "%g", m_value);
245 pp_string (pp, tmp);
248 /* class json::integer_number, a subclass of json::value, wrapping a long. */
250 /* Implementation of json::value::print for json::integer_number. */
252 void
253 integer_number::print (pretty_printer *pp,
254 bool formatted ATTRIBUTE_UNUSED) const
256 char tmp[1024];
257 snprintf (tmp, sizeof (tmp), "%ld", m_value);
258 pp_string (pp, tmp);
262 /* class json::string, a subclass of json::value. */
264 /* json::string's ctor. */
266 string::string (const char *utf8)
268 gcc_assert (utf8);
269 m_utf8 = xstrdup (utf8);
270 m_len = strlen (utf8);
273 string::string (const char *utf8, size_t len)
275 gcc_assert (utf8);
276 m_utf8 = XNEWVEC (char, len);
277 m_len = len;
278 memcpy (m_utf8, utf8, len);
281 /* Implementation of json::value::print for json::string. */
283 void
284 string::print (pretty_printer *pp,
285 bool formatted ATTRIBUTE_UNUSED) const
287 pp_character (pp, '"');
288 for (size_t i = 0; i != m_len; ++i)
290 char ch = m_utf8[i];
291 switch (ch)
293 case '"':
294 pp_string (pp, "\\\"");
295 break;
296 case '\\':
297 pp_string (pp, "\\\\");
298 break;
299 case '\b':
300 pp_string (pp, "\\b");
301 break;
302 case '\f':
303 pp_string (pp, "\\f");
304 break;
305 case '\n':
306 pp_string (pp, "\\n");
307 break;
308 case '\r':
309 pp_string (pp, "\\r");
310 break;
311 case '\t':
312 pp_string (pp, "\\t");
313 break;
314 case '\0':
315 pp_string (pp, "\\0");
316 break;
317 default:
318 pp_character (pp, ch);
321 pp_character (pp, '"');
324 /* class json::literal, a subclass of json::value. */
326 /* Implementation of json::value::print for json::literal. */
328 void
329 literal::print (pretty_printer *pp,
330 bool formatted ATTRIBUTE_UNUSED) const
332 switch (m_kind)
334 case JSON_TRUE:
335 pp_string (pp, "true");
336 break;
337 case JSON_FALSE:
338 pp_string (pp, "false");
339 break;
340 case JSON_NULL:
341 pp_string (pp, "null");
342 break;
343 default:
344 gcc_unreachable ();
349 #if CHECKING_P
351 namespace selftest {
353 /* Selftests. */
355 /* Verify that JV->print () prints EXPECTED_JSON. */
357 static void
358 assert_print_eq (const location &loc,
359 const json::value &jv,
360 bool formatted,
361 const char *expected_json)
363 pretty_printer pp;
364 jv.print (&pp, formatted);
365 ASSERT_STREQ_AT (loc, expected_json, pp_formatted_text (&pp));
368 #define ASSERT_PRINT_EQ(JV, FORMATTED, EXPECTED_JSON) \
369 assert_print_eq (SELFTEST_LOCATION, JV, FORMATTED, EXPECTED_JSON)
371 /* Verify that object::get works as expected. */
373 static void
374 test_object_get ()
376 object obj;
377 value *val = new json::string ("value");
378 obj.set ("foo", val);
379 ASSERT_EQ (obj.get ("foo"), val);
380 ASSERT_EQ (obj.get ("not-present"), NULL);
383 /* Verify that JSON objects are written correctly. */
385 static void
386 test_writing_objects ()
388 object obj;
389 obj.set_string ("foo", "bar");
390 obj.set_string ("baz", "quux");
391 /* This test relies on json::object writing out key/value pairs
392 in key-insertion order. */
393 ASSERT_PRINT_EQ (obj, true,
394 "{\"foo\": \"bar\",\n"
395 " \"baz\": \"quux\"}");
396 ASSERT_PRINT_EQ (obj, false,
397 "{\"foo\": \"bar\", \"baz\": \"quux\"}");
400 /* Verify that JSON arrays are written correctly. */
402 static void
403 test_writing_arrays ()
405 array arr;
406 ASSERT_PRINT_EQ (arr, true, "[]");
408 arr.append (new json::string ("foo"));
409 ASSERT_PRINT_EQ (arr, true, "[\"foo\"]");
411 arr.append (new json::string ("bar"));
412 ASSERT_PRINT_EQ (arr, true,
413 "[\"foo\",\n"
414 " \"bar\"]");
415 ASSERT_PRINT_EQ (arr, false,
416 "[\"foo\", \"bar\"]");
419 /* Verify that JSON numbers are written correctly. */
421 static void
422 test_writing_float_numbers ()
424 ASSERT_PRINT_EQ (float_number (0), true, "0");
425 ASSERT_PRINT_EQ (float_number (42), true, "42");
426 ASSERT_PRINT_EQ (float_number (-100), true, "-100");
427 ASSERT_PRINT_EQ (float_number (123456789), true, "1.23457e+08");
430 static void
431 test_writing_integer_numbers ()
433 ASSERT_PRINT_EQ (integer_number (0), true, "0");
434 ASSERT_PRINT_EQ (integer_number (42), true, "42");
435 ASSERT_PRINT_EQ (integer_number (-100), true, "-100");
436 ASSERT_PRINT_EQ (integer_number (123456789), true, "123456789");
437 ASSERT_PRINT_EQ (integer_number (-123456789), true, "-123456789");
440 /* Verify that JSON strings are written correctly. */
442 static void
443 test_writing_strings ()
445 string foo ("foo");
446 ASSERT_PRINT_EQ (foo, true, "\"foo\"");
448 string contains_quotes ("before \"quoted\" after");
449 ASSERT_PRINT_EQ (contains_quotes, true, "\"before \\\"quoted\\\" after\"");
451 const char data[] = {'a', 'b', 'c', 'd', '\0', 'e', 'f'};
452 string not_terminated (data, 3);
453 ASSERT_PRINT_EQ (not_terminated, true, "\"abc\"");
454 string embedded_null (data, sizeof data);
455 ASSERT_PRINT_EQ (embedded_null, true, "\"abcd\\0ef\"");
458 /* Verify that JSON literals are written correctly. */
460 static void
461 test_writing_literals ()
463 ASSERT_PRINT_EQ (literal (JSON_TRUE), true, "true");
464 ASSERT_PRINT_EQ (literal (JSON_FALSE), true, "false");
465 ASSERT_PRINT_EQ (literal (JSON_NULL), true, "null");
467 ASSERT_PRINT_EQ (literal (true), true, "true");
468 ASSERT_PRINT_EQ (literal (false), true, "false");
471 /* Verify that nested values are formatted correctly when written. */
473 static void
474 test_formatting ()
476 object obj;
477 object *child = new object;
478 object *grandchild = new object;
480 obj.set_string ("str", "bar");
481 obj.set ("child", child);
482 obj.set_integer ("int", 42);
484 child->set ("grandchild", grandchild);
485 child->set_integer ("int", 1776);
487 array *arr = new array;
488 for (int i = 0; i < 3; i++)
489 arr->append (new integer_number (i));
490 grandchild->set ("arr", arr);
491 grandchild->set_integer ("int", 1066);
493 /* This test relies on json::object writing out key/value pairs
494 in key-insertion order. */
495 ASSERT_PRINT_EQ (obj, true,
496 ("{\"str\": \"bar\",\n"
497 " \"child\": {\"grandchild\": {\"arr\": [0,\n"
498 " 1,\n"
499 " 2],\n"
500 " \"int\": 1066},\n"
501 " \"int\": 1776},\n"
502 " \"int\": 42}"));
503 ASSERT_PRINT_EQ (obj, false,
504 ("{\"str\": \"bar\", \"child\": {\"grandchild\":"
505 " {\"arr\": [0, 1, 2], \"int\": 1066},"
506 " \"int\": 1776}, \"int\": 42}"));
509 /* Run all of the selftests within this file. */
511 void
512 json_cc_tests ()
514 test_object_get ();
515 test_writing_objects ();
516 test_writing_arrays ();
517 test_writing_float_numbers ();
518 test_writing_integer_numbers ();
519 test_writing_strings ();
520 test_writing_literals ();
521 test_formatting ();
524 } // namespace selftest
526 #endif /* #if CHECKING_P */