xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/json.cc (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 /* JSON trees
2    Copyright (C) 2017-2019 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 /* class json::array, a subclass of json::value, representing
103    an ordered collection of values.  */
104 
105 /* json::array's dtor.  */
106 
107 array::~array ()
108 {
109   unsigned i;
110   value *v;
111   FOR_EACH_VEC_ELT (m_elements, i, v)
112     delete v;
113 }
114 
115 /* Implementation of json::value::print for json::array.  */
116 
117 void
118 array::print (pretty_printer *pp) const
119 {
120   pp_character (pp, '[');
121   unsigned i;
122   value *v;
123   FOR_EACH_VEC_ELT (m_elements, i, v)
124     {
125       if (i)
126 	pp_string (pp, ", ");
127       v->print (pp);
128     }
129   pp_character (pp, ']');
130 }
131 
132 /* Append non-NULL value V to a json::array, taking ownership of V.  */
133 
134 void
135 array::append (value *v)
136 {
137   gcc_assert (v);
138   m_elements.safe_push (v);
139 }
140 
141 /* class json::number, a subclass of json::value, wrapping a double.  */
142 
143 /* Implementation of json::value::print for json::number.  */
144 
145 void
146 number::print (pretty_printer *pp) const
147 {
148   char tmp[1024];
149   snprintf (tmp, sizeof (tmp), "%g", m_value);
150   pp_string (pp, tmp);
151 }
152 
153 /* class json::string, a subclass of json::value.  */
154 
155 /* json::string's ctor.  */
156 
157 string::string (const char *utf8)
158 {
159   gcc_assert (utf8);
160   m_utf8 = xstrdup (utf8);
161 }
162 
163 /* Implementation of json::value::print for json::string.  */
164 
165 void
166 string::print (pretty_printer *pp) const
167 {
168   pp_character (pp, '"');
169   for (const char *ptr = m_utf8; *ptr; ptr++)
170     {
171       char ch = *ptr;
172       switch (ch)
173 	{
174 	case '"':
175 	  pp_string (pp, "\\\"");
176 	  break;
177 	case '\\':
178 	  pp_string (pp, "\\n");
179 	  break;
180 	case '\b':
181 	  pp_string (pp, "\\b");
182 	  break;
183 	case '\f':
184 	  pp_string (pp, "\\f");
185 	  break;
186 	case '\n':
187 	  pp_string (pp, "\\n");
188 	  break;
189 	case '\r':
190 	  pp_string (pp, "\\r");
191 	  break;
192 	case '\t':
193 	  pp_string (pp, "\\t");
194 	  break;
195 
196 	default:
197 	  pp_character (pp, ch);
198 	}
199     }
200   pp_character (pp, '"');
201 }
202 
203 /* class json::literal, a subclass of json::value.  */
204 
205 /* Implementation of json::value::print for json::literal.  */
206 
207 void
208 literal::print (pretty_printer *pp) const
209 {
210   switch (m_kind)
211     {
212     case JSON_TRUE:
213       pp_string (pp, "true");
214       break;
215     case JSON_FALSE:
216       pp_string (pp, "false");
217       break;
218     case JSON_NULL:
219       pp_string (pp, "null");
220       break;
221     default:
222       gcc_unreachable ();
223     }
224 }
225 
226 
227 #if CHECKING_P
228 
229 namespace selftest {
230 
231 /* Selftests.  */
232 
233 /* Verify that JV->print () prints EXPECTED_JSON.  */
234 
235 static void
236 assert_print_eq (const json::value &jv, const char *expected_json)
237 {
238   pretty_printer pp;
239   jv.print (&pp);
240   ASSERT_STREQ (expected_json, pp_formatted_text (&pp));
241 }
242 
243 /* Verify that JSON objects are written correctly.  We can't test more than
244    one key/value pair, as we don't impose a guaranteed ordering.  */
245 
246 static void
247 test_writing_objects ()
248 {
249   object obj;
250   obj.set ("foo", new json::string ("bar"));
251   assert_print_eq (obj, "{\"foo\": \"bar\"}");
252 }
253 
254 /* Verify that JSON arrays are written correctly.  */
255 
256 static void
257 test_writing_arrays ()
258 {
259   array arr;
260   assert_print_eq (arr, "[]");
261 
262   arr.append (new json::string ("foo"));
263   assert_print_eq (arr, "[\"foo\"]");
264 
265   arr.append (new json::string ("bar"));
266   assert_print_eq (arr, "[\"foo\", \"bar\"]");
267 }
268 
269 /* Verify that JSON numbers are written correctly.  */
270 
271 static void
272 test_writing_numbers ()
273 {
274   assert_print_eq (number (0), "0");
275   assert_print_eq (number (42), "42");
276   assert_print_eq (number (-100), "-100");
277 }
278 
279 /* Verify that JSON strings are written correctly.  */
280 
281 static void
282 test_writing_strings ()
283 {
284   string foo ("foo");
285   assert_print_eq (foo, "\"foo\"");
286 
287   string contains_quotes ("before \"quoted\" after");
288   assert_print_eq (contains_quotes, "\"before \\\"quoted\\\" after\"");
289 }
290 
291 /* Verify that JSON literals are written correctly.  */
292 
293 static void
294 test_writing_literals ()
295 {
296   assert_print_eq (literal (JSON_TRUE), "true");
297   assert_print_eq (literal (JSON_FALSE), "false");
298   assert_print_eq (literal (JSON_NULL), "null");
299 
300   assert_print_eq (literal (true), "true");
301   assert_print_eq (literal (false), "false");
302 }
303 
304 /* Run all of the selftests within this file.  */
305 
306 void
307 json_cc_tests ()
308 {
309   test_writing_objects ();
310   test_writing_arrays ();
311   test_writing_numbers ();
312   test_writing_strings ();
313   test_writing_literals ();
314 }
315 
316 } // namespace selftest
317 
318 #endif /* #if CHECKING_P */
319