]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/json.cc
* doc/extend.texi (Common Function Attributes): Clarify
[thirdparty/gcc.git] / gcc / json.cc
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 /* 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::number, a subclass of json::value, wrapping a double. */
158
159 /* Implementation of json::value::print for json::number. */
160
161 void
162 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::string, a subclass of json::value. */
170
171 /* json::string's ctor. */
172
173 string::string (const char *utf8)
174 {
175 gcc_assert (utf8);
176 m_utf8 = xstrdup (utf8);
177 }
178
179 /* Implementation of json::value::print for json::string. */
180
181 void
182 string::print (pretty_printer *pp) const
183 {
184 pp_character (pp, '"');
185 for (const char *ptr = m_utf8; *ptr; ptr++)
186 {
187 char ch = *ptr;
188 switch (ch)
189 {
190 case '"':
191 pp_string (pp, "\\\"");
192 break;
193 case '\\':
194 pp_string (pp, "\\n");
195 break;
196 case '\b':
197 pp_string (pp, "\\b");
198 break;
199 case '\f':
200 pp_string (pp, "\\f");
201 break;
202 case '\n':
203 pp_string (pp, "\\n");
204 break;
205 case '\r':
206 pp_string (pp, "\\r");
207 break;
208 case '\t':
209 pp_string (pp, "\\t");
210 break;
211
212 default:
213 pp_character (pp, ch);
214 }
215 }
216 pp_character (pp, '"');
217 }
218
219 /* class json::literal, a subclass of json::value. */
220
221 /* Implementation of json::value::print for json::literal. */
222
223 void
224 literal::print (pretty_printer *pp) const
225 {
226 switch (m_kind)
227 {
228 case JSON_TRUE:
229 pp_string (pp, "true");
230 break;
231 case JSON_FALSE:
232 pp_string (pp, "false");
233 break;
234 case JSON_NULL:
235 pp_string (pp, "null");
236 break;
237 default:
238 gcc_unreachable ();
239 }
240 }
241
242 \f
243 #if CHECKING_P
244
245 namespace selftest {
246
247 /* Selftests. */
248
249 /* Verify that JV->print () prints EXPECTED_JSON. */
250
251 static void
252 assert_print_eq (const json::value &jv, const char *expected_json)
253 {
254 pretty_printer pp;
255 jv.print (&pp);
256 ASSERT_STREQ (expected_json, pp_formatted_text (&pp));
257 }
258
259 /* Verify that object::get works as expected. */
260
261 static void
262 test_object_get ()
263 {
264 object obj;
265 value *val = new json::string ("value");
266 obj.set ("foo", val);
267 ASSERT_EQ (obj.get ("foo"), val);
268 ASSERT_EQ (obj.get ("not-present"), NULL);
269 }
270
271 /* Verify that JSON objects are written correctly. We can't test more than
272 one key/value pair, as we don't impose a guaranteed ordering. */
273
274 static void
275 test_writing_objects ()
276 {
277 object obj;
278 obj.set ("foo", new json::string ("bar"));
279 assert_print_eq (obj, "{\"foo\": \"bar\"}");
280 }
281
282 /* Verify that JSON arrays are written correctly. */
283
284 static void
285 test_writing_arrays ()
286 {
287 array arr;
288 assert_print_eq (arr, "[]");
289
290 arr.append (new json::string ("foo"));
291 assert_print_eq (arr, "[\"foo\"]");
292
293 arr.append (new json::string ("bar"));
294 assert_print_eq (arr, "[\"foo\", \"bar\"]");
295 }
296
297 /* Verify that JSON numbers are written correctly. */
298
299 static void
300 test_writing_numbers ()
301 {
302 assert_print_eq (number (0), "0");
303 assert_print_eq (number (42), "42");
304 assert_print_eq (number (-100), "-100");
305 }
306
307 /* Verify that JSON strings are written correctly. */
308
309 static void
310 test_writing_strings ()
311 {
312 string foo ("foo");
313 assert_print_eq (foo, "\"foo\"");
314
315 string contains_quotes ("before \"quoted\" after");
316 assert_print_eq (contains_quotes, "\"before \\\"quoted\\\" after\"");
317 }
318
319 /* Verify that JSON literals are written correctly. */
320
321 static void
322 test_writing_literals ()
323 {
324 assert_print_eq (literal (JSON_TRUE), "true");
325 assert_print_eq (literal (JSON_FALSE), "false");
326 assert_print_eq (literal (JSON_NULL), "null");
327
328 assert_print_eq (literal (true), "true");
329 assert_print_eq (literal (false), "false");
330 }
331
332 /* Run all of the selftests within this file. */
333
334 void
335 json_cc_tests ()
336 {
337 test_object_get ();
338 test_writing_objects ();
339 test_writing_arrays ();
340 test_writing_numbers ();
341 test_writing_strings ();
342 test_writing_literals ();
343 }
344
345 } // namespace selftest
346
347 #endif /* #if CHECKING_P */