Line data Source code
1 : /* JSON parsing
2 : Copyright (C) 2017-2026 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 : #define INCLUDE_MAP
22 : #include "config.h"
23 : #include "system.h"
24 : #include "coretypes.h"
25 : #include "json-parsing.h"
26 : #include "pretty-print.h"
27 : #include "math.h"
28 : #include "selftest.h"
29 :
30 : using namespace json;
31 :
32 : /* Declarations relating to parsing JSON, all within an
33 : anonymous namespace. */
34 :
35 : namespace {
36 :
37 : /* A typedef representing a single unicode character. */
38 :
39 : typedef unsigned unichar;
40 :
41 : /* An enum for discriminating different kinds of JSON token. */
42 :
43 : enum token_id
44 : {
45 : TOK_ERROR,
46 :
47 : TOK_EOF,
48 :
49 : /* Punctuation. */
50 : TOK_OPEN_SQUARE,
51 : TOK_OPEN_CURLY,
52 : TOK_CLOSE_SQUARE,
53 : TOK_CLOSE_CURLY,
54 : TOK_COLON,
55 : TOK_COMMA,
56 :
57 : /* Literal names. */
58 : TOK_TRUE,
59 : TOK_FALSE,
60 : TOK_NULL,
61 :
62 : TOK_STRING,
63 : TOK_FLOAT_NUMBER,
64 : TOK_INTEGER_NUMBER
65 : };
66 :
67 : /* Human-readable descriptions of enum token_id. */
68 :
69 : static const char *token_id_name[] = {
70 : "error",
71 : "EOF",
72 : "'['",
73 : "'{'",
74 : "']'",
75 : "'}'",
76 : "':'",
77 : "','",
78 : "'true'",
79 : "'false'",
80 : "'null'",
81 : "string",
82 : "number",
83 : "number"
84 : };
85 :
86 : /* Tokens within the JSON lexer. */
87 :
88 : struct token
89 : {
90 : /* The kind of token. */
91 : enum token_id id;
92 :
93 : /* The location of this token within the unicode
94 : character stream. */
95 : location_map::range range;
96 :
97 : union
98 : {
99 : /* Value for TOK_ERROR and TOK_STRING. */
100 : char *string;
101 :
102 : /* Value for TOK_FLOAT_NUMBER. */
103 : double float_number;
104 :
105 : /* Value for TOK_INTEGER_NUMBER. */
106 : long integer_number;
107 : } u;
108 : };
109 :
110 : /* A class for lexing JSON. */
111 :
112 : class lexer
113 : {
114 : public:
115 : lexer (bool support_comments);
116 : ~lexer ();
117 :
118 : std::unique_ptr<error> add_utf8 (size_t length, const char *utf8_buf);
119 :
120 : const token *peek ();
121 :
122 : void consume ();
123 :
124 : private:
125 : bool get_char (unichar &out_char, location_map::point *out_point);
126 : void unget_char ();
127 : location_map::point get_next_point () const;
128 : static void dump_token (FILE *outf, const token *tok);
129 : void lex_token (token *out);
130 : void lex_string (token *out);
131 : void lex_number (token *out, unichar first_char);
132 : bool rest_of_literal (token *out, const char *suffix);
133 : std::unique_ptr<error> make_error (const char *msg);
134 : bool consume_single_line_comment (token *out);
135 : bool consume_multiline_comment (token *out);
136 :
137 : private:
138 : auto_vec<unichar> m_buffer;
139 : int m_next_char_idx;
140 : int m_next_char_line;
141 : int m_next_char_column;
142 : int m_prev_line_final_column; /* for handling unget_char after a '\n'. */
143 :
144 : static const int MAX_TOKENS = 1;
145 : token m_next_tokens[MAX_TOKENS];
146 : int m_num_next_tokens;
147 :
148 : bool m_support_comments;
149 : };
150 :
151 : /* A class for parsing JSON. */
152 :
153 : class parser
154 : {
155 : public:
156 : parser (location_map *out_loc_map,
157 : bool support_comments);
158 : ~parser ();
159 :
160 : std::unique_ptr<error>
161 : add_utf8 (size_t length, const char *utf8_buf);
162 :
163 : parser_result_t parse_value (int depth);
164 : parser_result_t parse_object (int depth);
165 : parser_result_t parse_array (int depth);
166 :
167 : std::unique_ptr<error>
168 : require_eof ();
169 :
170 : private:
171 : location_map::point get_next_token_start ();
172 : location_map::point get_next_token_end ();
173 :
174 : std::unique_ptr<error>
175 : require (enum token_id tok_id);
176 :
177 : result<enum token_id, std::unique_ptr<error>>
178 : require_one_of (enum token_id tok_id_a, enum token_id tok_id_b);
179 :
180 : std::unique_ptr<error>
181 : error_at (const location_map::range &r,
182 : const char *fmt, ...) ATTRIBUTE_PRINTF_3;
183 :
184 : void maybe_record_range (json::value *jv, const location_map::range &r);
185 : void maybe_record_range (json::value *jv,
186 : const location_map::point &start,
187 : const location_map::point &end);
188 :
189 : private:
190 : lexer m_lexer;
191 : location_map *m_loc_map;
192 : };
193 :
194 : } // anonymous namespace for parsing implementation
195 :
196 : /* Parser implementation. */
197 :
198 : /* lexer's ctor. */
199 :
200 116 : lexer::lexer (bool support_comments)
201 116 : : m_buffer (), m_next_char_idx (0),
202 116 : m_next_char_line (1), m_next_char_column (0),
203 116 : m_prev_line_final_column (-1),
204 116 : m_num_next_tokens (0),
205 116 : m_support_comments (support_comments)
206 : {
207 0 : }
208 :
209 : /* lexer's dtor. */
210 :
211 116 : lexer::~lexer ()
212 : {
213 136 : while (m_num_next_tokens > 0)
214 20 : consume ();
215 116 : }
216 :
217 : /* Peek the next token. */
218 :
219 : const token *
220 748 : lexer::peek ()
221 : {
222 748 : if (m_num_next_tokens == 0)
223 : {
224 536 : lex_token (&m_next_tokens[0]);
225 536 : m_num_next_tokens++;
226 : }
227 748 : return &m_next_tokens[0];
228 : }
229 :
230 : /* Consume the next token. */
231 :
232 : void
233 536 : lexer::consume ()
234 : {
235 536 : if (m_num_next_tokens == 0)
236 0 : peek ();
237 :
238 536 : gcc_assert (m_num_next_tokens > 0);
239 536 : gcc_assert (m_num_next_tokens <= MAX_TOKENS);
240 :
241 536 : if (0)
242 : {
243 : fprintf (stderr, "consuming token: ");
244 : dump_token (stderr, &m_next_tokens[0]);
245 : fprintf (stderr, "\n");
246 : }
247 :
248 536 : if (m_next_tokens[0].id == TOK_ERROR
249 536 : || m_next_tokens[0].id == TOK_STRING)
250 88 : free (m_next_tokens[0].u.string);
251 :
252 536 : m_num_next_tokens--;
253 536 : memmove (&m_next_tokens[0], &m_next_tokens[1],
254 536 : sizeof (token) * m_num_next_tokens);
255 536 : }
256 :
257 : /* Add LENGTH bytes of UTF-8 encoded text from UTF8_BUF to this lexer's
258 : buffer.
259 : Return null if successful, or the error if there was a problem. */
260 :
261 : std::unique_ptr<error>
262 116 : lexer::add_utf8 (size_t length, const char *utf8_buf)
263 : {
264 : /* Adapted from charset.c:one_utf8_to_cppchar. */
265 116 : static const uchar masks[6] = { 0x7F, 0x1F, 0x0F, 0x07, 0x03, 0x01 };
266 116 : static const uchar patns[6] = { 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
267 :
268 116 : const uchar *inbuf = (const unsigned char *) (utf8_buf);
269 116 : const uchar **inbufp = &inbuf;
270 116 : size_t *inbytesleftp = &length;
271 :
272 2860 : while (length > 0)
273 : {
274 2744 : unichar c;
275 2744 : const uchar *inbuf = *inbufp;
276 2744 : size_t nbytes, i;
277 :
278 2744 : c = *inbuf;
279 2744 : if (c < 0x80)
280 : {
281 2728 : m_buffer.safe_push (c);
282 2728 : *inbytesleftp -= 1;
283 2728 : *inbufp += 1;
284 2728 : continue;
285 : }
286 :
287 : /* The number of leading 1-bits in the first byte indicates how many
288 : bytes follow. */
289 32 : for (nbytes = 2; nbytes < 7; nbytes++)
290 32 : if ((c & ~masks[nbytes-1]) == patns[nbytes-1])
291 16 : goto found;
292 0 : return make_error ("ill-formed UTF-8 sequence");
293 16 : found:
294 :
295 16 : if (*inbytesleftp < nbytes)
296 0 : return make_error ("ill-formed UTF-8 sequence");
297 :
298 16 : c = (c & masks[nbytes-1]);
299 16 : inbuf++;
300 48 : for (i = 1; i < nbytes; i++)
301 : {
302 32 : unichar n = *inbuf++;
303 32 : if ((n & 0xC0) != 0x80)
304 0 : return make_error ("ill-formed UTF-8 sequence");
305 32 : c = ((c << 6) + (n & 0x3F));
306 : }
307 :
308 : /* Make sure the shortest possible encoding was used. */
309 16 : if (( c <= 0x7F && nbytes > 1)
310 16 : || (c <= 0x7FF && nbytes > 2)
311 16 : || (c <= 0xFFFF && nbytes > 3)
312 16 : || (c <= 0x1FFFFF && nbytes > 4)
313 16 : || (c <= 0x3FFFFFF && nbytes > 5))
314 0 : return make_error ("ill-formed UTF-8:"
315 0 : " shortest possible encoding not used");
316 :
317 : /* Make sure the character is valid. */
318 16 : if (c > 0x7FFFFFFF || (c >= 0xD800 && c <= 0xDFFF))
319 0 : return make_error ("ill-formed UTF-8: invalid character");
320 :
321 16 : m_buffer.safe_push (c);
322 16 : *inbufp = inbuf;
323 16 : *inbytesleftp -= nbytes;
324 : }
325 116 : return nullptr;
326 : }
327 :
328 : /* Attempt to get the next unicode character from this lexer's buffer.
329 : If successful, write it to OUT_CHAR, and its location to *OUT_POINT,
330 : and return true.
331 : Otherwise, return false. */
332 :
333 : bool
334 2672 : lexer::get_char (unichar &out_char, location_map::point *out_point)
335 : {
336 5340 : if (m_next_char_idx >= (int)m_buffer.length ())
337 : return false;
338 :
339 2540 : if (out_point)
340 2140 : *out_point = get_next_point ();
341 2540 : out_char = m_buffer[m_next_char_idx++];
342 :
343 2540 : if (out_char == '\n')
344 : {
345 92 : m_next_char_line++;
346 92 : m_prev_line_final_column = m_next_char_column;
347 92 : m_next_char_column = 0;
348 : }
349 : else
350 2448 : m_next_char_column++;
351 :
352 : return true;
353 : }
354 :
355 : /* Undo the last successful get_char. */
356 :
357 : void
358 392 : lexer::unget_char ()
359 : {
360 392 : --m_next_char_idx;
361 392 : if (m_next_char_column > 0)
362 364 : --m_next_char_column;
363 : else
364 : {
365 28 : m_next_char_line--;
366 28 : m_next_char_column = m_prev_line_final_column;
367 : /* We don't support more than one unget_char in a row. */
368 28 : gcc_assert (m_prev_line_final_column != -1);
369 28 : m_prev_line_final_column = -1;
370 : }
371 392 : }
372 :
373 : /* Get the location of the next char. */
374 :
375 : location_map::point
376 2228 : lexer::get_next_point () const
377 : {
378 2228 : location_map::point result;
379 2228 : result.m_unichar_idx = m_next_char_idx;
380 2228 : result.m_line = m_next_char_line;
381 2228 : result.m_column = m_next_char_column;
382 2140 : return result;
383 : }
384 :
385 : /* Print a textual representation of TOK to OUTF.
386 : This is intended for debugging the lexer and parser,
387 : rather than for user-facing output. */
388 :
389 : void
390 0 : lexer::dump_token (FILE *outf, const token *tok)
391 : {
392 0 : switch (tok->id)
393 : {
394 0 : case TOK_ERROR:
395 0 : fprintf (outf, "TOK_ERROR (\"%s\")", tok->u.string);
396 0 : break;
397 :
398 0 : case TOK_EOF:
399 0 : fprintf (outf, "TOK_EOF");
400 0 : break;
401 :
402 0 : case TOK_OPEN_SQUARE:
403 0 : fprintf (outf, "TOK_OPEN_SQUARE");
404 0 : break;
405 :
406 0 : case TOK_OPEN_CURLY:
407 0 : fprintf (outf, "TOK_OPEN_CURLY");
408 0 : break;
409 :
410 0 : case TOK_CLOSE_SQUARE:
411 0 : fprintf (outf, "TOK_CLOSE_SQUARE");
412 0 : break;
413 :
414 0 : case TOK_CLOSE_CURLY:
415 0 : fprintf (outf, "TOK_CLOSE_CURLY");
416 0 : break;
417 :
418 0 : case TOK_COLON:
419 0 : fprintf (outf, "TOK_COLON");
420 0 : break;
421 :
422 0 : case TOK_COMMA:
423 0 : fprintf (outf, "TOK_COMMA");
424 0 : break;
425 :
426 0 : case TOK_TRUE:
427 0 : fprintf (outf, "TOK_TRUE");
428 0 : break;
429 :
430 0 : case TOK_FALSE:
431 0 : fprintf (outf, "TOK_FALSE");
432 0 : break;
433 :
434 0 : case TOK_NULL:
435 0 : fprintf (outf, "TOK_NULL");
436 0 : break;
437 :
438 0 : case TOK_STRING:
439 0 : fprintf (outf, "TOK_STRING (\"%s\")", tok->u.string);
440 0 : break;
441 :
442 0 : case TOK_FLOAT_NUMBER:
443 0 : fprintf (outf, "TOK_FLOAT_NUMBER (%f)", tok->u.float_number);
444 0 : break;
445 :
446 0 : case TOK_INTEGER_NUMBER:
447 0 : fprintf (outf, "TOK_INTEGER_NUMBER (%ld)", tok->u.integer_number);
448 0 : break;
449 :
450 0 : default:
451 0 : gcc_unreachable ();
452 0 : break;
453 : }
454 0 : }
455 :
456 : /* Treat "//" as a comment to the end of the line.
457 :
458 : This isn't compliant with the JSON spec,
459 : but is very handy for writing DejaGnu tests.
460 :
461 : Return true if EOF and populate *OUT, false otherwise. */
462 :
463 : bool
464 16 : lexer::consume_single_line_comment (token *out)
465 : {
466 208 : while (1)
467 : {
468 112 : unichar next_char;
469 112 : if (!get_char (next_char, nullptr))
470 : {
471 0 : out->id = TOK_EOF;
472 0 : location_map::point p = get_next_point ();
473 0 : out->range.m_start = p;
474 0 : out->range.m_end = p;
475 0 : return true;
476 : }
477 112 : if (next_char == '\n')
478 : return false;
479 96 : }
480 : }
481 :
482 : /* Treat '/' '*' as a multiline comment until the next closing '*' '/'.
483 :
484 : This isn't compliant with the JSON spec,
485 : but is very handy for writing DejaGnu tests.
486 :
487 : Return true if EOF and populate *OUT, false otherwise. */
488 :
489 : bool
490 12 : lexer::consume_multiline_comment (token *out)
491 : {
492 276 : while (1)
493 : {
494 276 : unichar next_char;
495 276 : if (!get_char (next_char, nullptr))
496 : {
497 0 : out->id = TOK_ERROR;
498 0 : gcc_unreachable (); // TODO
499 : location_map::point p = get_next_point ();
500 : out->range.m_start = p;
501 : out->range.m_end = p;
502 : return true;
503 : }
504 276 : if (next_char != '*')
505 264 : continue;
506 12 : if (!get_char (next_char, nullptr))
507 : {
508 0 : out->id = TOK_ERROR;
509 0 : gcc_unreachable (); // TODO
510 : location_map::point p = get_next_point ();
511 : out->range.m_start = p;
512 : out->range.m_end = p;
513 : return true;
514 : }
515 12 : if (next_char == '/')
516 12 : return false;
517 : }
518 : }
519 :
520 : /* Attempt to lex the input buffer, writing the next token to OUT.
521 : On errors, TOK_ERROR (or TOK_EOF) is written to OUT. */
522 :
523 : void
524 536 : lexer::lex_token (token *out)
525 : {
526 : /* Skip to next non-whitespace char. */
527 1084 : unichar next_char;
528 1084 : location_map::point start_point;
529 1084 : while (1)
530 : {
531 1084 : if (!get_char (next_char, &start_point))
532 : {
533 88 : out->id = TOK_EOF;
534 88 : location_map::point p = get_next_point ();
535 88 : out->range.m_start = p;
536 88 : out->range.m_end = p;
537 88 : return;
538 : }
539 996 : if (m_support_comments)
540 160 : if (next_char == '/')
541 : {
542 28 : location_map::point point;
543 28 : unichar next_next_char;
544 28 : if (get_char (next_next_char, &point))
545 : {
546 28 : switch (next_next_char)
547 : {
548 16 : case '/':
549 16 : if (consume_single_line_comment (out))
550 0 : return;
551 28 : continue;
552 12 : case '*':
553 12 : if (consume_multiline_comment (out))
554 : return;
555 12 : continue;
556 0 : default:
557 : /* A stray single '/'. Break out of loop, so that we
558 : handle it below as an unexpected character. */
559 0 : goto non_whitespace;
560 : }
561 : }
562 : }
563 968 : if (next_char != ' '
564 968 : && next_char != '\t'
565 484 : && next_char != '\n'
566 448 : && next_char != '\r')
567 : break;
568 : }
569 :
570 448 : non_whitespace:
571 :
572 448 : out->range.m_start = start_point;
573 448 : out->range.m_end = start_point;
574 :
575 448 : switch (next_char)
576 : {
577 20 : case '[':
578 20 : out->id = TOK_OPEN_SQUARE;
579 20 : break;
580 :
581 24 : case '{':
582 24 : out->id = TOK_OPEN_CURLY;
583 24 : break;
584 :
585 16 : case ']':
586 16 : out->id = TOK_CLOSE_SQUARE;
587 16 : break;
588 :
589 20 : case '}':
590 20 : out->id = TOK_CLOSE_CURLY;
591 20 : break;
592 :
593 36 : case ':':
594 36 : out->id = TOK_COLON;
595 36 : break;
596 :
597 68 : case ',':
598 68 : out->id = TOK_COMMA;
599 68 : break;
600 :
601 72 : case '"':
602 72 : lex_string (out);
603 72 : break;
604 :
605 148 : case '-':
606 148 : case '0':
607 148 : case '1':
608 148 : case '2':
609 148 : case '3':
610 148 : case '4':
611 148 : case '5':
612 148 : case '6':
613 148 : case '7':
614 148 : case '8':
615 148 : case '9':
616 148 : lex_number (out, next_char);
617 148 : break;
618 :
619 8 : case 't':
620 : /* Handle literal "true". */
621 8 : if (rest_of_literal (out, "rue"))
622 : {
623 8 : out->id = TOK_TRUE;
624 8 : break;
625 : }
626 : else
627 0 : goto err;
628 :
629 8 : case 'f':
630 : /* Handle literal "false". */
631 8 : if (rest_of_literal (out, "alse"))
632 : {
633 8 : out->id = TOK_FALSE;
634 8 : break;
635 : }
636 : else
637 0 : goto err;
638 :
639 16 : case 'n':
640 : /* Handle literal "null". */
641 16 : if (rest_of_literal (out, "ull"))
642 : {
643 12 : out->id = TOK_NULL;
644 12 : break;
645 : }
646 : else
647 4 : goto err;
648 :
649 16 : err:
650 16 : default:
651 16 : out->id = TOK_ERROR;
652 16 : out->u.string = xasprintf ("unexpected character: '%c'", next_char);
653 16 : break;
654 : }
655 : }
656 :
657 : /* Having consumed an open-quote character from the lexer's buffer, attempt
658 : to lex the rest of a JSON string, writing the result to OUT (or TOK_ERROR)
659 : if an error occurred.
660 : (ECMA-404 section 9; RFC 7159 section 7). */
661 :
662 : void
663 72 : lexer::lex_string (token *out)
664 : {
665 72 : auto_vec<unichar> content;
666 72 : bool still_going = true;
667 496 : while (still_going)
668 : {
669 424 : unichar uc;
670 424 : if (!get_char (uc, &out->range.m_end))
671 : {
672 0 : out->id = TOK_ERROR;
673 0 : out->range.m_end = get_next_point ();
674 0 : out->u.string = xstrdup ("EOF within string");
675 0 : return;
676 : }
677 424 : switch (uc)
678 : {
679 : case '"':
680 : still_going = false;
681 : break;
682 24 : case '\\':
683 24 : {
684 24 : unichar next_char;
685 24 : if (!get_char (next_char, &out->range.m_end))
686 : {
687 0 : out->id = TOK_ERROR;
688 0 : out->range.m_end = get_next_point ();
689 0 : out->u.string = xstrdup ("EOF within string");;
690 0 : return;
691 : }
692 24 : switch (next_char)
693 : {
694 8 : case '"':
695 8 : case '\\':
696 8 : case '/':
697 8 : content.safe_push (next_char);
698 8 : break;
699 :
700 0 : case 'b':
701 0 : content.safe_push ('\b');
702 0 : break;
703 :
704 0 : case 'f':
705 0 : content.safe_push ('\f');
706 0 : break;
707 :
708 0 : case 'n':
709 0 : content.safe_push ('\n');
710 0 : break;
711 :
712 0 : case 'r':
713 0 : content.safe_push ('\r');
714 0 : break;
715 :
716 0 : case 't':
717 0 : content.safe_push ('\t');
718 0 : break;
719 :
720 16 : case 'u':
721 16 : {
722 16 : unichar result = 0;
723 80 : for (int i = 0; i < 4; i++)
724 : {
725 64 : unichar hexdigit;
726 64 : if (!get_char (hexdigit, &out->range.m_end))
727 : {
728 0 : out->id = TOK_ERROR;
729 0 : out->range.m_end = get_next_point ();
730 0 : out->u.string = xstrdup ("EOF within string");
731 0 : return;
732 : }
733 64 : result <<= 4;
734 64 : if (hexdigit >= '0' && hexdigit <= '9')
735 60 : result += hexdigit - '0';
736 4 : else if (hexdigit >= 'a' && hexdigit <= 'f')
737 4 : result += (hexdigit - 'a') + 10;
738 0 : else if (hexdigit >= 'A' && hexdigit <= 'F')
739 0 : result += (hexdigit - 'A') + 10;
740 : else
741 : {
742 0 : out->id = TOK_ERROR;
743 0 : out->range.m_start = out->range.m_end;
744 0 : out->u.string = xstrdup ("bogus hex char");
745 0 : return;
746 : }
747 : }
748 16 : content.safe_push (result);
749 : }
750 16 : break;
751 :
752 0 : default:
753 0 : out->id = TOK_ERROR;
754 0 : out->u.string = xstrdup ("unrecognized escape char");
755 0 : return;
756 : }
757 : }
758 24 : break;
759 :
760 328 : default:
761 : /* Reject unescaped control characters U+0000 through U+001F
762 : (ECMA-404 section 9 para 1; RFC 7159 section 7 para 1). */
763 328 : if (uc <= 0x1f)
764 : {
765 0 : out->id = TOK_ERROR;
766 0 : out->range.m_start = out->range.m_end;
767 0 : out->u.string = xstrdup ("unescaped control char");
768 0 : return;
769 : }
770 :
771 : /* Otherwise, add regular unicode code point. */
772 328 : content.safe_push (uc);
773 328 : break;
774 : }
775 : }
776 :
777 72 : out->id = TOK_STRING;
778 :
779 144 : auto_vec<char> utf8_buf;
780 : // Adapted from libcpp/charset.c:one_cppchar_to_utf8
781 424 : for (unsigned i = 0; i < content.length (); i++)
782 : {
783 352 : static const uchar masks[6] = { 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
784 352 : static const uchar limits[6] = { 0x80, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE };
785 352 : size_t nbytes;
786 352 : uchar buf[6], *p = &buf[6];
787 352 : unichar c = content[i];
788 :
789 352 : nbytes = 1;
790 352 : if (c < 0x80)
791 320 : *--p = c;
792 : else
793 : {
794 64 : do
795 : {
796 64 : *--p = ((c & 0x3F) | 0x80);
797 64 : c >>= 6;
798 64 : nbytes++;
799 : }
800 64 : while (c >= 0x3F || (c & limits[nbytes-1]));
801 32 : *--p = (c | masks[nbytes-1]);
802 : }
803 :
804 768 : while (p < &buf[6])
805 416 : utf8_buf.safe_push (*p++);
806 : }
807 :
808 144 : out->u.string = XNEWVEC (char, utf8_buf.length () + 1);
809 488 : for (unsigned i = 0; i < utf8_buf.length (); i++)
810 416 : out->u.string[i] = utf8_buf[i];
811 144 : out->u.string[utf8_buf.length ()] = '\0';
812 72 : }
813 :
814 : /* Having consumed FIRST_CHAR, an initial digit or '-' character from
815 : the lexer's buffer attempt to lex the rest of a JSON number, writing
816 : the result to OUT (or TOK_ERROR) if an error occurred.
817 : (ECMA-404 section 8; RFC 7159 section 6). */
818 :
819 : void
820 148 : lexer::lex_number (token *out, unichar first_char)
821 : {
822 148 : bool negate = false;
823 148 : double value = 0.0;
824 148 : if (first_char == '-')
825 : {
826 12 : negate = true;
827 12 : if (!get_char (first_char, &out->range.m_end))
828 : {
829 0 : out->id = TOK_ERROR;
830 0 : out->range.m_start = out->range.m_end;
831 0 : out->u.string = xstrdup ("expected digit");
832 0 : return;
833 : }
834 : }
835 :
836 148 : if (first_char == '0')
837 : value = 0.0;
838 140 : else if (!ISDIGIT (first_char))
839 : {
840 0 : out->id = TOK_ERROR;
841 0 : out->range.m_start = out->range.m_end;
842 0 : out->u.string = xstrdup ("expected digit");
843 0 : return;
844 : }
845 : else
846 : {
847 : /* Got a nonzero digit; expect zero or more digits. */
848 140 : value = first_char - '0';
849 372 : while (1)
850 : {
851 256 : unichar uc;
852 256 : location_map::point point;
853 256 : if (!get_char (uc, &point))
854 : break;
855 248 : if (ISDIGIT (uc))
856 : {
857 116 : value *= 10;
858 116 : value += uc -'0';
859 116 : out->range.m_end = point;
860 116 : continue;
861 : }
862 : else
863 : {
864 132 : unget_char ();
865 132 : break;
866 : }
867 : }
868 : }
869 :
870 : /* Optional '.', followed by one or more decimals. */
871 148 : unichar next_char;
872 148 : location_map::point point;
873 148 : if (get_char (next_char, &point))
874 : {
875 140 : if (next_char == '.')
876 : {
877 : /* Parse decimal digits. */
878 : bool had_digit = false;
879 : double digit_factor = 0.1;
880 44 : while (get_char (next_char, &point))
881 : {
882 40 : if (!ISDIGIT (next_char))
883 : {
884 8 : unget_char ();
885 8 : break;
886 : }
887 32 : value += (next_char - '0') * digit_factor;
888 32 : digit_factor *= 0.1;
889 32 : had_digit = true;
890 32 : out->range.m_end = point;
891 : }
892 12 : if (!had_digit)
893 : {
894 0 : out->id = TOK_ERROR;
895 0 : out->range.m_start = point;
896 0 : out->range.m_start = point;
897 0 : out->u.string = xstrdup ("expected digit");
898 0 : return;
899 : }
900 : }
901 : else
902 128 : unget_char ();
903 : }
904 :
905 : /* Parse 'e' and 'E'. */
906 148 : unichar exponent_char;
907 148 : if (get_char (exponent_char, &point))
908 : {
909 136 : if (exponent_char == 'e' || exponent_char == 'E')
910 : {
911 : /* Optional +/-. */
912 16 : unichar sign_char;
913 16 : int exponent = 0;
914 16 : bool negate_exponent = false;
915 16 : bool had_exponent_digit = false;
916 16 : if (!get_char (sign_char, &point))
917 : {
918 0 : out->id = TOK_ERROR;
919 0 : out->range.m_start = point;
920 0 : out->range.m_start = point;
921 0 : out->u.string = xstrdup ("EOF within exponent");
922 0 : return;
923 : }
924 16 : if (sign_char == '-')
925 : negate_exponent = true;
926 12 : else if (sign_char == '+')
927 : ;
928 8 : else if (ISDIGIT (sign_char))
929 : {
930 8 : exponent = sign_char - '0';
931 8 : had_exponent_digit = true;
932 : }
933 : else
934 : {
935 0 : out->id = TOK_ERROR;
936 0 : out->range.m_start = point;
937 0 : out->range.m_start = point;
938 0 : out->u.string
939 0 : = xstrdup ("expected '-','+' or digit within exponent");
940 0 : return;
941 : }
942 16 : out->range.m_end = point;
943 :
944 : /* One or more digits (we might have seen the digit above,
945 : though). */
946 32 : while (1)
947 : {
948 24 : unichar uc;
949 24 : location_map::point point;
950 24 : if (!get_char (uc, &point))
951 : break;
952 12 : if (ISDIGIT (uc))
953 : {
954 8 : exponent *= 10;
955 8 : exponent += uc -'0';
956 8 : had_exponent_digit = true;
957 8 : out->range.m_end = point;
958 8 : continue;
959 : }
960 : else
961 : {
962 4 : unget_char ();
963 4 : break;
964 : }
965 : }
966 16 : if (!had_exponent_digit)
967 : {
968 0 : out->id = TOK_ERROR;
969 0 : out->range.m_start = point;
970 0 : out->range.m_start = point;
971 0 : out->u.string = xstrdup ("expected digit within exponent");
972 0 : return;
973 : }
974 16 : if (negate_exponent)
975 4 : exponent = -exponent;
976 16 : value = value * pow (10, exponent);
977 : }
978 : else
979 120 : unget_char ();
980 : }
981 :
982 148 : if (negate)
983 12 : value = -value;
984 :
985 148 : if (value == (long)value)
986 : {
987 132 : out->id = TOK_INTEGER_NUMBER;
988 132 : out->u.integer_number = value;
989 : }
990 : else
991 : {
992 16 : out->id = TOK_FLOAT_NUMBER;
993 16 : out->u.float_number = value;
994 : }
995 : }
996 :
997 : /* Determine if the next characters to be lexed match SUFFIX.
998 : SUFFIX must be pure ASCII and not contain newlines.
999 : If so, consume the characters and return true.
1000 : Otherwise, return false. */
1001 :
1002 : bool
1003 32 : lexer::rest_of_literal (token *out, const char *suffix)
1004 : {
1005 32 : int suffix_idx = 0;
1006 32 : int buf_idx = m_next_char_idx;
1007 216 : while (1)
1008 : {
1009 124 : if (suffix[suffix_idx] == '\0')
1010 : {
1011 28 : m_next_char_idx += suffix_idx;
1012 28 : m_next_char_column += suffix_idx;
1013 28 : out->range.m_end.m_unichar_idx += suffix_idx;
1014 28 : out->range.m_end.m_column += suffix_idx;
1015 28 : return true;
1016 : }
1017 192 : if (buf_idx >= (int)m_buffer.length ())
1018 : return false;
1019 : /* This assumes that suffix is ASCII. */
1020 96 : if (m_buffer[buf_idx] != (unichar)suffix[suffix_idx])
1021 : return false;
1022 92 : buf_idx++;
1023 92 : suffix_idx++;
1024 : }
1025 : }
1026 :
1027 : /* Create a new error instance for MSG, using the location of the next
1028 : character for the location of the error. */
1029 :
1030 : std::unique_ptr<error>
1031 0 : lexer::make_error (const char *msg)
1032 : {
1033 0 : location_map::point p;
1034 0 : p.m_unichar_idx = m_next_char_idx;
1035 0 : p.m_line = m_next_char_line;
1036 0 : p.m_column = m_next_char_column;
1037 0 : location_map::range r;
1038 0 : r.m_start = p;
1039 0 : r.m_end = p;
1040 0 : return std::make_unique<error> (r, xstrdup (msg));
1041 : }
1042 :
1043 : /* parser's ctor. */
1044 :
1045 96 : parser::parser (location_map *out_loc_map,
1046 96 : bool support_comments)
1047 96 : : m_lexer (support_comments), m_loc_map (out_loc_map)
1048 : {
1049 0 : }
1050 :
1051 : /* parser's dtor. */
1052 :
1053 96 : parser::~parser ()
1054 : {
1055 96 : if (m_loc_map)
1056 96 : m_loc_map->on_finished_parsing ();
1057 96 : }
1058 :
1059 : /* Add LENGTH bytes of UTF-8 encoded text from UTF8_BUF to this parser's
1060 : lexer's buffer. */
1061 :
1062 : std::unique_ptr<error>
1063 96 : parser::add_utf8 (size_t length, const char *utf8_buf)
1064 : {
1065 0 : return m_lexer.add_utf8 (length, utf8_buf);
1066 : }
1067 :
1068 : /* Parse a JSON value (object, array, number, string, or literal).
1069 : (ECMA-404 section 5; RFC 7159 section 3). */
1070 :
1071 : parser_result_t
1072 196 : parser::parse_value (int depth)
1073 : {
1074 196 : const token *tok = m_lexer.peek ();
1075 :
1076 : /* Avoid stack overflow with deeply-nested inputs; RFC 7159 section 9
1077 : states: "An implementation may set limits on the maximum depth
1078 : of nesting.".
1079 :
1080 : Ideally we'd avoid this limit (e.g. by rewriting parse_value,
1081 : parse_object, and parse_array into a single function with a vec of
1082 : state). */
1083 196 : const int MAX_DEPTH = 100;
1084 196 : if (depth >= MAX_DEPTH)
1085 0 : return error_at (tok->range, "maximum nesting depth exceeded: %i",
1086 0 : MAX_DEPTH);
1087 :
1088 196 : switch (tok->id)
1089 : {
1090 20 : case TOK_OPEN_CURLY:
1091 20 : return parse_object (depth);
1092 :
1093 28 : case TOK_STRING:
1094 28 : {
1095 28 : auto val = std::make_unique<string> (tok->u.string);
1096 28 : m_lexer.consume ();
1097 28 : maybe_record_range (val.get (), tok->range);
1098 28 : return parser_result_t (std::move (val));
1099 28 : }
1100 :
1101 16 : case TOK_OPEN_SQUARE:
1102 16 : return parse_array (depth);
1103 :
1104 12 : case TOK_FLOAT_NUMBER:
1105 12 : {
1106 12 : auto val = std::make_unique<float_number> (tok->u.float_number);
1107 12 : m_lexer.consume ();
1108 12 : maybe_record_range (val.get (), tok->range);
1109 12 : return parser_result_t (std::move (val));
1110 12 : }
1111 :
1112 92 : case TOK_INTEGER_NUMBER:
1113 92 : {
1114 92 : auto val = std::make_unique<integer_number> (tok->u.integer_number);
1115 92 : m_lexer.consume ();
1116 92 : maybe_record_range (val.get (), tok->range);
1117 92 : return parser_result_t (std::move (val));
1118 92 : }
1119 :
1120 4 : case TOK_TRUE:
1121 4 : {
1122 4 : auto val = std::make_unique<literal> (JSON_TRUE);
1123 4 : m_lexer.consume ();
1124 4 : maybe_record_range (val.get (), tok->range);
1125 4 : return parser_result_t (std::move (val));
1126 4 : }
1127 :
1128 4 : case TOK_FALSE:
1129 4 : {
1130 4 : auto val = std::make_unique<literal> (JSON_FALSE);
1131 4 : m_lexer.consume ();
1132 4 : maybe_record_range (val.get (), tok->range);
1133 4 : return parser_result_t (std::move (val));
1134 4 : }
1135 :
1136 8 : case TOK_NULL:
1137 8 : {
1138 8 : auto val = std::make_unique<literal> (JSON_NULL);
1139 8 : m_lexer.consume ();
1140 8 : maybe_record_range (val.get (), tok->range);
1141 8 : return parser_result_t (std::move (val));
1142 8 : }
1143 :
1144 8 : case TOK_ERROR:
1145 8 : return error_at (tok->range, "invalid JSON token: %s", tok->u.string);
1146 :
1147 4 : default:
1148 4 : return error_at (tok->range, "expected a JSON value but got %s",
1149 4 : token_id_name[tok->id]);
1150 : }
1151 : }
1152 :
1153 : /* Parse a JSON object.
1154 : (ECMA-404 section 6; RFC 7159 section 4). */
1155 :
1156 : parser_result_t
1157 20 : parser::parse_object (int depth)
1158 : {
1159 40 : location_map::point start = get_next_token_start ();
1160 :
1161 20 : require (TOK_OPEN_CURLY);
1162 :
1163 20 : auto obj = std::make_unique<object> ();
1164 :
1165 20 : const token *tok = m_lexer.peek ();
1166 20 : if (tok->id == TOK_CLOSE_CURLY)
1167 : {
1168 8 : location_map::point end = get_next_token_end ();
1169 4 : maybe_record_range (obj.get (), start, end);
1170 4 : if (auto err = require (TOK_CLOSE_CURLY))
1171 4 : return parser_result_t (std::move (err));
1172 4 : return parser_result_t (std::move (obj));
1173 : }
1174 16 : if (tok->id != TOK_STRING)
1175 0 : return error_at (tok->range,
1176 : "expected string for object key after '{'; got %s",
1177 0 : token_id_name[tok->id]);
1178 20 : while (true)
1179 : {
1180 36 : tok = m_lexer.peek ();
1181 36 : if (tok->id != TOK_STRING)
1182 0 : return error_at (tok->range,
1183 : "expected string for object key after ','; got %s",
1184 0 : token_id_name[tok->id]);
1185 36 : label_text key = label_text::take (xstrdup (tok->u.string));
1186 36 : m_lexer.consume ();
1187 :
1188 36 : if (auto err = require (TOK_COLON))
1189 36 : return parser_result_t (std::move (err));
1190 :
1191 36 : parser_result_t r = parse_value (depth + 1);
1192 36 : if (r.m_err)
1193 0 : return r;
1194 36 : if (!r.m_val)
1195 0 : return parser_result_t (std::move (obj));
1196 :
1197 : /* We don't enforce uniqueness for keys. */
1198 36 : obj->set (key.get (), std::move (r.m_val));
1199 :
1200 72 : location_map::point end = get_next_token_end ();
1201 36 : result<enum token_id, std::unique_ptr<error>> result
1202 36 : (require_one_of (TOK_COMMA, TOK_CLOSE_CURLY));
1203 36 : if (result.m_err)
1204 4 : return parser_result_t (std::move (result.m_err));
1205 32 : if (result.m_val == TOK_COMMA)
1206 20 : continue;
1207 : else
1208 : {
1209 : /* TOK_CLOSE_CURLY. */
1210 12 : maybe_record_range (obj.get (), start, end);
1211 12 : return parser_result_t (std::move (obj));
1212 : }
1213 72 : }
1214 20 : }
1215 :
1216 : /* Parse a JSON array.
1217 : (ECMA-404 section 7; RFC 7159 section 5). */
1218 :
1219 : parser_result_t
1220 16 : parser::parse_array (int depth)
1221 : {
1222 32 : location_map::point start = get_next_token_start ();
1223 16 : if (auto err = require (TOK_OPEN_SQUARE))
1224 16 : return parser_result_t (std::move (err));
1225 :
1226 16 : auto arr = std::make_unique<array> ();
1227 :
1228 16 : const token *tok = m_lexer.peek ();
1229 16 : if (tok->id == TOK_CLOSE_SQUARE)
1230 : {
1231 0 : location_map::point end = get_next_token_end ();
1232 0 : maybe_record_range (arr.get (), start, end);
1233 0 : m_lexer.consume ();
1234 0 : return parser_result_t (std::move (arr));
1235 : }
1236 :
1237 112 : while (true)
1238 : {
1239 64 : parser_result_t r = parse_value (depth + 1);
1240 64 : if (r.m_err)
1241 0 : return r;
1242 :
1243 64 : arr->append (std::move (r.m_val));
1244 :
1245 128 : location_map::point end = get_next_token_end ();
1246 64 : result<enum token_id, std::unique_ptr<error>> result
1247 64 : (require_one_of (TOK_COMMA, TOK_CLOSE_SQUARE));
1248 64 : if (result.m_err)
1249 4 : return parser_result_t (std::move (result.m_err));
1250 60 : if (result.m_val == TOK_COMMA)
1251 48 : continue;
1252 : else
1253 : {
1254 : /* TOK_CLOSE_SQUARE. */
1255 12 : maybe_record_range (arr.get (), start, end);
1256 12 : return parser_result_t (std::move (arr));
1257 : }
1258 128 : }
1259 16 : }
1260 :
1261 : /* Get the start point of the next token. */
1262 :
1263 : location_map::point
1264 36 : parser::get_next_token_start ()
1265 : {
1266 36 : const token *tok = m_lexer.peek ();
1267 36 : return tok->range.m_start;
1268 : }
1269 :
1270 : /* Get the end point of the next token. */
1271 :
1272 : location_map::point
1273 104 : parser::get_next_token_end ()
1274 : {
1275 104 : const token *tok = m_lexer.peek ();
1276 104 : return tok->range.m_end;
1277 : }
1278 :
1279 : /* Require an EOF, or fail if there is surplus input. */
1280 :
1281 : std::unique_ptr<error>
1282 76 : parser::require_eof ()
1283 : {
1284 0 : return require (TOK_EOF);
1285 : }
1286 :
1287 : /* Consume the next token, issuing an error if it is not of kind TOK_ID. */
1288 :
1289 : std::unique_ptr<error>
1290 152 : parser::require (enum token_id tok_id)
1291 : {
1292 152 : const token *tok = m_lexer.peek ();
1293 152 : if (tok->id != tok_id)
1294 : {
1295 0 : if (tok->id == TOK_ERROR)
1296 0 : return error_at (tok->range,
1297 : "expected %s; got bad token: %s",
1298 0 : token_id_name[tok_id], tok->u.string);
1299 : else
1300 0 : return error_at (tok->range,
1301 0 : "expected %s; got %s", token_id_name[tok_id],
1302 0 : token_id_name[tok->id]);
1303 : }
1304 152 : m_lexer.consume ();
1305 152 : return nullptr;
1306 : }
1307 :
1308 : /* Consume the next token, issuing an error if it is not of
1309 : kind TOK_ID_A or TOK_ID_B.
1310 : Return which kind it was. */
1311 :
1312 : result<enum token_id, std::unique_ptr<error>>
1313 100 : parser::require_one_of (enum token_id tok_id_a, enum token_id tok_id_b)
1314 : {
1315 100 : const token *tok = m_lexer.peek ();
1316 100 : if ((tok->id != tok_id_a)
1317 32 : && (tok->id != tok_id_b))
1318 : {
1319 8 : if (tok->id == TOK_ERROR)
1320 0 : return error_at (tok->range, "expected %s or %s; got bad token: %s",
1321 0 : token_id_name[tok_id_a], token_id_name[tok_id_b],
1322 0 : tok->u.string);
1323 : else
1324 8 : return error_at (tok->range, "expected %s or %s; got %s",
1325 8 : token_id_name[tok_id_a], token_id_name[tok_id_b],
1326 8 : token_id_name[tok->id]);
1327 : }
1328 92 : enum token_id id = tok->id;
1329 92 : m_lexer.consume ();
1330 92 : return result<enum token_id, std::unique_ptr<error>> (id);
1331 : }
1332 :
1333 : /* Genarate a parsing error. */
1334 :
1335 : std::unique_ptr<error>
1336 20 : parser::error_at (const location_map::range &r, const char *fmt, ...)
1337 : {
1338 20 : va_list ap;
1339 20 : va_start (ap, fmt);
1340 20 : char *formatted_msg = xvasprintf (fmt, ap);
1341 20 : va_end (ap);
1342 :
1343 20 : return std::make_unique<error> (r, formatted_msg);
1344 : }
1345 :
1346 : /* Record that JV has range R within the input file. */
1347 :
1348 : void
1349 148 : parser::maybe_record_range (json::value *jv, const location_map::range &r)
1350 : {
1351 148 : if (m_loc_map)
1352 148 : m_loc_map->record_range_for_value (jv, r);
1353 148 : }
1354 :
1355 : /* Record that JV has range START to END within the input file. */
1356 :
1357 : void
1358 28 : parser::maybe_record_range (json::value *jv,
1359 : const location_map::point &start,
1360 : const location_map::point &end)
1361 : {
1362 28 : if (m_loc_map)
1363 : {
1364 28 : location_map::range r;
1365 28 : r.m_start = start;
1366 28 : r.m_end = end;
1367 28 : m_loc_map->record_range_for_value (jv, r);
1368 : }
1369 28 : }
1370 :
1371 : /* Attempt to parse the UTF-8 encoded buffer at UTF8_BUF
1372 : of the given LENGTH.
1373 : If ALLOW_COMMENTS is true, then allow C and C++ style-comments in the
1374 : buffer, as an extension to JSON, otherwise forbid them.
1375 : If successful, return an json::value in the result.
1376 : if there was a problem, return a json::error in the result.
1377 : If OUT_LOC_MAP is non-NULL, notify *OUT_LOC_MAP about
1378 : source locations of nodes seen during parsing. */
1379 :
1380 : parser_result_t
1381 96 : json::parse_utf8_string (size_t length,
1382 : const char *utf8_buf,
1383 : bool allow_comments,
1384 : location_map *out_loc_map)
1385 : {
1386 96 : parser p (out_loc_map, allow_comments);
1387 96 : if (auto err = p.add_utf8 (length, utf8_buf))
1388 96 : return parser_result_t (std::move (err));
1389 96 : parser_result_t r = p.parse_value (0);
1390 96 : if (r.m_err)
1391 20 : return r;
1392 76 : if (auto err = p.require_eof ())
1393 76 : return parser_result_t (std::move (err));
1394 76 : return r;
1395 96 : }
1396 :
1397 : /* Attempt to parse the nil-terminated UTF-8 encoded buffer at
1398 : UTF8_BUF.
1399 : If ALLOW_COMMENTS is true, then allow C and C++ style-comments in the
1400 : buffer, as an extension to JSON, otherwise forbid them.
1401 : If successful, return a non-NULL json::value *.
1402 : if there was a problem, return NULL and write an error
1403 : message to err_out, which must be deleted by the caller.
1404 : If OUT_LOC_MAP is non-NULL, notify *OUT_LOC_MAP about
1405 : source locations of nodes seen during parsing. */
1406 :
1407 : json::parser_result_t
1408 96 : json::parse_utf8_string (const char *utf8,
1409 : bool allow_comments,
1410 : location_map *out_loc_map)
1411 : {
1412 96 : return parse_utf8_string (strlen (utf8), utf8, allow_comments,
1413 96 : out_loc_map);
1414 : }
1415 :
1416 :
1417 : #if CHECKING_P
1418 :
1419 : namespace selftest {
1420 :
1421 : /* Selftests. */
1422 :
1423 : #define ASSERT_PRINT_EQ(JV, FORMATTED, EXPECTED_JSON) \
1424 : assert_print_eq (SELFTEST_LOCATION, JV, FORMATTED, EXPECTED_JSON)
1425 :
1426 : /* Implementation detail of ASSERT_RANGE_EQ. */
1427 :
1428 : static void
1429 424 : assert_point_eq (const location &loc,
1430 : const location_map::point &actual_point,
1431 : size_t exp_unichar_idx, int exp_line, int exp_column)
1432 : {
1433 424 : ASSERT_EQ_AT (loc, actual_point.m_unichar_idx, exp_unichar_idx);
1434 424 : ASSERT_EQ_AT (loc, actual_point.m_line, exp_line);
1435 424 : ASSERT_EQ_AT (loc, actual_point.m_column, exp_column);
1436 424 : }
1437 :
1438 : /* Implementation detail of ASSERT_RANGE_EQ. */
1439 :
1440 : static void
1441 212 : assert_range_eq (const location &loc,
1442 : const location_map::range &actual_range,
1443 : /* Expected location. */
1444 : size_t start_unichar_idx, int start_line, int start_column,
1445 : size_t end_unichar_idx, int end_line, int end_column)
1446 : {
1447 212 : assert_point_eq (loc, actual_range.m_start,
1448 : start_unichar_idx, start_line, start_column);
1449 212 : assert_point_eq (loc, actual_range.m_end,
1450 : end_unichar_idx, end_line, end_column);
1451 212 : }
1452 :
1453 : /* Assert that ACTUAL_RANGE starts at
1454 : (START_UNICHAR_IDX, START_LINE, START_COLUMN)
1455 : and ends at (END_UNICHAR_IDX, END_LINE, END_COLUMN). */
1456 :
1457 : #define ASSERT_RANGE_EQ(ACTUAL_RANGE, \
1458 : START_UNICHAR_IDX, START_LINE, START_COLUMN, \
1459 : END_UNICHAR_IDX, END_LINE, END_COLUMN) \
1460 : assert_range_eq ((SELFTEST_LOCATION), (ACTUAL_RANGE), \
1461 : (START_UNICHAR_IDX), (START_LINE), (START_COLUMN), \
1462 : (END_UNICHAR_IDX), (END_LINE), (END_COLUMN))
1463 :
1464 : /* Implementation detail of ASSERT_ERR_EQ. */
1465 :
1466 : static void
1467 16 : assert_err_eq (const location &loc,
1468 : const json::error *actual_err,
1469 : /* Expected location. */
1470 : size_t start_unichar_idx, int start_line, int start_column,
1471 : size_t end_unichar_idx, int end_line, int end_column,
1472 : const char *expected_msg)
1473 : {
1474 16 : ASSERT_TRUE_AT (loc, actual_err);
1475 16 : const location_map::range &actual_range = actual_err->get_range ();
1476 16 : ASSERT_EQ_AT (loc, actual_range.m_start.m_unichar_idx, start_unichar_idx);
1477 16 : ASSERT_EQ_AT (loc, actual_range.m_start.m_line, start_line);
1478 16 : ASSERT_EQ_AT (loc, actual_range.m_start.m_column, start_column);
1479 16 : ASSERT_EQ_AT (loc, actual_range.m_end.m_unichar_idx, end_unichar_idx);
1480 16 : ASSERT_EQ_AT (loc, actual_range.m_end.m_line, end_line);
1481 16 : ASSERT_EQ_AT (loc, actual_range.m_end.m_column, end_column);
1482 16 : ASSERT_STREQ_AT (loc, actual_err->get_msg (), expected_msg);
1483 16 : }
1484 :
1485 : /* Assert that ACTUAL_ERR is a non-NULL json::error *,
1486 : with message EXPECTED_MSG, and that its location starts
1487 : at (START_UNICHAR_IDX, START_LINE, START_COLUMN)
1488 : and ends at (END_UNICHAR_IDX, END_LINE, END_COLUMN). */
1489 :
1490 : #define ASSERT_ERR_EQ(ACTUAL_ERR, \
1491 : START_UNICHAR_IDX, START_LINE, START_COLUMN, \
1492 : END_UNICHAR_IDX, END_LINE, END_COLUMN, \
1493 : EXPECTED_MSG) \
1494 : assert_err_eq ((SELFTEST_LOCATION), (ACTUAL_ERR), \
1495 : (START_UNICHAR_IDX), (START_LINE), (START_COLUMN), \
1496 : (END_UNICHAR_IDX), (END_LINE), (END_COLUMN), \
1497 : (EXPECTED_MSG))
1498 :
1499 : /* Implementation detail of ASSERT_JSON_POINTER_EQ. */
1500 :
1501 : static void
1502 28 : assert_json_pointer_eq (const location &loc,
1503 : const json::value *jv,
1504 : const char *expected_str)
1505 : {
1506 28 : pretty_printer pp;
1507 28 : ASSERT_TRUE_AT (loc, jv);
1508 28 : jv->print_pointer (&pp);
1509 28 : ASSERT_STREQ_AT (loc, pp_formatted_text (&pp), expected_str);
1510 28 : }
1511 :
1512 : /* Assert that JV is a non-NULL json::value *, and that
1513 : jv->print_pointer prints EXPECTED_STR. */
1514 :
1515 : #define ASSERT_JSON_POINTER_EQ(JV, EXPECTED_STR) \
1516 : assert_json_pointer_eq ((SELFTEST_LOCATION), (JV), (EXPECTED_STR))
1517 :
1518 : /* Verify that the JSON lexer works as expected. */
1519 :
1520 : static void
1521 4 : test_lexer ()
1522 : {
1523 4 : lexer l (false);
1524 4 : const char *str
1525 : /* 0 1 2 3 4 . */
1526 : /* 01234567890123456789012345678901234567890123456789. */
1527 : = (" 1066 -1 \n"
1528 : " -273.15 1e6\n"
1529 : " [ ] null true false { } \"foo\" \n");
1530 4 : auto err = l.add_utf8 (strlen (str), str);
1531 4 : ASSERT_EQ (err, nullptr);
1532 :
1533 : /* Line 1. */
1534 4 : {
1535 4 : const size_t line_offset = 0;
1536 :
1537 : /* Expect token: "1066" in columns 4-7. */
1538 4 : {
1539 4 : const token *tok = l.peek ();
1540 4 : ASSERT_EQ (tok->id, TOK_INTEGER_NUMBER);
1541 4 : ASSERT_EQ (tok->u.integer_number, 1066);
1542 4 : ASSERT_RANGE_EQ (tok->range,
1543 : line_offset + 4, 1, 4,
1544 : line_offset + 7, 1, 7);
1545 4 : l.consume ();
1546 : }
1547 : /* Expect token: "-1" in columns 11-12. */
1548 4 : {
1549 4 : const token *tok = l.peek ();
1550 4 : ASSERT_EQ (tok->id, TOK_INTEGER_NUMBER);
1551 4 : ASSERT_EQ (tok->u.integer_number, -1);
1552 4 : ASSERT_RANGE_EQ (tok->range,
1553 : line_offset + 11, 1, 11,
1554 : line_offset + 12, 1, 12);
1555 4 : l.consume ();
1556 : }
1557 : }
1558 :
1559 : /* Line 2. */
1560 4 : {
1561 4 : const size_t line_offset = 16;
1562 :
1563 : /* Expect token: "-273.15" in columns 4-10. */
1564 4 : {
1565 4 : const token *tok = l.peek ();
1566 4 : ASSERT_EQ (tok->id, TOK_FLOAT_NUMBER);
1567 4 : ASSERT_EQ (int(tok->u.float_number), int(-273.15));
1568 4 : ASSERT_RANGE_EQ (tok->range,
1569 : line_offset + 4, 2, 4,
1570 : line_offset + 10, 2, 10);
1571 4 : l.consume ();
1572 : }
1573 : /* Expect token: "1e6" in columns 12-14. */
1574 4 : {
1575 4 : const token *tok = l.peek ();
1576 4 : ASSERT_EQ (tok->id, TOK_INTEGER_NUMBER);
1577 4 : ASSERT_EQ (tok->u.integer_number, 1000000);
1578 4 : ASSERT_RANGE_EQ (tok->range,
1579 : line_offset + 12, 2, 12,
1580 : line_offset + 14, 2, 14);
1581 4 : l.consume ();
1582 : }
1583 : }
1584 :
1585 : /* Line 3. */
1586 4 : {
1587 4 : const size_t line_offset = 32;
1588 :
1589 : /* Expect token: "[". */
1590 4 : {
1591 4 : const token *tok = l.peek ();
1592 4 : ASSERT_EQ (tok->id, TOK_OPEN_SQUARE);
1593 4 : ASSERT_RANGE_EQ (tok->range,
1594 : line_offset + 2, 3, 2,
1595 : line_offset + 2, 3, 2);
1596 4 : l.consume ();
1597 : }
1598 : /* Expect token: "]". */
1599 4 : {
1600 4 : const token *tok = l.peek ();
1601 4 : ASSERT_EQ (tok->id, TOK_CLOSE_SQUARE);
1602 4 : ASSERT_RANGE_EQ (tok->range,
1603 : line_offset + 6, 3, 6,
1604 : line_offset + 6, 3, 6);
1605 4 : l.consume ();
1606 : }
1607 : /* Expect token: "null". */
1608 4 : {
1609 4 : const token *tok = l.peek ();
1610 4 : ASSERT_EQ (tok->id, TOK_NULL);
1611 4 : ASSERT_RANGE_EQ (tok->range,
1612 : line_offset + 8, 3, 8,
1613 : line_offset + 11, 3, 11);
1614 4 : l.consume ();
1615 : }
1616 : /* Expect token: "true". */
1617 4 : {
1618 4 : const token *tok = l.peek ();
1619 4 : ASSERT_EQ (tok->id, TOK_TRUE);
1620 4 : ASSERT_RANGE_EQ (tok->range,
1621 : line_offset + 15, 3, 15,
1622 : line_offset + 18, 3, 18);
1623 4 : l.consume ();
1624 : }
1625 : /* Expect token: "false". */
1626 4 : {
1627 4 : const token *tok = l.peek ();
1628 4 : ASSERT_EQ (tok->id, TOK_FALSE);
1629 4 : ASSERT_RANGE_EQ (tok->range,
1630 : line_offset + 21, 3, 21,
1631 : line_offset + 25, 3, 25);
1632 4 : l.consume ();
1633 : }
1634 : /* Expect token: "{". */
1635 4 : {
1636 4 : const token *tok = l.peek ();
1637 4 : ASSERT_EQ (tok->id, TOK_OPEN_CURLY);
1638 4 : ASSERT_RANGE_EQ (tok->range,
1639 : line_offset + 28, 3, 28,
1640 : line_offset + 28, 3, 28);
1641 4 : l.consume ();
1642 : }
1643 : /* Expect token: "}". */
1644 4 : {
1645 4 : const token *tok = l.peek ();
1646 4 : ASSERT_EQ (tok->id, TOK_CLOSE_CURLY);
1647 4 : ASSERT_RANGE_EQ (tok->range,
1648 : line_offset + 31, 3, 31,
1649 : line_offset + 31, 3, 31);
1650 4 : l.consume ();
1651 : }
1652 : /* Expect token: "\"foo\"". */
1653 4 : {
1654 4 : const token *tok = l.peek ();
1655 4 : ASSERT_EQ (tok->id, TOK_STRING);
1656 4 : ASSERT_RANGE_EQ (tok->range,
1657 : line_offset + 34, 3, 34,
1658 : line_offset + 38, 3, 38);
1659 4 : l.consume ();
1660 : }
1661 : }
1662 4 : }
1663 :
1664 : /* Verify that the JSON lexer complains about single-line comments
1665 : when comments are disabled. */
1666 :
1667 : static void
1668 4 : test_lexing_unsupported_single_line_comment ()
1669 : {
1670 4 : lexer l (false);
1671 4 : const char *str
1672 : /* 0 1 2 3 4 . */
1673 : /* 01234567890123456789012345678901234567890123456789. */
1674 : = (" 1066 // Hello world\n");
1675 4 : auto err = l.add_utf8 (strlen (str), str);
1676 4 : ASSERT_EQ (err, nullptr);
1677 :
1678 : /* Line 1. */
1679 4 : {
1680 4 : const size_t line_offset = 0;
1681 4 : const int line_1 = 1;
1682 :
1683 : /* Expect token: "1066" in columns 4-7. */
1684 4 : {
1685 4 : const token *tok = l.peek ();
1686 4 : ASSERT_EQ (tok->id, TOK_INTEGER_NUMBER);
1687 4 : ASSERT_EQ (tok->u.integer_number, 1066);
1688 4 : ASSERT_RANGE_EQ (tok->range,
1689 : line_offset + 4, line_1, 4,
1690 : line_offset + 7, line_1, 7);
1691 4 : l.consume ();
1692 : }
1693 :
1694 : /* Expect error. */
1695 4 : {
1696 4 : const token *tok = l.peek ();
1697 4 : ASSERT_EQ (tok->id, TOK_ERROR);
1698 4 : ASSERT_STREQ (tok->u.string, "unexpected character: '/'");
1699 4 : ASSERT_RANGE_EQ (tok->range,
1700 : line_offset + 11, line_1, 11,
1701 : line_offset + 11, line_1, 11);
1702 4 : l.consume ();
1703 : }
1704 : }
1705 4 : }
1706 :
1707 : /* Verify that the JSON lexer complains about multiline comments
1708 : when comments are disabled. */
1709 :
1710 : static void
1711 4 : test_lexing_unsupported_multiline_comment ()
1712 : {
1713 4 : lexer l (false);
1714 4 : const char *str
1715 : /* 0 1 2 3 4 . */
1716 : /* 01234567890123456789012345678901234567890123456789. */
1717 : = (" 1066 /* Hello world\n"
1718 : " continuation of comment\n"
1719 : " end of comment */ 42\n");
1720 4 : auto err = l.add_utf8 (strlen (str), str);
1721 4 : ASSERT_EQ (err, nullptr);
1722 :
1723 : /* Line 1. */
1724 4 : {
1725 4 : const size_t line_offset = 0;
1726 4 : const int line_1 = 1;
1727 :
1728 : /* Expect token: "1066" in line 1, columns 4-7. */
1729 4 : {
1730 4 : const token *tok = l.peek ();
1731 4 : ASSERT_EQ (tok->id, TOK_INTEGER_NUMBER);
1732 4 : ASSERT_EQ (tok->u.integer_number, 1066);
1733 4 : ASSERT_RANGE_EQ (tok->range,
1734 : line_offset + 4, line_1, 4,
1735 : line_offset + 7, line_1, 7);
1736 4 : l.consume ();
1737 : }
1738 :
1739 : /* Expect error. */
1740 4 : {
1741 4 : const token *tok = l.peek ();
1742 4 : ASSERT_EQ (tok->id, TOK_ERROR);
1743 4 : ASSERT_STREQ (tok->u.string, "unexpected character: '/'");
1744 4 : ASSERT_RANGE_EQ (tok->range,
1745 : line_offset + 11, line_1, 11,
1746 : line_offset + 11, line_1, 11);
1747 4 : l.consume ();
1748 : }
1749 : }
1750 4 : }
1751 :
1752 : /* Verify that the JSON lexer handles single-line comments
1753 : when comments are enabled. */
1754 :
1755 : static void
1756 4 : test_lexing_supported_single_line_comment ()
1757 : {
1758 4 : lexer l (true);
1759 4 : const char *str
1760 : /* 0 1 2 3 4 . */
1761 : /* 01234567890123456789012345678901234567890123456789. */
1762 : = (" 1066 // Hello world\n"
1763 : " 42 // etc\n");
1764 4 : auto err = l.add_utf8 (strlen (str), str);
1765 4 : ASSERT_EQ (err, nullptr);
1766 :
1767 4 : const size_t line_1_offset = 0;
1768 4 : const size_t line_2_offset = 26;
1769 4 : const size_t line_3_offset = line_2_offset + 17;
1770 :
1771 : /* Expect token: "1066" in line 1, columns 4-7. */
1772 4 : {
1773 4 : const int line_1 = 1;
1774 4 : const token *tok = l.peek ();
1775 4 : ASSERT_EQ (tok->id, TOK_INTEGER_NUMBER);
1776 4 : ASSERT_EQ (tok->u.integer_number, 1066);
1777 4 : ASSERT_RANGE_EQ (tok->range,
1778 : line_1_offset + 4, line_1, 4,
1779 : line_1_offset + 7, line_1, 7);
1780 4 : l.consume ();
1781 : }
1782 :
1783 : /* Expect token: "42" in line 2, columns 5-6. */
1784 4 : {
1785 4 : const int line_2 = 2;
1786 4 : const token *tok = l.peek ();
1787 4 : ASSERT_EQ (tok->id, TOK_INTEGER_NUMBER);
1788 4 : ASSERT_EQ (tok->u.integer_number, 42);
1789 4 : ASSERT_RANGE_EQ (tok->range,
1790 : line_2_offset + 5, line_2, 5,
1791 : line_2_offset + 6, line_2, 6);
1792 4 : l.consume ();
1793 : }
1794 :
1795 : /* Expect EOF. */
1796 4 : {
1797 4 : const int line_3 = 3;
1798 4 : const token *tok = l.peek ();
1799 4 : ASSERT_EQ (tok->id, TOK_EOF);
1800 4 : ASSERT_RANGE_EQ (tok->range,
1801 : line_3_offset + 0, line_3, 0,
1802 : line_3_offset + 0, line_3, 0);
1803 4 : l.consume ();
1804 : }
1805 4 : }
1806 :
1807 : /* Verify that the JSON lexer handles multiline comments
1808 : when comments are enabled. */
1809 :
1810 : static void
1811 4 : test_lexing_supported_multiline_comment ()
1812 : {
1813 4 : lexer l (true);
1814 4 : const char *str
1815 : /* 0 1 2 3 4 . */
1816 : /* 01234567890123456789012345678901234567890123456789. */
1817 : = (" 1066 /* Hello world\n"
1818 : " continuation of comment\n"
1819 : " end of comment */ 42\n");
1820 4 : auto err = l.add_utf8 (strlen (str), str);
1821 4 : ASSERT_EQ (err, nullptr);
1822 :
1823 4 : const size_t line_1_offset = 0;
1824 4 : const size_t line_2_offset = 26;
1825 4 : const size_t line_3_offset = line_2_offset + 25;
1826 4 : const size_t line_4_offset = line_3_offset + 23;
1827 :
1828 : /* Expect token: "1066" in line 1, columns 4-7. */
1829 4 : {
1830 4 : const int line_1 = 1;
1831 4 : const token *tok = l.peek ();
1832 4 : ASSERT_EQ (tok->id, TOK_INTEGER_NUMBER);
1833 4 : ASSERT_EQ (tok->u.integer_number, 1066);
1834 4 : ASSERT_RANGE_EQ (tok->range,
1835 : line_1_offset + 4, line_1, 4,
1836 : line_1_offset + 7, line_1, 7);
1837 4 : l.consume ();
1838 : }
1839 :
1840 : /* Expect token: "42" in line 3, columns 20-21. */
1841 4 : {
1842 4 : const int line_3 = 3;
1843 4 : const token *tok = l.peek ();
1844 4 : ASSERT_EQ (tok->id, TOK_INTEGER_NUMBER);
1845 4 : ASSERT_EQ (tok->u.integer_number, 42);
1846 4 : ASSERT_RANGE_EQ (tok->range,
1847 : line_3_offset + 20, line_3, 20,
1848 : line_3_offset + 21, line_3, 21);
1849 4 : l.consume ();
1850 : }
1851 :
1852 : /* Expect EOF. */
1853 4 : {
1854 4 : const int line_4 = 4;
1855 4 : const token *tok = l.peek ();
1856 4 : ASSERT_EQ (tok->id, TOK_EOF);
1857 4 : ASSERT_RANGE_EQ (tok->range,
1858 : line_4_offset + 0, line_4, 0,
1859 : line_4_offset + 0, line_4, 0);
1860 4 : l.consume ();
1861 : }
1862 4 : }
1863 :
1864 : /* Helper class for writing JSON parsing testcases.
1865 : Attempts to parse a string in ctor, and captures the result (either
1866 : a json::value or a json::error), and a location map. */
1867 :
1868 : struct parser_testcase
1869 : {
1870 : public:
1871 96 : parser_testcase (const char *utf8_string, bool allow_comments = false)
1872 96 : : m_loc_map (),
1873 96 : m_result (parse_utf8_string (utf8_string, allow_comments, &m_loc_map))
1874 : {
1875 96 : }
1876 :
1877 96 : const json::value *get_value () const { return m_result.m_val.get (); }
1878 100 : const json::error *get_error () const { return m_result.m_err.get (); }
1879 :
1880 : const location_map::range *
1881 124 : get_range_for_value (const json::value *jv) const
1882 : {
1883 248 : return m_loc_map.get_range_for_value (jv);
1884 : }
1885 :
1886 : private:
1887 : /* Concrete implementation of location_map for use in
1888 : JSON parsing selftests. */
1889 : class test_location_map : public location_map
1890 : {
1891 : public:
1892 176 : void record_range_for_value (json::value *jv, const range &r) final override
1893 : {
1894 176 : m_map.put (jv, r);
1895 176 : }
1896 :
1897 124 : range *get_range_for_value (const json::value *jv) const
1898 : {
1899 124 : return const_cast<hash_map<const json::value *, range> &> (m_map)
1900 124 : .get (jv);
1901 : }
1902 :
1903 : private:
1904 : hash_map<const json::value *, range> m_map;
1905 : };
1906 :
1907 : test_location_map m_loc_map;
1908 : json::parser_result_t m_result;
1909 : };
1910 :
1911 : /* Verify that parse_utf8_string works as expected. */
1912 :
1913 : static void
1914 4 : test_parse_string ()
1915 : {
1916 4 : const int line_1 = 1;
1917 :
1918 4 : {
1919 4 : parser_testcase tc ("\"foo\"");
1920 4 : ASSERT_EQ (tc.get_error (), nullptr);
1921 4 : const json::value *jv = tc.get_value ();
1922 4 : ASSERT_EQ (jv->get_kind (), JSON_STRING);
1923 4 : ASSERT_STREQ (as_a <const json::string *> (jv)->get_string (), "foo");
1924 4 : ASSERT_PRINT_EQ (*jv, true, "\"foo\"");
1925 4 : auto range = tc.get_range_for_value (jv);
1926 4 : ASSERT_TRUE (range);
1927 4 : ASSERT_RANGE_EQ (*range,
1928 : 0, line_1, 0,
1929 : 4, line_1, 4);
1930 4 : }
1931 :
1932 4 : {
1933 4 : const char *contains_quotes = "\"before \\\"quoted\\\" after\"";
1934 4 : parser_testcase tc (contains_quotes);
1935 4 : ASSERT_EQ (tc.get_error (), nullptr);
1936 4 : const json::value *jv = tc.get_value ();
1937 4 : ASSERT_EQ (jv->get_kind (), JSON_STRING);
1938 4 : ASSERT_STREQ (as_a <const json::string *> (jv)->get_string (),
1939 : "before \"quoted\" after");
1940 4 : ASSERT_PRINT_EQ (*jv, true, contains_quotes);
1941 4 : auto range = tc.get_range_for_value (jv);
1942 4 : ASSERT_TRUE (range);
1943 4 : ASSERT_RANGE_EQ (*range,
1944 : 0, line_1, 0,
1945 : 24, line_1, 24);
1946 4 : }
1947 :
1948 : /* Test of non-ASCII input. This string is the Japanese word "mojibake",
1949 : written as C octal-escaped UTF-8. */
1950 4 : const char *mojibake = (/* Opening quote. */
1951 : "\""
1952 : /* U+6587 CJK UNIFIED IDEOGRAPH-6587
1953 : UTF-8: 0xE6 0x96 0x87
1954 : C octal escaped UTF-8: \346\226\207. */
1955 : "\346\226\207"
1956 : /* U+5B57 CJK UNIFIED IDEOGRAPH-5B57
1957 : UTF-8: 0xE5 0xAD 0x97
1958 : C octal escaped UTF-8: \345\255\227. */
1959 : "\345\255\227"
1960 : /* U+5316 CJK UNIFIED IDEOGRAPH-5316
1961 : UTF-8: 0xE5 0x8C 0x96
1962 : C octal escaped UTF-8: \345\214\226. */
1963 : "\345\214\226"
1964 : /* U+3051 HIRAGANA LETTER KE
1965 : UTF-8: 0xE3 0x81 0x91
1966 : C octal escaped UTF-8: \343\201\221. */
1967 : "\343\201\221"
1968 : /* Closing quote. */
1969 : "\"");
1970 4 : {
1971 4 : parser_testcase tc (mojibake);
1972 4 : ASSERT_EQ (tc.get_error (), nullptr);
1973 4 : const json::value *jv = tc.get_value ();
1974 4 : ASSERT_EQ (jv->get_kind (), JSON_STRING);
1975 : /* Result of get_string should be UTF-8 encoded, without quotes. */
1976 4 : ASSERT_STREQ (as_a <const json::string *> (jv)->get_string (),
1977 : "\346\226\207" "\345\255\227" "\345\214\226" "\343\201\221");
1978 : /* Result of dump should be UTF-8 encoded, with quotes. */
1979 4 : ASSERT_PRINT_EQ (*jv, false, mojibake);
1980 4 : auto range = tc.get_range_for_value (jv);
1981 4 : ASSERT_TRUE (range);
1982 4 : ASSERT_RANGE_EQ (*range,
1983 : 0, line_1, 0,
1984 : 5, line_1, 5);
1985 4 : }
1986 :
1987 : /* Test of \u-escaped unicode. This is "mojibake" again, as above. */
1988 4 : {
1989 4 : const char *escaped_unicode = "\"\\u6587\\u5b57\\u5316\\u3051\"";
1990 4 : parser_testcase tc (escaped_unicode);
1991 4 : ASSERT_EQ (tc.get_error (), nullptr);
1992 4 : const json::value *jv = tc.get_value ();
1993 4 : ASSERT_EQ (jv->get_kind (), JSON_STRING);
1994 : /* Result of get_string should be UTF-8 encoded, without quotes. */
1995 4 : ASSERT_STREQ (as_a <const json::string *> (jv)->get_string (),
1996 : "\346\226\207" "\345\255\227" "\345\214\226" "\343\201\221");
1997 : /* Result of dump should be UTF-8 encoded, with quotes. */
1998 4 : ASSERT_PRINT_EQ (*jv, false, mojibake);
1999 4 : auto range = tc.get_range_for_value (jv);
2000 4 : ASSERT_TRUE (range);
2001 4 : ASSERT_RANGE_EQ (*range,
2002 : 0, line_1, 0,
2003 : 25, line_1, 25);
2004 4 : }
2005 4 : }
2006 :
2007 : /* Verify that we can parse various kinds of JSON numbers. */
2008 :
2009 : static void
2010 4 : test_parse_number ()
2011 : {
2012 4 : const int line_1 = 1;
2013 :
2014 4 : {
2015 4 : parser_testcase tc ("42");
2016 4 : ASSERT_EQ (tc.get_error (), nullptr);
2017 4 : const json::value *jv = tc.get_value ();
2018 4 : ASSERT_EQ (jv->get_kind (), JSON_INTEGER);
2019 4 : ASSERT_EQ (as_a <const json::integer_number *> (jv)->get (), 42.0);
2020 4 : ASSERT_PRINT_EQ (*jv, true, "42");
2021 4 : auto range = tc.get_range_for_value (jv);
2022 4 : ASSERT_TRUE (range);
2023 4 : ASSERT_RANGE_EQ (*range,
2024 : 0, line_1, 0,
2025 : 1, line_1, 1);
2026 4 : }
2027 :
2028 : /* Negative number. */
2029 4 : {
2030 4 : parser_testcase tc ("-17");
2031 4 : ASSERT_EQ (tc.get_error (), nullptr);
2032 4 : const json::value *jv = tc.get_value ();
2033 4 : ASSERT_EQ (jv->get_kind (), JSON_INTEGER);
2034 4 : ASSERT_EQ (as_a<const json::integer_number *> (jv)->get (), -17.0);
2035 4 : ASSERT_PRINT_EQ (*jv, true, "-17");
2036 4 : auto range = tc.get_range_for_value (jv);
2037 4 : ASSERT_TRUE (range);
2038 4 : ASSERT_RANGE_EQ (*range,
2039 : 0, line_1, 0,
2040 : 2, line_1, 2);
2041 4 : }
2042 :
2043 : /* Decimal. */
2044 4 : {
2045 4 : parser_testcase tc ("3.141");
2046 4 : ASSERT_EQ (tc.get_error (), nullptr);
2047 4 : const json::value *jv = tc.get_value ();
2048 4 : ASSERT_EQ (JSON_FLOAT, jv->get_kind ());
2049 4 : ASSERT_NEAR (3.141, ((const json::float_number *)jv)->get (), 0.001);
2050 4 : auto range = tc.get_range_for_value (jv);
2051 4 : ASSERT_TRUE (range);
2052 4 : ASSERT_RANGE_EQ (*range,
2053 : 0, line_1, 0,
2054 : 4, line_1, 4);
2055 4 : }
2056 :
2057 : /* Exponents. */
2058 4 : {
2059 4 : {
2060 4 : parser_testcase tc ("3.141e+0");
2061 4 : ASSERT_EQ (tc.get_error (), nullptr);
2062 4 : const json::value *jv = tc.get_value ();
2063 4 : ASSERT_EQ (jv->get_kind (), JSON_FLOAT);
2064 4 : ASSERT_NEAR (as_a <const json::float_number *> (jv)->get (), 3.141, 0.1);
2065 4 : auto range = tc.get_range_for_value (jv);
2066 4 : ASSERT_TRUE (range);
2067 4 : ASSERT_RANGE_EQ (*range,
2068 : 0, line_1, 0,
2069 : 7, line_1, 7);
2070 4 : }
2071 4 : {
2072 4 : parser_testcase tc ("42e2");
2073 4 : ASSERT_EQ (tc.get_error (), nullptr);
2074 4 : const json::value *jv = tc.get_value ();
2075 4 : ASSERT_EQ (jv->get_kind (), JSON_INTEGER);
2076 4 : ASSERT_EQ (as_a <const json::integer_number *> (jv)->get (), 4200);
2077 4 : ASSERT_PRINT_EQ (*jv, true, "4200");
2078 4 : auto range = tc.get_range_for_value (jv);
2079 4 : ASSERT_TRUE (range);
2080 4 : ASSERT_RANGE_EQ (*range,
2081 : 0, line_1, 0,
2082 : 3, line_1, 3);
2083 4 : }
2084 4 : {
2085 4 : parser_testcase tc ("42e-1");
2086 4 : ASSERT_EQ (tc.get_error (), nullptr);
2087 4 : const json::value *jv = tc.get_value ();
2088 4 : ASSERT_EQ (jv->get_kind (), JSON_FLOAT);
2089 4 : ASSERT_NEAR (as_a <const json::float_number *> (jv)->get (), 4.2, 0.1);
2090 4 : auto range = tc.get_range_for_value (jv);
2091 4 : ASSERT_TRUE (range);
2092 4 : ASSERT_RANGE_EQ (*range,
2093 : 0, line_1, 0,
2094 : 4, line_1, 4);
2095 4 : }
2096 : }
2097 4 : }
2098 :
2099 : /* Verify that JSON array parsing works. */
2100 :
2101 : static void
2102 4 : test_parse_array ()
2103 : {
2104 4 : const int line_1 = 1;
2105 :
2106 4 : parser_testcase tc ("[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
2107 4 : ASSERT_EQ (tc.get_error (), nullptr);
2108 4 : const json::value *jv = tc.get_value ();
2109 4 : ASSERT_EQ (jv->get_kind (), JSON_ARRAY);
2110 4 : const json::array *arr = as_a <const json::array *> (jv);
2111 4 : ASSERT_EQ (arr->length (), 10);
2112 4 : auto range = tc.get_range_for_value (jv);
2113 4 : ASSERT_TRUE (range);
2114 4 : ASSERT_RANGE_EQ (*range,
2115 : 0, line_1, 0,
2116 : 29, line_1, 29);
2117 44 : for (int i = 0; i < 10; i++)
2118 : {
2119 40 : json::value *element = arr->get (i);
2120 40 : ASSERT_EQ (element->get_kind (), JSON_INTEGER);
2121 40 : ASSERT_EQ (as_a <json::integer_number *> (element)->get (), i);
2122 40 : range = tc.get_range_for_value (element);
2123 40 : ASSERT_TRUE (range);
2124 40 : const int offset = 1 + (i * 3);
2125 40 : ASSERT_RANGE_EQ (*range,
2126 : offset, line_1, offset,
2127 : offset, line_1, offset);
2128 : }
2129 4 : ASSERT_PRINT_EQ (*jv, false, "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
2130 4 : }
2131 :
2132 : /* Verify that JSON object parsing works. */
2133 :
2134 : static void
2135 4 : test_parse_object ()
2136 : {
2137 4 : const int line_1 = 1;
2138 4 : std::unique_ptr<error> err;
2139 : /* 0 1 2 3 . */
2140 : /* 01 2345 678 9012 345 6789 0123456789012. */
2141 4 : parser_testcase tc ("{\"foo\": \"bar\", \"baz\": [42, null]}");
2142 :
2143 4 : ASSERT_EQ (tc.get_error (), nullptr);
2144 4 : const json::value *jv = tc.get_value ();
2145 4 : ASSERT_NE (jv, nullptr);
2146 4 : ASSERT_EQ (jv->get_kind (), JSON_OBJECT);
2147 4 : auto range = tc.get_range_for_value (jv);
2148 4 : ASSERT_TRUE (range);
2149 4 : ASSERT_RANGE_EQ (*range,
2150 : 0, line_1, 0,
2151 : 32, line_1, 32);
2152 4 : const json::object *jo = static_cast <const json::object *> (jv);
2153 4 : ASSERT_JSON_POINTER_EQ (jv, "");
2154 :
2155 4 : json::value *foo_value = jo->get ("foo");
2156 4 : ASSERT_NE (foo_value, nullptr);
2157 4 : ASSERT_EQ (foo_value->get_kind (), JSON_STRING);
2158 4 : ASSERT_STREQ (as_a <json::string *> (foo_value)->get_string (), "bar");
2159 4 : range = tc.get_range_for_value (foo_value);
2160 4 : ASSERT_TRUE (range);
2161 4 : ASSERT_RANGE_EQ (*range,
2162 : 8, line_1, 8,
2163 : 12, line_1, 12);
2164 4 : ASSERT_JSON_POINTER_EQ (foo_value, "/foo");
2165 :
2166 4 : json::value *baz_value = jo->get ("baz");
2167 4 : ASSERT_NE (baz_value, nullptr);
2168 4 : ASSERT_EQ (baz_value->get_kind (), JSON_ARRAY);
2169 4 : range = tc.get_range_for_value (baz_value);
2170 4 : ASSERT_TRUE (range);
2171 4 : ASSERT_RANGE_EQ (*range,
2172 : 22, line_1, 22,
2173 : 31, line_1, 31);
2174 4 : ASSERT_JSON_POINTER_EQ (baz_value, "/baz");
2175 :
2176 4 : json::array *baz_array = as_a <json::array *> (baz_value);
2177 4 : ASSERT_EQ (baz_array->length (), 2);
2178 :
2179 4 : json::value *element0 = baz_array->get (0);
2180 4 : ASSERT_EQ (as_a <json::integer_number *> (element0)->get (), 42);
2181 4 : range = tc.get_range_for_value (element0);
2182 4 : ASSERT_TRUE (range);
2183 4 : ASSERT_RANGE_EQ (*range,
2184 : 23, line_1, 23,
2185 : 24, line_1, 24);
2186 4 : ASSERT_JSON_POINTER_EQ (element0, "/baz/0");
2187 :
2188 4 : json::value *element1 = baz_array->get (1);
2189 4 : ASSERT_EQ (element1->get_kind (), JSON_NULL);
2190 4 : range = tc.get_range_for_value (element1);
2191 4 : ASSERT_TRUE (range);
2192 4 : ASSERT_RANGE_EQ (*range,
2193 : 27, line_1, 27,
2194 : 30, line_1, 30);
2195 4 : ASSERT_JSON_POINTER_EQ (element1, "/baz/1");
2196 4 : }
2197 :
2198 : /* Verify that the JSON literals "true", "false" and "null" are parsed
2199 : correctly. */
2200 :
2201 : static void
2202 4 : test_parse_literals ()
2203 : {
2204 4 : const int line_1 = 1;
2205 4 : {
2206 4 : parser_testcase tc ("true");
2207 4 : ASSERT_EQ (tc.get_error (), nullptr);
2208 4 : const json::value *jv = tc.get_value ();
2209 4 : ASSERT_NE (jv, nullptr);
2210 4 : ASSERT_EQ (jv->get_kind (), JSON_TRUE);
2211 4 : ASSERT_PRINT_EQ (*jv, false, "true");
2212 4 : auto range = tc.get_range_for_value (jv);
2213 4 : ASSERT_TRUE (range);
2214 4 : ASSERT_RANGE_EQ (*range,
2215 : 0, line_1, 0,
2216 : 3, line_1, 3);
2217 4 : }
2218 :
2219 4 : {
2220 4 : parser_testcase tc ("false");
2221 4 : ASSERT_EQ (tc.get_error (), nullptr);
2222 4 : const json::value *jv = tc.get_value ();
2223 4 : ASSERT_NE (jv, nullptr);
2224 4 : ASSERT_EQ (jv->get_kind (), JSON_FALSE);
2225 4 : ASSERT_PRINT_EQ (*jv, false, "false");
2226 4 : auto range = tc.get_range_for_value (jv);
2227 4 : ASSERT_TRUE (range);
2228 4 : ASSERT_RANGE_EQ (*range,
2229 : 0, line_1, 0,
2230 : 4, line_1, 4);
2231 4 : }
2232 :
2233 4 : {
2234 4 : parser_testcase tc ("null");
2235 4 : ASSERT_EQ (tc.get_error (), nullptr);
2236 4 : const json::value *jv = tc.get_value ();
2237 4 : ASSERT_NE (jv, nullptr);
2238 4 : ASSERT_EQ (jv->get_kind (), JSON_NULL);
2239 4 : ASSERT_PRINT_EQ (*jv, false, "null");
2240 4 : auto range = tc.get_range_for_value (jv);
2241 4 : ASSERT_TRUE (range);
2242 4 : ASSERT_RANGE_EQ (*range,
2243 : 0, line_1, 0,
2244 : 3, line_1, 3);
2245 4 : }
2246 4 : }
2247 :
2248 : /* Verify that we can parse a simple JSON-RPC request. */
2249 :
2250 : static void
2251 4 : test_parse_jsonrpc ()
2252 : {
2253 4 : std::unique_ptr<error> err;
2254 4 : const char *request
2255 : /* 0 1 2 3 4. */
2256 : /* 01 23456789 012 3456 789 0123456 789 012345678 90. */
2257 : = ("{\"jsonrpc\": \"2.0\", \"method\": \"subtract\",\n"
2258 : /* 0 1 2 3 4. */
2259 : /* 0 1234567 8901234567890 1234 56789012345678 90. */
2260 : " \"params\": [42, 23], \"id\": 1}");
2261 4 : const int line_1 = 1;
2262 4 : const int line_2 = 2;
2263 4 : const size_t line_2_offset = 41;
2264 4 : parser_testcase tc (request);
2265 4 : ASSERT_EQ (tc.get_error (), nullptr);
2266 4 : const json::value *jv = tc.get_value ();
2267 4 : ASSERT_NE (jv, nullptr);
2268 4 : auto range = tc.get_range_for_value (jv);
2269 4 : ASSERT_TRUE (range);
2270 4 : ASSERT_RANGE_EQ (*range,
2271 : 0, line_1, 0,
2272 : line_2_offset + 28, line_2, 28);
2273 4 : }
2274 :
2275 : /* Verify that we can parse an empty JSON object. */
2276 :
2277 : static void
2278 4 : test_parse_empty_object ()
2279 : {
2280 4 : const int line_1 = 1;
2281 4 : std::unique_ptr<error> err;
2282 4 : parser_testcase tc ("{}");
2283 4 : ASSERT_EQ (tc.get_error (), nullptr);
2284 4 : const json::value *jv = tc.get_value ();
2285 4 : ASSERT_NE (jv, nullptr);
2286 4 : ASSERT_EQ (jv->get_kind (), JSON_OBJECT);
2287 4 : ASSERT_PRINT_EQ (*jv, true, "{}");
2288 4 : auto range = tc.get_range_for_value (jv);
2289 4 : ASSERT_TRUE (range);
2290 4 : ASSERT_RANGE_EQ (*range,
2291 : 0, line_1, 0,
2292 : 1, line_1, 1);
2293 4 : }
2294 :
2295 : /* Verify that comment-parsing can be enabled or disabled. */
2296 :
2297 : static void
2298 4 : test_parsing_comments ()
2299 : {
2300 4 : const char *str = ("// foo\n"
2301 : "/*...\n"
2302 : "...*/ 42 // bar\n"
2303 : "/* etc */\n");
2304 :
2305 : /* Parsing with comment support disabled. */
2306 4 : {
2307 4 : parser_testcase tc (str);
2308 4 : ASSERT_NE (tc.get_error (), nullptr);
2309 4 : ASSERT_STREQ (tc.get_error ()->get_msg (),
2310 : "invalid JSON token: unexpected character: '/'");
2311 4 : ASSERT_EQ (tc.get_value (), nullptr);
2312 4 : }
2313 :
2314 : /* Parsing with comment support enabled. */
2315 4 : {
2316 4 : parser_testcase tc (str, true);
2317 4 : ASSERT_EQ (tc.get_error (), nullptr);
2318 4 : const json::value *jv = tc.get_value ();
2319 4 : ASSERT_NE (jv, nullptr);
2320 4 : ASSERT_EQ (jv->get_kind (), JSON_INTEGER);
2321 4 : ASSERT_EQ (((const json::integer_number *)jv)->get (), 42);
2322 4 : }
2323 4 : }
2324 :
2325 : /* Verify that JSON Pointers are correctly escaped. */
2326 :
2327 : static void
2328 4 : test_pointer_escaping ()
2329 : {
2330 4 : std::unique_ptr<error> err;
2331 : /* Example adapted from RFC 6901 section 5. */
2332 4 : parser_testcase tc
2333 : (" {\n"
2334 : " \"a/b\": 1,\n"
2335 : " \"m~n\": 8\n"
2336 4 : " }\n");
2337 4 : ASSERT_EQ (tc.get_error (), nullptr);
2338 4 : const json::value *jv = tc.get_value ();
2339 4 : ASSERT_NE (jv, nullptr);
2340 4 : ASSERT_EQ (jv->get_kind (), JSON_OBJECT);
2341 :
2342 4 : auto jo = static_cast <const json::object *> (jv);
2343 4 : ASSERT_JSON_POINTER_EQ (jo->get ("a/b"), "/a~1b");
2344 4 : ASSERT_JSON_POINTER_EQ (jo->get ("m~n"), "/m~0n");
2345 4 : }
2346 :
2347 : /* Verify that we can parse an empty JSON string. */
2348 :
2349 : static void
2350 4 : test_error_empty_string ()
2351 : {
2352 4 : const int line_1 = 1;
2353 4 : parser_testcase tc ("");
2354 4 : ASSERT_ERR_EQ (tc.get_error (),
2355 : 0, line_1, 0,
2356 : 0, line_1, 0,
2357 : "expected a JSON value but got EOF");
2358 4 : ASSERT_EQ (tc.get_value (), nullptr);
2359 4 : }
2360 :
2361 : /* Verify that JSON parsing gracefully handles an invalid token. */
2362 :
2363 : static void
2364 4 : test_error_bad_token ()
2365 : {
2366 4 : const int line_1 = 1;
2367 4 : parser_testcase tc (" not valid ");
2368 4 : ASSERT_ERR_EQ (tc.get_error (),
2369 : 2, line_1, 2,
2370 : 2, line_1, 2,
2371 : "invalid JSON token: unexpected character: 'n'");
2372 4 : ASSERT_EQ (tc.get_value (), nullptr);
2373 4 : }
2374 :
2375 : /* Verify that JSON parsing gracefully handles a missing comma
2376 : within an object. */
2377 :
2378 : static void
2379 4 : test_error_object_with_missing_comma ()
2380 : {
2381 4 : const int line_1 = 1;
2382 : /* 0 1 2. */
2383 : /* 01 2345 6789012 3456 7890. */
2384 4 : const char *json = "{\"foo\" : 42 \"bar\"";
2385 4 : parser_testcase tc (json);
2386 4 : ASSERT_ERR_EQ (tc.get_error (),
2387 : 12, line_1, 12,
2388 : 16, line_1, 16,
2389 : "expected ',' or '}'; got string");
2390 4 : ASSERT_EQ (tc.get_value (), nullptr);
2391 4 : }
2392 :
2393 : /* Verify that JSON parsing gracefully handles a missing comma
2394 : within an array. */
2395 :
2396 : static void
2397 4 : test_error_array_with_missing_comma ()
2398 : {
2399 4 : const int line_1 = 1;
2400 : /* 01234567. */
2401 4 : const char *json = "[0, 1 42]";
2402 4 : parser_testcase tc (json);
2403 4 : ASSERT_ERR_EQ (tc.get_error (),
2404 : 6, line_1, 6,
2405 : 7, line_1, 7,
2406 : "expected ',' or ']'; got number");
2407 4 : ASSERT_EQ (tc.get_value (), nullptr);
2408 4 : }
2409 :
2410 : /* Run all of the selftests within this file. */
2411 :
2412 : void
2413 4 : json_parser_cc_tests ()
2414 : {
2415 4 : test_lexer ();
2416 4 : test_lexing_unsupported_single_line_comment ();
2417 4 : test_lexing_unsupported_multiline_comment ();
2418 4 : test_lexing_supported_single_line_comment ();
2419 4 : test_lexing_supported_multiline_comment ();
2420 4 : test_parse_string ();
2421 4 : test_parse_number ();
2422 4 : test_parse_array ();
2423 4 : test_parse_object ();
2424 4 : test_parse_literals ();
2425 4 : test_parse_jsonrpc ();
2426 4 : test_parse_empty_object ();
2427 4 : test_parsing_comments ();
2428 4 : test_pointer_escaping ();
2429 4 : test_error_empty_string ();
2430 4 : test_error_bad_token ();
2431 4 : test_error_object_with_missing_comma ();
2432 4 : test_error_array_with_missing_comma ();
2433 4 : }
2434 :
2435 : } // namespace selftest
2436 :
2437 : #endif /* #if CHECKING_P */
|