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
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"
31 /* class json::value. */
33 /* Dump this json::value tree to OUTF.
35 No formatting is done.
37 The key/value pairs of json::objects are printed in the order
38 in which the keys were originally inserted. */
41 value::dump (FILE *outf
) const
44 pp_buffer (&pp
)->stream
= outf
;
49 /* class json::object, a subclass of json::value, representing
50 an ordered collection of key/value pairs. */
52 /* json:object's dtor. */
56 for (map_t::iterator it
= m_map
.begin (); it
!= m_map
.end (); ++it
)
58 free (const_cast <char *>((*it
).first
));
59 delete ((*it
).second
);
63 /* Implementation of json::value::print for json::object. */
66 object::print (pretty_printer
*pp
) const
68 pp_character (pp
, '{');
70 /* Iterate in the order that the keys were inserted. */
73 FOR_EACH_VEC_ELT (m_keys
, i
, key
)
77 map_t
&mut_map
= const_cast<map_t
&> (m_map
);
78 value
*value
= *mut_map
.get (key
);
80 pp_string (pp
, key
); // FIXME: escaping?
85 pp_character (pp
, '}');
88 /* Set the json::value * for KEY, taking ownership of V
89 (and taking a copy of KEY if necessary). */
92 object::set (const char *key
, value
*v
)
97 value
**ptr
= m_map
.get (key
);
100 /* If the key is already present, delete the existing value
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
);
115 /* Get the json::value * for KEY.
117 The object retains ownership of the value. */
120 object::get (const char *key
) const
124 value
**ptr
= const_cast <map_t
&> (m_map
).get (key
);
131 /* Set value of KEY within this object to a JSON
132 string value based on UTF8_VALUE. */
135 object::set_string (const char *key
, const char *utf8_value
)
137 set (key
, new json::string (utf8_value
));
140 /* Set value of KEY within this object to a JSON
141 integer value based on V. */
144 object::set_integer (const char *key
, long v
)
146 set (key
, new json::integer_number (v
));
149 /* Set value of KEY within this object to a JSON
150 floating point value based on V. */
153 object::set_float (const char *key
, double v
)
155 set (key
, new json::float_number (v
));
158 /* Set value of KEY within this object to the JSON
159 literal true or false, based on V. */
162 object::set_bool (const char *key
, bool v
)
164 set (key
, new json::literal (v
));
167 /* class json::array, a subclass of json::value, representing
168 an ordered collection of values. */
170 /* json::array's dtor. */
176 FOR_EACH_VEC_ELT (m_elements
, i
, v
)
180 /* Implementation of json::value::print for json::array. */
183 array::print (pretty_printer
*pp
) const
185 pp_character (pp
, '[');
188 FOR_EACH_VEC_ELT (m_elements
, i
, v
)
191 pp_string (pp
, ", ");
194 pp_character (pp
, ']');
197 /* Append non-NULL value V to a json::array, taking ownership of V. */
200 array::append (value
*v
)
203 m_elements
.safe_push (v
);
206 /* class json::float_number, a subclass of json::value, wrapping a double. */
208 /* Implementation of json::value::print for json::float_number. */
211 float_number::print (pretty_printer
*pp
) const
214 snprintf (tmp
, sizeof (tmp
), "%g", m_value
);
218 /* class json::integer_number, a subclass of json::value, wrapping a long. */
220 /* Implementation of json::value::print for json::integer_number. */
223 integer_number::print (pretty_printer
*pp
) const
226 snprintf (tmp
, sizeof (tmp
), "%ld", m_value
);
231 /* class json::string, a subclass of json::value. */
233 /* json::string's ctor. */
235 string::string (const char *utf8
)
238 m_utf8
= xstrdup (utf8
);
239 m_len
= strlen (utf8
);
242 string::string (const char *utf8
, size_t len
)
245 m_utf8
= XNEWVEC (char, len
);
247 memcpy (m_utf8
, utf8
, len
);
250 /* Implementation of json::value::print for json::string. */
253 string::print (pretty_printer
*pp
) const
255 pp_character (pp
, '"');
256 for (size_t i
= 0; i
!= m_len
; ++i
)
262 pp_string (pp
, "\\\"");
265 pp_string (pp
, "\\\\");
268 pp_string (pp
, "\\b");
271 pp_string (pp
, "\\f");
274 pp_string (pp
, "\\n");
277 pp_string (pp
, "\\r");
280 pp_string (pp
, "\\t");
283 pp_string (pp
, "\\0");
286 pp_character (pp
, ch
);
289 pp_character (pp
, '"');
292 /* class json::literal, a subclass of json::value. */
294 /* Implementation of json::value::print for json::literal. */
297 literal::print (pretty_printer
*pp
) const
302 pp_string (pp
, "true");
305 pp_string (pp
, "false");
308 pp_string (pp
, "null");
322 /* Verify that JV->print () prints EXPECTED_JSON. */
325 assert_print_eq (const location
&loc
, const json::value
&jv
, const char *expected_json
)
329 ASSERT_STREQ_AT (loc
, expected_json
, pp_formatted_text (&pp
));
332 #define ASSERT_PRINT_EQ(JV, EXPECTED_JSON) \
333 assert_print_eq (SELFTEST_LOCATION, JV, EXPECTED_JSON)
335 /* Verify that object::get works as expected. */
341 value
*val
= new json::string ("value");
342 obj
.set ("foo", val
);
343 ASSERT_EQ (obj
.get ("foo"), val
);
344 ASSERT_EQ (obj
.get ("not-present"), NULL
);
347 /* Verify that JSON objects are written correctly. */
350 test_writing_objects ()
353 obj
.set_string ("foo", "bar");
354 obj
.set_string ("baz", "quux");
355 /* This test relies on json::object writing out key/value pairs
356 in key-insertion order. */
357 ASSERT_PRINT_EQ (obj
, "{\"foo\": \"bar\", \"baz\": \"quux\"}");
360 /* Verify that JSON arrays are written correctly. */
363 test_writing_arrays ()
366 ASSERT_PRINT_EQ (arr
, "[]");
368 arr
.append (new json::string ("foo"));
369 ASSERT_PRINT_EQ (arr
, "[\"foo\"]");
371 arr
.append (new json::string ("bar"));
372 ASSERT_PRINT_EQ (arr
, "[\"foo\", \"bar\"]");
375 /* Verify that JSON numbers are written correctly. */
378 test_writing_float_numbers ()
380 ASSERT_PRINT_EQ (float_number (0), "0");
381 ASSERT_PRINT_EQ (float_number (42), "42");
382 ASSERT_PRINT_EQ (float_number (-100), "-100");
383 ASSERT_PRINT_EQ (float_number (123456789), "1.23457e+08");
387 test_writing_integer_numbers ()
389 ASSERT_PRINT_EQ (integer_number (0), "0");
390 ASSERT_PRINT_EQ (integer_number (42), "42");
391 ASSERT_PRINT_EQ (integer_number (-100), "-100");
392 ASSERT_PRINT_EQ (integer_number (123456789), "123456789");
393 ASSERT_PRINT_EQ (integer_number (-123456789), "-123456789");
396 /* Verify that JSON strings are written correctly. */
399 test_writing_strings ()
402 ASSERT_PRINT_EQ (foo
, "\"foo\"");
404 string
contains_quotes ("before \"quoted\" after");
405 ASSERT_PRINT_EQ (contains_quotes
, "\"before \\\"quoted\\\" after\"");
407 const char data
[] = {'a', 'b', 'c', 'd', '\0', 'e', 'f'};
408 string
not_terminated (data
, 3);
409 ASSERT_PRINT_EQ (not_terminated
, "\"abc\"");
410 string
embedded_null (data
, sizeof data
);
411 ASSERT_PRINT_EQ (embedded_null
, "\"abcd\\0ef\"");
414 /* Verify that JSON literals are written correctly. */
417 test_writing_literals ()
419 ASSERT_PRINT_EQ (literal (JSON_TRUE
), "true");
420 ASSERT_PRINT_EQ (literal (JSON_FALSE
), "false");
421 ASSERT_PRINT_EQ (literal (JSON_NULL
), "null");
423 ASSERT_PRINT_EQ (literal (true), "true");
424 ASSERT_PRINT_EQ (literal (false), "false");
427 /* Run all of the selftests within this file. */
433 test_writing_objects ();
434 test_writing_arrays ();
435 test_writing_float_numbers ();
436 test_writing_integer_numbers ();
437 test_writing_strings ();
438 test_writing_literals ();
441 } // namespace selftest
443 #endif /* #if CHECKING_P */