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