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
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
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/>. */
23 #include "coretypes.h"
25 #include "pretty-print.h"
27 #include "make-unique.h"
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. */
37 print_escaped_json_string (pretty_printer
*pp
,
41 pp_character (pp
, '"');
42 for (size_t i
= 0; i
!= len
; ++i
)
44 char ch
= utf8_str
[i
];
48 pp_string (pp
, "\\\"");
51 pp_string (pp
, "\\\\");
54 pp_string (pp
, "\\b");
57 pp_string (pp
, "\\f");
60 pp_string (pp
, "\\n");
63 pp_string (pp
, "\\r");
66 pp_string (pp
, "\\t");
69 pp_string (pp
, "\\0");
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. */
86 value::dump (FILE *outf
, bool formatted
) const
89 pp_buffer (&pp
)->m_stream
= outf
;
90 print (&pp
, formatted
);
94 /* A convenience function for debugging.
95 Dump to stderr with formatting, and a trailing newline. */
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. */
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. */
121 object::print (pretty_printer
*pp
, bool formatted
) const
123 pp_character (pp
, '{');
125 pp_indentation (pp
) += 1;
127 /* Iterate in the order that the keys were inserted. */
130 FOR_EACH_VEC_ELT (m_keys
, i
, key
)
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;
149 pp_indentation (pp
) += indent
;
150 value
->print (pp
, formatted
);
152 pp_indentation (pp
) -= indent
;
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). */
163 object::set (const char *key
, value
*v
)
168 value
**ptr
= m_map
.get (key
);
171 /* If the key is already present, delete the existing value
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. */
191 object::get (const char *key
) const
195 value
**ptr
= const_cast <map_t
&> (m_map
).get (key
);
202 /* Set value of KEY within this object to a JSON
203 string value based on UTF8_VALUE. */
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. */
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. */
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. */
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. */
247 FOR_EACH_VEC_ELT (m_elements
, i
, v
)
251 /* Implementation of json::value::print for json::array. */
254 array::print (pretty_printer
*pp
, bool formatted
) const
256 pp_character (pp
, '[');
258 pp_indentation (pp
) += 1;
261 FOR_EACH_VEC_ELT (m_elements
, i
, v
)
274 v
->print (pp
, formatted
);
277 pp_indentation (pp
) -= 1;
278 pp_character (pp
, ']');
281 /* Append non-NULL value V to a json::array, taking ownership of V. */
284 array::append (value
*v
)
287 m_elements
.safe_push (v
);
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. */
302 float_number::print (pretty_printer
*pp
,
303 bool formatted ATTRIBUTE_UNUSED
) const
306 snprintf (tmp
, sizeof (tmp
), "%g", m_value
);
310 /* class json::integer_number, a subclass of json::value, wrapping a long. */
312 /* Implementation of json::value::print for json::integer_number. */
315 integer_number::print (pretty_printer
*pp
,
316 bool formatted ATTRIBUTE_UNUSED
) const
319 snprintf (tmp
, sizeof (tmp
), "%ld", m_value
);
324 /* class json::string, a subclass of json::value. */
326 /* json::string's ctor. */
328 string::string (const char *utf8
)
331 m_utf8
= xstrdup (utf8
);
332 m_len
= strlen (utf8
);
335 string::string (const char *utf8
, size_t len
)
338 m_utf8
= XNEWVEC (char, len
);
340 memcpy (m_utf8
, utf8
, len
);
343 /* Implementation of json::value::print for json::string. */
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. */
357 literal::print (pretty_printer
*pp
,
358 bool formatted ATTRIBUTE_UNUSED
) const
363 pp_string (pp
, "true");
366 pp_string (pp
, "false");
369 pp_string (pp
, "null");
383 /* Verify that JV->print () prints EXPECTED_JSON. */
386 assert_print_eq (const location
&loc
,
387 const json::value
&jv
,
389 const char *expected_json
)
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. */
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. */
414 test_writing_objects ()
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. */
435 test_writing_arrays ()
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,
447 ASSERT_PRINT_EQ (arr
, false,
448 "[\"foo\", \"bar\"]");
451 /* Verify that JSON numbers are written correctly. */
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");
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. */
475 test_writing_strings ()
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. */
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).*/
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"
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. */
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 ();
559 } // namespace selftest
561 #endif /* #if CHECKING_P */