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