xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/json.cc (revision ccd9df534e375a4366c5b55f23782053c7a98d82)
1 /* JSON trees
2    Copyright (C) 2017-2020 Free Software Foundation, Inc.
3    Contributed by David Malcolm <dmalcolm@redhat.com>.
4 
5 This file is part of GCC.
6 
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.
11 
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.
16 
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/>.  */
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 
29 using namespace json;
30 
31 /* class json::value.  */
32 
33 /* Dump this json::value tree to OUTF.
34    No formatting is done.  There are no guarantees about the order
35    in which the key/value pairs of json::objects are printed.  */
36 
37 void
38 value::dump (FILE *outf) const
39 {
40   pretty_printer pp;
41   pp_buffer (&pp)->stream = outf;
42   print (&pp);
43   pp_flush (&pp);
44 }
45 
46 /* class json::object, a subclass of json::value, representing
47    an unordered collection of key/value pairs.  */
48 
49 /* json:object's dtor.  */
50 
51 object::~object ()
52 {
53   for (map_t::iterator it = m_map.begin (); it != m_map.end (); ++it)
54     {
55       free (const_cast <char *>((*it).first));
56       delete ((*it).second);
57     }
58 }
59 
60 /* Implementation of json::value::print for json::object.  */
61 
62 void
63 object::print (pretty_printer *pp) const
64 {
65   /* Note that the order is not guaranteed.  */
66   pp_character (pp, '{');
67   for (map_t::iterator it = m_map.begin (); it != m_map.end (); ++it)
68     {
69       if (it != m_map.begin ())
70 	pp_string (pp, ", ");
71       const char *key = const_cast <char *>((*it).first);
72       value *value = (*it).second;
73       pp_printf (pp, "\"%s\": ", key); // FIXME: escaping?
74       value->print (pp);
75     }
76   pp_character (pp, '}');
77 }
78 
79 /* Set the json::value * for KEY, taking ownership of V
80    (and taking a copy of KEY if necessary).  */
81 
82 void
83 object::set (const char *key, value *v)
84 {
85   gcc_assert (key);
86   gcc_assert (v);
87 
88   value **ptr = m_map.get (key);
89   if (ptr)
90     {
91       /* If the key is already present, delete the existing value
92 	 and overwrite it.  */
93       delete *ptr;
94       *ptr = v;
95     }
96   else
97     /* If the key wasn't already present, take a copy of the key,
98        and store the value.  */
99     m_map.put (xstrdup (key), v);
100 }
101 
102 /* Get the json::value * for KEY.
103 
104    The object retains ownership of the value.  */
105 
106 value *
107 object::get (const char *key) const
108 {
109   gcc_assert (key);
110 
111   value **ptr = const_cast <map_t &> (m_map).get (key);
112   if (ptr)
113     return *ptr;
114   else
115     return NULL;
116 }
117 
118 /* class json::array, a subclass of json::value, representing
119    an ordered collection of values.  */
120 
121 /* json::array's dtor.  */
122 
123 array::~array ()
124 {
125   unsigned i;
126   value *v;
127   FOR_EACH_VEC_ELT (m_elements, i, v)
128     delete v;
129 }
130 
131 /* Implementation of json::value::print for json::array.  */
132 
133 void
134 array::print (pretty_printer *pp) const
135 {
136   pp_character (pp, '[');
137   unsigned i;
138   value *v;
139   FOR_EACH_VEC_ELT (m_elements, i, v)
140     {
141       if (i)
142 	pp_string (pp, ", ");
143       v->print (pp);
144     }
145   pp_character (pp, ']');
146 }
147 
148 /* Append non-NULL value V to a json::array, taking ownership of V.  */
149 
150 void
151 array::append (value *v)
152 {
153   gcc_assert (v);
154   m_elements.safe_push (v);
155 }
156 
157 /* class json::float_number, a subclass of json::value, wrapping a double.  */
158 
159 /* Implementation of json::value::print for json::float_number.  */
160 
161 void
162 float_number::print (pretty_printer *pp) const
163 {
164   char tmp[1024];
165   snprintf (tmp, sizeof (tmp), "%g", m_value);
166   pp_string (pp, tmp);
167 }
168 
169 /* class json::integer_number, a subclass of json::value, wrapping a long.  */
170 
171 /* Implementation of json::value::print for json::integer_number.  */
172 
173 void
174 integer_number::print (pretty_printer *pp) const
175 {
176   char tmp[1024];
177   snprintf (tmp, sizeof (tmp), "%ld", m_value);
178   pp_string (pp, tmp);
179 }
180 
181 
182 /* class json::string, a subclass of json::value.  */
183 
184 /* json::string's ctor.  */
185 
186 string::string (const char *utf8)
187 {
188   gcc_assert (utf8);
189   m_utf8 = xstrdup (utf8);
190 }
191 
192 /* Implementation of json::value::print for json::string.  */
193 
194 void
195 string::print (pretty_printer *pp) const
196 {
197   pp_character (pp, '"');
198   for (const char *ptr = m_utf8; *ptr; ptr++)
199     {
200       char ch = *ptr;
201       switch (ch)
202 	{
203 	case '"':
204 	  pp_string (pp, "\\\"");
205 	  break;
206 	case '\\':
207 	  pp_string (pp, "\\n");
208 	  break;
209 	case '\b':
210 	  pp_string (pp, "\\b");
211 	  break;
212 	case '\f':
213 	  pp_string (pp, "\\f");
214 	  break;
215 	case '\n':
216 	  pp_string (pp, "\\n");
217 	  break;
218 	case '\r':
219 	  pp_string (pp, "\\r");
220 	  break;
221 	case '\t':
222 	  pp_string (pp, "\\t");
223 	  break;
224 
225 	default:
226 	  pp_character (pp, ch);
227 	}
228     }
229   pp_character (pp, '"');
230 }
231 
232 /* class json::literal, a subclass of json::value.  */
233 
234 /* Implementation of json::value::print for json::literal.  */
235 
236 void
237 literal::print (pretty_printer *pp) const
238 {
239   switch (m_kind)
240     {
241     case JSON_TRUE:
242       pp_string (pp, "true");
243       break;
244     case JSON_FALSE:
245       pp_string (pp, "false");
246       break;
247     case JSON_NULL:
248       pp_string (pp, "null");
249       break;
250     default:
251       gcc_unreachable ();
252     }
253 }
254 
255 
256 #if CHECKING_P
257 
258 namespace selftest {
259 
260 /* Selftests.  */
261 
262 /* Verify that JV->print () prints EXPECTED_JSON.  */
263 
264 static void
265 assert_print_eq (const json::value &jv, const char *expected_json)
266 {
267   pretty_printer pp;
268   jv.print (&pp);
269   ASSERT_STREQ (expected_json, pp_formatted_text (&pp));
270 }
271 
272 /* Verify that object::get works as expected.  */
273 
274 static void
275 test_object_get ()
276 {
277   object obj;
278   value *val = new json::string ("value");
279   obj.set ("foo", val);
280   ASSERT_EQ (obj.get ("foo"), val);
281   ASSERT_EQ (obj.get ("not-present"), NULL);
282 }
283 
284 /* Verify that JSON objects are written correctly.  We can't test more than
285    one key/value pair, as we don't impose a guaranteed ordering.  */
286 
287 static void
288 test_writing_objects ()
289 {
290   object obj;
291   obj.set ("foo", new json::string ("bar"));
292   assert_print_eq (obj, "{\"foo\": \"bar\"}");
293 }
294 
295 /* Verify that JSON arrays are written correctly.  */
296 
297 static void
298 test_writing_arrays ()
299 {
300   array arr;
301   assert_print_eq (arr, "[]");
302 
303   arr.append (new json::string ("foo"));
304   assert_print_eq (arr, "[\"foo\"]");
305 
306   arr.append (new json::string ("bar"));
307   assert_print_eq (arr, "[\"foo\", \"bar\"]");
308 }
309 
310 /* Verify that JSON numbers are written correctly.  */
311 
312 static void
313 test_writing_float_numbers ()
314 {
315   assert_print_eq (float_number (0), "0");
316   assert_print_eq (float_number (42), "42");
317   assert_print_eq (float_number (-100), "-100");
318   assert_print_eq (float_number (123456789), "1.23457e+08");
319 }
320 
321 static void
322 test_writing_integer_numbers ()
323 {
324   assert_print_eq (integer_number (0), "0");
325   assert_print_eq (integer_number (42), "42");
326   assert_print_eq (integer_number (-100), "-100");
327   assert_print_eq (integer_number (123456789), "123456789");
328   assert_print_eq (integer_number (-123456789), "-123456789");
329 }
330 
331 /* Verify that JSON strings are written correctly.  */
332 
333 static void
334 test_writing_strings ()
335 {
336   string foo ("foo");
337   assert_print_eq (foo, "\"foo\"");
338 
339   string contains_quotes ("before \"quoted\" after");
340   assert_print_eq (contains_quotes, "\"before \\\"quoted\\\" after\"");
341 }
342 
343 /* Verify that JSON literals are written correctly.  */
344 
345 static void
346 test_writing_literals ()
347 {
348   assert_print_eq (literal (JSON_TRUE), "true");
349   assert_print_eq (literal (JSON_FALSE), "false");
350   assert_print_eq (literal (JSON_NULL), "null");
351 
352   assert_print_eq (literal (true), "true");
353   assert_print_eq (literal (false), "false");
354 }
355 
356 /* Run all of the selftests within this file.  */
357 
358 void
359 json_cc_tests ()
360 {
361   test_object_get ();
362   test_writing_objects ();
363   test_writing_arrays ();
364   test_writing_float_numbers ();
365   test_writing_integer_numbers ();
366   test_writing_strings ();
367   test_writing_literals ();
368 }
369 
370 } // namespace selftest
371 
372 #endif /* #if CHECKING_P */
373