]> git.ipfire.org Git - people/ms/gcc.git/blob - gcc/json.cc
c++: namespace-scoped friend in local class [PR69410]
[people/ms/gcc.git] / gcc / json.cc
1 /* JSON trees
2 Copyright (C) 2017-2023 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_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
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 *
110 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
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
137 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
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
165 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
177 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
189 string::string (const char *utf8)
190 {
191 gcc_assert (utf8);
192 m_utf8 = xstrdup (utf8);
193 m_len = strlen (utf8);
194 }
195
196 string::string (const char *utf8, size_t len)
197 {
198 gcc_assert (utf8);
199 m_utf8 = XNEWVEC (char, len);
200 m_len = len;
201 memcpy (m_utf8, utf8, len);
202 }
203
204 /* Implementation of json::value::print for json::string. */
205
206 void
207 string::print (pretty_printer *pp) const
208 {
209 pp_character (pp, '"');
210 for (size_t i = 0; i != m_len; ++i)
211 {
212 char ch = m_utf8[i];
213 switch (ch)
214 {
215 case '"':
216 pp_string (pp, "\\\"");
217 break;
218 case '\\':
219 pp_string (pp, "\\\\");
220 break;
221 case '\b':
222 pp_string (pp, "\\b");
223 break;
224 case '\f':
225 pp_string (pp, "\\f");
226 break;
227 case '\n':
228 pp_string (pp, "\\n");
229 break;
230 case '\r':
231 pp_string (pp, "\\r");
232 break;
233 case '\t':
234 pp_string (pp, "\\t");
235 break;
236 case '\0':
237 pp_string (pp, "\\0");
238 break;
239 default:
240 pp_character (pp, ch);
241 }
242 }
243 pp_character (pp, '"');
244 }
245
246 /* class json::literal, a subclass of json::value. */
247
248 /* Implementation of json::value::print for json::literal. */
249
250 void
251 literal::print (pretty_printer *pp) const
252 {
253 switch (m_kind)
254 {
255 case JSON_TRUE:
256 pp_string (pp, "true");
257 break;
258 case JSON_FALSE:
259 pp_string (pp, "false");
260 break;
261 case JSON_NULL:
262 pp_string (pp, "null");
263 break;
264 default:
265 gcc_unreachable ();
266 }
267 }
268
269 \f
270 #if CHECKING_P
271
272 namespace selftest {
273
274 /* Selftests. */
275
276 /* Verify that JV->print () prints EXPECTED_JSON. */
277
278 static void
279 assert_print_eq (const json::value &jv, const char *expected_json)
280 {
281 pretty_printer pp;
282 jv.print (&pp);
283 ASSERT_STREQ (expected_json, pp_formatted_text (&pp));
284 }
285
286 /* Verify that object::get works as expected. */
287
288 static void
289 test_object_get ()
290 {
291 object obj;
292 value *val = new json::string ("value");
293 obj.set ("foo", val);
294 ASSERT_EQ (obj.get ("foo"), val);
295 ASSERT_EQ (obj.get ("not-present"), NULL);
296 }
297
298 /* Verify that JSON objects are written correctly. We can't test more than
299 one key/value pair, as we don't impose a guaranteed ordering. */
300
301 static void
302 test_writing_objects ()
303 {
304 object obj;
305 obj.set ("foo", new json::string ("bar"));
306 assert_print_eq (obj, "{\"foo\": \"bar\"}");
307 }
308
309 /* Verify that JSON arrays are written correctly. */
310
311 static void
312 test_writing_arrays ()
313 {
314 array arr;
315 assert_print_eq (arr, "[]");
316
317 arr.append (new json::string ("foo"));
318 assert_print_eq (arr, "[\"foo\"]");
319
320 arr.append (new json::string ("bar"));
321 assert_print_eq (arr, "[\"foo\", \"bar\"]");
322 }
323
324 /* Verify that JSON numbers are written correctly. */
325
326 static void
327 test_writing_float_numbers ()
328 {
329 assert_print_eq (float_number (0), "0");
330 assert_print_eq (float_number (42), "42");
331 assert_print_eq (float_number (-100), "-100");
332 assert_print_eq (float_number (123456789), "1.23457e+08");
333 }
334
335 static void
336 test_writing_integer_numbers ()
337 {
338 assert_print_eq (integer_number (0), "0");
339 assert_print_eq (integer_number (42), "42");
340 assert_print_eq (integer_number (-100), "-100");
341 assert_print_eq (integer_number (123456789), "123456789");
342 assert_print_eq (integer_number (-123456789), "-123456789");
343 }
344
345 /* Verify that JSON strings are written correctly. */
346
347 static void
348 test_writing_strings ()
349 {
350 string foo ("foo");
351 assert_print_eq (foo, "\"foo\"");
352
353 string contains_quotes ("before \"quoted\" after");
354 assert_print_eq (contains_quotes, "\"before \\\"quoted\\\" after\"");
355
356 const char data[] = {'a', 'b', 'c', 'd', '\0', 'e', 'f'};
357 string not_terminated (data, 3);
358 assert_print_eq (not_terminated, "\"abc\"");
359 string embedded_null (data, sizeof data);
360 assert_print_eq (embedded_null, "\"abcd\\0ef\"");
361 }
362
363 /* Verify that JSON literals are written correctly. */
364
365 static void
366 test_writing_literals ()
367 {
368 assert_print_eq (literal (JSON_TRUE), "true");
369 assert_print_eq (literal (JSON_FALSE), "false");
370 assert_print_eq (literal (JSON_NULL), "null");
371
372 assert_print_eq (literal (true), "true");
373 assert_print_eq (literal (false), "false");
374 }
375
376 /* Run all of the selftests within this file. */
377
378 void
379 json_cc_tests ()
380 {
381 test_object_get ();
382 test_writing_objects ();
383 test_writing_arrays ();
384 test_writing_float_numbers ();
385 test_writing_integer_numbers ();
386 test_writing_strings ();
387 test_writing_literals ();
388 }
389
390 } // namespace selftest
391
392 #endif /* #if CHECKING_P */