|
1 /* |
|
2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. |
|
8 * |
|
9 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
12 * version 2 for more details (a copy is included in the LICENSE file that |
|
13 * accompanied this code). |
|
14 * |
|
15 * You should have received a copy of the GNU General Public License version |
|
16 * 2 along with this work; if not, write to the Free Software Foundation, |
|
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
18 * |
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
20 * or visit www.oracle.com if you need additional information or have any |
|
21 * questions. |
|
22 * |
|
23 */ |
|
24 |
|
25 /* |
|
26 * This is not really json in the state it is now. |
|
27 * Some differences: |
|
28 * - Double quotes around the key in an object is not enforced. |
|
29 * i.e you can write: { foo : "bar" } instead of { "foo" : "bar" }. |
|
30 * - Comments are allowed. |
|
31 * - The last element in an object or array can have an ending comma. |
|
32 */ |
|
33 |
|
34 #include "precompiled.hpp" |
|
35 #include "utilities/json.hpp" |
|
36 #include "utilities/ostream.hpp" |
|
37 #include <math.h> |
|
38 |
|
39 const char* strchrnul_(const char *s, int c) { |
|
40 const char* tmp = strchr(s, c); |
|
41 return tmp == NULL ? s + strlen(s) : tmp; |
|
42 } |
|
43 |
|
44 JSON::JSON(const char* text, bool silent, outputStream* st) |
|
45 : start(text), pos(text), mark(text), |
|
46 level(0), line(1), column(0), silent(silent), _valid(true), _st(st) |
|
47 { |
|
48 } |
|
49 |
|
50 void JSON::parse() { |
|
51 assert(start != NULL, "Need something to parse"); |
|
52 if (start == NULL) { |
|
53 _valid = false; |
|
54 error(INTERNAL_ERROR, "JSON parser was called with a string that was NULL."); |
|
55 } else { |
|
56 _valid = parse_json_value(); |
|
57 } |
|
58 } |
|
59 |
|
60 bool JSON::valid() { |
|
61 return _valid; |
|
62 } |
|
63 |
|
64 bool JSON::parse_json_value() { |
|
65 int c; |
|
66 |
|
67 c = skip_to_token(); |
|
68 if (c == -1) { |
|
69 return false; |
|
70 } |
|
71 |
|
72 // Must start with object or array |
|
73 if (level == 0) { |
|
74 |
|
75 switch (c) { |
|
76 case '{': |
|
77 if (parse_json_object() == false) { |
|
78 return false; |
|
79 } |
|
80 c = skip_to_token(); |
|
81 if (c > 0) { |
|
82 mark_pos(); |
|
83 error(SYNTAX_ERROR, "Only one top level object/array is allowed."); |
|
84 return false; |
|
85 } else if (c < 0) { |
|
86 return false; |
|
87 } |
|
88 return true; |
|
89 |
|
90 case '[': |
|
91 if (parse_json_array() == false) { |
|
92 return false; |
|
93 } |
|
94 c = skip_to_token(); |
|
95 if (c > 0) { |
|
96 mark_pos(); |
|
97 error(SYNTAX_ERROR, "Only one top level object/array is allowed."); |
|
98 return false; |
|
99 } else if (c < 0) { |
|
100 return false; |
|
101 } |
|
102 return true; |
|
103 |
|
104 case 0: |
|
105 error(SYNTAX_ERROR, "EOS was encountered before any json declarations"); |
|
106 return false; |
|
107 |
|
108 default: |
|
109 error(SYNTAX_ERROR, "Json must start with an object or an array."); |
|
110 return false; |
|
111 } |
|
112 } else { // level > 0 |
|
113 switch (c) { |
|
114 case '{': |
|
115 return parse_json_object(); |
|
116 |
|
117 case '[': |
|
118 return parse_json_array(); |
|
119 |
|
120 case '"': |
|
121 return parse_json_string(); |
|
122 |
|
123 case '-': case '0': |
|
124 case '1': case '2': case '3': |
|
125 case '4': case '5': case '6': |
|
126 case '7': case '8': case '9': |
|
127 return parse_json_number(); |
|
128 |
|
129 case 't': |
|
130 return parse_json_symbol("true", JSON_TRUE); |
|
131 |
|
132 case 'f': |
|
133 return parse_json_symbol("false", JSON_FALSE); |
|
134 |
|
135 case 'n': |
|
136 return parse_json_symbol("null", JSON_NULL); |
|
137 |
|
138 case 0: |
|
139 error(SYNTAX_ERROR, "EOS was encountered when expecting a json value."); |
|
140 return false; |
|
141 |
|
142 default: |
|
143 error(SYNTAX_ERROR, "Could not parse as a json value (did you forget to quote your strings?)."); |
|
144 return false; |
|
145 } |
|
146 } |
|
147 } |
|
148 |
|
149 // Should only be called when we actually have the start of an object |
|
150 // Otherwise it is an internal error |
|
151 bool JSON::parse_json_object() { |
|
152 NOT_PRODUCT(const char* prev_pos); |
|
153 int c; |
|
154 |
|
155 mark_pos(); |
|
156 // Check that we are not called in error |
|
157 if (expect_any("{", "object start", INTERNAL_ERROR) <= 0) { |
|
158 return false; |
|
159 } |
|
160 |
|
161 if (!callback(JSON_OBJECT_BEGIN, NULL, level++)) { |
|
162 return false; |
|
163 } |
|
164 |
|
165 for (;;) { |
|
166 mark_pos(); |
|
167 c = skip_to_token(); |
|
168 if (c == 0) { |
|
169 error(SYNTAX_ERROR, "EOS when expecting an object key or object end"); |
|
170 return false; |
|
171 } else if (c < 0) { |
|
172 return false; |
|
173 } else if (c == '}') { |
|
174 // We got here from either empty object "{}" or ending comma "{a:1,}" |
|
175 next(); |
|
176 break; |
|
177 } |
|
178 |
|
179 NOT_PRODUCT(prev_pos = pos); |
|
180 if (parse_json_key() == false) { |
|
181 return false; |
|
182 } |
|
183 assert(pos > prev_pos, "parsing stalled"); |
|
184 |
|
185 skip_to_token(); |
|
186 mark_pos(); |
|
187 if (expect_any(":", "object key-value separator") <= 0) { |
|
188 return false; |
|
189 } |
|
190 |
|
191 skip_to_token(); |
|
192 mark_pos(); |
|
193 NOT_PRODUCT(prev_pos = pos); |
|
194 if (parse_json_value() == false) { |
|
195 return false; |
|
196 } |
|
197 assert(pos > prev_pos, "parsing stalled"); |
|
198 |
|
199 c = skip_to_token(); |
|
200 mark_pos(); |
|
201 if (expect_any(",}", "value separator or object end") <= 0) { |
|
202 return false; |
|
203 } |
|
204 if (c == '}') { |
|
205 break; |
|
206 } |
|
207 } |
|
208 |
|
209 assert(c == '}', "array parsing ended without object end token ('}')"); |
|
210 return callback(JSON_OBJECT_END, NULL, --level); |
|
211 } |
|
212 |
|
213 // Should only be called when we actually have the start of an array |
|
214 // Otherwise it is an internal error |
|
215 bool JSON::parse_json_array() { |
|
216 NOT_PRODUCT(const char* prev_pos); |
|
217 int c; |
|
218 |
|
219 mark_pos(); |
|
220 // Check that we are not called in error |
|
221 if (expect_any("[", "array start character", INTERNAL_ERROR) <= 0) { |
|
222 return false; |
|
223 } |
|
224 |
|
225 if (!callback(JSON_ARRAY_BEGIN, NULL, level++)) { |
|
226 return false; |
|
227 } |
|
228 |
|
229 for (;;) { |
|
230 mark_pos(); |
|
231 c = skip_to_token(); |
|
232 if (c == 0) { |
|
233 error(SYNTAX_ERROR, "EOS when expecting a json value or array end"); |
|
234 return false; |
|
235 } else if (c < 0) { |
|
236 return false; |
|
237 } else if (c == ']') { |
|
238 // We got here from either empty array "[]" or ending comma "[1,]" |
|
239 next(); |
|
240 break; |
|
241 } |
|
242 |
|
243 mark_pos(); |
|
244 NOT_PRODUCT(prev_pos = pos); |
|
245 if (parse_json_value() == false) { |
|
246 return false; |
|
247 } |
|
248 assert(pos > prev_pos, "parsing stalled"); |
|
249 |
|
250 c = skip_to_token(); |
|
251 mark_pos(); |
|
252 if (expect_any(",]", "value separator or array end") <= 0) { |
|
253 return false; |
|
254 } |
|
255 if (c == ']') { |
|
256 break; |
|
257 } |
|
258 } |
|
259 |
|
260 assert(c == ']', "array parsing ended without array end token (']')"); |
|
261 return callback(JSON_ARRAY_END, NULL, --level); |
|
262 } |
|
263 |
|
264 bool JSON::parse_json_string(bool key) { |
|
265 const char* end; |
|
266 JSON_VAL v; |
|
267 |
|
268 mark_pos(); |
|
269 if (expect_any("\"", "string start character", INTERNAL_ERROR) <= 0) { |
|
270 return false; |
|
271 } |
|
272 |
|
273 end = strchr(pos, '"'); // TODO: escapes |
|
274 if (end == NULL) { |
|
275 error(SYNTAX_ERROR, "String started here never ended. Expected \'\"\' before EOS."); |
|
276 return false; |
|
277 } |
|
278 |
|
279 v.str.start = pos; |
|
280 v.str.length = end - pos; |
|
281 skip(end - pos); |
|
282 |
|
283 if (expect_any("\"", "string end character", INTERNAL_ERROR) <= 0) { |
|
284 return false; |
|
285 } |
|
286 |
|
287 if (key == true) { |
|
288 return callback(JSON_KEY, &v, level); |
|
289 } else { |
|
290 return callback(JSON_STRING, &v, level); |
|
291 } |
|
292 } |
|
293 |
|
294 // TODO: hotspot equivalents? |
|
295 static bool is_alpha(u_char c) { |
|
296 return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); |
|
297 } |
|
298 static bool is_numeric(u_char c) { |
|
299 return (c >= '0' && c <= '9'); |
|
300 } |
|
301 static bool is_alnum(u_char c) { |
|
302 return is_alpha(c) || is_numeric(c); |
|
303 } |
|
304 static bool is_word(u_char c) { |
|
305 return c == '_' || is_alnum(c); |
|
306 } |
|
307 |
|
308 // Allow object keys to be without quotation, |
|
309 // but then restrict to ([a-zA-Z0-9_])+ |
|
310 bool JSON::parse_json_key() { |
|
311 const char* begin; |
|
312 JSON_VAL v; |
|
313 u_char c; |
|
314 |
|
315 mark_pos(); |
|
316 c = peek(); |
|
317 if (c == '"') { |
|
318 return parse_json_string(true); |
|
319 } |
|
320 |
|
321 begin = pos; |
|
322 c = peek(); |
|
323 if (c == 0) { |
|
324 error(SYNTAX_ERROR, "Got EOS when expecting an object key."); |
|
325 return false; |
|
326 } else if (is_word(c) == false) { |
|
327 error(SYNTAX_ERROR, "Expected an object key, which can be a double-quoted (\") string or a simple string (only alphanumeric characters and underscore, separated by whitespace) that doesn't need to be quoted."); |
|
328 return false; |
|
329 } |
|
330 |
|
331 for (;;) { |
|
332 c = peek(); |
|
333 // Allow the key to be delimited by control characters and the object key-value separator ':' |
|
334 if (c <= ' ' || c == ':') { |
|
335 break; |
|
336 } else if (is_word(c) == false) { |
|
337 error(SYNTAX_ERROR, "Object key need to be quoted, or consist entirely of alphanumeric characters and underscores."); |
|
338 return false; |
|
339 } |
|
340 next(); |
|
341 } |
|
342 |
|
343 v.str.start = begin; |
|
344 v.str.length = pos - begin; |
|
345 return callback(JSON_KEY, &v, level); |
|
346 } |
|
347 |
|
348 bool JSON::parse_json_number() { |
|
349 double double_value; |
|
350 int tokens, read; |
|
351 JSON_VAL v; |
|
352 |
|
353 mark_pos(); |
|
354 |
|
355 // Parsing number - for simplicity ints are limited to 2**53 |
|
356 // sscanf as a double and check if part is 0. |
|
357 tokens = sscanf(pos, "%lf%n", &double_value, &read); |
|
358 assert(tokens <= 1, "scanf implementation that counts as a token, parsing json numbers will always fail"); |
|
359 if (tokens == 1) { |
|
360 assert(read > 0, "sanity"); |
|
361 |
|
362 if (floor(double_value) == double_value) { |
|
363 // No exponent - treat as an int |
|
364 v.int_value = (int)double_value; |
|
365 if (!callback(JSON_NUMBER_INT, &v, level)) { |
|
366 return false; |
|
367 } |
|
368 } else { |
|
369 v.double_value = double_value; |
|
370 if (!callback(JSON_NUMBER_FLOAT, &v, level)) { |
|
371 return false; |
|
372 } |
|
373 } |
|
374 skip(read); |
|
375 return true; |
|
376 } |
|
377 |
|
378 error(SYNTAX_ERROR, "Couldn't parse json number (note that exponents are not supported)."); |
|
379 return false; |
|
380 } |
|
381 |
|
382 bool JSON::parse_json_symbol(const char* name, JSON_TYPE symbol) { |
|
383 if (expect_string(name, "maybe you forgot to quote your strings?") == false) { |
|
384 mark_pos(); |
|
385 return false; |
|
386 } |
|
387 return callback(symbol, NULL, level); |
|
388 } |
|
389 |
|
390 void JSON::mark_pos() { |
|
391 assert((mark == start || *(mark - 1)) != 0, "buffer overrun"); |
|
392 assert(mark <= pos, "mark runahead"); |
|
393 |
|
394 u_char c; |
|
395 |
|
396 while (mark < pos) { |
|
397 c = *mark; |
|
398 assert(c != 0, "pos buffer overrun?"); |
|
399 if (c != 0) { |
|
400 mark++; |
|
401 column++; |
|
402 } |
|
403 if (c == '\n') { |
|
404 line++; |
|
405 column = 0; |
|
406 } |
|
407 } |
|
408 |
|
409 assert(mark <= pos, "mark runahead"); |
|
410 } |
|
411 |
|
412 u_char JSON::next() { |
|
413 assert((pos == start || *(pos - 1)) != 0, "buffer overrun"); |
|
414 |
|
415 u_char c = *pos; |
|
416 if (c != 0) { |
|
417 pos++; |
|
418 } |
|
419 return c; |
|
420 } |
|
421 |
|
422 u_char JSON::peek() { |
|
423 return *pos; |
|
424 } |
|
425 |
|
426 // Peek ahead i chars (0 is same as peek()) |
|
427 u_char JSON::peek(size_t i) { |
|
428 u_char c; |
|
429 const char* p; |
|
430 |
|
431 p = pos; |
|
432 c = *p; |
|
433 while (i > 0 && c != 0) { |
|
434 i--; |
|
435 p++; |
|
436 c = *p; |
|
437 } |
|
438 return c; |
|
439 } |
|
440 |
|
441 /* |
|
442 * Check that one of the expected characters is next in the stream. |
|
443 * If not, it is an error. |
|
444 * Returns 0 if EOS is encountered. |
|
445 * Returns -1 if the next character was not one of the expected. |
|
446 * Otherwise consumes and returns the expected character that was encountered. |
|
447 */ |
|
448 int JSON::expect_any(const char* valid_chars, const char* error_msg, JSON_ERROR e) { |
|
449 size_t len; |
|
450 u_char c; |
|
451 |
|
452 len = strlen(valid_chars); |
|
453 assert(len > 0, "need non-empty string"); |
|
454 |
|
455 c = peek(); |
|
456 if (c == 0) { |
|
457 error(e, "Got EOS when expecting %s (%s\'%s\').", error_msg, len > 1 ? "one of " : "", valid_chars); |
|
458 return 0; |
|
459 } |
|
460 for (size_t i = 0; i < len; i++) { |
|
461 if (c == valid_chars[i]) { |
|
462 return next(); |
|
463 } |
|
464 } |
|
465 error(e, "Expected %s (%s\'%s\').", error_msg, len > 1 ? "one of " : "", valid_chars); |
|
466 return -1; |
|
467 } |
|
468 |
|
469 /* |
|
470 * Check that the expected string is next in the stream. |
|
471 * If not, it is an error. |
|
472 * Consumes the expected characters if they are present. |
|
473 * Returns true if the expected characters were present, otherwise false. |
|
474 */ |
|
475 bool JSON::expect_string(const char* expected_string, const char* error_msg, JSON_ERROR e) { |
|
476 u_char c, expected_char; |
|
477 size_t len; |
|
478 |
|
479 assert(expected_string != NULL, "need non-null string"); |
|
480 len = strlen(expected_string); |
|
481 assert(len > 0, "need non-empty string"); |
|
482 |
|
483 for (size_t i = 0; i < len; i++) { |
|
484 expected_char = expected_string[i]; |
|
485 assert(expected_char > ' ', "not sane for control characters"); |
|
486 if (expected_char <= ' ') { |
|
487 error(INTERNAL_ERROR, "expect got a control char"); |
|
488 } |
|
489 c = pos[i]; |
|
490 if (c == 0) { |
|
491 error(e, "EOS encountered when expecting %s (\"%s\")", error_msg, expected_string); |
|
492 return false; |
|
493 } else if (c != expected_char) { |
|
494 error(e, "Expected \"%s\" (%s)", expected_string, error_msg); |
|
495 return false; |
|
496 } |
|
497 } |
|
498 skip(len); |
|
499 return true; |
|
500 } |
|
501 |
|
502 /* |
|
503 * Skip i characters. |
|
504 * Returns number of characters skipped. |
|
505 */ |
|
506 size_t JSON::skip(size_t i) { |
|
507 u_char c; |
|
508 size_t j; |
|
509 |
|
510 c = peek(); |
|
511 for (j = i; c != 0 && j > 0; j--) { |
|
512 c = next(); |
|
513 } |
|
514 return i - j; |
|
515 } |
|
516 |
|
517 /* |
|
518 * Skip whitespace and comments. |
|
519 * Returns the first token after whitespace/comments without consuming it |
|
520 * Returns 0 if EOS is encountered. |
|
521 * Returns -1 if there is an error |
|
522 */ |
|
523 int JSON::skip_to_token() { |
|
524 for (;;) { |
|
525 int c = peek(0); |
|
526 if (c == '/') { |
|
527 u_char c2 = peek(1); |
|
528 if (c2 == '/') { |
|
529 c = skip_line_comment(); |
|
530 } else if (c2 == '*') { |
|
531 c = skip_block_comment(); |
|
532 if (c < 0) { |
|
533 return -1; |
|
534 } |
|
535 } |
|
536 // Fall through to keep checking if there |
|
537 // are more whitespace / comments to skip |
|
538 } |
|
539 if (c == 0 || c > ' ') { |
|
540 return c; |
|
541 } |
|
542 next(); |
|
543 } |
|
544 return 0; |
|
545 } |
|
546 |
|
547 /* |
|
548 * Skip to, and return the wanted char without consuming it |
|
549 * Returns 0 if EOS is encountered. |
|
550 */ |
|
551 u_char JSON::skip_to(u_char want) { |
|
552 // We want the bookkeeping done in next(). |
|
553 // Otherwise strchr could have been used. |
|
554 u_char c; |
|
555 for(;;) { |
|
556 c = peek(); |
|
557 if (c == 0 || c == want) { |
|
558 return c; |
|
559 } |
|
560 next(); |
|
561 } |
|
562 } |
|
563 |
|
564 /* |
|
565 * Should only be called when we actually have a line comment to skip. |
|
566 * Otherwise it is an internal error. |
|
567 * |
|
568 * Will return the first token after the line comment without consuming it. |
|
569 * Returns 0 if EOS is encoutered. |
|
570 */ |
|
571 u_char JSON::skip_line_comment() { |
|
572 u_char c; |
|
573 |
|
574 // Check that we are not called in error |
|
575 expect_any("/", "line comment start", INTERNAL_ERROR); |
|
576 expect_any("/", "line comment start", INTERNAL_ERROR); |
|
577 |
|
578 c = skip_to('\n'); |
|
579 if (c == 0) { |
|
580 return 0; |
|
581 } |
|
582 next(); |
|
583 return next(); |
|
584 } |
|
585 |
|
586 /* |
|
587 * Should only be called when we actually have a block comment to skip. |
|
588 * Otherwise it is an internal error. |
|
589 * |
|
590 * Returns the first token after the block comment without consuming it. |
|
591 * Returns -1 if EOS is encountered in the middle of a comment. |
|
592 */ |
|
593 int JSON::skip_block_comment() { |
|
594 const char* current; |
|
595 |
|
596 // Check that we are not called in error. |
|
597 if (peek() != '/' || peek(1) != '*') { |
|
598 // Let expect handle EOS. |
|
599 expect_string("/*", "block comment start", INTERNAL_ERROR); |
|
600 return 0; |
|
601 } |
|
602 |
|
603 current = pos; |
|
604 for (;;) { |
|
605 current = strchrnul_(current, '*'); |
|
606 |
|
607 if (current[0] == 0 || current[1] == 0) { |
|
608 // Advance error marker to start of block comment |
|
609 mark_pos(); |
|
610 error(SYNTAX_ERROR, "Block comment started here never ended. Expected \"*/\" before EOS."); |
|
611 return -1; |
|
612 } |
|
613 |
|
614 if (current[1] == '/') { |
|
615 pos = current; |
|
616 if (expect_string("*/", "block comment end", INTERNAL_ERROR) == false) { |
|
617 return -1; |
|
618 } |
|
619 // Found block comment end |
|
620 return peek(); |
|
621 } |
|
622 current++; |
|
623 } |
|
624 } |
|
625 |
|
626 const char* JSON::strerror(JSON_ERROR e) { |
|
627 switch (e) { |
|
628 case SYNTAX_ERROR: |
|
629 return "Syntax error"; |
|
630 case INTERNAL_ERROR: |
|
631 return "Internal error"; |
|
632 case KEY_ERROR: |
|
633 return "Key error"; |
|
634 case VALUE_ERROR: |
|
635 return "Value error"; |
|
636 default: |
|
637 ShouldNotReachHere(); |
|
638 return "Unknown error"; |
|
639 } |
|
640 } |
|
641 |
|
642 void JSON::error(JSON_ERROR e, const char* format, ...) { |
|
643 _valid = false; |
|
644 |
|
645 if (!silent) { |
|
646 const char* line_start; |
|
647 const char* tmp; |
|
648 size_t line_length; |
|
649 va_list args; |
|
650 u_char c; |
|
651 |
|
652 _st->print("%s on line %u byte %u: ", JSON::strerror(e), line, column + 1); |
|
653 va_start(args, format); |
|
654 _st->vprint(format, args); |
|
655 _st->cr(); |
|
656 va_end(args); |
|
657 |
|
658 line_start = mark - column; |
|
659 assert(line_start >= start, "out of bounds"); |
|
660 assert(line_start <= mark, "out of bounds"); |
|
661 assert(line_start == start || line_start[-1] == '\n', "line counting error"); |
|
662 |
|
663 c = *pos; |
|
664 if (c == 0) { |
|
665 _st->print(" Got "); |
|
666 _st->print_cr("EOS."); |
|
667 } |
|
668 tmp = mark; |
|
669 c = *tmp; |
|
670 if (c > ' ') { |
|
671 _st->print(" At "); |
|
672 _st->print("'"); |
|
673 while (c > ' ') { |
|
674 _st->print("%c", c); |
|
675 tmp++; |
|
676 c = *tmp; |
|
677 } |
|
678 _st->print_cr("'."); |
|
679 } |
|
680 |
|
681 // Skip to newline or EOS |
|
682 tmp = strchrnul_(mark, '\n'); |
|
683 line_length = tmp - line_start; |
|
684 |
|
685 _st->print_cr("%s", line_start); |
|
686 } |
|
687 } |
|
688 |
|
689 #ifndef PRODUCT |
|
690 void JSONTest::test(const char* text, bool should_pass) { |
|
691 JSONTest json(text); |
|
692 if (should_pass) { |
|
693 assert(json.valid() == true, "failed on a valid json string"); |
|
694 if (VerboseInternalVMTests) { |
|
695 tty->print_cr("-- json test passed as expected --"); |
|
696 } |
|
697 } else { |
|
698 assert(json.valid() == false, "succeeded on an invalid json string"); |
|
699 if (VerboseInternalVMTests) { |
|
700 tty->print_cr("-- json test failed as expected --"); |
|
701 } |
|
702 } |
|
703 } |
|
704 |
|
705 JSONTest::JSONTest(const char* text) : JSON(text, !VerboseInternalVMTests, tty) { |
|
706 prev = JSON_NONE; |
|
707 parse(); |
|
708 } |
|
709 |
|
710 bool JSONTest::test() { |
|
711 JSONTest::test("{}", true); |
|
712 JSONTest::test("[]", true); |
|
713 JSONTest::test(" { } ", true); |
|
714 JSONTest::test(" [ ] ", true); |
|
715 |
|
716 JSONTest::test("\"error\"", false); |
|
717 JSONTest::test("error", false); |
|
718 JSONTest::test("1", false); |
|
719 JSONTest::test("1.2", false); |
|
720 JSONTest::test("true", false); |
|
721 JSONTest::test("false", false); |
|
722 JSONTest::test("null", false); |
|
723 |
|
724 JSONTest::test("[ 1 ]", true); |
|
725 JSONTest::test("[ 1, ]", true); |
|
726 JSONTest::test("[ true ]", true); |
|
727 JSONTest::test("[ true, ]", true); |
|
728 JSONTest::test("[ false ]", true); |
|
729 JSONTest::test("[ false, ]", true); |
|
730 JSONTest::test("[ null ]", true); |
|
731 JSONTest::test("[ null, ]", true); |
|
732 JSONTest::test("[ \"\" ]", true); |
|
733 JSONTest::test("[ \"\", ]", true); |
|
734 JSONTest::test("[ \"elem1\" ]", true); |
|
735 JSONTest::test("[ \"elem1\", ]", true); |
|
736 JSONTest::test("[ \"elem1\", ]", true); |
|
737 JSONTest::test("[ \"elem1\" ]", true); |
|
738 JSONTest::test("[ \"elem1\", \"elem2\" ]", true); |
|
739 JSONTest::test("[ \"elem1\", \"elem2\", ]", true); |
|
740 |
|
741 |
|
742 JSONTest::test("[ \"elem1\" ] { }", false); |
|
743 JSONTest::test("[ elem1, \"elem2\" ]", false); |
|
744 JSONTest::test("[ \"elem1\"", false); |
|
745 JSONTest::test("[ \"elem1 ]", false); |
|
746 JSONTest::test("[ \"elem1\", \"elem2\"", false); |
|
747 JSONTest::test("[ truefoo ]", false); |
|
748 JSONTest::test("[ falsefoo ]", false); |
|
749 JSONTest::test("[ nullfoo ]", false); |
|
750 |
|
751 JSONTest::test("{ key : 1 }", true); |
|
752 JSONTest::test("{ key : 1, }", true); |
|
753 JSONTest::test("{ key : 1.2 }", true); |
|
754 JSONTest::test("{ key : true }", true); |
|
755 JSONTest::test("{ key : true, }", true); |
|
756 JSONTest::test("{ key : false }", true); |
|
757 JSONTest::test("{ key : false, }", true); |
|
758 JSONTest::test("{ key : null }", true); |
|
759 JSONTest::test("{ key : null, }", true); |
|
760 JSONTest::test("{ \"\" : \"\" }", true); |
|
761 JSONTest::test("{ \"\" : \"\", }", true); |
|
762 JSONTest::test("{ \"key1\" : \"val1\" }", true); |
|
763 JSONTest::test("{ \"key1\" : \"val1\", }", true); |
|
764 JSONTest::test("{ \"key1\" : \"val1\", \"key2\" : \"val2\" }", true); |
|
765 JSONTest::test("{ \"key1\" : \"val1\", \"key2\" : \"val2\", }", true); |
|
766 |
|
767 JSONTest::test("{ \"key\" : \"val\" } [ \"error\" ]", false); |
|
768 JSONTest::test("{ \"key\" : \"val\" ", false); |
|
769 |
|
770 JSONTest::test("/**/ { }", true); |
|
771 JSONTest::test("/* */ { }", true); |
|
772 JSONTest::test("/*foo*/ { }", true); |
|
773 JSONTest::test("/* *foo */ { }", true); |
|
774 JSONTest::test("/* *foo* */ { }", true); |
|
775 JSONTest::test("/* /*foo */ { }", true); |
|
776 JSONTest::test("{ } /* foo */", true); |
|
777 JSONTest::test("{ } /* foo */ ", true); |
|
778 JSONTest::test("{ } //", true); |
|
779 JSONTest::test("{ } // ", true); |
|
780 JSONTest::test("{ } // foo", true); |
|
781 |
|
782 JSONTest::test("/* * / { }", false); |
|
783 JSONTest::test("/ * */ { }", false); |
|
784 JSONTest::test("// { }", false); |
|
785 JSONTest::test("/* { } */", false); |
|
786 JSONTest::test("/* { } */ ", false); |
|
787 JSONTest::test("/* { } ", false); |
|
788 JSONTest::test("{ } /* ", false); |
|
789 JSONTest::test("/* { } *", false); |
|
790 JSONTest::test("{ /* } */", false); |
|
791 JSONTest::test("[ /* ] */", false); |
|
792 JSONTest::test("{ key : \"val\", /* } */", false); |
|
793 JSONTest::test("[ \"val\", /* ] */", false); |
|
794 |
|
795 JSONTest::test("/* comment */{ key1 : { \"key2\" : { \"key3\" : [ \"elem1\", \"elem2\", { \"key4\" : null }, 3 , 2 , 1 , 0 , -1 , -2 , -3 , true, false, null, ] }, \"key5\" : true }, \"key6\" : [ \"☃\" ], key7 : \"val\",}", true); |
|
796 JSONTest::test("/* comment */ { \"key1\" : { \"key2\" : { \"key3\" : [ \"elem1\", \"elem2\", { \"key4\" : null }, 3 , 2 , 1 , 0 , -1 , -2 , -3 , true, false, null, ] }, \"key5\" : true }, \"key6\" : [ \"☃\" ], key7 : \"val\",}", true); |
|
797 JSONTest::test("/*comment*/{\"ff1 fsd\":{\"☃\":{\"☃\":[\"☃\",\"☃\"]},\"☃\":true},\"☃\":[\"☃\"],\"foo\":\"☃\",}", true); |
|
798 JSONTest::test("/* comment */ { key1 error : { \"☃\" : { \"☃\" : [ \"☃\", \"☃\" ] }, \"☃\" : true }, \"baz\" : [ \"☃\" ], foo : \"☃\",}", false); // first key needs to be quoted since it contains a space |
|
799 |
|
800 |
|
801 JSONTest::test("[\n]", true); |
|
802 |
|
803 JSONTest::test( |
|
804 "[" "\n" |
|
805 " {" |
|
806 " // pattern to match against class+method+signature" "\n" |
|
807 " // leading and trailing wildcard (*) allowed" "\n" |
|
808 " match: \"foo.bar.*\"," "\n" |
|
809 " " "\n" |
|
810 " // override defaults for specified compiler" "\n" |
|
811 " // we may differentiate between levels too. TBD." "\n" |
|
812 " c1: {" "\n" |
|
813 " //override c1 presets " "\n" |
|
814 " array_bounds_check_removal: false" "\n" |
|
815 " }," "\n" |
|
816 "" "\n" |
|
817 " c2: {" "\n" |
|
818 " // control inlining of method" "\n" |
|
819 " // + force inline, - dont inline" "\n" |
|
820 " inline : [ \"+java.util.*\", \"-com.sun.*\"]," "\n" |
|
821 " }," "\n" |
|
822 "" "\n" |
|
823 " // directives outside a specific preset applies to all compilers" "\n" |
|
824 " inline : [ \"+java.util.*\", \"-com.sun.*\"]," "\n" |
|
825 " print_assembly: true," "\n" |
|
826 " verify_oopmaps: true," "\n" |
|
827 " max_loop_unrolling: 5" "\n" |
|
828 " }," "\n" |
|
829 " {" "\n" |
|
830 " // matching several patterns require an array" "\n" |
|
831 " match: [\"baz.*\",\"frob*\"]," "\n" |
|
832 "" "\n" |
|
833 " // only enable c1 for this directive" "\n" |
|
834 " // all enabled by default. Command disables all not listed" "\n" |
|
835 " enable: \"c1\"," "\n" |
|
836 "" "\n" |
|
837 " // applies to all compilers" "\n" |
|
838 " // + force inline, - dont inline" "\n" |
|
839 " inline : [ \"+java.util.*\", \"-com.sun.*\"]," "\n" |
|
840 " print_inlining: true," "\n" |
|
841 "" "\n" |
|
842 " // force matching compiles to be blocking/syncronous" "\n" |
|
843 " blocking_compile: true" "\n" |
|
844 " }," "\n" |
|
845 "]" "\n", true); |
|
846 |
|
847 return true; |
|
848 } |
|
849 |
|
850 void JSONTest::log(uint indent, const char* format, ...) { |
|
851 if (VerboseInternalVMTests) { |
|
852 if (prev != JSON_KEY) { |
|
853 for (uint i = 0; i < indent; i++) { |
|
854 _st->print(" "); |
|
855 } |
|
856 } |
|
857 va_list args; |
|
858 va_start(args, format); |
|
859 _st->vprint(format, args); |
|
860 va_end(args); |
|
861 } |
|
862 } |
|
863 |
|
864 bool JSONTest::callback(JSON_TYPE t, JSON_VAL* v, uint rlevel) { |
|
865 switch (t) { |
|
866 case JSON_OBJECT_BEGIN: |
|
867 log(rlevel, "{\n"); |
|
868 prev = JSON_NONE; // Only care about JSON_KEY, to indent correctly |
|
869 return true; |
|
870 |
|
871 case JSON_OBJECT_END: |
|
872 log(rlevel, "},\n"); |
|
873 prev = JSON_NONE; |
|
874 return true; |
|
875 |
|
876 case JSON_ARRAY_BEGIN: |
|
877 log(rlevel, "[\n"); |
|
878 prev = JSON_NONE; |
|
879 return true; |
|
880 |
|
881 case JSON_ARRAY_END: |
|
882 log(rlevel, "],\n"); |
|
883 prev = JSON_NONE; |
|
884 return true; |
|
885 |
|
886 case JSON_KEY: |
|
887 if (VerboseInternalVMTests) { |
|
888 for (uint i = 0; i < rlevel; i++) { |
|
889 _st->print(" "); |
|
890 } |
|
891 _st->print("<key>"); |
|
892 for (size_t i = 0; i < v->str.length; i++) { |
|
893 u_char c = v->str.start[i]; |
|
894 assert(c != 0, "string overrun"); |
|
895 if (c == 0) { |
|
896 return false; |
|
897 } |
|
898 _st->print("%c", c); |
|
899 } |
|
900 _st->print(" : "); |
|
901 } |
|
902 prev = JSON_KEY; |
|
903 return true; |
|
904 |
|
905 case JSON_STRING: |
|
906 if (VerboseInternalVMTests) { |
|
907 if (prev != JSON_KEY) { |
|
908 for (uint i = 0; i < rlevel; i++) { |
|
909 _st->print(" "); |
|
910 } |
|
911 } |
|
912 _st->print("<str>"); |
|
913 for (size_t i = 0; i < v->str.length; i++) { |
|
914 u_char c = v->str.start[i]; |
|
915 assert(c != 0, "string overrun"); |
|
916 if (c == 0) { |
|
917 return false; |
|
918 } |
|
919 _st->print("%c", c); |
|
920 } |
|
921 _st->print(",\n"); |
|
922 } |
|
923 prev = JSON_NONE; |
|
924 return true; |
|
925 |
|
926 case JSON_NUMBER_INT: |
|
927 log(rlevel, "<int>%" PRId64 ",\n", v->int_value); |
|
928 prev = JSON_NONE; |
|
929 return true; |
|
930 |
|
931 case JSON_NUMBER_FLOAT: |
|
932 log(rlevel, "<double>%lf,\n", v->double_value); |
|
933 prev = JSON_NONE; |
|
934 return true; |
|
935 |
|
936 case JSON_TRUE: |
|
937 log(rlevel, "<true>,\n"); |
|
938 prev = JSON_NONE; |
|
939 return true; |
|
940 |
|
941 case JSON_FALSE: |
|
942 log(rlevel, "<false>,\n"); |
|
943 prev = JSON_NONE; |
|
944 return true; |
|
945 |
|
946 case JSON_NULL: |
|
947 log(rlevel, "<null>,\n"); |
|
948 prev = JSON_NONE; |
|
949 return true; |
|
950 |
|
951 default: |
|
952 error(INTERNAL_ERROR, "unknown JSON type"); |
|
953 return false; |
|
954 } |
|
955 } |
|
956 #endif |