LCOV - code coverage report
Current view: top level - src/compiler - codegen_schema.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 139 159 87.4 %
Date: 2016-11-30 13:12:14 Functions: 11 12 91.7 %
Branches: 71 96 74.0 %

           Branch data     Line data    Source code
       1                 :            : #include <stdio.h>
       2                 :            : #include <stdlib.h>
       3                 :            : #include "flatcc/reflection/reflection_builder.h"
       4                 :            : #include "symbols.h"
       5                 :            : #include "parser.h"
       6                 :            : #include "codegen.h"
       7                 :            : #include "fileio.h"
       8                 :            : /* Needed to store length prefix. */
       9                 :            : #include "catalog.h"
      10                 :            : 
      11                 :            : #define BaseType(x) FLATBUFFERS_WRAP_NAMESPACE(reflection_BaseType, x)
      12                 :            : 
      13                 :         69 : static reflection_Type_ref_t export_type(flatcc_builder_t *B, fb_value_t type)
      14                 :            : {
      15                 :            :     fb_scalar_type_t st = fb_missing_type;
      16                 :            :     int32_t index = -1;
      17                 :            :     reflection_BaseType_enum_t base_type = BaseType(None);
      18                 :            :     reflection_BaseType_enum_t element = BaseType(None);
      19                 :            :     reflection_BaseType_enum_t primitive = BaseType(None);
      20                 :            : 
      21   [ +  +  +  +  :         69 :     switch (type.type) {
                -  +  + ]
      22                 :            :     case vt_scalar_type:
      23                 :         38 :         st = type.st;
      24                 :         38 :         break;
      25                 :            :     case vt_vector_type:
      26                 :          4 :         st = type.st;
      27                 :            :         base_type = BaseType(Vector);
      28                 :          4 :         break;
      29                 :            :     case vt_vector_string_type:
      30                 :            :         element = BaseType(String);
      31                 :            :         base_type = BaseType(Vector);
      32                 :          1 :         break;
      33                 :            :     case vt_vector_compound_type_ref:
      34                 :          3 :         index = (int32_t)type.ct->export_index;
      35      [ -  +  - ]:          3 :         switch (type.ct->symbol.kind) {
      36                 :            :         case fb_is_enum:
      37                 :          0 :             st = type.ct->type.st;
      38                 :            :             base_type = BaseType(Vector);
      39                 :          0 :             break;
      40                 :            :         case fb_is_struct:
      41                 :            :         case fb_is_table:
      42                 :            :             base_type = BaseType(Vector);
      43                 :            :             element = BaseType(Obj);
      44                 :          3 :             break;
      45                 :            :         default:
      46                 :            :             break;
      47                 :            :         }
      48                 :            :         break;
      49                 :            :     case vt_string:
      50                 :            :         base_type = BaseType(String);
      51                 :          0 :         break;
      52                 :            :     case vt_compound_type_ref:
      53                 :         18 :         index = (int32_t)type.ct->export_index;
      54   [ +  +  -  + ]:         18 :         switch (type.ct->symbol.kind) {
      55                 :            :         case fb_is_enum:
      56                 :          8 :             st = type.ct->type.st;
      57                 :          8 :             break;
      58                 :            :         case fb_is_struct:
      59                 :            :         case fb_is_table:
      60                 :            :             base_type = BaseType(Obj);
      61                 :            :             break;
      62                 :            :         case fb_is_union:
      63                 :            :             base_type = BaseType(Union);
      64                 :          2 :             break;
      65                 :            :         default:
      66                 :            :             index = -1;
      67         [ +  + ]:         69 :             break;
      68                 :            :         }
      69                 :            :         break;
      70                 :            :     default:
      71                 :            :         break;
      72                 :            :     }
      73                 :            :     /* If st is set, resolve scalar type and set it to base_type or element. */
      74                 :            :     switch (st) {
      75                 :            :     case fb_missing_type: break;
      76                 :            :     case fb_ulong: primitive = BaseType(ULong); break;
      77                 :            :     case fb_uint: primitive = BaseType(UInt); break;
      78                 :            :     case fb_ushort: primitive = BaseType(UShort); break;
      79                 :            :     case fb_ubyte: primitive = BaseType(UByte); break;
      80                 :            :     case fb_bool: primitive = BaseType(Bool); break;
      81                 :            :     case fb_long: primitive = BaseType(Long); break;
      82                 :            :     case fb_int: primitive = BaseType(Int); break;
      83                 :            :     case fb_short: primitive = BaseType(Short); break;
      84                 :            :     case fb_byte: primitive = BaseType(Byte); break;
      85                 :            :     case fb_double: primitive = BaseType(Double); break;
      86                 :            :     case fb_float: primitive = BaseType(Float); break;
      87                 :            :     default: break;
      88                 :            :     }
      89                 :            : 
      90         [ +  + ]:         69 :     if (base_type == BaseType(None)) {
      91                 :            :         base_type = primitive;
      92         [ +  + ]:         18 :     } else if (base_type == BaseType(Vector)) {
      93         [ +  + ]:          8 :         if (element == BaseType(None)) {
      94                 :            :             element = primitive;
      95                 :            :         }
      96                 :            :     }
      97                 :         69 :     return reflection_Type_create(B, base_type, element, index);
      98                 :            : }
      99                 :            : 
     100                 :         30 : static void export_fields(flatcc_builder_t *B, fb_compound_type_t *ct)
     101                 :            : {
     102                 :            :     fb_symbol_t *sym;
     103                 :            :     fb_member_t *member;
     104                 :            :     flatbuffers_bool_t has_key, deprecated, required, key_processed = 0;
     105                 :            :     int64_t default_integer;
     106                 :            :     double default_real;
     107                 :            : 
     108         [ +  + ]:         78 :     for (sym = ct->members; sym; sym = sym->link) {
     109                 :            :         member = (fb_member_t *)sym;
     110                 :            :         /*
     111                 :            :          * Unlike `flatc` we allow multiple keys in the parser, but
     112                 :            :          * there is no way to tell which key is default in the
     113                 :            :          * reflection schema because the fields are sorted, so we only
     114                 :            :          * export the default (first) key.
     115                 :            :          */
     116 [ +  + ][ +  + ]:         63 :         has_key = !key_processed && (member->metadata_flags & fb_f_key) != 0;
     117                 :         63 :         required = (member->metadata_flags & fb_f_required) != 0;
     118                 :            :         default_integer = 0;
     119                 :            :         default_real = 0.0;
     120                 :         63 :         deprecated = (member->metadata_flags & fb_f_deprecated) != 0;
     121                 :            : 
     122 [ +  + ][ +  + ]:         63 :         if (member->type.type == vt_compound_type_ref && member->type.ct->symbol.kind == fb_is_union) {
     123                 :            :             reflection_Field_vec_push_start(B);
     124                 :            :             reflection_Field_name_start(B);
     125                 :          2 :             reflection_Field_name_append(B, member->symbol.ident->text, member->symbol.ident->len);
     126                 :            :             reflection_Field_name_append(B, "_type", 5);
     127                 :          2 :             reflection_Field_name_end(B);
     128                 :          2 :             reflection_Field_type_create(B, BaseType(UType), BaseType(None), -1);
     129                 :          2 :             reflection_Field_offset_add(B, (uint16_t)(member->id - 1 + 2) * sizeof(flatbuffers_voffset_t));
     130                 :          2 :             reflection_Field_id_add(B, (uint16_t)(member->id - 1));
     131                 :          2 :             reflection_Field_deprecated_add(B, deprecated);
     132                 :          2 :             reflection_Field_vec_push_end(B);
     133                 :            :         }
     134                 :            :         reflection_Field_vec_push_start(B);
     135                 :         63 :         reflection_Field_name_create(B, member->symbol.ident->text, member->symbol.ident->len);
     136                 :         63 :         reflection_Field_type_add(B, export_type(B, member->type));
     137      [ +  +  - ]:         63 :         switch (ct->symbol.kind) {
     138                 :            :         case fb_is_table:
     139   [ +  +  +  -  :         52 :             switch (member->value.type) {
                      + ]
     140                 :            :             case vt_uint:
     141                 :          9 :                 default_integer = (int64_t)member->value.u;
     142                 :            :                 break;
     143                 :            :             case vt_int:
     144                 :         19 :                 default_integer = (int64_t)member->value.i;
     145                 :            :                 break;
     146                 :            :             case vt_bool:
     147                 :          2 :                 default_integer = (int64_t)member->value.b;
     148                 :            :                 break;
     149                 :            :             case vt_float:
     150                 :          0 :                 default_real = member->value.f;
     151                 :            :                 break;
     152                 :            :             }
     153                 :         52 :             reflection_Field_default_integer_add(B, default_integer);
     154                 :         52 :             reflection_Field_default_real_add(B, default_real);
     155                 :         52 :             reflection_Field_id_add(B, (uint16_t)member->id);
     156                 :         52 :             reflection_Field_offset_add(B, (uint16_t)(member->id + 2) * sizeof(flatbuffers_voffset_t));
     157                 :         52 :             reflection_Field_key_add(B, has_key);
     158                 :         52 :             reflection_Field_required_add(B, required);
     159                 :            :             break;
     160                 :            :         case fb_is_struct:
     161                 :         11 :             reflection_Field_offset_add(B, (uint16_t)member->offset);
     162                 :            :             break;
     163                 :            :         default: break;
     164                 :            :         }
     165                 :            :         /* Deprecated struct fields not supported by `flatc` but is here as an option. */
     166                 :         63 :         reflection_Field_deprecated_add(B, deprecated);
     167                 :         63 :         reflection_Field_vec_push_end(B);
     168                 :         63 :         key_processed |= has_key;
     169                 :            :     }
     170                 :         15 : }
     171                 :            : 
     172                 :            : /* `vec` is filled with references to the constructed objects. */
     173                 :          2 : static void export_objects(flatcc_builder_t *B, object_entry_t *objects, int nobjects,
     174                 :            :         reflection_Object_ref_t *object_map)
     175                 :            : {
     176                 :            :     int i, is_struct;
     177                 :            :     fb_compound_type_t *ct;
     178                 :            : 
     179         [ +  + ]:         17 :     for (i = 0; i < nobjects; ++i) {
     180                 :         15 :         ct = objects[i].ct;
     181                 :            :         reflection_Object_start(B);
     182                 :         15 :         reflection_Object_name_create_str(B, objects[i].name);
     183                 :            :         /*
     184                 :            :          * We can post sort-fields because the index is not used, unlike
     185                 :            :          * objects and enums.
     186                 :            :          */
     187                 :            :         reflection_Object_fields_start(B);
     188                 :         15 :         export_fields(B, ct);
     189                 :         15 :         reflection_Object_fields_end(B);
     190                 :         15 :         is_struct = ct->symbol.kind == fb_is_struct;
     191         [ +  + ]:         15 :         if (is_struct) {
     192                 :          6 :             reflection_Object_bytesize_add(B, (uint32_t)ct->size);
     193                 :            :         }
     194                 :         15 :         reflection_Object_is_struct_add(B, is_struct);
     195                 :         15 :         reflection_Object_minalign_add(B, ct->align);
     196                 :         30 :         object_map[i] = reflection_Object_end(B);
     197                 :            :     }
     198                 :          2 :     reflection_Schema_objects_create(B, object_map, nobjects);
     199                 :          2 : }
     200                 :            : 
     201                 :         14 : static void export_enumval(flatcc_builder_t *B, fb_member_t *member, reflection_Object_ref_t *object_map)
     202                 :            : {
     203                 :            :     reflection_EnumVal_vec_push_start(B);
     204                 :         14 :     reflection_EnumVal_name_create(B, member->symbol.ident->text, member->symbol.ident->len);
     205 [ +  + ][ +  + ]:         14 :     if (object_map && member->type.type == vt_compound_type_ref) {
     206                 :          3 :         reflection_EnumVal_object_add(B, object_map[member->type.ct->export_index]);
     207                 :            :     }
     208                 :         14 :     reflection_EnumVal_value_add(B, member->value.u);
     209                 :         14 :     reflection_EnumVal_vec_push_end(B);
     210                 :         14 : }
     211                 :            : 
     212                 :          2 : static void export_enums(flatcc_builder_t *B, enum_entry_t *enums, int nenums,
     213                 :            :         reflection_Object_ref_t *object_map)
     214                 :            : {
     215                 :            :     int i, is_union;
     216                 :            :     fb_compound_type_t *ct;
     217                 :            :     fb_symbol_t *sym;
     218                 :            :     reflection_Enum_ref_t *vec;
     219                 :            : 
     220                 :            :     reflection_Schema_enums_start(B);
     221                 :          2 :     vec = reflection_Schema_enums_extend(B, nenums);
     222         [ +  + ]:          8 :     for (i = 0; i < nenums; ++i) {
     223                 :          6 :         ct = enums[i].ct;
     224                 :          6 :         is_union = ct->symbol.kind == fb_is_union;
     225                 :            :         reflection_Enum_start(B);
     226                 :          6 :         reflection_Enum_name_create_str(B, enums[i].name);
     227                 :            :         reflection_Enum_values_start(B);
     228         [ +  + ]:         20 :         for (sym = ct->members; sym; sym = sym->link) {
     229         [ +  + ]:         14 :             export_enumval(B, (fb_member_t *)sym, is_union ? object_map : 0);
     230                 :            :         }
     231                 :          6 :         reflection_Enum_values_end(B);
     232                 :          6 :         reflection_Enum_is_union_add(B, is_union);
     233                 :          6 :         reflection_Enum_underlying_type_add(B, export_type(B, ct->type));
     234                 :         12 :         vec[i] = reflection_Enum_end(B);
     235                 :            :     }
     236                 :          2 :     reflection_Schema_enums_end(B);
     237                 :          2 : }
     238                 :            : 
     239                 :          2 : static void export_root_type(flatcc_builder_t *B, fb_symbol_t * root_type,
     240                 :            :         reflection_Object_ref_t *object_map)
     241                 :            : {
     242                 :            :     fb_compound_type_t *ct;
     243         [ +  - ]:          2 :     if (root_type) {
     244                 :            :         /*
     245                 :            :          * We could also store a struct object here, but since the
     246                 :            :          * binrary schema says root_table, not root_type as in the text
     247                 :            :          * schema, it would be misleading.
     248                 :            :          */
     249         [ +  - ]:          2 :         if (root_type->kind == fb_is_table) {
     250                 :            :             ct = (fb_compound_type_t *)root_type;
     251                 :          2 :             reflection_Schema_root_table_add(B, object_map[ct->export_index]);
     252                 :            :         }
     253                 :            :     }
     254                 :          2 : }
     255                 :            : 
     256                 :          4 : static int export_schema(flatcc_builder_t *B, fb_options_t *opts, fb_schema_t *S)
     257                 :            : {
     258                 :            :     catalog_t catalog;
     259                 :            :     reflection_Object_ref_t *object_map = 0;
     260                 :            : 
     261         [ +  - ]:          2 :     if (build_catalog(&catalog, S, opts->bgen_qualify_names, &S->root_schema->scope_index)) {
     262                 :            :         return -1;
     263                 :            :     }
     264                 :            : 
     265 [ +  - ][ -  + ]:          2 :     if (catalog.nobjects > 0 && !(object_map = malloc(catalog.nobjects * sizeof(object_map[0])))) {
     266                 :          0 :         clear_catalog(&catalog);
     267                 :            :         return -1;
     268                 :            :     }
     269                 :            : 
     270                 :            :     /* Build the schema. */
     271                 :            : 
     272         [ -  + ]:          2 :     if (opts->bgen_length_prefix) {
     273                 :          0 :         reflection_Schema_start_as_root_with_size(B);
     274                 :            :     } else {
     275                 :          2 :         reflection_Schema_start_as_root(B);
     276                 :            :     }
     277         [ +  + ]:          2 :     if (S->file_identifier.type == vt_string) {
     278                 :          1 :         reflection_Schema_file_ident_create(B,
     279                 :          2 :                 S->file_identifier.s.s, S->file_identifier.s.len);
     280                 :            :     }
     281         [ +  + ]:          2 :     if (S->file_extension.type == vt_string) {
     282                 :          1 :         reflection_Schema_file_ext_create(B,
     283                 :          2 :                 S->file_extension.s.s, S->file_extension.s.len);
     284                 :            :     }
     285                 :          2 :     export_objects(B, catalog.objects, catalog.nobjects, object_map);
     286                 :          2 :     export_enums(B, catalog.enums, catalog.nenums, object_map);
     287                 :          2 :     export_root_type(B, S->root_type.type, object_map);
     288                 :            : 
     289                 :          2 :     reflection_Schema_end_as_root(B);
     290                 :            : 
     291                 :            :     /* Clean up support datastructures. */
     292                 :            : 
     293                 :          2 :     clear_catalog(&catalog);
     294         [ +  - ]:          2 :     if (object_map) {
     295                 :          2 :         free(object_map);
     296                 :            :     }
     297                 :            :     return 0;
     298                 :            : }
     299                 :            : 
     300                 :            : /* Field sorting is easier done on the finished buffer. */
     301                 :          2 : static void sort_fields(void *buffer)
     302                 :            : {
     303                 :            :     size_t i;
     304                 :            :     reflection_Schema_table_t schema;
     305                 :            :     reflection_Object_vec_t objects;
     306                 :            :     reflection_Object_table_t object;
     307                 :            :     reflection_Field_vec_t fields;
     308                 :            :     reflection_Field_mutable_vec_t mfields;
     309                 :            : 
     310                 :            :     schema = reflection_Schema_as_root(buffer);
     311                 :            :     objects = reflection_Schema_objects(schema);
     312         [ +  + ]:         34 :     for (i = 0; i < reflection_Object_vec_len(objects); ++i) {
     313                 :            :         object = reflection_Object_vec_at(objects, i);
     314                 :            :         fields = reflection_Object_fields(object);
     315                 :            :         mfields = (reflection_Field_mutable_vec_t)fields;
     316                 :            :         reflection_Field_vec_sort(mfields);
     317                 :            :     }
     318                 :          2 : }
     319                 :            : 
     320                 :          2 : static FILE *open_file(fb_options_t *opts, fb_schema_t *S)
     321                 :            : {
     322                 :            :     FILE *fp = 0;
     323                 :            :     char *path;
     324         [ +  - ]:          2 :     const char *prefix = opts->outpath ? opts->outpath : "";
     325                 :          2 :     size_t len, prefix_len = strlen(prefix);
     326                 :            :     const char *name;
     327                 :            :     const char *ext;
     328                 :            : 
     329                 :          2 :     name = S->basename;
     330                 :          2 :     len = strlen(name);
     331                 :            : 
     332                 :            :     ext = flatbuffers_extension;
     333                 :            : 
     334                 :            :     /* We generally should not use cgen options here, but in this case it makes sense. */
     335         [ -  + ]:          2 :     if (opts->gen_stdout) {
     336                 :          0 :         return stdout;
     337                 :            :     }
     338                 :          2 :     checkmem((path = fb_create_join_path_n(prefix, prefix_len, name, len, ext, 1)));
     339                 :          2 :     fp = fopen(path, "wb");
     340         [ -  + ]:          2 :     if (!fp) {
     341                 :          0 :         fprintf(stderr, "error opening file for writing binary schema: %s\n", path);
     342                 :            :     }
     343                 :          2 :     free(path);
     344                 :            :     return fp;
     345                 :            : }
     346                 :            : 
     347                 :            : static void close_file(FILE *fp)
     348                 :            : {
     349         [ +  - ]:          2 :     if (fp && fp != stdout) {
     350                 :          2 :         fclose(fp);
     351                 :            :     }
     352                 :            : }
     353                 :            : 
     354                 :            : /*
     355                 :            :  * Normally enums are required to be ascending in the schema and
     356                 :            :  * therefore there is no need to sort enums. If not, we export them in
     357                 :            :  * the order defined anyway becuase there is no well-defined ordering
     358                 :            :  * and blindly sorting the content would just loose more information.
     359                 :            :  *
     360                 :            :  * In conclusion: find by enum value is only support when enums are
     361                 :            :  * defined in consequtive order.
     362                 :            :  *
     363                 :            :  * refers to: `opts->ascending_enum`
     364                 :            :  *
     365                 :            :  * `size` must hold the maximum buffer size.
     366                 :            :  * Returns intput buffer if successful and updates size argument.
     367                 :            :  */
     368                 :          0 : void *fb_codegen_bfbs_to_buffer(fb_options_t *opts, fb_schema_t *S, void *buffer, size_t *size)
     369                 :            : {
     370                 :            :     flatcc_builder_t builder, *B;
     371                 :            : 
     372                 :            :     B = &builder;
     373                 :          0 :     flatcc_builder_init(B);
     374                 :          0 :     export_schema(B, opts, S);
     375         [ #  # ]:          0 :     if (!flatcc_builder_copy_buffer(B, buffer, *size)) {
     376                 :            :         goto done;
     377                 :            :     }
     378                 :          0 :     sort_fields(buffer);
     379                 :            : done:
     380                 :          0 :     *size = flatcc_builder_get_buffer_size(B);
     381                 :          0 :     flatcc_builder_clear(B);
     382                 :          0 :     return buffer;
     383                 :            : }
     384                 :            : 
     385                 :            : /*
     386                 :            :  * Like to_buffer, but returns allocated buffer.
     387                 :            :  * Updates size argument with buffer size if not null.
     388                 :            :  * Returned buffer must be deallocatd with `free`.
     389                 :            :  * The buffer is malloc aligned which should suffice for reflection buffers.
     390                 :            :  */
     391                 :          2 : void *fb_codegen_bfbs_alloc_buffer(fb_options_t *opts, fb_schema_t *S, size_t *size)
     392                 :            : {
     393                 :            :     flatcc_builder_t builder, *B;
     394                 :            :     void *buffer = 0;
     395                 :            : 
     396                 :            :     B = &builder;
     397                 :          2 :     flatcc_builder_init(B);
     398         [ +  - ]:          2 :     if (export_schema(B, opts, S)) {
     399                 :            :         goto done;
     400                 :            :     }
     401         [ +  - ]:          2 :     if (!(buffer = flatcc_builder_finalize_buffer(B, size))) {
     402                 :            :         goto done;
     403                 :            :     }
     404                 :          2 :     sort_fields(buffer);
     405                 :            : done:
     406                 :          2 :     flatcc_builder_clear(B);
     407                 :          2 :     return buffer;
     408                 :            : }
     409                 :            : 
     410                 :          2 : int fb_codegen_bfbs_to_file(fb_options_t *opts, fb_schema_t *S)
     411                 :            : {
     412                 :            :     void *buffer;
     413                 :            :     size_t size;
     414                 :            :     FILE *fp;
     415                 :            :     int ret = -1;
     416                 :            : 
     417                 :          2 :     fp = open_file(opts, S);
     418         [ +  - ]:          2 :     if (!fp) {
     419                 :            :         return -1;
     420                 :            :     }
     421                 :          2 :     buffer = fb_codegen_bfbs_alloc_buffer(opts, S, &size);
     422         [ -  + ]:          2 :     if (!buffer) {
     423                 :          0 :         printf("failed to generate binary schema\n");
     424                 :          0 :         goto done;
     425                 :            :     }
     426         [ -  + ]:          2 :     if (size != fwrite(buffer, 1, size, fp)) {
     427                 :          0 :         fprintf(stderr, "could not write binary schema to file\n");
     428                 :          0 :         goto done;
     429                 :            :     }
     430                 :            :     ret = 0;
     431                 :            : done:
     432         [ +  - ]:          2 :     if (buffer) {
     433                 :          2 :         free(buffer);
     434                 :            :     }
     435                 :            :     close_file(fp);
     436                 :            :     return ret;
     437                 :            : }

Generated by: LCOV version 1.12