OpenMP: Update documentation of metadirective implementation status.
[gcc.git] / gcc / json.cc
blob4cf962fe340a604517b3a8829df79b6db82f72f7
1 /* JSON trees
2 Copyright (C) 2017-2025 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 "make-unique.h"
28 #include "selftest.h"
30 using namespace json;
32 /* Print a JSON string to PP, escaping '"', control characters,
33 and embedded null bytes.
34 The string is required to be UTF-8 encoded. */
36 static void
37 print_escaped_json_string (pretty_printer *pp,
38 const char *utf8_str,
39 size_t len)
41 pp_character (pp, '"');
42 for (size_t i = 0; i != len; ++i)
44 char ch = utf8_str[i];
45 switch (ch)
47 case '"':
48 pp_string (pp, "\\\"");
49 break;
50 case '\\':
51 pp_string (pp, "\\\\");
52 break;
53 case '\b':
54 pp_string (pp, "\\b");
55 break;
56 case '\f':
57 pp_string (pp, "\\f");
58 break;
59 case '\n':
60 pp_string (pp, "\\n");
61 break;
62 case '\r':
63 pp_string (pp, "\\r");
64 break;
65 case '\t':
66 pp_string (pp, "\\t");
67 break;
68 case '\0':
69 pp_string (pp, "\\0");
70 break;
71 default:
72 pp_character (pp, ch);
75 pp_character (pp, '"');
78 /* class json::value. */
80 /* Dump this json::value tree to OUTF.
82 The key/value pairs of json::objects are printed in the order
83 in which the keys were originally inserted. */
85 void
86 value::dump (FILE *outf, bool formatted) const
88 pretty_printer pp;
89 pp_buffer (&pp)->m_stream = outf;
90 print (&pp, formatted);
91 pp_flush (&pp);
94 /* A convenience function for debugging.
95 Dump to stderr with formatting, and a trailing newline. */
97 void
98 value::dump () const
100 dump (stderr, true);
101 fprintf (stderr, "\n");
104 /* class json::object, a subclass of json::value, representing
105 an ordered collection of key/value pairs. */
107 /* json:object's dtor. */
109 object::~object ()
111 for (map_t::iterator it = m_map.begin (); it != m_map.end (); ++it)
113 free (const_cast <char *>((*it).first));
114 delete ((*it).second);
118 /* Implementation of json::value::print for json::object. */
120 void
121 object::print (pretty_printer *pp, bool formatted) const
123 pp_character (pp, '{');
124 if (formatted)
125 pp_indentation (pp) += 1;
127 /* Iterate in the order that the keys were inserted. */
128 unsigned i;
129 const char *key;
130 FOR_EACH_VEC_ELT (m_keys, i, key)
132 if (i > 0)
134 pp_string (pp, ",");
135 if (formatted)
137 pp_newline (pp);
138 pp_indent (pp);
140 else
141 pp_space (pp);
143 map_t &mut_map = const_cast<map_t &> (m_map);
144 value *value = *mut_map.get (key);
145 print_escaped_json_string (pp, key, strlen (key));
146 pp_string (pp, ": ");
147 const int indent = strlen (key) + 4;
148 if (formatted)
149 pp_indentation (pp) += indent;
150 value->print (pp, formatted);
151 if (formatted)
152 pp_indentation (pp) -= indent;
154 if (formatted)
155 pp_indentation (pp) -= 1;
156 pp_character (pp, '}');
159 /* Set the json::value * for KEY, taking ownership of V
160 (and taking a copy of KEY if necessary). */
162 void
163 object::set (const char *key, value *v)
165 gcc_assert (key);
166 gcc_assert (v);
168 value **ptr = m_map.get (key);
169 if (ptr)
171 /* If the key is already present, delete the existing value
172 and overwrite it. */
173 delete *ptr;
174 *ptr = v;
176 else
178 /* If the key wasn't already present, take a copy of the key,
179 and store the value. */
180 char *owned_key = xstrdup (key);
181 m_map.put (owned_key, v);
182 m_keys.safe_push (owned_key);
186 /* Get the json::value * for KEY.
188 The object retains ownership of the value. */
190 value *
191 object::get (const char *key) const
193 gcc_assert (key);
195 value **ptr = const_cast <map_t &> (m_map).get (key);
196 if (ptr)
197 return *ptr;
198 else
199 return NULL;
202 /* Set value of KEY within this object to a JSON
203 string value based on UTF8_VALUE. */
205 void
206 object::set_string (const char *key, const char *utf8_value)
208 set (key, new json::string (utf8_value));
211 /* Set value of KEY within this object to a JSON
212 integer value based on V. */
214 void
215 object::set_integer (const char *key, long v)
217 set (key, new json::integer_number (v));
220 /* Set value of KEY within this object to a JSON
221 floating point value based on V. */
223 void
224 object::set_float (const char *key, double v)
226 set (key, new json::float_number (v));
229 /* Set value of KEY within this object to the JSON
230 literal true or false, based on V. */
232 void
233 object::set_bool (const char *key, bool v)
235 set (key, new json::literal (v));
238 /* class json::array, a subclass of json::value, representing
239 an ordered collection of values. */
241 /* json::array's dtor. */
243 array::~array ()
245 unsigned i;
246 value *v;
247 FOR_EACH_VEC_ELT (m_elements, i, v)
248 delete v;
251 /* Implementation of json::value::print for json::array. */
253 void
254 array::print (pretty_printer *pp, bool formatted) const
256 pp_character (pp, '[');
257 if (formatted)
258 pp_indentation (pp) += 1;
259 unsigned i;
260 value *v;
261 FOR_EACH_VEC_ELT (m_elements, i, v)
263 if (i)
265 pp_string (pp, ",");
266 if (formatted)
268 pp_newline (pp);
269 pp_indent (pp);
271 else
272 pp_space (pp);
274 v->print (pp, formatted);
276 if (formatted)
277 pp_indentation (pp) -= 1;
278 pp_character (pp, ']');
281 /* Append non-NULL value V to a json::array, taking ownership of V. */
283 void
284 array::append (value *v)
286 gcc_assert (v);
287 m_elements.safe_push (v);
290 void
291 array::append_string (const char *utf8_value)
293 gcc_assert (utf8_value);
294 append (new json::string (utf8_value));
297 /* class json::float_number, a subclass of json::value, wrapping a double. */
299 /* Implementation of json::value::print for json::float_number. */
301 void
302 float_number::print (pretty_printer *pp,
303 bool formatted ATTRIBUTE_UNUSED) const
305 char tmp[1024];
306 snprintf (tmp, sizeof (tmp), "%g", m_value);
307 pp_string (pp, tmp);
310 /* class json::integer_number, a subclass of json::value, wrapping a long. */
312 /* Implementation of json::value::print for json::integer_number. */
314 void
315 integer_number::print (pretty_printer *pp,
316 bool formatted ATTRIBUTE_UNUSED) const
318 char tmp[1024];
319 snprintf (tmp, sizeof (tmp), "%ld", m_value);
320 pp_string (pp, tmp);
324 /* class json::string, a subclass of json::value. */
326 /* json::string's ctor. */
328 string::string (const char *utf8)
330 gcc_assert (utf8);
331 m_utf8 = xstrdup (utf8);
332 m_len = strlen (utf8);
335 string::string (const char *utf8, size_t len)
337 gcc_assert (utf8);
338 m_utf8 = XNEWVEC (char, len);
339 m_len = len;
340 memcpy (m_utf8, utf8, len);
343 /* Implementation of json::value::print for json::string. */
345 void
346 string::print (pretty_printer *pp,
347 bool formatted ATTRIBUTE_UNUSED) const
349 print_escaped_json_string (pp, m_utf8, m_len);
352 /* class json::literal, a subclass of json::value. */
354 /* Implementation of json::value::print for json::literal. */
356 void
357 literal::print (pretty_printer *pp,
358 bool formatted ATTRIBUTE_UNUSED) const
360 switch (m_kind)
362 case JSON_TRUE:
363 pp_string (pp, "true");
364 break;
365 case JSON_FALSE:
366 pp_string (pp, "false");
367 break;
368 case JSON_NULL:
369 pp_string (pp, "null");
370 break;
371 default:
372 gcc_unreachable ();
377 #if CHECKING_P
379 namespace selftest {
381 /* Selftests. */
383 /* Verify that JV->print () prints EXPECTED_JSON. */
385 void
386 assert_print_eq (const location &loc,
387 const json::value &jv,
388 bool formatted,
389 const char *expected_json)
391 pretty_printer pp;
392 jv.print (&pp, formatted);
393 ASSERT_STREQ_AT (loc, expected_json, pp_formatted_text (&pp));
396 #define ASSERT_PRINT_EQ(JV, FORMATTED, EXPECTED_JSON) \
397 assert_print_eq (SELFTEST_LOCATION, JV, FORMATTED, EXPECTED_JSON)
399 /* Verify that object::get works as expected. */
401 static void
402 test_object_get ()
404 object obj;
405 value *val = new json::string ("value");
406 obj.set ("foo", val);
407 ASSERT_EQ (obj.get ("foo"), val);
408 ASSERT_EQ (obj.get ("not-present"), NULL);
411 /* Verify that JSON objects are written correctly. */
413 static void
414 test_writing_objects ()
416 object obj;
417 obj.set_string ("foo", "bar");
418 obj.set_string ("baz", "quux");
419 obj.set_string ("\"\\\b\f\n\r\t", "value for awkward key");
421 /* This test relies on json::object writing out key/value pairs
422 in key-insertion order. */
423 ASSERT_PRINT_EQ (obj, true,
424 "{\"foo\": \"bar\",\n"
425 " \"baz\": \"quux\",\n"
426 " \"\\\"\\\\\\b\\f\\n\\r\\t\": \"value for awkward key\"}");
427 ASSERT_PRINT_EQ (obj, false,
428 "{\"foo\": \"bar\", \"baz\": \"quux\""
429 ", \"\\\"\\\\\\b\\f\\n\\r\\t\": \"value for awkward key\"}");
432 /* Verify that JSON arrays are written correctly. */
434 static void
435 test_writing_arrays ()
437 array arr;
438 ASSERT_PRINT_EQ (arr, true, "[]");
440 arr.append (new json::string ("foo"));
441 ASSERT_PRINT_EQ (arr, true, "[\"foo\"]");
443 arr.append_string ("bar");
444 ASSERT_PRINT_EQ (arr, true,
445 "[\"foo\",\n"
446 " \"bar\"]");
447 ASSERT_PRINT_EQ (arr, false,
448 "[\"foo\", \"bar\"]");
451 /* Verify that JSON numbers are written correctly. */
453 static void
454 test_writing_float_numbers ()
456 ASSERT_PRINT_EQ (float_number (0), true, "0");
457 ASSERT_PRINT_EQ (float_number (42), true, "42");
458 ASSERT_PRINT_EQ (float_number (-100), true, "-100");
459 ASSERT_PRINT_EQ (float_number (123456789), true, "1.23457e+08");
462 static void
463 test_writing_integer_numbers ()
465 ASSERT_PRINT_EQ (integer_number (0), true, "0");
466 ASSERT_PRINT_EQ (integer_number (42), true, "42");
467 ASSERT_PRINT_EQ (integer_number (-100), true, "-100");
468 ASSERT_PRINT_EQ (integer_number (123456789), true, "123456789");
469 ASSERT_PRINT_EQ (integer_number (-123456789), true, "-123456789");
472 /* Verify that JSON strings are written correctly. */
474 static void
475 test_writing_strings ()
477 string foo ("foo");
478 ASSERT_PRINT_EQ (foo, true, "\"foo\"");
480 string contains_quotes ("before \"quoted\" after");
481 ASSERT_PRINT_EQ (contains_quotes, true, "\"before \\\"quoted\\\" after\"");
483 const char data[] = {'a', 'b', 'c', 'd', '\0', 'e', 'f'};
484 string not_terminated (data, 3);
485 ASSERT_PRINT_EQ (not_terminated, true, "\"abc\"");
486 string embedded_null (data, sizeof data);
487 ASSERT_PRINT_EQ (embedded_null, true, "\"abcd\\0ef\"");
490 /* Verify that JSON literals are written correctly. */
492 static void
493 test_writing_literals ()
495 ASSERT_PRINT_EQ (literal (JSON_TRUE), true, "true");
496 ASSERT_PRINT_EQ (literal (JSON_FALSE), true, "false");
497 ASSERT_PRINT_EQ (literal (JSON_NULL), true, "null");
499 ASSERT_PRINT_EQ (literal (true), true, "true");
500 ASSERT_PRINT_EQ (literal (false), true, "false");
503 /* Verify that nested values are formatted correctly when written.
505 Also, make use of array::append(std::unique_ptr<value>) and
506 object::set (const char *key, std::unique_ptr<value> v).*/
508 static void
509 test_formatting ()
511 object obj;
512 object *child = new object;
513 std::unique_ptr<object> grandchild = ::make_unique<object> ();
515 obj.set_string ("str", "bar");
516 obj.set ("child", child);
517 obj.set_integer ("int", 42);
519 array *arr = new array;
520 for (int i = 0; i < 3; i++)
521 arr->append (::make_unique<integer_number> (i));
522 grandchild->set ("arr", arr);
523 grandchild->set_integer ("int", 1066);
525 child->set ("grandchild", std::move (grandchild));
526 child->set_integer ("int", 1776);
528 /* This test relies on json::object writing out key/value pairs
529 in key-insertion order. */
530 ASSERT_PRINT_EQ (obj, true,
531 ("{\"str\": \"bar\",\n"
532 " \"child\": {\"grandchild\": {\"arr\": [0,\n"
533 " 1,\n"
534 " 2],\n"
535 " \"int\": 1066},\n"
536 " \"int\": 1776},\n"
537 " \"int\": 42}"));
538 ASSERT_PRINT_EQ (obj, false,
539 ("{\"str\": \"bar\", \"child\": {\"grandchild\":"
540 " {\"arr\": [0, 1, 2], \"int\": 1066},"
541 " \"int\": 1776}, \"int\": 42}"));
544 /* Run all of the selftests within this file. */
546 void
547 json_cc_tests ()
549 test_object_get ();
550 test_writing_objects ();
551 test_writing_arrays ();
552 test_writing_float_numbers ();
553 test_writing_integer_numbers ();
554 test_writing_strings ();
555 test_writing_literals ();
556 test_formatting ();
559 } // namespace selftest
561 #endif /* #if CHECKING_P */