31
char str[];
32
};
33
34
-typedef struct JSONParserContext {
35
- Error *err;
36
- JSONToken *current;
37
- GQueue *buf;
38
- va_list *ap;
39
-} JSONParserContext;
34
+/*
35
+ * The JSON parser is a push parser, returning a completed top-level
36
+ * object, an error, or NULL (if the object is incomplete and no error
37
+ * happened) after every token. Therefore it has an explicit
38
+ * representation of its parser stack; each stack entry consists of a
39
+ * parser state and a QObject: - a QList, for an array that is being
40
+ * added to - a QDict, for a dictionary that is being added to - a
41
+ * QString, for the key of the next pair that will be added to a QDict
42
+ *
43
+ * The stack represents an arbitrary nesting of arrays and dictionaries
44
+ * (whose next key has been parsed); it can also have a dictionary whose
45
+ * next key has not been parsed, but that can only happen at the top level.
46
+ * Because of this, the stack contents are always of the form
47
+ * "(QList | QDict QString)* QDict?".
48
+ *
49
+ * An empty stack represents the beginning of the parsing process, with
50
+ * start state BEFORE_VALUE.
51
+ */
52
+
53
+typedef enum JSONParserState {
54
+ AFTER_LCURLY,
55
+ AFTER_LSQUARE,
56
+ BEFORE_KEY,
57
+ BEFORE_VALUE,
58
+ END_OF_KEY,
59
+ END_OF_VALUE,
60
+} JSONParserState;
61
+
62
+typedef struct JSONParserStackEntry {
63
+ /*
64
+ * State when the container is completed or, for the top of the stack,
65
+ * entry state for the next token.
66
+ */
67
+ JSONParserState state;
68
+
69
+ /*
70
+ * A QString with the last parsed key, or a QList/QDict for the current
71
+ * container.
72
+ */
73
+ QObject *partial;
74
+} JSONParserStackEntry;
75
+
76
+/*
77
+ * This is the JSON grammar that's parsed, with the state transition and
78
+ * action at each point of the grammar. While this is not a formal
79
+ * description, "-> action" represents the pseudocode of the action
80
+ * and "-> STATE" sets the top stack entry's state to STATE.
81
+ *
82
+ * The state alone is enough to tell you what to parse; the state plus
83
+ * the type of the top of stack tells you which action to take.
84
+ *
85
+ * // The initial state is BEFORE_VALUE.
86
+ * input := value -> END_OF_VALUE -> return parsed value
87
+ * (input | END_OF_INPUT)
88
+ *
89
+ * // entered on BEFORE_VALUE; after any of these rules are processed, the
90
+ * // parser has completed a QObject and is in the END_OF_VALUE state.
91
+ * //
92
+ * // When the parser reaches the END_OF_VALUE state, it examines the
93
+ * // top of the stack to see if it's coming from "input" (stack empty),
94
+ * // "array_items" (TOS is a QList) or "dict_pairs" (TOS is a QString; the
95
+ * // item below will be a QDict). It then proceeds with the corresponding
96
+ * // actions, which will be one of:
97
+ * // - return parsed value
98
+ * // - add value to QList
99
+ * // - pop QString with the key, add key/value to the QDict
100
+ * value := literal -> END_OF_VALUE
101
+ * | '[' -> push empty QList -> AFTER_LSQUARE
102
+ * after_lsquare -> END_OF_VALUE
103
+ * | '{' -> push empty QDict -> AFTER_LCURLY
104
+ * after_lcurly -> END_OF_VALUE
105
+ *
106
+ * // non-recursive values, entered on BEFORE_VALUE
107
+ * literal := INTEGER -> END_OF_VALUE
108
+ * | FLOAT -> END_OF_VALUE
109
+ * | KEYWORD -> END_OF_VALUE
110
+ * | STRING -> END_OF_VALUE
111
+ * | INTERP -> END_OF_VALUE
112
+ *
113
+ * // entered on AFTER_LSQUARE
114
+ * after_lsquare := ']' -> pop completed QList -> END_OF_VALUE
115
+ * | ϵ -> BEFORE_VALUE
116
+ * array_items -> END_OF_VALUE
117
+ *
118
+ * // entered on BEFORE_VALUE, with TOS being a QList
119
+ * array_items := value -> add value to QList -> END_OF_VALUE
120
+ * (']' -> pop completed QList -> END_OF_VALUE
121
+ * | ',' -> BEFORE_VALUE
122
+ * array_items) -> END_OF_VALUE
123
+ *
124
+ * // entered on AFTER_LCURLY
125
+ * after_lcurly := '}' -> pop completed QDict -> END_OF_VALUE
126
+ * | ϵ -> BEFORE_KEY
127
+ * dict_pairs -> END_OF_VALUE
128
+ *
129
+ * // entered on BEFORE_KEY, with TOS being a QDict
130
+ * dict_pairs := (STRING | INTERP) -> push QString -> END_OF_KEY
131
+ * ':' -> BEFORE_VALUE
132
+ * value -> pop QString + add pair to QDict -> END_OF_VALUE
133
+ * ('}' -> pop completed QDict -> END_OF_VALUE
134
+ * | ',' -> BEFORE_KEY
135
+ * dict_pairs) -> END_OF_VALUE
136
+ *
137
+ * Parse errors ignore the token. json_parser_reset() can be
138
+ * called to restart parsing from scratch, with an empty stack.
139
+ */
140
141
#define BUG_ON(cond) assert(!(cond))
142
149
* 4) deal with premature EOI
150
*/
151
52
-static QObject *parse_value(JSONParserContext *ctxt);
152
+static inline JSONParserStackEntry *current_entry(JSONParserContext *ctxt)
153
+{
154
+ return g_queue_peek_tail(ctxt->stack);
155
+}
156
+
157
+static void push_entry(JSONParserContext *ctxt, QObject *partial,
158
+ JSONParserState state)
159
+{
160
+ JSONParserStackEntry *entry = g_new(JSONParserStackEntry, 1);
161
+ entry->partial = partial;
162
+ entry->state = state;
163
+ g_queue_push_tail(ctxt->stack, entry);
164
+}
165
+
166
+/* Drop the top entry and return the new top entry. */
167
+static JSONParserStackEntry *pop_entry(JSONParserContext *ctxt)
168
+{
169
+ JSONParserStackEntry *entry = g_queue_pop_tail(ctxt->stack);
170
+ g_free(entry);
171
+ return current_entry(ctxt);
172
+}
173
174
/**
175
* Error handler
356
return NULL;
357
}
358
239
-/* Note: the token object returned by parser_context_peek_token or
240
- * parser_context_pop_token is deleted as soon as parser_context_pop_token
241
- * is called again.
242
- */
243
-static const JSONToken *parser_context_pop_token(JSONParserContext *ctxt)
244
-{
245
- g_free(ctxt->current);
246
- ctxt->current = g_queue_pop_head(ctxt->buf);
247
- return ctxt->current;
248
-}
249
-
250
-static const JSONToken *parser_context_peek_token(JSONParserContext *ctxt)
251
-{
252
- return g_queue_peek_head(ctxt->buf);
253
-}
254
-
255
-/**
256
- * Parsing rules
257
- */
258
-static int parse_pair(JSONParserContext *ctxt, QDict *dict)
259
-{
260
- QObject *key_obj = NULL;
261
- QString *key;
262
- QObject *value;
263
- const JSONToken *peek, *token;
264
-
265
- peek = parser_context_peek_token(ctxt);
266
- if (peek == NULL) {
267
- parse_error(ctxt, NULL, "premature EOI");
268
- goto out;
269
- }
270
-
271
- key_obj = parse_value(ctxt);
272
- key = qobject_to(QString, key_obj);
273
- if (!key) {
274
- parse_error(ctxt, peek, "key is not a string in object");
275
- goto out;
276
- }
277
-
278
- token = parser_context_pop_token(ctxt);
279
- if (token == NULL) {
280
- parse_error(ctxt, NULL, "premature EOI");
281
- goto out;
282
- }
283
-
284
- if (token->type != JSON_COLON) {
285
- parse_error(ctxt, token, "missing : in object pair");
286
- goto out;
287
- }
288
-
289
- value = parse_value(ctxt);
290
- if (value == NULL) {
291
- parse_error(ctxt, token, "Missing value in dict");
292
- goto out;
293
- }
294
-
295
- if (qdict_haskey(dict, qstring_get_str(key))) {
296
- parse_error(ctxt, token, "duplicate key");
297
- goto out;
298
- }
299
-
300
- qdict_put_obj(dict, qstring_get_str(key), value);
301
-
302
- qobject_unref(key_obj);
303
- return 0;
304
-
305
-out:
306
- qobject_unref(key_obj);
307
- return -1;
308
-}
309
-
310
-static QObject *parse_object(JSONParserContext *ctxt)
311
-{
312
- QDict *dict = NULL;
313
- const JSONToken *token, *peek;
314
-
315
- token = parser_context_pop_token(ctxt);
316
- assert(token && token->type == JSON_LCURLY);
317
-
318
- dict = qdict_new();
319
-
320
- peek = parser_context_peek_token(ctxt);
321
- if (peek == NULL) {
322
- parse_error(ctxt, NULL, "premature EOI");
323
- goto out;
324
- }
325
-
326
- if (peek->type != JSON_RCURLY) {
327
- if (parse_pair(ctxt, dict) == -1) {
328
- goto out;
329
- }
330
-
331
- token = parser_context_pop_token(ctxt);
332
- if (token == NULL) {
333
- parse_error(ctxt, NULL, "premature EOI");
334
- goto out;
335
- }
336
-
337
- while (token->type != JSON_RCURLY) {
338
- if (token->type != JSON_COMMA) {
339
- parse_error(ctxt, token, "expected separator in dict");
340
- goto out;
341
- }
342
-
343
- if (parse_pair(ctxt, dict) == -1) {
344
- goto out;
345
- }
346
-
347
- token = parser_context_pop_token(ctxt);
348
- if (token == NULL) {
349
- parse_error(ctxt, NULL, "premature EOI");
350
- goto out;
351
- }
352
- }
353
- } else {
354
- (void)parser_context_pop_token(ctxt);
355
- }
356
-
357
- return QOBJECT(dict);
358
-
359
-out:
360
- qobject_unref(dict);
361
- return NULL;
362
-}
363
-
364
-static QObject *parse_array(JSONParserContext *ctxt)
365
-{
366
- QList *list = NULL;
367
- const JSONToken *token, *peek;
368
-
369
- token = parser_context_pop_token(ctxt);
370
- assert(token && token->type == JSON_LSQUARE);
371
-
372
- list = qlist_new();
373
-
374
- peek = parser_context_peek_token(ctxt);
375
- if (peek == NULL) {
376
- parse_error(ctxt, NULL, "premature EOI");
377
- goto out;
378
- }
379
-
380
- if (peek->type != JSON_RSQUARE) {
381
- QObject *obj;
382
-
383
- obj = parse_value(ctxt);
384
- if (obj == NULL) {
385
- parse_error(ctxt, token, "expecting value");
386
- goto out;
387
- }
388
-
389
- qlist_append_obj(list, obj);
390
-
391
- token = parser_context_pop_token(ctxt);
392
- if (token == NULL) {
393
- parse_error(ctxt, NULL, "premature EOI");
394
- goto out;
395
- }
396
-
397
- while (token->type != JSON_RSQUARE) {
398
- if (token->type != JSON_COMMA) {
399
- parse_error(ctxt, token, "expected separator in list");
400
- goto out;
401
- }
402
-
403
- obj = parse_value(ctxt);
404
- if (obj == NULL) {
405
- parse_error(ctxt, token, "expecting value");
406
- goto out;
407
- }
408
-
409
- qlist_append_obj(list, obj);
359
+/* Terminals */
360
411
- token = parser_context_pop_token(ctxt);
412
- if (token == NULL) {
413
- parse_error(ctxt, NULL, "premature EOI");
414
- goto out;
415
- }
416
- }
417
- } else {
418
- (void)parser_context_pop_token(ctxt);
419
- }
420
-
421
- return QOBJECT(list);
422
-
423
-out:
424
- qobject_unref(list);
425
- return NULL;
426
-}
427
-
428
-static QObject *parse_keyword(JSONParserContext *ctxt)
361
+static QObject *parse_keyword(JSONParserContext *ctxt, const JSONToken *token)
362
{
430
- const JSONToken *token;
431
-
432
- token = parser_context_pop_token(ctxt);
363
assert(token && token->type == JSON_KEYWORD);
364
365
if (!strcmp(token->str, "true")) {
373
return NULL;
374
}
375
446
-static QObject *parse_interpolation(JSONParserContext *ctxt)
376
+static QObject *parse_interpolation(JSONParserContext *ctxt,
377
+ const JSONToken *token)
378
{
448
- const JSONToken *token;
449
-
450
- token = parser_context_pop_token(ctxt);
379
assert(token && token->type == JSON_INTERP);
380
381
if (!strcmp(token->str, "%p")) {
407
return NULL;
408
}
409
482
-static QObject *parse_literal(JSONParserContext *ctxt)
410
+static QObject *parse_literal(JSONParserContext *ctxt, const JSONToken *token)
411
{
484
- const JSONToken *token;
485
-
486
- token = parser_context_pop_token(ctxt);
412
assert(token);
413
414
switch (token->type) {
456
}
457
}
458
534
-static QObject *parse_value(JSONParserContext *ctxt)
535
-{
536
- const JSONToken *token;
537
-
538
- token = parser_context_peek_token(ctxt);
539
- if (token == NULL) {
540
- parse_error(ctxt, NULL, "premature EOI");
541
- return NULL;
542
- }
459
+/* Parsing state machine */
460
461
+static QObject *parse_begin_value(JSONParserContext *ctxt,
462
+ const JSONToken *token)
463
+{
464
switch (token->type) {
465
case JSON_LCURLY:
546
- return parse_object(ctxt);
466
+ push_entry(ctxt, QOBJECT(qdict_new()), AFTER_LCURLY);
467
+ return NULL;
468
case JSON_LSQUARE:
548
- return parse_array(ctxt);
469
+ push_entry(ctxt, QOBJECT(qlist_new()), AFTER_LSQUARE);
470
+ return NULL;
471
case JSON_INTERP:
550
- return parse_interpolation(ctxt);
472
+ return parse_interpolation(ctxt, token);
473
case JSON_INTEGER:
474
case JSON_FLOAT:
475
case JSON_STRING:
554
- return parse_literal(ctxt);
476
+ return parse_literal(ctxt, token);
477
case JSON_KEYWORD:
556
- return parse_keyword(ctxt);
478
+ return parse_keyword(ctxt, token);
479
default:
480
parse_error(ctxt, token, "expecting value");
481
return NULL;
482
}
483
}
484
485
+static QObject *parse_token(JSONParserContext *ctxt, const JSONToken *token)
486
+{
487
+ JSONParserStackEntry *entry;
488
+ JSONParserState state;
489
+ QString *key;
490
+ QObject *key_obj = NULL, *value = NULL;
491
+
492
+ entry = current_entry(ctxt);
493
+ state = entry ? entry->state : BEFORE_VALUE;
494
+ switch (state) {
495
+ case AFTER_LCURLY:
496
+ /* Grab '}' for empty object or fall through to BEFORE_KEY */
497
+ assert(qobject_type(entry->partial) == QTYPE_QDICT);
498
+ if (token->type == JSON_RCURLY) {
499
+ value = entry->partial;
500
+ entry = pop_entry(ctxt);
501
+ break;
502
+ }
503
+ entry->state = BEFORE_KEY;
504
+ /* fall through */
505
+
506
+ case BEFORE_KEY:
507
+ /* Expecting object key */
508
+ assert(qobject_type(entry->partial) == QTYPE_QDICT);
509
+ if (token->type != JSON_STRING && token->type != JSON_INTERP) {
510
+ parse_error(ctxt, token, "expecting key");
511
+ return NULL;
512
+ }
513
+
514
+ key_obj = parse_begin_value(ctxt, token);
515
+ if (!key_obj) {
516
+ /* Parse error already reported */
517
+ } else if (qobject_type(key_obj) != QTYPE_QSTRING) {
518
+ /* An interpolation was valid syntactically but not %s */
519
+ parse_error(ctxt, token, "key is not a string in object");
520
+ } else {
521
+ /* Store key in a special entry on the stack */
522
+ push_entry(ctxt, key_obj, END_OF_KEY);
523
+ }
524
+ return NULL;
525
+
526
+ case END_OF_KEY:
527
+ /* Expecting ':' after key */
528
+ assert(qobject_type(entry->partial) == QTYPE_QSTRING);
529
+ if (token->type == JSON_COLON) {
530
+ entry->state = BEFORE_VALUE;
531
+ } else {
532
+ parse_error(ctxt, token, "expecting ':'");
533
+ }
534
+ return NULL;
535
+
536
+ case AFTER_LSQUARE:
537
+ /* Grab ']' for empty array or fall through to BEFORE_VALUE */
538
+ assert(qobject_type(entry->partial) == QTYPE_QLIST);
539
+ if (token->type == JSON_RSQUARE) {
540
+ value = entry->partial;
541
+ entry = pop_entry(ctxt);
542
+ break;
543
+ }
544
+ entry->state = BEFORE_VALUE;
545
+ /* fall through */
546
+
547
+ case BEFORE_VALUE:
548
+ /* Expecting value */
549
+ assert(!entry || qobject_type(entry->partial) != QTYPE_QDICT);
550
+ value = parse_begin_value(ctxt, token);
551
+ if (!value) {
552
+ /* Error or '['/'{' */
553
+ return NULL;
554
+ }
555
+ /* Return value or insert it into a container */
556
+ break;
557
+
558
+ case END_OF_VALUE:
559
+ /* Grab ',' or ']' for array; ',' or '}' for object */
560
+ if (qobject_to(QList, entry->partial)) {
561
+ /* Array */
562
+ if (token->type != JSON_RSQUARE) {
563
+ if (token->type == JSON_COMMA) {
564
+ entry->state = BEFORE_VALUE;
565
+ } else {
566
+ parse_error(ctxt, token, "expected ',' or ']'");
567
+ }
568
+ return NULL;
569
+ }
570
+ } else if (qobject_to(QDict, entry->partial)) {
571
+ /* Object */
572
+ if (token->type != JSON_RCURLY) {
573
+ if (token->type == JSON_COMMA) {
574
+ entry->state = BEFORE_KEY;
575
+ } else {
576
+ parse_error(ctxt, token, "expected ',' or '}'");
577
+ }
578
+ return NULL;
579
+ }
580
+ } else {
581
+ g_assert_not_reached();
582
+ }
583
+
584
+ /* Got ']' or '}'; return full value or insert into parent container */
585
+ value = entry->partial;
586
+ entry = pop_entry(ctxt);
587
+ break;
588
+ }
589
+
590
+ assert(value);
591
+ if (entry == NULL) {
592
+ /* Parse stack now empty, the top-level value is complete. */
593
+ return value;
594
+ }
595
+
596
+ /*
597
+ * Parse stack is not empty and entry->partial is the top of stack.
598
+ * It's a QString with the key (and a QDict is below it) if we're
599
+ * parsing an object, or a QList if we're parsing an array.
600
+ */
601
+ key = qobject_to(QString, entry->partial);
602
+ if (key) {
603
+ const char *key_str;
604
+ QDict *dict;
605
+
606
+ /* Pop off key, and store (key, value) in QDict. */
607
+ entry = pop_entry(ctxt);
608
+ dict = qobject_to(QDict, entry->partial);
609
+ assert(dict);
610
+ key_str = qstring_get_str(key);
611
+ if (qdict_haskey(dict, key_str)) {
612
+ parse_error(ctxt, token, "duplicate key");
613
+ qobject_unref(value);
614
+ return NULL;
615
+ }
616
+ qdict_put_obj(dict, key_str, value);
617
+ qobject_unref(key);
618
+ } else {
619
+ /* Array, just store value in the QList. */
620
+ qlist_append_obj(qobject_to(QList, entry->partial), value);
621
+ }
622
+
623
+ entry->state = END_OF_VALUE;
624
+ return NULL;
625
+}
626
+
627
JSONToken *json_token(JSONTokenType type, int x, int y, GString *tokstr)
628
{
629
JSONToken *token = g_malloc(sizeof(JSONToken) + tokstr->len + 1);
636
return token;
637
}
638
575
-QObject *json_parser_parse(GQueue *tokens, va_list *ap, Error **errp)
639
+void json_parser_reset(JSONParserContext *ctxt)
640
{
577
- JSONParserContext ctxt = { .buf = tokens, .ap = ap };
578
- QObject *result;
641
+ JSONParserStackEntry *entry;
642
580
- result = parse_value(&ctxt);
581
- assert(ctxt.err || g_queue_is_empty(ctxt.buf));
643
+ ctxt->err = NULL;
644
+ while ((entry = g_queue_pop_tail(ctxt->stack)) != NULL) {
645
+ qobject_unref(entry->partial);
646
+ g_free(entry);
647
+ }
648
+}
649
583
- error_propagate(errp, ctxt.err);
650
+void json_parser_init(JSONParserContext *ctxt, va_list *ap)
651
+{
652
+ ctxt->stack = g_queue_new();
653
+ ctxt->ap = ap;
654
+ json_parser_reset(ctxt);
655
+}
656
585
- while (!g_queue_is_empty(ctxt.buf)) {
586
- parser_context_pop_token(&ctxt);
657
+void json_parser_destroy(JSONParserContext *ctxt)
658
+{
659
+ json_parser_reset(ctxt);
660
+ g_queue_free(ctxt->stack);
661
+ ctxt->stack = NULL;
662
+}
663
+
664
+/*
665
+ * Advance the parser based on the token that is passed.
666
+ * Return the finished top-level value if the token completes it, else
667
+ * NULL.
668
+ * Once an error is returned, the function must not be called again
669
+ * without first resetting the parser.
670
+ */
671
+QObject *json_parser_feed(JSONParserContext *ctxt, const JSONToken *token,
672
+ Error **errp)
673
+{
674
+ QObject *result = NULL;
675
+
676
+ assert(!ctxt->err);
677
+ switch (token->type) {
678
+ case JSON_END_OF_INPUT:
679
+ /* Check for premature end of input */
680
+ if (!g_queue_is_empty(ctxt->stack)) {
681
+ parse_error(ctxt, token, "premature end of input");
682
+ }
683
+ break;
684
+
685
+ default:
686
+ result = parse_token(ctxt, token);
687
+ break;
688
}
588
- g_free(ctxt.current);
689
690
+ error_propagate(errp, ctxt->err);
691
return result;
692
}