codegen_c_json_parser.c (69028B)
1 #include <stdlib.h> 2 #include "codegen_c.h" 3 #include "flatcc/flatcc_types.h" 4 #include "catalog.h" 5 6 /* -DFLATCC_PORTABLE may help if inttypes.h is missing. */ 7 #ifndef PRId64 8 #include <inttypes.h> 9 #endif 10 11 #define PRINTLN_SPMAX 64 12 static char println_spaces[PRINTLN_SPMAX]; 13 14 static void println(fb_output_t *out, const char * format, ...) 15 { 16 int i = out->indent * out->opts->cgen_spacing; 17 va_list ap; 18 19 if (println_spaces[0] == 0) { 20 memset(println_spaces, 0x20, PRINTLN_SPMAX); 21 } 22 /* Don't indent on blank lines. */ 23 if (*format) { 24 while (i > PRINTLN_SPMAX) { 25 fprintf(out->fp, "%.*s", (int)PRINTLN_SPMAX, println_spaces); 26 i -= PRINTLN_SPMAX; 27 } 28 /* Use modulo to reset margin if we go too far. */ 29 fprintf(out->fp, "%.*s", i, println_spaces); 30 va_start (ap, format); 31 vfprintf (out->fp, format, ap); 32 va_end (ap); 33 } 34 fprintf(out->fp, "\n"); 35 } 36 37 /* 38 * Unknown fields and unknown union members can be failed 39 * rather than ignored with a config flag. 40 * 41 * Default values an be forced with a config flat. 42 * 43 * Forward schema isn't perfect: Unknown symbolic constants 44 * cannot be used with known fields but will be ignored 45 * in ignored fields. 46 */ 47 48 static int gen_json_parser_pretext(fb_output_t *out) 49 { 50 println(out, "#ifndef %s_JSON_PARSER_H", out->S->basenameup); 51 println(out, "#define %s_JSON_PARSER_H", out->S->basenameup); 52 println(out, ""); 53 println(out, "/* " FLATCC_GENERATED_BY " */"); 54 println(out, ""); 55 println(out, "#include \"flatcc/flatcc_json_parser.h\""); 56 fb_gen_c_includes(out, "_json_parser.h", "_JSON_PARSER_H"); 57 gen_prologue(out); 58 println(out, ""); 59 return 0; 60 } 61 62 static int gen_json_parser_footer(fb_output_t *out) 63 { 64 gen_epilogue(out); 65 println(out, "#endif /* %s_JSON_PARSER_H */", out->S->basenameup); 66 return 0; 67 } 68 69 typedef struct dict_entry dict_entry_t; 70 struct dict_entry { 71 const char *text; 72 int len; 73 void *data; 74 int hint; 75 }; 76 77 /* Returns length of name that reminds after tag at current position. */ 78 static int get_dict_suffix_len(dict_entry_t *de, int pos) 79 { 80 int n; 81 82 n = de->len; 83 if (pos + 8 > n) { 84 return 0; 85 } 86 return n - pos - 8; 87 } 88 89 /* 90 * Returns the length name that reminds if it terminates at the tag 91 * and 0 if it has a suffix. 92 */ 93 static int get_dict_tag_len(dict_entry_t *de, int pos) 94 { 95 int n; 96 97 n = de->len; 98 if (pos + 8 >= n) { 99 return n - pos; 100 } 101 return 0; 102 } 103 104 /* 105 * 8 byte word part of the name starting at characert `pos` in big 106 * endian encoding with first char always at msb, zero padded at lsb. 107 * Returns length of tag [0;8]. 108 */ 109 static int get_dict_tag(dict_entry_t *de, int pos, uint64_t *tag, uint64_t *mask, 110 const char **tag_name, int *tag_len) 111 { 112 int i, n = 0; 113 const char *a = 0; 114 uint64_t w = 0; 115 116 if (pos > de->len) { 117 goto done; 118 } 119 a = de->text + pos; 120 n = de->len - pos; 121 if (n > 8) { 122 n = 8; 123 } 124 i = n; 125 while (i--) { 126 w |= ((uint64_t)a[i]) << (56 - (i * 8)); 127 } 128 *tag = w; 129 *mask = ~(((uint64_t)(1) << (8 - n) * 8) - 1); 130 done: 131 if (tag_name) { 132 *tag_name = a; 133 } 134 if (tag_len) { 135 *tag_len = n; 136 } 137 return n; 138 } 139 140 141 /* 142 * Find the median, but move earlier if the previous entry 143 * is a strict prefix within the range. 144 * 145 * `b` is inclusive. 146 * 147 * The `pos` is a window into the key at an 8 byte multiple. 148 * 149 * Only consider the range `[pos;pos+8)` and move the median 150 * up if an earlier key is a prefix or match within this 151 * window. This is needed to handle trailing data in 152 * a compared external key, and also to handle sub-tree 153 * branching when two keys has same tag at pos. 154 * 155 * Worst case we get a linear search of length 8 if all 156 * keys are perfect prefixes of their successor key: 157 * `a, ab, abc, ..., abcdefgh` 158 * While the midpoint stills seeks towards 'a' for longer 159 * such sequences, the branch logic will pool those 160 * squences the share prefix groups of length 8. 161 */ 162 static int split_dict_left(dict_entry_t *dict, int a, int b, int pos) 163 { 164 int m = a + (b - a) / 2; 165 uint64_t wf = 0, wg = 0, wmf = 0, wmg = 0; 166 167 while (m > a) { 168 get_dict_tag(&dict[m - 1], pos, &wf, &wmf, 0, 0); 169 get_dict_tag(&dict[m], pos, &wg, &wmg, 0, 0); 170 if (((wf ^ wg) & wmf) != 0) { 171 return m; 172 } 173 --m; 174 } 175 return m; 176 } 177 178 /* 179 * When multiple tags are identical after split_dict_left has moved 180 * intersection up so a == m, we need to split in the opposite direction 181 * to ensure progress untill all tags in the range are identical 182 * at which point the trie must descend. 183 * 184 * If all tags are the same from intersection to end, b + 1 is returned 185 * which is not a valid element. 186 */ 187 static int split_dict_right(dict_entry_t *dict, int a, int b, int pos) 188 { 189 int m = a + (b - a) / 2; 190 uint64_t wf = 0, wg = 0, wmf = 0, wmg = 0; 191 192 while (m < b) { 193 get_dict_tag(&dict[m], pos, &wf, &wmf, 0, 0); 194 get_dict_tag(&dict[m + 1], pos, &wg, &wmg, 0, 0); 195 if (((wf ^ wg) & wmf) != 0) { 196 return m + 1; 197 } 198 ++m; 199 } 200 return m + 1; 201 } 202 203 /* 204 * Returns the first index where the tag does not terminate at 205 * [pos..pos+7], or b + 1 if none exists. 206 */ 207 static int split_dict_descend(dict_entry_t *dict, int a, int b, int pos) 208 { 209 while (a <= b) { 210 if (0 < get_dict_suffix_len(&dict[a], pos)) { 211 break; 212 } 213 ++a; 214 } 215 return a; 216 } 217 218 219 static int dict_cmp(const void *x, const void *y) 220 { 221 const dict_entry_t *a = x, *b = y; 222 int k, n = a->len > b->len ? b->len : a->len; 223 224 k = memcmp(a->text, b->text, (size_t)n); 225 return k ? k : a->len - b->len; 226 } 227 228 /* Includes union vectors. */ 229 static inline int is_union_member(fb_member_t *member) 230 { 231 return (member->type.type == vt_compound_type_ref || member->type.type == vt_vector_compound_type_ref) 232 && member->type.ct->symbol.kind == fb_is_union; 233 } 234 235 static dict_entry_t *build_compound_dict(fb_compound_type_t *ct, int *count_out) 236 { 237 fb_symbol_t *sym; 238 fb_member_t *member; 239 size_t n; 240 dict_entry_t *dict, *de; 241 char *strbuf = 0; 242 size_t strbufsiz = 0; 243 int is_union; 244 size_t union_index = 0; 245 246 n = 0; 247 for (sym = ct->members; sym; sym = sym->link) { 248 member = (fb_member_t *)sym; 249 if (member->metadata_flags & fb_f_deprecated) { 250 continue; 251 } 252 is_union = is_union_member(member); 253 if (is_union) { 254 ++n; 255 strbufsiz += (size_t)member->symbol.ident->len + 6; 256 } 257 ++n; 258 } 259 *count_out = (int)n; 260 if (n == 0) { 261 return 0; 262 } 263 dict = malloc(n * sizeof(dict_entry_t) + strbufsiz); 264 if (!dict) { 265 return 0; 266 } 267 strbuf = (char *)dict + n * sizeof(dict_entry_t); 268 de = dict; 269 for (sym = ct->members; sym; sym = sym->link) { 270 member = (fb_member_t *)sym; 271 if (member->metadata_flags & fb_f_deprecated) { 272 continue; 273 } 274 de->text = member->symbol.ident->text; 275 de->len = (int)member->symbol.ident->len; 276 de->data = member; 277 de->hint = 0; 278 ++de; 279 is_union = is_union_member(member); 280 if (is_union) { 281 member->export_index = union_index++; 282 de->len = (int)member->symbol.ident->len + 5; 283 de->text = strbuf; 284 memcpy(strbuf, member->symbol.ident->text, (size_t)member->symbol.ident->len); 285 strbuf += member->symbol.ident->len; 286 strcpy(strbuf, "_type"); 287 strbuf += 6; 288 de->data = member; 289 de->hint = 1; 290 ++de; 291 } 292 } 293 qsort(dict, n, sizeof(dict[0]), dict_cmp); 294 return dict; 295 } 296 297 typedef struct { 298 int count; 299 fb_schema_t *schema; 300 dict_entry_t *de; 301 } install_enum_context_t; 302 303 static void count_visible_enum_symbol(void *context, fb_symbol_t *sym) 304 { 305 install_enum_context_t *p = context; 306 307 if (get_enum_if_visible(p->schema, sym)) { 308 p->count++; 309 } 310 } 311 312 static void install_visible_enum_symbol(void *context, fb_symbol_t *sym) 313 { 314 install_enum_context_t *p = context; 315 316 if (get_enum_if_visible(p->schema, sym)) { 317 p->de->text = sym->ident->text; 318 p->de->len = (int)sym->ident->len; 319 p->de->data = sym; 320 p->de++; 321 } 322 } 323 324 /* 325 * A scope dictionary contains all the enum types defined under the given 326 * namespace of the scope. The actually namespace is not contained in 327 * the name - it is an implicit prefix. It is used when looking up a 328 * symbolic constant assigned to a field such that the constant is first 329 * searched for in the same scope (namespace) as the one that defined 330 * the table owning the field assigned to. If that fails, a global 331 * namespace prefixed lookup is needed, but this is separate from this 332 * dictionary. In case of conflicts the local scope takes precedence 333 * and must be searched first. Because each table parsed can a have a 334 * unique local scope, we cannot install the the unprefixed lookup in 335 * the same dictionary as the global lookup. 336 * 337 * NOTE: the scope may have been contanimated by being expanded by a 338 * parent schema so we check that each symbol is visible to the current 339 * schema. If we didn't do this, we would risk referring to enum parsers 340 * that are not included in the generated source. The default empty 341 * namespace (i.e. scope) is an example where this easily could happen. 342 */ 343 static dict_entry_t *build_local_scope_dict(fb_schema_t *schema, fb_scope_t *scope, int *count_out) 344 { 345 dict_entry_t *dict; 346 install_enum_context_t iec; 347 348 fb_clear(iec); 349 350 iec.schema = schema; 351 352 fb_symbol_table_visit(&scope->symbol_index, count_visible_enum_symbol, &iec); 353 *count_out = iec.count; 354 355 if (iec.count == 0) { 356 return 0; 357 } 358 dict = malloc((size_t)iec.count * sizeof(dict[0])); 359 if (!dict) { 360 return 0; 361 } 362 iec.de = dict; 363 fb_symbol_table_visit(&scope->symbol_index, install_visible_enum_symbol, &iec); 364 qsort(dict, (size_t)iec.count, sizeof(dict[0]), dict_cmp); 365 return dict; 366 } 367 368 static dict_entry_t *build_global_scope_dict(catalog_t *catalog, int *count_out) 369 { 370 size_t i, n = (size_t)catalog->nenums; 371 dict_entry_t *dict; 372 373 *count_out = (int)n; 374 if (n == 0) { 375 return 0; 376 } 377 dict = malloc(n * sizeof(dict[0])); 378 if (!dict) { 379 return 0; 380 } 381 for (i = 0; i < (size_t)catalog->nenums; ++i) { 382 dict[i].text = catalog->enums[i].name; 383 dict[i].len = (int)strlen(catalog->enums[i].name); 384 dict[i].data = catalog->enums[i].ct; 385 dict[i].hint = 0; 386 } 387 qsort(dict, (size_t)catalog->nenums, sizeof(dict[0]), dict_cmp); 388 *count_out = catalog->nenums; 389 return dict; 390 } 391 392 static void clear_dict(dict_entry_t *dict) 393 { 394 if (dict) { 395 free(dict); 396 } 397 } 398 399 static int gen_field_match_handler(fb_output_t *out, fb_compound_type_t *ct, void *data, int is_union_type) 400 { 401 fb_member_t *member = data; 402 fb_scoped_name_t snref; 403 fb_symbol_text_t scope_name; 404 405 int is_struct_container; 406 int is_string = 0; 407 int is_enum = 0; 408 int is_vector = 0; 409 int is_offset = 0; 410 int is_scalar = 0; 411 int is_optional = 0; 412 int is_table = 0; 413 int is_struct = 0; 414 int is_union = 0; 415 int is_union_vector = 0; 416 int is_union_type_vector = 0; 417 int is_base64 = 0; 418 int is_base64url = 0; 419 int is_nested = 0; 420 int is_array = 0; 421 int is_char_array = 0; 422 size_t array_len = 0; 423 fb_scalar_type_t st = 0; 424 const char *tname_prefix = "n/a", *tname = "n/a"; /* suppress compiler warnigns */ 425 fb_literal_t literal; 426 427 fb_clear(snref); 428 429 fb_copy_scope(ct->scope, scope_name); 430 is_struct_container = ct->symbol.kind == fb_is_struct; 431 is_optional = !!(member->flags & fb_fm_optional); 432 433 switch (member->type.type) { 434 case vt_vector_type: 435 case vt_vector_compound_type_ref: 436 case vt_vector_string_type: 437 is_vector = 1; 438 break; 439 } 440 441 switch (member->type.type) { 442 case vt_fixed_array_compound_type_ref: 443 case vt_vector_compound_type_ref: 444 case vt_compound_type_ref: 445 fb_compound_name(member->type.ct, &snref); 446 is_enum = member->type.ct->symbol.kind == fb_is_enum; 447 is_struct = member->type.ct->symbol.kind == fb_is_struct; 448 is_table = member->type.ct->symbol.kind == fb_is_table; 449 is_union = member->type.ct->symbol.kind == fb_is_union && !is_union_type; 450 if (is_enum) { 451 st = member->type.ct->type.st; 452 is_scalar = 1; 453 } 454 break; 455 case vt_vector_string_type: 456 case vt_string_type: 457 is_string = 1; 458 break; 459 case vt_vector_type: 460 /* Nested types are processed twice, once as an array, once as an object. */ 461 is_nested = member->nest != 0; 462 is_base64 = member->metadata_flags & fb_f_base64; 463 is_base64url = member->metadata_flags & fb_f_base64url; 464 is_scalar = 1; 465 st = member->type.st; 466 break; 467 case vt_fixed_array_type: 468 is_scalar = 1; 469 is_array = 1; 470 array_len = member->type.len; 471 st = member->type.st; 472 break; 473 case vt_scalar_type: 474 is_scalar = 1; 475 st = member->type.st; 476 break; 477 } 478 if (member->type.type == vt_fixed_array_compound_type_ref) { 479 assert(is_struct_container); 480 is_array = 1; 481 array_len = member->type.len; 482 } 483 if (is_base64 || is_base64url) { 484 /* Even if it is nested, parse it as a regular base64 or base64url encoded vector. */ 485 if (st != fb_ubyte || !is_vector) { 486 gen_panic(out, "internal error: unexpected base64 or base64url field type\n"); 487 return -1; 488 } 489 is_nested = 0; 490 is_vector = 0; 491 is_scalar = 0; 492 } 493 if (is_union_type) { 494 is_scalar = 0; 495 } 496 if (is_vector && is_union_type) { 497 is_union_type_vector = 1; 498 is_vector = 0; 499 } 500 if (is_vector && is_union) { 501 is_union_vector = 1; 502 is_vector = 0; 503 } 504 if (is_array && is_scalar && st == fb_char) { 505 is_array = 0; 506 is_scalar = 0; 507 is_char_array = 1; 508 } 509 if (is_nested == 1) { 510 println(out, "if (buf != end && *buf == '[') { /* begin nested */"); indent(); 511 } 512 repeat_nested: 513 if (is_nested == 2) { 514 unindent(); println(out, "} else { /* nested */"); indent(); 515 fb_compound_name((fb_compound_type_t *)&member->nest->symbol, &snref); 516 if (member->nest->symbol.kind == fb_is_table) { 517 is_table = 1; 518 } else { 519 is_struct = 1; 520 } 521 is_vector = 0; 522 is_scalar = 0; 523 println(out, "if (flatcc_builder_start_buffer(ctx->ctx, 0, 0, 0)) goto failed;"); 524 } 525 is_offset = !is_scalar && !is_struct && !is_union_type; 526 527 if (is_scalar) { 528 tname_prefix = scalar_type_prefix(st); 529 tname = st == fb_bool ? "uint8_t" : scalar_type_name(st); 530 } 531 532 /* Other types can also be vector, so we wrap. */ 533 if (is_vector) { 534 if (is_offset) { 535 println(out, "if (flatcc_builder_start_offset_vector(ctx->ctx)) goto failed;"); 536 } else { 537 println(out, 538 "if (flatcc_builder_start_vector(ctx->ctx, %"PRIu64", %hu, UINT64_C(%"PRIu64"))) goto failed;", 539 (uint64_t)member->size, (short)member->align, 540 (uint64_t)FLATBUFFERS_COUNT_MAX(member->size)); 541 } 542 } 543 if (is_array) { 544 if (is_scalar) { 545 println(out, "size_t count = %d;", array_len); 546 println(out, "%s *base = (%s *)((size_t)struct_base + %"PRIu64");", 547 tname, tname, (uint64_t)member->offset); 548 } 549 else { 550 println(out, "size_t count = %d;", array_len); 551 println(out, "void *base = (void *)((size_t)struct_base + %"PRIu64");", 552 (uint64_t)member->offset); 553 } 554 } 555 if (is_char_array) { 556 println(out, "char *base = (char *)((size_t)struct_base + %"PRIu64");", 557 (uint64_t)member->offset); 558 println(out, "buf = flatcc_json_parser_char_array(ctx, buf, end, base, %d);", array_len); 559 } 560 if (is_array || is_vector) { 561 println(out, "buf = flatcc_json_parser_array_start(ctx, buf, end, &more);"); 562 /* Note that we reuse `more` which is safe because it is updated at the end of the main loop. */ 563 println(out, "while (more) {"); indent(); 564 } 565 if (is_scalar) { 566 println(out, "%s val = 0;", tname); 567 println(out, "static flatcc_json_parser_integral_symbol_f *symbolic_parsers[] = {"); 568 indent(); indent(); 569 /* 570 * The scope name may be empty when no namespace is used. In that 571 * case the global scope is the same, but performance the 572 * duplicate doesn't matter. 573 */ 574 if (is_enum) { 575 println(out, "%s_parse_json_enum,", snref.text); 576 println(out, "%s_local_%sjson_parser_enum,", out->S->basename, scope_name); 577 println(out, "%s_global_json_parser_enum, 0 };", out->S->basename); 578 } else { 579 println(out, "%s_local_%sjson_parser_enum,", out->S->basename, scope_name); 580 println(out, "%s_global_json_parser_enum, 0 };", out->S->basename); 581 } 582 unindent(); unindent(); 583 } 584 /* It is not safe to acquire the pointer before building element table or string. */ 585 if (is_vector && !is_offset) { 586 println(out, "if (!(pval = flatcc_builder_extend_vector(ctx->ctx, 1))) goto failed;"); 587 } 588 if (is_struct_container) { 589 if (!is_array && !is_char_array) { 590 /* `struct_base` is given as argument to struct parsers. */ 591 println(out, "pval = (void *)((size_t)struct_base + %"PRIu64");", (uint64_t)member->offset); 592 } 593 } else if (is_struct && !is_vector) { 594 /* Same logic as scalars in tables, but scalars must be tested for default. */ 595 println(out, 596 "if (!(pval = flatcc_builder_table_add(ctx->ctx, %"PRIu64", %"PRIu64", %"PRIu16"))) goto failed;", 597 (uint64_t)member->id, (uint64_t)member->size, (uint16_t)member->align); 598 } 599 if (is_scalar) { 600 println(out, "buf = flatcc_json_parser_%s(ctx, (mark = buf), end, &val);", tname_prefix); 601 println(out, "if (mark == buf) {"); indent(); 602 println(out, "buf = flatcc_json_parser_symbolic_%s(ctx, (mark = buf), end, symbolic_parsers, &val);", tname_prefix); 603 println(out, "if (buf == mark || buf == end) goto failed;"); 604 unindent(); println(out, "}"); 605 if (!is_struct_container && !is_vector && !is_base64 && !is_base64url) { 606 #if !FLATCC_JSON_PARSE_FORCE_DEFAULTS 607 /* We need to create a check for the default value and create a table field if not the default. */ 608 if (!is_optional) { 609 if (!print_literal(st, &member->value, literal)) return -1; 610 println(out, "if (val != %s || (ctx->flags & flatcc_json_parser_f_force_add)) {", literal); indent(); 611 } 612 #endif 613 println(out, "if (!(pval = flatcc_builder_table_add(ctx->ctx, %"PRIu64", %"PRIu64", %hu))) goto failed;", 614 (uint64_t)member->id, (uint64_t)member->size, (short)member->align); 615 #if !FLATCC_JSON_PARSE_FORCE_DEFAULTS 616 #endif 617 } 618 /* For scalars in table field, and in struct container. */ 619 if (is_array) { 620 println(out, "if (count) {"); indent(); 621 println(out, "%s%s_write_to_pe(base, val);", out->nsc, tname_prefix); 622 println(out, "--count;"); 623 println(out, "++base;"); 624 unindent(); println(out, "} else if (!(ctx->flags & flatcc_json_parser_f_skip_array_overflow)) {"); indent(); 625 println(out, "return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_array_overflow);"); 626 unindent(); println(out, "}"); 627 } else { 628 println(out, "%s%s_write_to_pe(pval, val);", out->nsc, tname_prefix); 629 } 630 if (!is_struct_container && !is_vector && !(is_scalar && is_optional)) { 631 unindent(); println(out, "}"); 632 } 633 } else if (is_struct) { 634 if (is_array) { 635 println(out, "if (count) {"); indent(); 636 println(out, "buf = %s_parse_json_struct_inline(ctx, buf, end, base);", snref.text); 637 println(out, "--count;"); 638 println(out, "base = (void *)((size_t)base + %"PRIu64");", member->type.ct->size); 639 unindent(); println(out, "} else if (!(ctx->flags & flatcc_json_parser_f_skip_array_overflow)) {"); indent(); 640 println(out, "return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_array_overflow);"); 641 unindent(); println(out, "}"); 642 } else { 643 println(out, "buf = %s_parse_json_struct_inline(ctx, buf, end, pval);", snref.text); 644 } 645 } else if (is_string) { 646 println(out, "buf = flatcc_json_parser_build_string(ctx, buf, end, &ref);"); 647 } else if (is_base64 || is_base64url) { 648 println(out, "buf = flatcc_json_parser_build_uint8_vector_base64(ctx, buf, end, &ref, %u);", 649 !is_base64); 650 } else if (is_table) { 651 println(out, "buf = %s_parse_json_table(ctx, buf, end, &ref);", snref.text); 652 } else if (is_union) { 653 if (is_union_vector) { 654 println(out, "buf = flatcc_json_parser_union_vector(ctx, buf, end, %"PRIu64", %"PRIu64", h_unions, %s_parse_json_union);", 655 (uint64_t)member->export_index, member->id, snref.text); 656 } else { 657 println(out, "buf = flatcc_json_parser_union(ctx, buf, end, %"PRIu64", %"PRIu64", h_unions, %s_parse_json_union);", 658 (uint64_t)member->export_index, member->id, snref.text); 659 } 660 } else if (is_union_type) { 661 println(out, "static flatcc_json_parser_integral_symbol_f *symbolic_parsers[] = {"); 662 indent(); indent(); 663 println(out, "%s_parse_json_enum,", snref.text); 664 println(out, "%s_local_%sjson_parser_enum,", out->S->basename, scope_name); 665 println(out, "%s_global_json_parser_enum, 0 };", out->S->basename); 666 unindent(); unindent(); 667 if (is_union_type_vector) { 668 println(out, "buf = flatcc_json_parser_union_type_vector(ctx, buf, end, %"PRIu64", %"PRIu64", h_unions, symbolic_parsers, %s_parse_json_union, %s_json_union_accept_type);", 669 (uint64_t)member->export_index, member->id, snref.text, snref.text); 670 } else { 671 println(out, "buf = flatcc_json_parser_union_type(ctx, buf, end, %"PRIu64", %"PRIu64", h_unions, symbolic_parsers, %s_parse_json_union);", 672 (uint64_t)member->export_index, member->id, snref.text); 673 } 674 } else if (!is_vector && !is_char_array) { 675 gen_panic(out, "internal error: unexpected type for trie member\n"); 676 return -1; 677 } 678 if (is_vector) { 679 if (is_offset) { 680 /* Deal with table and string vector elements - unions cannot be elements. */ 681 println(out, "if (!ref || !(pref = flatcc_builder_extend_offset_vector(ctx->ctx, 1))) goto failed;"); 682 /* We don't need to worry about endian conversion - offsets vectors fix this automatically. */ 683 println(out, "*pref = ref;"); 684 } 685 println(out, "buf = flatcc_json_parser_array_end(ctx, buf, end, &more);"); 686 unindent(); println(out, "}"); 687 if (is_offset) { 688 println(out, "ref = flatcc_builder_end_offset_vector(ctx->ctx);"); 689 } else { 690 println(out, "ref = flatcc_builder_end_vector(ctx->ctx);"); 691 } 692 } 693 if (is_array) { 694 println(out, "buf = flatcc_json_parser_array_end(ctx, buf, end, &more);"); 695 unindent(); println(out, "}"); 696 println(out, "if (count) {"); indent(); 697 println(out, "if (ctx->flags & flatcc_json_parser_f_reject_array_underflow) {"); indent(); 698 println(out, "return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_array_underflow);"); 699 unindent(); println(out, "}"); 700 if (is_scalar) { 701 println(out, "memset(base, 0, count * sizeof(*base));"); 702 } else { 703 println(out, "memset(base, 0, count * %"PRIu64");", (uint64_t)member->type.ct->size); 704 } 705 unindent(); println(out, "}"); 706 } 707 if (is_nested == 1) { 708 is_nested = 2; 709 goto repeat_nested; 710 } 711 if (is_nested == 2) { 712 println(out, "if (!ref) goto failed;"); 713 println(out, "ref = flatcc_builder_end_buffer(ctx->ctx, ref);"); 714 unindent(); println(out, "} /* end nested */"); 715 } 716 if (is_nested || is_vector || is_table || is_string || is_base64 || is_base64url) { 717 println(out, "if (!ref || !(pref = flatcc_builder_table_add_offset(ctx->ctx, %"PRIu64"))) goto failed;", member->id); 718 println(out, "*pref = ref;"); 719 } 720 return 0; 721 } 722 723 static void gen_field_match(fb_output_t *out, fb_compound_type_t *ct, void *data, int hint, int n) 724 { 725 println(out, "buf = flatcc_json_parser_match_symbol(ctx, (mark = buf), end, %d);", n); 726 println(out, "if (mark != buf) {"); indent(); 727 gen_field_match_handler(out, ct, data, hint); 728 unindent(); println(out, "} else {"); indent(); 729 } 730 731 /* This also handles union type enumerations. */ 732 static void gen_enum_match_handler(fb_output_t *out, fb_compound_type_t *ct, void *data, int unused_hint) 733 { 734 fb_member_t *member = data; 735 736 (void)unused_hint; 737 738 /* 739 * This is rather unrelated to the rest, we just use the same 740 * trie generation logic. Here we simply need to assign a known 741 * value to the enum parsers output arguments. 742 */ 743 switch (ct->type.st) { 744 case fb_bool: 745 case fb_ubyte: 746 case fb_ushort: 747 case fb_uint: 748 case fb_ulong: 749 println(out, "*value = UINT64_C(%"PRIu64"), *value_sign = 0;", 750 member->value.u); 751 break; 752 case fb_byte: 753 case fb_short: 754 case fb_int: 755 case fb_long: 756 if (member->value.i < 0) { 757 println(out, "*value = UINT64_C(%"PRIu64"), *value_sign = 1;", member->value.i); 758 } else { 759 println(out, "*value = UINT64_C(%"PRIu64"), *value_sign = 0;", member->value.i); 760 } 761 break; 762 default: 763 gen_panic(out, "internal error: invalid enum type\n"); 764 } 765 } 766 767 static void gen_enum_match(fb_output_t *out, fb_compound_type_t *ct, void *data, int hint, int n) 768 { 769 println(out, "buf = flatcc_json_parser_match_constant(ctx, (mark = buf), end, %d, aggregate);", n); 770 println(out, "if (buf != mark) {"); indent(); 771 gen_enum_match_handler(out, ct, data, hint); 772 unindent(); println(out, "} else {"); indent(); 773 } 774 775 static void gen_scope_match_handler(fb_output_t *out, fb_compound_type_t *unused_ct, void *data, int unused_hint) 776 { 777 fb_compound_type_t *ct = data; 778 fb_scoped_name_t snt; 779 780 (void)unused_ct; 781 (void)unused_hint; 782 assert(ct->symbol.kind == fb_is_enum || ct->symbol.kind == fb_is_union); 783 784 fb_clear(snt); 785 fb_compound_name(ct, &snt); 786 /* May be included from another file. Unions also have _enum parsers. */ 787 println(out, "buf = %s_parse_json_enum(ctx, buf, end, value_type, value, aggregate);", snt.text); 788 } 789 790 static void gen_scope_match(fb_output_t *out, fb_compound_type_t *ct, void *data, int hint, int n) 791 { 792 println(out, "buf = flatcc_json_parser_match_scope(ctx, (mark = buf), end, %d);", n); 793 println(out, "if (buf != mark) {"); indent(); 794 gen_scope_match_handler(out, ct, data, hint); 795 unindent(); println(out, "} else {"); indent(); 796 } 797 798 static void gen_field_unmatched(fb_output_t *out) 799 { 800 println(out, "buf = flatcc_json_parser_unmatched_symbol(ctx, buf, end);"); 801 } 802 803 static void gen_enum_unmatched(fb_output_t *out) 804 { 805 println(out, "return unmatched;"); 806 } 807 808 static void gen_scope_unmatched(fb_output_t *out) 809 { 810 println(out, "return unmatched;"); 811 } 812 813 /* 814 * Generate a trie for all members or a compound type. 815 * This may be a struct or a table. 816 * 817 * We have a ternary trie where a search word w compares: 818 * w < wx_tag is one branch [a;x), iff a < x. 819 * w > wx_tag is another branch (y;b], iff b > y 820 * and w == wx_tag is a third branch [x;y]. 821 * 822 * The sets [a;x) and (y;b] may be empty in which case a non-match 823 * action is triggered. 824 * 825 * [x..y] is a set of one or more fields that share the same tag at the 826 * current position. The first (and only the first) field name in this 827 * set may terminate withint the current tag (when suffix length k == 828 * 0). There is therefore potentially both a direct field action and a 829 * sub-tree action. Once there is only one field in the set and the 830 * field name terminates within the current tag, the search word is 831 * masked and tested against the field tag and the search word is also 832 * tested for termination in the buffer at the first position after the 833 * field match. If the termination was not found a non-match action is 834 * triggered. 835 * 836 * A non-match action may be to silently consume the rest of the 837 * search identifier and then the json value, or to report and 838 * error. 839 * 840 * A match action triggers a json value parse of a known type 841 * which updates into a flatcc builder object. If the type is 842 * basic (string or scalar) the update simple, otherwise if 843 * the type is within the same schema, we push context 844 * and switch to parse the nested type, otherwise we call 845 * a parser in another schema. When a trie is done, we 846 * switch back context if in the same schema. The context 847 * lives on a stack. This avoids deep recursion because 848 * schema parsers are not mutually recursive. 849 * 850 * The trie is also used to parse enums and scopes (namespace prefixes) 851 * with a slight modification. 852 */ 853 854 enum trie_type { table_trie, struct_trie, enum_trie, local_scope_trie, global_scope_trie }; 855 typedef struct trie trie_t; 856 857 typedef void gen_match_f(fb_output_t *out, fb_compound_type_t *ct, void *data, int hint, int n); 858 typedef void gen_unmatched_f(fb_output_t *out); 859 860 struct trie { 861 dict_entry_t *dict; 862 gen_match_f *gen_match; 863 gen_unmatched_f *gen_unmatched; 864 /* Not used with scopes. */ 865 fb_compound_type_t *ct; 866 int type; 867 int union_total; 868 int label; 869 }; 870 871 /* 872 * This function is a final handler of the `gen_trie` function. Often 873 * just to handle a single match, but also to handle a prefix range 874 * special case like keys in `{ a, alpha, alpha2 }`. 875 * 876 * (See also special case of two non-prefix keys below). 877 * 878 * We know that all keys [a..b] have length in the range [pos..pos+8) 879 * and also that key x is proper prefix of key x + 1, x in [a..b). 880 * 881 * It is possible that `a == b`. 882 * 883 * We conduct a binary search by testing the middle for masked match and 884 * gradually refine until we do not have a match or have a single 885 * element match. 886 * 887 * (An alternative algorithm xors 8 byte tag with longest prefix and 888 * finds ceiling of log 2 using a few bit logic operations or intrinsic 889 * zero count and creates a jump table of at most 8 elements, but is 890 * hardly worthwhile vs 3 comparisons and 3 AND operations and often 891 * less than that.) 892 * 893 * Once we have a single element match we need to confirm the successor 894 * symbol is not any valid key - this differs among trie types and is 895 * therefore the polymorph match logic handles the final confirmed match 896 * or mismatch. 897 * 898 * Each trie type has special operation for implementing a matched and 899 * a failed match. Our job is to call these for each key in the range. 900 * 901 * While not the original intention, the `gen_prefix_trie` also handles the 902 * special case where the set has two keys where one is not a prefix of 903 * the other, but both terminate in the same tag. In this case we can 904 * immediately do an exact match test and skip the less than 905 * comparision. We need no special code for this, assuming the function 906 * is called correctly. This significantly reduces the branching in a 907 * case like "Red, Green, Blue". 908 * 909 * If `label` is positive, it is used to jump to additional match logic 910 * when a prefix was not matched. If 0 there is no additional logic and 911 * the symbol is considered unmatched immediately. 912 */ 913 static void gen_prefix_trie(fb_output_t *out, trie_t *trie, int a, int b, int pos, int label) 914 { 915 int m, n; 916 uint64_t tag = 00, mask = 0; 917 const char *name; 918 int len; 919 920 /* 921 * Weigh the intersection towards the longer prefix. Notably if we 922 * have two keys it makes no sense to check the shorter key first. 923 */ 924 m = a + (b - a + 1) / 2; 925 926 n = get_dict_tag(&trie->dict[m], pos, &tag, &mask, &name, &len); 927 if (n == 8) { 928 println(out, "if (w == 0x%"PRIx64") { /* \"%.*s\" */", tag, len, name); indent(); 929 } else { 930 println(out, "if ((w & 0x%"PRIx64") == 0x%"PRIx64") { /* \"%.*s\" */", 931 mask, tag, len, name); indent(); 932 } 933 if (m == a) { 934 /* There can be only one. */ 935 trie->gen_match(out, trie->ct, trie->dict[m].data, trie->dict[m].hint, n); 936 if (label > 0) { 937 println(out, "goto pfguard%d;", label); 938 } else { 939 trie->gen_unmatched(out); 940 } 941 unindent(); println(out, "}"); 942 unindent(); println(out, "} else { /* \"%.*s\" */", len, name); indent(); 943 if (label > 0) { 944 println(out, "goto pfguard%d;", label); 945 } else { 946 trie->gen_unmatched(out); 947 } 948 } else { 949 if (m == b) { 950 trie->gen_match(out, trie->ct, trie->dict[m].data, trie->dict[m].hint, n); 951 if (label > 0) { 952 println(out, "goto pfguard%d;", label); 953 } else { 954 trie->gen_unmatched(out); 955 } 956 unindent(); println(out, "}"); 957 } else { 958 gen_prefix_trie(out, trie, m, b, pos, label); 959 } 960 unindent(); println(out, "} else { /* \"%.*s\" */", len, name); indent(); 961 gen_prefix_trie(out, trie, a, m - 1, pos, label); 962 } 963 unindent(); println(out, "} /* \"%.*s\" */", len, name); 964 } 965 966 static void gen_trie(fb_output_t *out, trie_t *trie, int a, int b, int pos) 967 { 968 int x, k; 969 uint64_t tag = 0, mask = 0; 970 const char *name = ""; 971 int len = 0, has_prefix_key = 0, prefix_guard = 0, has_descend; 972 int label = 0; 973 974 /* 975 * Process a trie at the level given by pos. A single level covers 976 * one tag. 977 * 978 * A tag is a range of 8 characters [pos..pos+7] that is read as a 979 * single big endian word and tested as against a ternary trie 980 * generated in code. In generated code the tag is stored in "w". 981 * 982 * Normally trailing data in a tag is not a problem 983 * because the difference between two keys happen in the middle and 984 * trailing data is not valid key material. When the difference is 985 * at the end, we get a lot of special cases to handle. 986 * 987 * Regardless, when we believe we have a match, a final check is 988 * made to ensure that the next character after the match is not a 989 * valid key character - for quoted keys a valid termiantot is a 990 * quote, for unquoted keys it can be one of several characters - 991 * therefore quoted keys are faster to parse, even if they consume 992 * more space. The trie does not care about these details, the 993 * gen_match function handles this transparently for different 994 * symbol types. 995 */ 996 997 998 /* 999 * If we have one or two keys that terminate in this tag, there is no 1000 * need to do a branch test before matching exactly. 1001 * 1002 * We observe that `gen_prefix_trie` actually handles this 1003 * case well, even though it was not designed for it. 1004 */ 1005 if ((get_dict_suffix_len(&trie->dict[a], pos) == 0) && 1006 (b == a || (b == a + 1 && get_dict_suffix_len(&trie->dict[b], pos) == 0))) { 1007 gen_prefix_trie(out, trie, a, b, pos, 0); 1008 return; 1009 } 1010 1011 /* 1012 * Due trie nature, we have a left, middle, and right range where 1013 * the middle range all compare the same at the current trie level 1014 * when masked against shortest (and first) key in middle range. 1015 */ 1016 x = split_dict_left(trie->dict, a, b, pos); 1017 1018 if (x > a) { 1019 /* 1020 * This is normal early branch with a key `a < x < b` such that 1021 * any shared prefix ranges do not span x. 1022 */ 1023 get_dict_tag(&trie->dict[x], pos, &tag, &mask, &name, &len); 1024 println(out, "if (w < 0x%"PRIx64") { /* branch \"%.*s\" */", tag, len, name); indent(); 1025 gen_trie(out, trie, a, x - 1, pos); 1026 unindent(); println(out, "} else { /* branch \"%.*s\" */", len, name); indent(); 1027 gen_trie(out, trie, x, b, pos); 1028 unindent(); println(out, "} /* branch \"%.*s\" */", len, name); 1029 return; 1030 } 1031 x = split_dict_right(trie->dict, a, b, pos); 1032 1033 /* 1034 * [a .. x-1] is a non-empty sequence of prefixes, 1035 * for example { a123, a1234, a12345 }. 1036 * The keys might not terminate in the current tag. To find those 1037 * that do, we will evaluate k such that: 1038 * [a .. k-1] are prefixes that terminate in the current tag if any 1039 * such exists. 1040 * [x..b] are keys that are prefixes up to at least pos + 7 but 1041 * do not terminate in the current tag. 1042 * [k..x-1] are prefixes that do not termiante in the current tag. 1043 * Note that they might not be prefixes when considering more than the 1044 * current tag. 1045 * The range [a .. x-1] can ge generated with `gen_prefix_trie`. 1046 * 1047 * We generally have the form 1048 * 1049 * [a..b] = 1050 * (a)<prefixes>, (k-1)<descend-prefix>, (k)<descend>, (x)<reminder> 1051 * 1052 * Where <prefixes> are keys that terminate at the current tag. 1053 * <descend> are keys that have the prefixes as prefix but do not 1054 * terminate at the current tag. 1055 * <descend-prerfix> is a single key that terminates exactly 1056 * where the tag ends. If there are no descend keys it is part of 1057 * prefixes, otherwise it is tested as a special case. 1058 * <reminder> are any keys larger than the prefixes. 1059 * 1060 * The reminder keys cannot be tested before we are sure that no 1061 * prefix is matching at least no prefixes that is not a 1062 * descend-prefix. This is because less than comparisons are 1063 * affected by trailing data within the tag caused by prefixes 1064 * terminating early. Trailing data is not a problem if two keys are 1065 * longer than the point where they differ even if they terminate 1066 * within the current tag. 1067 * 1068 * Thus, if we have non-empty <descend> and non-empty <reminder>, 1069 * the reminder must guard against any matches in prefix but not 1070 * against any matches in <descend>. If <descend> is empty and 1071 * <prefixes> == <descend-prefix> a guard is also not needed. 1072 */ 1073 1074 /* Find first prefix that does not terminate at the current level, or x if absent */ 1075 k = split_dict_descend(trie->dict, a, x - 1, pos); 1076 has_descend = k < x; 1077 1078 /* If we have a descend, process that in isolation. */ 1079 if (has_descend) { 1080 has_prefix_key = k > a && get_dict_tag_len(&trie->dict[k - 1], pos) == 8; 1081 get_dict_tag(&trie->dict[k], pos, &tag, &mask, &name, &len); 1082 println(out, "if (w == 0x%"PRIx64") { /* descend \"%.*s\" */", tag, len, name); indent(); 1083 if (has_prefix_key) { 1084 /* We have a key that terminates at the descend prefix. */ 1085 println(out, "/* descend prefix key \"%.*s\" */", len, name); 1086 trie->gen_match(out, trie->ct, trie->dict[k - 1].data, trie->dict[k - 1].hint, 8); 1087 println(out, "/* descend suffix \"%.*s\" */", len, name); 1088 } 1089 println(out, "buf += 8;"); 1090 println(out, "w = flatcc_json_parser_symbol_part(buf, end);"); 1091 gen_trie(out, trie, k, x - 1, pos + 8); 1092 if (has_prefix_key) { 1093 unindent(); println(out, "} /* desend suffix \"%.*s\" */", len, name); 1094 /* Here we move the <descend-prefix> key out of the <descend> range. */ 1095 --k; 1096 } 1097 unindent(); println(out, "} else { /* descend \"%.*s\" */", len, name); indent(); 1098 } 1099 prefix_guard = a < k && x <= b; 1100 if (prefix_guard) { 1101 label = ++trie->label; 1102 } 1103 if (a < k) { 1104 gen_prefix_trie(out, trie, a, k - 1, pos, label); 1105 } 1106 if (prefix_guard) { 1107 /* All prefixes tested, but none matched. */ 1108 println(out, "goto endpfguard%d;", label); 1109 margin(); 1110 println(out, "pfguard%d:", label); 1111 unmargin(); 1112 } 1113 if (x <= b) { 1114 gen_trie(out, trie, x, b, pos); 1115 } else if (a >= k) { 1116 trie->gen_unmatched(out); 1117 } 1118 if (prefix_guard) { 1119 margin(); 1120 println(out, "endpfguard%d:", label); 1121 unmargin(); 1122 println(out, "(void)0;"); 1123 } 1124 if (has_descend) { 1125 unindent(); println(out, "} /* descend \"%.*s\" */", len, name); 1126 } 1127 } 1128 1129 1130 /* 1131 * Parsing symbolic constants: 1132 * 1133 * An enum parser parses the local symbols and translate them into 1134 * numeric values. 1135 * 1136 * If a symbol wasn't matched, e.g. "Red", it might be matched with 1137 * "Color.Red" but the enum parser does not handle this. 1138 * 1139 * Instead a scope parser maps each type in the scope to a call 1140 * to an enum parser, e.g. "Color." maps to a color enum parser 1141 * that understands "Red". If this also fails, a call is made 1142 * to a global scope parser that maps a namespace to a local 1143 * scope parser, for example "Graphics.Color.Red" first 1144 * recognizes the namespace "Graphics." which may or may not 1145 * be the same as the local scope tried earlier, then "Color." 1146 * is matched and finally "Red". 1147 * 1148 * The scope and namespace parsers may cover extend namespaces from 1149 * include files so each file calls into dependencies as necessary. 1150 * This means the same scope can have multiple parsers and must 1151 * therefore be name prefixed by the basename of the include file. 1152 * 1153 * The enums can only exist in a single file. 1154 * 1155 * The local scope is defined as the scope in which the consuming 1156 * fields container is defined, so if Pen is a table in Graphics 1157 * with a field named "ink" and the pen is parsed as 1158 * { "ink": "Color.Red" }, then Color would be parsed in the 1159 * Graphics scope. If ink was and enum of type Color, the enum 1160 * parser would be tried first. If ink was, say, an integer 1161 * type, it would not try an enum parse first but try the local 1162 * scope, then the namespace scope. 1163 * 1164 * It is permitted to have multiple symbols in a string when 1165 * the enum type has flag attribute so values can be or'ed together. 1166 * The parser does not attempt to validate this and will simple 1167 * 'or' together multiple values after coercing each to the 1168 * receiving field type: "Has.ink Has.shape Has.brush". 1169 */ 1170 1171 1172 /* 1173 * Used by scalar/enum/union_type table fields to look up symbolic 1174 * constants in same scope as the table was defined, thus avoiding 1175 * namespace prefix. 1176 * 1177 * Theh matched name then calls into the type specific parser which 1178 * may be in a dependent file. 1179 * 1180 * Because each scope may be extended in dependent schema files 1181 * we recreate the scope in full in each file. 1182 */ 1183 static void gen_local_scope_parser(void *context, fb_scope_t *scope) 1184 { 1185 fb_output_t *out = context; 1186 int n = 0; 1187 trie_t trie; 1188 fb_symbol_text_t scope_name; 1189 1190 fb_clear(trie); 1191 fb_copy_scope(scope, scope_name); 1192 if (((trie.dict = build_local_scope_dict(out->S, scope, &n)) == 0) && n > 0) { 1193 gen_panic(out, "internal error: could not build dictionary for json parser\n"); 1194 return; 1195 } 1196 /* Not used for scopes. */ 1197 trie.ct = 0; 1198 trie.type = local_scope_trie; 1199 trie.gen_match = gen_scope_match; 1200 trie.gen_unmatched = gen_scope_unmatched; 1201 println(out, "static const char *%s_local_%sjson_parser_enum(flatcc_json_parser_t *ctx, const char *buf, const char *end,", 1202 out->S->basename, scope_name); 1203 indent(); indent(); 1204 println(out, "int *value_type, uint64_t *value, int *aggregate)"); 1205 unindent(); unindent(); 1206 println(out, "{"); indent(); 1207 if (n == 0) { 1208 println(out, "/* Scope has no enum / union types to look up. */"); 1209 println(out, "return buf; /* unmatched; */"); 1210 unindent(); println(out, "}"); 1211 } else { 1212 println(out, "const char *unmatched = buf;"); 1213 println(out, "const char *mark;"); 1214 println(out, "uint64_t w;"); 1215 println(out, ""); 1216 println(out, "w = flatcc_json_parser_symbol_part(buf, end);"); 1217 gen_trie(out, &trie, 0, n - 1, 0); 1218 println(out, "return buf;"); 1219 unindent(); println(out, "}"); 1220 } 1221 println(out, ""); 1222 clear_dict(trie.dict); 1223 } 1224 1225 /* 1226 * This parses namespace prefixed types. Because scopes can be extended 1227 * in dependent schema files, each file has its own global scope parser. 1228 * The matched types call into type specific parsers that may be in 1229 * a dependent file. 1230 * 1231 * When a local scope is also parsed, it should be tried before the 1232 * global scope. 1233 */ 1234 static int gen_global_scope_parser(fb_output_t *out) 1235 { 1236 int n = 0; 1237 trie_t trie; 1238 catalog_t catalog; 1239 1240 fb_clear(trie); 1241 if (build_catalog(&catalog, out->S, 1, &out->S->root_schema->scope_index)) { 1242 return -1; 1243 } 1244 1245 if ((trie.dict = build_global_scope_dict(&catalog, &n)) == 0 && n > 0) { 1246 clear_catalog(&catalog); 1247 gen_panic(out, "internal error: could not build dictionary for json parser\n"); 1248 return -1; 1249 } 1250 /* Not used for scopes. */ 1251 trie.ct = 0; 1252 trie.type = global_scope_trie; 1253 trie.gen_match = gen_scope_match; 1254 trie.gen_unmatched = gen_scope_unmatched; 1255 println(out, "static const char *%s_global_json_parser_enum(flatcc_json_parser_t *ctx, const char *buf, const char *end,", out->S->basename); 1256 indent(); indent(); 1257 println(out, "int *value_type, uint64_t *value, int *aggregate)"); 1258 unindent(); unindent(); 1259 println(out, "{"); indent(); 1260 if (n == 0) { 1261 println(out, "/* Global scope has no enum / union types to look up. */"); 1262 println(out, "return buf; /* unmatched; */"); 1263 unindent(); println(out, "}"); 1264 } else { 1265 println(out, "const char *unmatched = buf;"); 1266 println(out, "const char *mark;"); 1267 println(out, "uint64_t w;"); 1268 println(out, ""); 1269 println(out, "w = flatcc_json_parser_symbol_part(buf, end);"); 1270 gen_trie(out, &trie, 0, n - 1, 0); 1271 println(out, "return buf;"); 1272 unindent(); println(out, "}"); 1273 } 1274 println(out, ""); 1275 clear_dict(trie.dict); 1276 clear_catalog(&catalog); 1277 return 0; 1278 } 1279 1280 /* 1281 * Constants have the form `"Red"` or `Red` but may also be part 1282 * of a list of flags: `"Normal High Average"` or `Normal High 1283 * Average`. `more` indicates more symbols follow. 1284 * 1285 * Returns input argument if there was no valid match, 1286 * `end` on syntax error, and `more=1` if matched and 1287 * there are more constants to parse. 1288 * Applies the mached and coerced constant to `pval` 1289 * with a binary `or` operation so `pval` must be initialized 1290 * to 0 before teh first constant in a list. 1291 */ 1292 static int gen_enum_parser(fb_output_t *out, fb_compound_type_t *ct) 1293 { 1294 fb_scoped_name_t snt; 1295 int n = 0; 1296 trie_t trie; 1297 1298 fb_clear(trie); 1299 assert(ct->symbol.kind == fb_is_enum || ct->symbol.kind == fb_is_union); 1300 1301 if ((trie.dict = build_compound_dict(ct, &n)) == 0 && n > 0) { 1302 gen_panic(out, "internal error: could not build dictionary for json parser\n"); 1303 return -1; 1304 } 1305 trie.ct = ct; 1306 trie.type = enum_trie; 1307 trie.gen_match = gen_enum_match; 1308 trie.gen_unmatched = gen_enum_unmatched; 1309 1310 fb_clear(snt); 1311 fb_compound_name(ct, &snt); 1312 1313 println(out, "static const char *%s_parse_json_enum(flatcc_json_parser_t *ctx, const char *buf, const char *end,", snt.text); 1314 indent(); indent(); 1315 println(out, "int *value_sign, uint64_t *value, int *aggregate)"); 1316 unindent(); unindent(); 1317 println(out, "{"); indent(); 1318 if (n == 0) { 1319 println(out, "/* Enum has no fields. */"); 1320 println(out, "*aggregate = 0;"); 1321 println(out, "return buf; /* unmatched; */"); 1322 unindent(); println(out, "}"); 1323 } else { 1324 println(out, "const char *unmatched = buf;"); 1325 println(out, "const char *mark;"); 1326 println(out, "uint64_t w;"); 1327 println(out, ""); 1328 println(out, "w = flatcc_json_parser_symbol_part(buf, end);"); 1329 gen_trie(out, &trie, 0, n - 1, 0); 1330 println(out, "return buf;"); 1331 unindent(); println(out, "}"); 1332 } 1333 println(out, ""); 1334 clear_dict(trie.dict); 1335 return 0; 1336 } 1337 1338 /* 1339 * We do not check for duplicate settings or missing struct fields. 1340 * Missing fields are zeroed. 1341 * 1342 * TODO: we should track nesting level because nested structs do not 1343 * interact with the builder so the builders level limit will not kick 1344 * in. As long as we get input from our own parser we should, however, 1345 * be reasonable safe as nesting is bounded. 1346 */ 1347 static int gen_struct_parser_inline(fb_output_t *out, fb_compound_type_t *ct) 1348 { 1349 fb_scoped_name_t snt; 1350 int n; 1351 trie_t trie; 1352 1353 fb_clear(trie); 1354 assert(ct->symbol.kind == fb_is_struct); 1355 if ((trie.dict = build_compound_dict(ct, &n)) == 0 && n > 0) { 1356 gen_panic(out, "internal error: could not build dictionary for json parser\n"); 1357 return -1; 1358 } 1359 trie.ct = ct; 1360 trie.type = struct_trie; 1361 trie.gen_match = gen_field_match; 1362 trie.gen_unmatched = gen_field_unmatched; 1363 1364 fb_clear(snt); 1365 fb_compound_name(ct, &snt); 1366 println(out, "static const char *%s_parse_json_struct_inline(flatcc_json_parser_t *ctx, const char *buf, const char *end, void *struct_base)", snt.text); 1367 println(out, "{"); indent(); 1368 println(out, "int more;"); 1369 if (n > 0) { 1370 println(out, "flatcc_builder_ref_t ref;"); 1371 println(out, "void *pval;"); 1372 println(out, "const char *mark;"); 1373 println(out, "uint64_t w;"); 1374 } 1375 println(out, ""); 1376 println(out, "buf = flatcc_json_parser_object_start(ctx, buf, end, &more);"); 1377 println(out, "while (more) {"); indent(); 1378 if (n == 0) { 1379 println(out, "/* Empty struct. */"); 1380 println(out, "buf = flatcc_json_parser_unmatched_symbol(ctx, buf, end);"); 1381 } else { 1382 println(out, "buf = flatcc_json_parser_symbol_start(ctx, buf, end);"); 1383 println(out, "w = flatcc_json_parser_symbol_part(buf, end);"); 1384 gen_trie(out, &trie, 0, n - 1, 0); 1385 } 1386 println(out, "buf = flatcc_json_parser_object_end(ctx, buf, end , &more);"); 1387 unindent(); println(out, "}"); 1388 println(out, "return buf;"); 1389 if (n > 0) { 1390 /* Set runtime error if no other error was set already. */ 1391 margin(); 1392 println(out, "failed:"); 1393 unmargin(); 1394 println(out, "return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_runtime);"); 1395 } 1396 unindent(); println(out, "}"); 1397 println(out, ""); 1398 clear_dict(trie.dict); 1399 return 0; 1400 } 1401 1402 static int gen_struct_parser(fb_output_t *out, fb_compound_type_t *ct) 1403 { 1404 fb_scoped_name_t snt; 1405 1406 assert(ct->symbol.kind == fb_is_struct); 1407 fb_clear(snt); 1408 fb_compound_name(ct, &snt); 1409 println(out, "static const char *%s_parse_json_struct(flatcc_json_parser_t *ctx, const char *buf, const char *end, flatcc_builder_ref_t *result)", snt.text); 1410 println(out, "{"); indent(); 1411 println(out, "void *pval;"); 1412 println(out, ""); 1413 println(out, "*result = 0;"); 1414 println(out, "if (!(pval = flatcc_builder_start_struct(ctx->ctx, %"PRIu64", %"PRIu16"))) goto failed;", 1415 (uint64_t)ct->size, (uint16_t)ct->align); 1416 println(out, "buf = %s_parse_json_struct_inline(ctx, buf, end, pval);", snt.text); 1417 println(out, "if (ctx->error || !(*result = flatcc_builder_end_struct(ctx->ctx))) goto failed;"); 1418 println(out, "return buf;"); 1419 margin(); 1420 println(out, "failed:"); 1421 unmargin(); 1422 println(out, "return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_runtime);"); 1423 unindent(); println(out, "}"); 1424 println(out, ""); 1425 println(out, "static inline int %s_parse_json_as_root(flatcc_builder_t *B, flatcc_json_parser_t *ctx, const char *buf, size_t bufsiz, flatcc_json_parser_flags_t flags, const char *fid)", snt.text); 1426 println(out, "{"); indent(); 1427 println(out, "return flatcc_json_parser_struct_as_root(B, ctx, buf, bufsiz, flags, fid, %s_parse_json_struct);", 1428 snt.text); 1429 unindent(); println(out, "}"); 1430 println(out, ""); 1431 return 0; 1432 } 1433 1434 static int gen_table_parser(fb_output_t *out, fb_compound_type_t *ct) 1435 { 1436 fb_scoped_name_t snt; 1437 fb_member_t *member; 1438 int first, i, n; 1439 int is_union, is_required; 1440 trie_t trie; 1441 1442 fb_clear(trie); 1443 assert(ct->symbol.kind == fb_is_table); 1444 if ((trie.dict = build_compound_dict(ct, &n)) == 0 && n > 0) { 1445 gen_panic(out, "internal error: could not build dictionary for json parser\n"); 1446 return -1; 1447 } 1448 trie.ct = ct; 1449 trie.type = table_trie; 1450 trie.gen_match = gen_field_match; 1451 trie.gen_unmatched = gen_field_unmatched; 1452 1453 trie.union_total = 0; 1454 for (i = 0; i < n; ++i) { 1455 trie.union_total += !!trie.dict[i].hint; 1456 } 1457 1458 fb_clear(snt); 1459 fb_compound_name(ct, &snt); 1460 println(out, "static const char *%s_parse_json_table(flatcc_json_parser_t *ctx, const char *buf, const char *end, flatcc_builder_ref_t *result)", snt.text); 1461 println(out, "{"); indent(); 1462 println(out, "int more;"); 1463 1464 if (n > 0) { 1465 println(out, "void *pval;"); 1466 println(out, "flatcc_builder_ref_t ref, *pref;"); 1467 println(out, "const char *mark;"); 1468 println(out, "uint64_t w;"); 1469 } 1470 if (trie.union_total) { 1471 println(out, "size_t h_unions;"); 1472 } 1473 println(out, ""); 1474 println(out, "*result = 0;"); 1475 println(out, "if (flatcc_builder_start_table(ctx->ctx, %"PRIu64")) goto failed;", 1476 ct->count); 1477 if (trie.union_total) { 1478 println(out, "if (end == flatcc_json_parser_prepare_unions(ctx, buf, end, %"PRIu64", &h_unions)) goto failed;", (uint64_t)trie.union_total); 1479 } 1480 println(out, "buf = flatcc_json_parser_object_start(ctx, buf, end, &more);"); 1481 println(out, "while (more) {"); indent(); 1482 println(out, "buf = flatcc_json_parser_symbol_start(ctx, buf, end);"); 1483 if (n > 0) { 1484 println(out, "w = flatcc_json_parser_symbol_part(buf, end);"); 1485 gen_trie(out, &trie, 0, n - 1, 0); 1486 } else { 1487 println(out, "/* Table has no fields. */"); 1488 println(out, "buf = flatcc_json_parser_unmatched_symbol(ctx, buf, end);"); 1489 } 1490 println(out, "buf = flatcc_json_parser_object_end(ctx, buf, end, &more);"); 1491 unindent(); println(out, "}"); 1492 println(out, "if (ctx->error) goto failed;"); 1493 for (first = 1, i = 0; i < n; ++i) { 1494 member = trie.dict[i].data; 1495 if (member->metadata_flags & fb_f_deprecated) { 1496 continue; 1497 } 1498 is_union = is_union_member(member); 1499 is_required = member->metadata_flags & fb_f_required; 1500 if (is_required) { 1501 if (first) { 1502 println(out, "if (!flatcc_builder_check_required_field(ctx->ctx, %"PRIu64")", member->id - !!is_union); 1503 indent(); 1504 } else { 1505 println(out, "|| !flatcc_builder_check_required_field(ctx->ctx, %"PRIu64")", member->id - !!is_union); 1506 } 1507 first = 0; 1508 } 1509 } 1510 if (!first) { 1511 unindent(); println(out, ") {"); indent(); 1512 println(out, "buf = flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_required);"); 1513 println(out, "goto failed;"); 1514 unindent(); println(out, "}"); 1515 } 1516 if (trie.union_total) { 1517 println(out, "buf = flatcc_json_parser_finalize_unions(ctx, buf, end, h_unions);"); 1518 } 1519 println(out, "if (!(*result = flatcc_builder_end_table(ctx->ctx))) goto failed;"); 1520 println(out, "return buf;"); 1521 /* Set runtime error if no other error was set already. */ 1522 margin(); 1523 println(out, "failed:"); 1524 unmargin(); 1525 println(out, "return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_runtime);"); 1526 unindent(); println(out, "}"); 1527 println(out, ""); 1528 println(out, "static inline int %s_parse_json_as_root(flatcc_builder_t *B, flatcc_json_parser_t *ctx, const char *buf, size_t bufsiz, flatcc_json_parser_flags_t flags, const char *fid)", snt.text); 1529 println(out, "{"); indent(); 1530 println(out, "return flatcc_json_parser_table_as_root(B, ctx, buf, bufsiz, flags, fid, %s_parse_json_table);", 1531 snt.text); 1532 unindent(); println(out, "}"); 1533 println(out, ""); 1534 clear_dict(trie.dict); 1535 return 0; 1536 } 1537 1538 static int gen_union_parser(fb_output_t *out, fb_compound_type_t *ct) 1539 { 1540 fb_scoped_name_t snt, snref; 1541 fb_symbol_t *sym; 1542 fb_member_t *member; 1543 int n; 1544 const char *s; 1545 1546 fb_clear(snt); 1547 fb_clear(snref); 1548 fb_compound_name(ct, &snt); 1549 println(out, "static const char *%s_parse_json_union(flatcc_json_parser_t *ctx, const char *buf, const char *end, uint8_t type, flatcc_builder_ref_t *result)", snt.text); 1550 println(out, "{"); indent(); 1551 println(out, ""); 1552 println(out, "*result = 0;"); 1553 println(out, "switch (type) {"); 1554 println(out, "case 0: /* NONE */"); indent(); 1555 println(out, "return flatcc_json_parser_none(ctx, buf, end);"); 1556 unindent(); 1557 for (sym = ct->members; sym; sym = sym->link) { 1558 member = (fb_member_t *)sym; 1559 symbol_name(sym, &n, &s); 1560 switch (member->type.type) { 1561 case vt_missing: 1562 /* NONE is of type vt_missing and already handled. */ 1563 continue; 1564 case vt_compound_type_ref: 1565 fb_compound_name(member->type.ct, &snref); 1566 println(out, "case %u: /* %.*s */", (unsigned)member->value.u, n, s); indent(); 1567 switch (member->type.ct->symbol.kind) { 1568 case fb_is_table: 1569 println(out, "buf = %s_parse_json_table(ctx, buf, end, result);", snref.text); 1570 break; 1571 case fb_is_struct: 1572 println(out, "buf = %s_parse_json_struct(ctx, buf, end, result);", snref.text); 1573 break; 1574 default: 1575 gen_panic(out, "internal error: unexpected compound union member type\n"); 1576 return -1; 1577 } 1578 println(out, "break;"); 1579 unindent(); 1580 continue; 1581 case vt_string_type: 1582 println(out, "case %u: /* %.*s */", (unsigned)member->value.u, n, s); indent(); 1583 println(out, "buf = flatcc_json_parser_build_string(ctx, buf, end, result);"); 1584 println(out, "break;"); 1585 unindent(); 1586 continue; 1587 default: 1588 gen_panic(out, "internal error: unexpected union member type\n"); 1589 return -1; 1590 } 1591 } 1592 /* Unknown union, but not an error if we allow schema forwarding. */ 1593 println(out, "default:"); indent(); 1594 println(out, "if (!(ctx->flags & flatcc_json_parser_f_skip_unknown)) {"); indent(); 1595 println(out, "return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_unknown_union);"); 1596 unindent(); println(out, "} else {"); indent(); 1597 println(out, "return flatcc_json_parser_generic_json(ctx, buf, end);"); 1598 unindent(); println(out, "}"); 1599 unindent(); println(out, "}"); 1600 println(out, "if (ctx->error) return buf;"); 1601 println(out, "if (!*result) {"); 1602 indent(); println(out, "return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_runtime);"); 1603 unindent(); println(out, "}"); 1604 println(out, "return buf;"); 1605 unindent(); println(out, "}"); 1606 println(out, ""); 1607 return 0; 1608 } 1609 1610 static int gen_union_accept_type(fb_output_t *out, fb_compound_type_t *ct) 1611 { 1612 fb_scoped_name_t snt, snref; 1613 fb_symbol_t *sym; 1614 fb_member_t *member; 1615 int n; 1616 const char *s; 1617 1618 fb_clear(snt); 1619 fb_clear(snref); 1620 fb_compound_name(ct, &snt); 1621 println(out, "static int %s_json_union_accept_type(uint8_t type)", snt.text); 1622 println(out, "{"); indent(); 1623 println(out, "switch (type) {"); 1624 for (sym = ct->members; sym; sym = sym->link) { 1625 member = (fb_member_t *)sym; 1626 symbol_name(sym, &n, &s); 1627 if (member->type.type == vt_missing) { 1628 println(out, "case 0: return 1; /* NONE */"); 1629 continue; 1630 } 1631 println(out, "case %u: return 1; /* %.*s */", (unsigned)member->value.u, n, s); 1632 } 1633 /* Unknown union, but not an error if we allow schema forwarding. */ 1634 println(out, "default: return 0;"); indent(); 1635 unindent(); println(out, "}"); 1636 unindent(); println(out, "}"); 1637 println(out, ""); 1638 return 0; 1639 } 1640 1641 static void gen_local_scope_prototype(void *context, fb_scope_t *scope) 1642 { 1643 fb_output_t *out = context; 1644 fb_symbol_text_t scope_name; 1645 1646 fb_copy_scope(scope, scope_name); 1647 1648 println(out, "static const char *%s_local_%sjson_parser_enum(flatcc_json_parser_t *ctx, const char *buf, const char *end,", 1649 out->S->basename, scope_name); 1650 println(out, "int *value_type, uint64_t *value, int *aggregate);"); 1651 } 1652 1653 static int gen_root_table_parser(fb_output_t *out, fb_compound_type_t *ct) 1654 { 1655 fb_scoped_name_t snt; 1656 1657 fb_clear(snt); 1658 fb_compound_name(ct, &snt); 1659 1660 println(out, "static int %s_parse_json(flatcc_builder_t *B, flatcc_json_parser_t *ctx,", out->S->basename); 1661 indent(); indent(); 1662 println(out, "const char *buf, size_t bufsiz, flatcc_json_parser_flags_t flags)"); 1663 unindent(); unindent(); 1664 println(out, "{"); indent(); 1665 println(out, "flatcc_json_parser_t parser;"); 1666 println(out, "flatcc_builder_ref_t root;"); 1667 println(out, ""); 1668 println(out, "ctx = ctx ? ctx : &parser;"); 1669 println(out, "flatcc_json_parser_init(ctx, B, buf, buf + bufsiz, flags);"); 1670 if (out->S->file_identifier.type == vt_string) { 1671 println(out, "if (flatcc_builder_start_buffer(B, \"%.*s\", 0, 0)) return -1;", 1672 out->S->file_identifier.s.len, out->S->file_identifier.s.s); 1673 } else { 1674 println(out, "if (flatcc_builder_start_buffer(B, 0, 0, 0)) return -1;"); 1675 } 1676 println(out, "%s_parse_json_table(ctx, buf, buf + bufsiz, &root);", snt.text); 1677 println(out, "if (ctx->error) {"); indent(); 1678 println(out, "return ctx->error;"); 1679 unindent(); println(out, "}"); 1680 println(out, "if (!flatcc_builder_end_buffer(B, root)) return -1;"); 1681 println(out, "ctx->end_loc = buf;"); 1682 println(out, "return 0;"); 1683 unindent(); println(out, "}"); 1684 println(out, ""); 1685 return 0; 1686 } 1687 1688 static int gen_root_struct_parser(fb_output_t *out, fb_compound_type_t *ct) 1689 { 1690 fb_scoped_name_t snt; 1691 1692 fb_clear(snt); 1693 fb_compound_name(ct, &snt); 1694 1695 println(out, "static int %s_parse_json(flatcc_builder_t *B, flatcc_json_parser_t *ctx,", out->S->basename); 1696 indent(); indent(); 1697 println(out, "const char *buf, size_t bufsiz, int flags)"); 1698 unindent(); unindent(); 1699 println(out, "{"); indent(); 1700 println(out, "flatcc_json_parser_t ctx_;"); 1701 println(out, "flatcc_builder_ref_t root;"); 1702 println(out, ""); 1703 println(out, "ctx = ctx ? ctx : &ctx_;"); 1704 println(out, "flatcc_json_parser_init(ctx, B, buf, buf + bufsiz, flags);"); 1705 if (out->S->file_identifier.type == vt_string) { 1706 println(out, "if (flatcc_builder_start_buffer(B, \"%.*s\", 0, 0)) return -1;", 1707 out->S->file_identifier.s.len, out->S->file_identifier.s.s); 1708 } else { 1709 println(out, "if (flatcc_builder_start_buffer(B, 0, 0, 0)) return -1;"); 1710 } 1711 println(out, "buf = %s_parse_json_struct(ctx, buf, buf + bufsiz, &root);", snt.text); 1712 println(out, "if (ctx->error) {"); indent(); 1713 println(out, "return ctx->error;"); 1714 unindent(); println(out, "}"); 1715 println(out, "if (!flatcc_builder_end_buffer(B, root)) return -1;"); 1716 println(out, "ctx->end_loc = buf;"); 1717 println(out, "return 0;"); 1718 unindent(); println(out, "}"); 1719 println(out, ""); 1720 return 0; 1721 } 1722 1723 1724 static int gen_root_parser(fb_output_t *out) 1725 { 1726 fb_symbol_t *root_type = out->S->root_type.type; 1727 1728 if (!root_type) { 1729 return 0; 1730 } 1731 if (root_type) { 1732 switch (root_type->kind) { 1733 case fb_is_table: 1734 return gen_root_table_parser(out, (fb_compound_type_t *)root_type); 1735 case fb_is_struct: 1736 return gen_root_struct_parser(out, (fb_compound_type_t *)root_type); 1737 default: 1738 break; 1739 } 1740 } 1741 return 0; 1742 } 1743 1744 static int gen_json_parser_prototypes(fb_output_t *out) 1745 { 1746 fb_symbol_t *sym; 1747 fb_scoped_name_t snt; 1748 fb_symbol_t *root_type = out->S->root_type.type; 1749 1750 fb_clear(snt); 1751 1752 if (root_type) 1753 switch (root_type->kind) { 1754 case fb_is_table: 1755 case fb_is_struct: 1756 println(out, "/*"); 1757 println(out, " * Parses the default root table or struct of the schema and constructs a FlatBuffer."); 1758 println(out, " *"); 1759 println(out, " * Builder `B` must be initialized. `ctx` can be null but will hold"); 1760 println(out, " * hold detailed error info on return when available."); 1761 println(out, " * Returns 0 on success, or error code."); 1762 println(out, " * `flags` : 0 by default, `flatcc_json_parser_f_skip_unknown` silently"); 1763 println(out, " * ignores unknown table and structs fields, and union types."); 1764 println(out, " */"); 1765 println(out, "static int %s_parse_json(flatcc_builder_t *B, flatcc_json_parser_t *ctx,", 1766 out->S->basename); 1767 indent(); indent(); 1768 println(out, "const char *buf, size_t bufsiz, flatcc_json_parser_flags_t flags);"); 1769 unindent(); unindent(); 1770 println(out, ""); 1771 break; 1772 default: 1773 break; 1774 } 1775 for (sym = out->S->symbols; sym; sym = sym->link) { 1776 switch (sym->kind) { 1777 case fb_is_union: 1778 fb_compound_name((fb_compound_type_t *)sym, &snt); 1779 println(out, "static const char *%s_parse_json_union(flatcc_json_parser_t *ctx, const char *buf, const char *end, uint8_t type, flatcc_builder_ref_t *pref);", snt.text); 1780 println(out, "static int %s_json_union_accept_type(uint8_t type);", snt.text); 1781 /* A union also has an enum parser to get the type. */ 1782 println(out, "static const char *%s_parse_json_enum(flatcc_json_parser_t *ctx, const char *buf, const char *end,", snt.text); 1783 indent(); indent(); 1784 println(out, "int *value_type, uint64_t *value, int *aggregate);"); 1785 unindent(); unindent(); 1786 break; 1787 case fb_is_struct: 1788 fb_compound_name((fb_compound_type_t *)sym, &snt); 1789 println(out, "static const char *%s_parse_json_struct_inline(flatcc_json_parser_t *ctx, const char *buf, const char *end, void *struct_base);", snt.text); 1790 println(out, "static const char *%s_parse_json_struct(flatcc_json_parser_t *ctx, const char *buf, const char *end, flatcc_builder_ref_t *result);", snt.text); 1791 break; 1792 case fb_is_table: 1793 fb_compound_name((fb_compound_type_t *)sym, &snt); 1794 println(out, "static const char *%s_parse_json_table(flatcc_json_parser_t *ctx, const char *buf, const char *end, flatcc_builder_ref_t *result);", snt.text); 1795 break; 1796 case fb_is_enum: 1797 fb_compound_name((fb_compound_type_t *)sym, &snt); 1798 println(out, "static const char *%s_parse_json_enum(flatcc_json_parser_t *ctx, const char *buf, const char *end,", snt.text); 1799 indent(); indent(); 1800 println(out, "int *value_type, uint64_t *value, int *aggregate);", snt.text); 1801 unindent(); unindent(); 1802 break; 1803 } 1804 } 1805 fb_scope_table_visit(&out->S->root_schema->scope_index, gen_local_scope_prototype, out); 1806 println(out, "static const char *%s_global_json_parser_enum(flatcc_json_parser_t *ctx, const char *buf, const char *end,", out->S->basename); 1807 indent(); indent(); 1808 println(out, "int *value_type, uint64_t *value, int *aggregate);"); 1809 unindent(); unindent(); 1810 println(out, ""); 1811 return 0; 1812 } 1813 1814 static int gen_json_parsers(fb_output_t *out) 1815 { 1816 fb_symbol_t *sym; 1817 1818 for (sym = out->S->symbols; sym; sym = sym->link) { 1819 switch (sym->kind) { 1820 case fb_is_union: 1821 gen_union_parser(out, (fb_compound_type_t *)sym); 1822 gen_union_accept_type(out, (fb_compound_type_t *)sym); 1823 gen_enum_parser(out, (fb_compound_type_t *)sym); 1824 break; 1825 case fb_is_struct: 1826 gen_struct_parser_inline(out, (fb_compound_type_t *)sym); 1827 gen_struct_parser(out, (fb_compound_type_t *)sym); 1828 break; 1829 case fb_is_table: 1830 gen_table_parser(out, (fb_compound_type_t *)sym); 1831 break; 1832 case fb_is_enum: 1833 gen_enum_parser(out, (fb_compound_type_t *)sym); 1834 break; 1835 } 1836 } 1837 fb_scope_table_visit(&out->S->root_schema->scope_index, gen_local_scope_parser, out); 1838 gen_global_scope_parser(out); 1839 gen_root_parser(out); 1840 return 0; 1841 } 1842 1843 int fb_gen_c_json_parser(fb_output_t *out) 1844 { 1845 gen_json_parser_pretext(out); 1846 gen_json_parser_prototypes(out); 1847 gen_json_parsers(out); 1848 gen_json_parser_footer(out); 1849 return 0; 1850 }