1 /* JSON trees 2 Copyright (C) 2017-2022 Free Software Foundation, Inc. 3 Contributed by David Malcolm <dmalcolm (at) 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 } 194 195 /* Implementation of json::value::print for json::string. */ 196 197 void 198 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, "\\\\"); 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 240 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 261 262 namespace selftest { 263 264 /* Selftests. */ 265 266 /* Verify that JV->print () prints EXPECTED_JSON. */ 267 268 static void 269 assert_print_eq (const json::value &jv, const char *expected_json) 270 { 271 pretty_printer pp; 272 jv.print (&pp); 273 ASSERT_STREQ (expected_json, pp_formatted_text (&pp)); 274 } 275 276 /* Verify that object::get works as expected. */ 277 278 static void 279 test_object_get () 280 { 281 object obj; 282 value *val = new json::string ("value"); 283 obj.set ("foo", val); 284 ASSERT_EQ (obj.get ("foo"), val); 285 ASSERT_EQ (obj.get ("not-present"), NULL); 286 } 287 288 /* Verify that JSON objects are written correctly. We can't test more than 289 one key/value pair, as we don't impose a guaranteed ordering. */ 290 291 static void 292 test_writing_objects () 293 { 294 object obj; 295 obj.set ("foo", new json::string ("bar")); 296 assert_print_eq (obj, "{\"foo\": \"bar\"}"); 297 } 298 299 /* Verify that JSON arrays are written correctly. */ 300 301 static void 302 test_writing_arrays () 303 { 304 array arr; 305 assert_print_eq (arr, "[]"); 306 307 arr.append (new json::string ("foo")); 308 assert_print_eq (arr, "[\"foo\"]"); 309 310 arr.append (new json::string ("bar")); 311 assert_print_eq (arr, "[\"foo\", \"bar\"]"); 312 } 313 314 /* Verify that JSON numbers are written correctly. */ 315 316 static void 317 test_writing_float_numbers () 318 { 319 assert_print_eq (float_number (0), "0"); 320 assert_print_eq (float_number (42), "42"); 321 assert_print_eq (float_number (-100), "-100"); 322 assert_print_eq (float_number (123456789), "1.23457e+08"); 323 } 324 325 static void 326 test_writing_integer_numbers () 327 { 328 assert_print_eq (integer_number (0), "0"); 329 assert_print_eq (integer_number (42), "42"); 330 assert_print_eq (integer_number (-100), "-100"); 331 assert_print_eq (integer_number (123456789), "123456789"); 332 assert_print_eq (integer_number (-123456789), "-123456789"); 333 } 334 335 /* Verify that JSON strings are written correctly. */ 336 337 static void 338 test_writing_strings () 339 { 340 string foo ("foo"); 341 assert_print_eq (foo, "\"foo\""); 342 343 string contains_quotes ("before \"quoted\" after"); 344 assert_print_eq (contains_quotes, "\"before \\\"quoted\\\" after\""); 345 } 346 347 /* Verify that JSON literals are written correctly. */ 348 349 static void 350 test_writing_literals () 351 { 352 assert_print_eq (literal (JSON_TRUE), "true"); 353 assert_print_eq (literal (JSON_FALSE), "false"); 354 assert_print_eq (literal (JSON_NULL), "null"); 355 356 assert_print_eq (literal (true), "true"); 357 assert_print_eq (literal (false), "false"); 358 } 359 360 /* Run all of the selftests within this file. */ 361 362 void 363 json_cc_tests () 364 { 365 test_object_get (); 366 test_writing_objects (); 367 test_writing_arrays (); 368 test_writing_float_numbers (); 369 test_writing_integer_numbers (); 370 test_writing_strings (); 371 test_writing_literals (); 372 } 373 374 } // namespace selftest 375 376 #endif /* #if CHECKING_P */ 377