nostrdb

an unfairly fast embedded nostr database backed by lmdb
git clone git://jb55.com/nostrdb
Log | Files | Refs | Submodules | README | LICENSE

codegen_c_json_printer.c (29303B)


      1 #include "codegen_c.h"
      2 #include "flatcc/flatcc_types.h"
      3 
      4 /* -DFLATCC_PORTABLE may help if inttypes.h is missing. */
      5 #ifndef PRId64
      6 #include <inttypes.h>
      7 #endif
      8 
      9 static int gen_json_printer_pretext(fb_output_t *out)
     10 {
     11     fprintf(out->fp,
     12         "#ifndef %s_JSON_PRINTER_H\n"
     13         "#define %s_JSON_PRINTER_H\n",
     14         out->S->basenameup, out->S->basenameup);
     15 
     16     fprintf(out->fp, "\n/* " FLATCC_GENERATED_BY " */\n\n");
     17     fprintf(out->fp, "#include \"flatcc/flatcc_json_printer.h\"\n");
     18     fb_gen_c_includes(out, "_json_printer.h", "_JSON_PRINTER_H");
     19     gen_prologue(out);
     20     fprintf(out->fp, "\n");
     21     return 0;
     22 }
     23 
     24 static int gen_json_printer_footer(fb_output_t *out)
     25 {
     26     gen_epilogue(out);
     27     fprintf(out->fp,
     28         "#endif /* %s_JSON_PRINTER_H */\n",
     29         out->S->basenameup);
     30     return 0;
     31 }
     32 
     33 static int gen_json_printer_enum(fb_output_t *out, fb_compound_type_t *ct)
     34 {
     35     fb_symbol_t *sym;
     36     fb_member_t *member;
     37     fb_scoped_name_t snt, snref;
     38     const char *tp, *tn, *ns;
     39     int bit_flags;
     40     uint64_t mask = 0;
     41     char *constwrap = "";
     42     char *ut = "";
     43     fb_scalar_type_t st = ct->type.st;
     44 
     45     fb_clear(snt);
     46     fb_clear(snref);
     47     fb_compound_name(ct, &snt);
     48     tp = scalar_type_prefix(st);
     49     tn = scalar_type_name(st);
     50     ns = scalar_type_ns(st, out->nsc);
     51 
     52     bit_flags = !!(ct->metadata_flags & fb_f_bit_flags);
     53     if (bit_flags) {
     54         switch (ct->size) {
     55         case 1:
     56             mask = UINT8_MAX, constwrap = "UINT8_C", ut = "uint8_t";
     57             break;
     58         case 2:
     59             mask = UINT16_MAX, constwrap = "UINT16_C", ut = "uint16_t";
     60             break;
     61         case 4:
     62             mask = UINT32_MAX, constwrap = "UINT32_C", ut = "uint32_t";
     63             break;
     64         default:
     65             mask = UINT64_MAX, constwrap = "UINT64_C", ut = "uint64_t";
     66             break;
     67         }
     68         for (sym = ct->members; sym; sym = sym->link) {
     69             member = (fb_member_t *)sym;
     70             switch (member->value.type) {
     71             case vt_uint:
     72                 mask &= ~(uint64_t)member->value.u;
     73                 break;
     74             case vt_int:
     75                 mask &= ~(uint64_t)member->value.i;
     76                 break;
     77             case vt_bool:
     78                 mask &= ~(uint64_t)member->value.b;
     79                 break;
     80             }
     81         }
     82     }
     83 
     84     fprintf(out->fp,
     85             "static void %s_print_json_enum(flatcc_json_printer_t *ctx, %s%s v)\n{\n",
     86             snt.text, ns, tn);
     87     if (bit_flags) {
     88         if (strcmp(ut, tn)) {
     89             fprintf(out->fp, "    %s x = (%s)v;\n", ut, ut);
     90         } else {
     91             fprintf(out->fp, "    %s x = v;\n", ut);
     92         }
     93         fprintf(out->fp,
     94                 "    int multiple = 0 != (x & (x - 1));\n"
     95                 "    int i = 0;\n");
     96 
     97         fprintf(out->fp, "\n");
     98         /*
     99          * If the value is not entirely within the known bit flags, print as
    100          * a number.
    101          */
    102         if (mask) {
    103             fprintf(out->fp,
    104                     "    if ((x & %s(0x%"PRIx64")) || x == 0) {\n"
    105                     "        flatcc_json_printer_%s(ctx, v);\n"
    106                     "        return;\n"
    107                     "    }\n",
    108                    constwrap, mask, tp);
    109         }
    110         /*
    111          * Test if multiple bits set. We may have a configuration option
    112          * that requires multiple flags to be quoted like `color: "Red Green"`
    113          * but unquoted if just a single value like `color: Green`.
    114          *
    115          * The index `i` is used to add space separators much like an
    116          * index is provided for struct members to handle comma.
    117          */
    118         fprintf(out->fp, "    flatcc_json_printer_delimit_enum_flags(ctx, multiple);\n");
    119         for (sym = ct->members; sym; sym = sym->link) {
    120             member = (fb_member_t *)sym;
    121             switch (member->value.type) {
    122             case vt_uint:
    123                 fprintf(out->fp, "    if (x & %s(0x%"PRIx64")) flatcc_json_printer_enum_flag(ctx, i++, \"%.*s\", %ld);\n",
    124                         constwrap, member->value.u, (int)sym->ident->len, sym->ident->text, sym->ident->len);
    125                 break;
    126             case vt_int:
    127                 fprintf(out->fp, "    if (x & %s(0x%"PRIx64")) flatcc_json_printer_enum_flag(ctx, i++, \"%.*s\", %ld);\n",
    128                         constwrap, (uint64_t)member->value.i, (int)sym->ident->len, sym->ident->text, sym->ident->len);
    129                 break;
    130             case vt_bool:
    131                 fprintf(out->fp, "    if (x & %s(0x%"PRIx64")) flatcc_json_printer_enum_flag(ctx, i++, \"%.*s\", %ld);\n",
    132                         constwrap, (uint64_t)member->value.b, (int)sym->ident->len, sym->ident->text, sym->ident->len);
    133                 break;
    134             default:
    135                 gen_panic(out, "internal error: unexpected value type for enum json_print");
    136                 break;
    137             }
    138         }
    139         fprintf(out->fp, "    flatcc_json_printer_delimit_enum_flags(ctx, multiple);\n");
    140     } else {
    141         fprintf(out->fp, "\n    switch (v) {\n");
    142         for (sym = ct->members; sym; sym = sym->link) {
    143             member = (fb_member_t *)sym;
    144             switch (member->value.type) {
    145             case vt_uint:
    146                 fprintf(out->fp, "    case %s(%"PRIu64"): flatcc_json_printer_enum(ctx, \"%.*s\", %ld); break;\n",
    147                         constwrap, member->value.u, (int)sym->ident->len, sym->ident->text, sym->ident->len);
    148                 break;
    149             case vt_int:
    150                 fprintf(out->fp, "    case %s(%"PRId64"): flatcc_json_printer_enum(ctx, \"%.*s\", %ld); break;\n",
    151                         constwrap, member->value.i, (int)sym->ident->len, sym->ident->text, sym->ident->len);
    152                 break;
    153             case vt_bool:
    154                 fprintf(out->fp, "    case %s(%u): flatcc_json_printer_enum(ctx, \"%.*s\", %ld); break;\n",
    155                         constwrap, member->value.b, (int)sym->ident->len, sym->ident->text, sym->ident->len);
    156                 break;
    157             default:
    158                 gen_panic(out, "internal error: unexpected value type for enum json_print");
    159                 break;
    160             }
    161         }
    162         fprintf(out->fp,
    163                 "    default: flatcc_json_printer_%s(ctx, v); break;\n"
    164                 "    }\n",
    165                 tp);
    166     }
    167     fprintf(out->fp, "}\n\n");
    168     return 0;
    169 }
    170 
    171 static int gen_json_printer_union_type(fb_output_t *out, fb_compound_type_t *ct)
    172 {
    173     fb_symbol_t *sym;
    174     fb_member_t *member;
    175     fb_scoped_name_t snt;
    176 
    177     fb_clear(snt);
    178     fb_compound_name(ct, &snt);
    179 
    180     fprintf(out->fp,
    181             "static void %s_print_json_union_type(flatcc_json_printer_t *ctx, flatbuffers_utype_t type)\n"
    182             "{\n    switch (type) {\n",
    183             snt.text);
    184     for (sym = ct->members; sym; sym = sym->link) {
    185         member = (fb_member_t *)sym;
    186         if (member->type.type == vt_missing) {
    187             continue;
    188         }
    189         fprintf(out->fp,
    190                 "    case %u:\n"
    191                 "        flatcc_json_printer_enum(ctx, \"%.*s\", %ld);\n"
    192                 "        break;\n",
    193                 (unsigned)member->value.u, (int)sym->ident->len, sym->ident->text, sym->ident->len);
    194     }
    195     fprintf(out->fp,
    196             "    default:\n"
    197             "        flatcc_json_printer_enum(ctx, \"NONE\", 4);\n"
    198             "        break;\n");
    199     fprintf(out->fp,
    200             "    }\n}\n\n");
    201     return 0;
    202 }
    203 
    204 static int gen_json_printer_union_member(fb_output_t *out, fb_compound_type_t *ct)
    205 {
    206     fb_symbol_t *sym;
    207     fb_member_t *member;
    208     fb_scoped_name_t snt, snref;
    209 
    210     fb_clear(snt);
    211     fb_clear(snref);
    212     fb_compound_name(ct, &snt);
    213 
    214     fprintf(out->fp,
    215             "static void %s_print_json_union(flatcc_json_printer_t *ctx, flatcc_json_printer_union_descriptor_t *ud)\n"
    216             "{\n    switch (ud->type) {\n",
    217             snt.text);
    218     for (sym = ct->members; sym; sym = sym->link) {
    219         member = (fb_member_t *)sym;
    220         switch (member->type.type) {
    221         case vt_missing:
    222             continue;
    223         case vt_compound_type_ref:
    224             fb_compound_name(member->type.ct, &snref);
    225             switch (member->type.ct->symbol.kind) {
    226             case fb_is_table:
    227                 fprintf(out->fp,
    228                         "    case %u:\n"
    229                         "        flatcc_json_printer_union_table(ctx, ud, %s_print_json_table);\n"
    230                         "        break;\n",
    231                         (unsigned)member->value.u, snref.text);
    232                 continue;
    233             case fb_is_struct:
    234                 fprintf(out->fp,
    235                         "    case %u:\n"
    236                         "        flatcc_json_printer_union_struct(ctx, ud, %s_print_json_struct);\n"
    237                         "        break;\n",
    238                         (unsigned)member->value.u, snref.text);
    239                 continue;
    240             default:
    241                 gen_panic(out, "internal error: unexpected union type\n");
    242                 return -1;
    243             }
    244         case vt_string_type:
    245             fprintf(out->fp,
    246                     "    case %u:\n"
    247                     "        flatcc_json_printer_union_string(ctx, ud);\n"
    248                     "        break;\n",
    249                         (unsigned)member->value.u);
    250             continue;
    251         default:
    252             gen_panic(out, "internal error: unexpected union type\n");
    253             return -1;
    254         }
    255     }
    256     fprintf(out->fp,
    257                 "    default:\n"
    258                 "        break;\n");
    259     fprintf(out->fp,
    260             "    }\n}\n\n");
    261     return 0;
    262 }
    263 
    264 static int gen_json_printer_union(fb_output_t *out, fb_compound_type_t *ct)
    265 {
    266     gen_json_printer_union_type(out, ct);
    267     gen_json_printer_union_member(out, ct);
    268     return 0;
    269 }
    270 
    271 static int gen_json_printer_struct(fb_output_t *out, fb_compound_type_t *ct)
    272 {
    273     fb_symbol_t *sym;
    274     fb_member_t *member;
    275     fb_scoped_name_t snt, snref;
    276     int index = 0;
    277     const char *tp;
    278 
    279     fb_clear(snt);
    280     fb_clear(snref);
    281     fb_compound_name(ct, &snt);
    282 
    283     fprintf(out->fp,
    284             "static void %s_print_json_struct(flatcc_json_printer_t *ctx, const void *p)\n"
    285             "{\n",
    286             snt.text);
    287     for (sym = ct->members; sym; ++index, sym = sym->link) {
    288         member = (fb_member_t *)sym;
    289         if (member->metadata_flags & fb_f_deprecated) {
    290             continue;
    291         }
    292         switch (member->type.type) {
    293         case vt_scalar_type:
    294             tp = scalar_type_prefix(member->type.st);
    295             fprintf(
    296                     out->fp,
    297                     "    flatcc_json_printer_%s_struct_field(ctx, %d, p, %"PRIu64", \"%.*s\", %ld);\n",
    298                     tp, index, (uint64_t)member->offset, (int)sym->ident->len, sym->ident->text, sym->ident->len);
    299             break;
    300         case vt_fixed_array_type:
    301             tp = scalar_type_prefix(member->type.st);
    302             fprintf(
    303                     out->fp,
    304                     "    flatcc_json_printer_%s_array_struct_field(ctx, %d, p, %"PRIu64", \"%.*s\", %ld, %d);\n",
    305                     tp, index, (uint64_t)member->offset, (int)sym->ident->len, sym->ident->text, sym->ident->len, member->type.len);
    306             break;
    307         case vt_fixed_array_compound_type_ref:
    308             fb_compound_name(member->type.ct, &snref);
    309             switch (member->type.ct->symbol.kind) {
    310             case fb_is_enum:
    311 #if FLATCC_JSON_PRINT_MAP_ENUMS
    312                 tp = scalar_type_prefix(member->type.ct->type.st);
    313                 fprintf(out->fp,
    314                         "    flatcc_json_printer_%s_enum_array_struct_field(ctx, %d, p, %"PRIu64", \"%.*s\", %ld, %d, %s_print_json_enum);\n",
    315                         tp, index, (uint64_t)member->offset, (int)sym->ident->len, sym->ident->text, sym->ident->len, member->type.len, snref.text);
    316                 break;
    317 #else
    318                 tp = scalar_type_prefix(member->type.ct->type.st);
    319                 fprintf(
    320                         out->fp,
    321                         "    flatcc_json_printer_%s_array_struct_field(ctx, %d, p, %"PRIu64", \"%.*s\", %ld, %d);\n",
    322                         tp, index, (uint64_t)member->offset, (int)sym->ident->len, sym->ident->text, sym->ident->len, member->type.len);
    323                 break;
    324 #endif
    325             case fb_is_struct:
    326                 fprintf(out->fp,
    327                         "    flatcc_json_printer_embedded_struct_array_field(ctx, %d, p, %"PRIu64", \"%.*s\", %ld, %"PRIu64", %"PRIu64", %s_print_json_struct);\n",
    328                         index, (uint64_t)member->offset, (int)sym->ident->len, sym->ident->text, sym->ident->len,
    329                         (uint64_t)member->type.ct->size, (uint64_t)member->type.len, snref.text);
    330             }
    331             break;
    332         case vt_compound_type_ref:
    333             fb_compound_name(member->type.ct, &snref);
    334             switch (member->type.ct->symbol.kind) {
    335             case fb_is_enum:
    336 #if FLATCC_JSON_PRINT_MAP_ENUMS
    337                 tp = scalar_type_prefix(member->type.ct->type.st);
    338                 fprintf(out->fp,
    339                         "    flatcc_json_printer_%s_enum_struct_field(ctx, %d, p, %"PRIu64", \"%.*s\", %ld, %s_print_json_enum);\n",
    340                         tp, index, (uint64_t)member->offset, (int)sym->ident->len, sym->ident->text, sym->ident->len, snref.text);
    341                 break;
    342 #else
    343                 tp = scalar_type_prefix(member->type.ct->type.st);
    344                 fprintf(
    345                         out->fp,
    346                         "    flatcc_json_printer_%s_struct_field(ctx, %d, p, %"PRIu64", \"%.*s\", %ld);\n",
    347                         tp, index, (uint64_t)member->offset, (int)sym->ident->len, sym->ident->text, sym->ident->len);
    348                 break;
    349 #endif
    350             case fb_is_struct:
    351                 fprintf(out->fp,
    352                         "    flatcc_json_printer_embedded_struct_field(ctx, %d, p, %"PRIu64", \"%.*s\", %ld, %s_print_json_struct);\n",
    353                         index, (uint64_t)member->offset, (int)sym->ident->len, sym->ident->text, sym->ident->len, snref.text);
    354                 break;
    355             }
    356             break;
    357         }
    358     }
    359     fprintf(out->fp, "}\n\n");
    360     fprintf(out->fp,
    361             "static inline int %s_print_json_as_root(flatcc_json_printer_t *ctx, const void *buf, size_t bufsiz, const char *fid)\n"
    362             "{\n    return flatcc_json_printer_struct_as_root(ctx, buf, bufsiz, fid, %s_print_json_struct);\n}\n\n",
    363             snt.text, snt.text);
    364     return 0;
    365 }
    366 
    367 static int gen_json_printer_table(fb_output_t *out, fb_compound_type_t *ct)
    368 {
    369     fb_symbol_t *sym;
    370     fb_member_t *member;
    371     fb_scoped_name_t snt, snref;
    372     const char *tp;
    373     int is_optional;
    374     int ret = 0;
    375 
    376     fb_clear(snt);
    377     fb_clear(snref);
    378     fb_compound_name(ct, &snt);
    379 
    380     /* Fields are printed in field id order for consistency across schema version. */
    381     fprintf(out->fp,
    382             "static void %s_print_json_table(flatcc_json_printer_t *ctx, flatcc_json_printer_table_descriptor_t *td)\n"
    383             "{",
    384             snt.text);
    385 
    386     for (sym = ct->members; sym; sym = sym->link) {
    387         member = (fb_member_t *)sym;
    388         sym = &member->symbol;
    389         if (member->metadata_flags & fb_f_deprecated) {
    390             continue;
    391         }
    392         is_optional = !!(member->flags & fb_fm_optional);
    393         fprintf(out->fp, "\n    ");
    394         switch (member->type.type) {
    395         case vt_scalar_type:
    396             tp = scalar_type_prefix(member->type.st);
    397             if (is_optional) {
    398                 fprintf( out->fp,
    399                     "flatcc_json_printer_%s_optional_field(ctx, td, %"PRIu64", \"%.*s\", %ld);",
    400                     tp, member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len);
    401             } else {
    402                 fb_literal_t literal;
    403                 if (!print_literal(member->type.st, &member->value, literal)) return -1;
    404                 fprintf( out->fp,
    405                     "flatcc_json_printer_%s_field(ctx, td, %"PRIu64", \"%.*s\", %ld, %s);",
    406                     tp, member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, literal);
    407             }
    408             break;
    409         case vt_vector_type:
    410             if (member->metadata_flags & (fb_f_base64 | fb_f_base64url)) {
    411                 fprintf(out->fp,
    412                         "flatcc_json_printer_uint8_vector_base64_field(ctx, td, %"PRIu64", \"%.*s\", %ld, %u);",
    413                         member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len,
    414                         !(member->metadata_flags & fb_f_base64));
    415             } else if (member->nest) {
    416                 fb_compound_name((fb_compound_type_t *)&member->nest->symbol, &snref);
    417                 if (member->nest->symbol.kind == fb_is_table) {
    418                     /*
    419                      * Always set fid to 0 since it is difficult to know what is right.
    420                      * We do know the type from the field attribute.
    421                      */
    422                     fprintf(out->fp,
    423                         "flatcc_json_printer_table_as_nested_root(ctx, td, %"PRIu64", \"%.*s\", %ld, 0, %s_print_json_table);",
    424                         member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, snref.text);
    425                 } else {
    426                     /*
    427                      * Always set fid to 0 since it is difficult to know what is right.
    428                      * We do know the type from the field attribute.
    429                      */
    430                     fprintf(out->fp,
    431                         "flatcc_json_printer_struct_as_nested_root(ctx, td, %"PRIu64", \"%.*s\", %ld, 0, %s_print_json_struct);",
    432                         member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, snref.text);
    433                 }
    434             } else {
    435                 tp = scalar_type_prefix(member->type.st);
    436                 fprintf(out->fp,
    437                         "flatcc_json_printer_%s_vector_field(ctx, td, %"PRIu64", \"%.*s\", %ld);",
    438                         tp, member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len);
    439             }
    440             break;
    441         case vt_string_type:
    442             fprintf(out->fp,
    443                     "flatcc_json_printer_string_field(ctx, td, %"PRIu64", \"%.*s\", %ld);",
    444                     member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len);
    445             break;
    446         case vt_vector_string_type:
    447             fprintf(out->fp,
    448                     "flatcc_json_printer_string_vector_field(ctx, td, %"PRIu64", \"%.*s\", %ld);",
    449                     member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len);
    450             break;
    451         case vt_compound_type_ref:
    452             fb_compound_name(member->type.ct, &snref);
    453             switch (member->type.ct->symbol.kind) {
    454             case fb_is_enum:
    455                 tp = scalar_type_prefix(member->type.ct->type.st);
    456 #if FLATCC_JSON_PRINT_MAP_ENUMS
    457                 if (is_optional) {
    458                     fprintf(out->fp,
    459                         "flatcc_json_printer_%s_enum_optional_field(ctx, td, %"PRIu64", \"%.*s\", %ld, %s_print_json_enum);",
    460                         tp, member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, snref.text);
    461                 } else {
    462                     fb_literal_t literal;
    463                     if (!print_literal(member->type.ct->type.st, &member->value, literal)) return -1;
    464                     fprintf(out->fp,
    465                         "flatcc_json_printer_%s_enum_field(ctx, td, %"PRIu64", \"%.*s\", %ld, %s, %s_print_json_enum);",
    466                         tp, member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, literal, snref.text);
    467                 }
    468 #else
    469                 if (is_optional) {
    470                     fprintf( out->fp,
    471                         "flatcc_json_printer_%s_optional_field(ctx, td, %"PRIu64", \"%.*s\", %ld);",
    472                         tp, member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len);
    473                 } else {
    474                     fb_literal_t literal;
    475                     if (!print_literal(member->type.ct->type.st, &member->value, literal)) return -1;
    476                     fprintf( out->fp,
    477                         "flatcc_json_printer_%s_field(ctx, td, %"PRIu64", \"%.*s\", %ld, %s);",
    478                         tp, member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, literal);
    479                 }
    480 #endif
    481                 break;
    482             case fb_is_struct:
    483                 fprintf(out->fp,
    484                         "flatcc_json_printer_struct_field(ctx, td, %"PRIu64", \"%.*s\", %ld, %s_print_json_struct);",
    485                         member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, snref.text);
    486                 break;
    487             case fb_is_table:
    488                 fprintf(out->fp,
    489                         "flatcc_json_printer_table_field(ctx, td, %"PRIu64", \"%.*s\", %ld, %s_print_json_table);",
    490                         member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, snref.text);
    491                 break;
    492             case fb_is_union:
    493                 fprintf(out->fp,
    494                         "flatcc_json_printer_union_field(ctx, td, %"PRIu64", \"%.*s\", %ld, "
    495                         "%s_print_json_union_type, %s_print_json_union);",
    496                         member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, snref.text, snref.text);
    497                 break;
    498             default:
    499                 gen_panic(out, "internal error: unexpected compound type for table json_print");
    500                 goto fail;
    501             }
    502             break;
    503         case vt_vector_compound_type_ref:
    504             fb_compound_name(member->type.ct, &snref);
    505             switch (member->type.ct->symbol.kind) {
    506             case fb_is_table:
    507                 fprintf(out->fp,
    508                         "flatcc_json_printer_table_vector_field(ctx, td, %"PRIu64", \"%.*s\", %ld, %s_print_json_table);",
    509                         member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, snref.text);
    510                 break;
    511             case fb_is_enum:
    512                 tp = scalar_type_prefix(member->type.ct->type.st);
    513 #if FLATCC_JSON_PRINT_MAP_ENUMS
    514                 fprintf(out->fp,
    515                         "flatcc_json_printer_%s_enum_vector_field(ctx, td, %"PRIu64", \"%.*s\", %ld, %s_print_json_enum);",
    516                         tp, member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, snref.text);
    517                 break;
    518 #else
    519                 fprintf(out->fp,
    520                         "flatcc_json_printer_%s_vector_field(ctx, td, %"PRIu64", \"%.*s\", %ld);",
    521                         tp, member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len);
    522                 break;
    523 #endif
    524             case fb_is_struct:
    525                 fprintf(out->fp,
    526                         "flatcc_json_printer_struct_vector_field(ctx, td, %"PRIu64", \"%.*s\", %ld, %"PRIu64", %s_print_json_struct);",
    527                         member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, (uint64_t)member->size, snref.text);
    528                 break;
    529             case fb_is_union:
    530                 fprintf(out->fp,
    531                         "flatcc_json_printer_union_vector_field(ctx, td, %"PRIu64", \"%.*s\", %ld, "
    532                         "%s_print_json_union_type, %s_print_json_union);",
    533                         member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, snref.text, snref.text);
    534                 break;
    535 
    536             default:
    537                 gen_panic(out, "internal error: unexpected vector compound type for table json_print");
    538                 goto fail;
    539             }
    540             break;
    541         }
    542     }
    543     fprintf(out->fp, "\n}\n\n");
    544     fprintf(out->fp,
    545             "static inline int %s_print_json_as_root(flatcc_json_printer_t *ctx, const void *buf, size_t bufsiz, const char *fid)\n"
    546             "{\n    return flatcc_json_printer_table_as_root(ctx, buf, bufsiz, fid, %s_print_json_table);\n}\n\n",
    547             snt.text, snt.text);
    548 done:
    549     return ret;
    550 fail:
    551     ret = -1;
    552     goto done;
    553 }
    554 
    555 /*
    556  * Only tables are mutually recursive. Structs are sorted and unions are
    557  * defined earlier, depending on the table prototypes.
    558  */
    559 static int gen_json_printer_prototypes(fb_output_t *out)
    560 {
    561     fb_symbol_t *sym;
    562     fb_scoped_name_t snt;
    563     fb_symbol_t *root_type = out->S->root_type.type;
    564 
    565     fb_clear(snt);
    566 
    567     if (root_type)
    568     switch (root_type->kind) {
    569     case fb_is_table:
    570     case fb_is_struct:
    571         fprintf(out->fp,
    572                 "/*\n"
    573                 " * Prints the default root table or struct from a buffer which must have\n"
    574                 " * the schema declared file identifier, if any. It is also possible to\n"
    575                 " * call the type specific `print_json_as_root` function wich accepts an\n"
    576                 " * optional identifier (or 0) as argument. The printer `ctx` object must\n"
    577                 " * be initialized with the appropriate output type, or it can be 0 which\n"
    578                 " * defaults to stdout. NOTE: `ctx` is not generally allowed to be null, only\n"
    579                 " * here for a simplified interface.\n"
    580                 " */\n");
    581     fprintf(out->fp,
    582             "static int %s_print_json(flatcc_json_printer_t *ctx, const char *buf, size_t bufsiz);\n\n",
    583             out->S->basename);
    584         break;
    585     default:
    586         break;
    587     }
    588 
    589     for (sym = out->S->symbols; sym; sym = sym->link) {
    590         switch (sym->kind) {
    591         case fb_is_union:
    592             fb_compound_name((fb_compound_type_t *)sym, &snt);
    593             fprintf(out->fp,
    594                     "static void %s_print_json_union_type(flatcc_json_printer_t *ctx, flatbuffers_utype_t type);\n"
    595                     "static void %s_print_json_union(flatcc_json_printer_t *ctx, flatcc_json_printer_union_descriptor_t *ud);\n",
    596                     snt.text, snt.text);
    597             break;
    598         case fb_is_table:
    599             fb_compound_name((fb_compound_type_t *)sym, &snt);
    600             fprintf(out->fp,
    601                     "static void %s_print_json_table(flatcc_json_printer_t *ctx, flatcc_json_printer_table_descriptor_t *td);\n",
    602                     snt.text);
    603             break;
    604         case fb_is_struct:
    605             fb_compound_name((fb_compound_type_t *)sym, &snt);
    606             fprintf(out->fp,
    607                     "static void %s_print_json_struct(flatcc_json_printer_t *ctx, const void *p);\n",
    608                     snt.text);
    609             break;
    610         }
    611     }
    612     fprintf(out->fp, "\n");
    613     return 0;
    614 }
    615 
    616 static int gen_json_printer_enums(fb_output_t *out)
    617 {
    618     fb_symbol_t *sym;
    619 
    620     for (sym = out->S->symbols; sym; sym = sym->link) {
    621         switch (sym->kind) {
    622         case fb_is_enum:
    623             gen_json_printer_enum(out, (fb_compound_type_t *)sym);
    624         }
    625     }
    626     return 0;
    627 }
    628 
    629 static int gen_json_printer_unions(fb_output_t *out)
    630 {
    631     fb_symbol_t *sym;
    632 
    633     for (sym = out->S->symbols; sym; sym = sym->link) {
    634         switch (sym->kind) {
    635         case fb_is_union:
    636             gen_json_printer_union(out, (fb_compound_type_t *)sym);
    637         }
    638     }
    639     return 0;
    640 }
    641 
    642 static int gen_json_printer_structs(fb_output_t *out)
    643 {
    644     fb_symbol_t *sym;
    645 
    646     for (sym = out->S->symbols; sym; sym = sym->link) {
    647         switch (sym->kind) {
    648         case fb_is_struct:
    649             gen_json_printer_struct(out, (fb_compound_type_t *)sym);
    650         }
    651     }
    652     return 0;
    653 }
    654 
    655 static int gen_json_printer_tables(fb_output_t *out)
    656 {
    657     fb_symbol_t *sym;
    658 
    659     for (sym = out->S->symbols; sym; sym = sym->link) {
    660         switch (sym->kind) {
    661         case fb_is_table:
    662             gen_json_printer_table(out, (fb_compound_type_t *)sym);
    663         }
    664     }
    665     return 0;
    666 }
    667 
    668 /* Same for structs and tables. */
    669 static int gen_root_type_printer(fb_output_t *out, fb_compound_type_t *ct)
    670 {
    671     fb_scoped_name_t snt;
    672 
    673     fb_clear(snt);
    674     fb_compound_name(ct, &snt);
    675 
    676     fprintf(out->fp,
    677             "static int %s_print_json(flatcc_json_printer_t *ctx, const char *buf, size_t bufsiz)\n",
    678             out->S->basename);
    679     fprintf(out->fp,
    680             "{\n"
    681             "    flatcc_json_printer_t printer;\n"
    682             "\n"
    683             "    if (ctx == 0) {\n"
    684             "        ctx = &printer;\n"
    685             "        flatcc_json_printer_init(ctx, 0);\n"
    686             "    }\n"
    687             "    return %s_print_json_as_root(ctx, buf, bufsiz, ",
    688             snt.text);
    689     if (out->S->file_identifier.type == vt_string) {
    690         fprintf(out->fp,
    691                 "\"%.*s\");\n",
    692                 out->S->file_identifier.s.len, out->S->file_identifier.s.s);
    693     } else {
    694         fprintf(out->fp,
    695                 "0);");
    696     }
    697     fprintf(out->fp,
    698         "}\n\n");
    699     return 0;
    700 }
    701 
    702 static int gen_json_root_printer(fb_output_t *out)
    703 {
    704     fb_symbol_t *root_type = out->S->root_type.type;
    705 
    706     if (!root_type) {
    707         return 0;
    708     }
    709     if (root_type) {
    710         switch (root_type->kind) {
    711         case fb_is_table:
    712         case fb_is_struct:
    713             return gen_root_type_printer(out, (fb_compound_type_t *)root_type);
    714         default:
    715             break;
    716         }
    717     }
    718     return 0;
    719 }
    720 
    721 int fb_gen_c_json_printer(fb_output_t *out)
    722 {
    723     gen_json_printer_pretext(out);
    724     gen_json_printer_prototypes(out);
    725     gen_json_printer_enums(out);
    726     gen_json_printer_unions(out);
    727     gen_json_printer_structs(out);
    728     gen_json_printer_tables(out);
    729     gen_json_root_printer(out);
    730     gen_json_printer_footer(out);
    731     return 0;
    732 }