From c8c5763d0a197d2c611fe5d28f05f20637f48adb Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Fri, 8 Oct 2021 23:12:32 -0700 Subject: [PATCH] [examples] progress on type metadata commentary --- examples/type_metadata/generated/meta_types.c | 8 +-- examples/type_metadata/generated/meta_types.h | 6 +- .../type_metadata/type_info_final_program.c | 23 ++++---- examples/type_metadata/type_metadata.c | 59 +++++++++++++++++-- examples/type_metadata/type_metadata.h | 2 + 5 files changed, 74 insertions(+), 24 deletions(-) diff --git a/examples/type_metadata/generated/meta_types.c b/examples/type_metadata/generated/meta_types.c index f0b52fa..a5eb56c 100644 --- a/examples/type_metadata/generated/meta_types.c +++ b/examples/type_metadata/generated/meta_types.c @@ -1,4 +1,4 @@ -// generated by W:/metadesk/examples/type_metadata/type_metadata.c:874 +// generated by W:/metadesk/examples/type_metadata/type_metadata.c:914 TypeInfoMember Circle_members[2] = { {"r", 1, -1, &F32_type_info}, {"pos", 3, -1, &V2F32_type_info}, @@ -14,14 +14,14 @@ TypeInfoMember RoundedPolygon_members[3] = { {"p", 1, 1, &V2F32_type_info}, }; -// generated by W:/metadesk/examples/type_metadata/type_metadata.c:913 +// generated by W:/metadesk/examples/type_metadata/type_metadata.c:953 TypeInfoEnumerant Shape_members[3] = { {"Circle", 6, 1}, {"Segment", 7, 2}, {"Polygon", 7, 3}, }; -// generated by W:/metadesk/examples/type_metadata/type_metadata.c:949 +// generated by W:/metadesk/examples/type_metadata/type_metadata.c:989 TypeInfo U32_type_info = {TypeKind_Basic, "U32", 3, 4, 0, 0}; TypeInfo F32_type_info = {TypeKind_Basic, "F32", 3, 4, 0, 0}; TypeInfo V2F32_type_info = {TypeKind_Basic, "V2F32", 5, 8, 0, 0}; @@ -30,7 +30,7 @@ TypeInfo RoundedSegment_type_info = {TypeKind_Struct, "RoundedSegment", 14, 3, R TypeInfo RoundedPolygon_type_info = {TypeKind_Struct, "RoundedPolygon", 14, 3, RoundedPolygon_members, 0}; TypeInfo Shape_type_info = {TypeKind_Enum, "Shape", 5, 3, Shape_members, &U32_type_info}; -// generated by W:/metadesk/examples/type_metadata/type_metadata.c:1009 +// generated by W:/metadesk/examples/type_metadata/type_metadata.c:1049 TypeInfo* type_info_from_shape(Shape v) { diff --git a/examples/type_metadata/generated/meta_types.h b/examples/type_metadata/generated/meta_types.h index 5fe38c9..b969a2c 100644 --- a/examples/type_metadata/generated/meta_types.h +++ b/examples/type_metadata/generated/meta_types.h @@ -1,6 +1,6 @@ #if !defined(META_TYPES_H) #define META_TYPES_H -// generated by W:/metadesk/examples/type_metadata/type_metadata.c:751 +// generated by W:/metadesk/examples/type_metadata/type_metadata.c:791 typedef struct Circle Circle; struct Circle { @@ -29,11 +29,11 @@ Shape_Segment = 2, Shape_Polygon = 3, }; -// generated by W:/metadesk/examples/type_metadata/type_metadata.c:835 +// generated by W:/metadesk/examples/type_metadata/type_metadata.c:875 TypeInfo* type_info_from_shape(Shape v); U32 max_slot_from_shape(Shape v); -// generated by W:/metadesk/examples/type_metadata/type_metadata.c:858 +// generated by W:/metadesk/examples/type_metadata/type_metadata.c:898 extern TypeInfo U32_type_info; extern TypeInfo F32_type_info; extern TypeInfo V2F32_type_info; diff --git a/examples/type_metadata/type_info_final_program.c b/examples/type_metadata/type_info_final_program.c index 886d8c5..4875493 100644 --- a/examples/type_metadata/type_info_final_program.c +++ b/examples/type_metadata/type_info_final_program.c @@ -44,7 +44,8 @@ U8 raw_buffer[] = { #include int -print_data_from_type_info(U8 **ptr_inout, U8 *opl, TypeInfo *type_info, int indent){ +print_data_from_type_info(U8 **ptr_inout, U8 *opl, TypeInfo *type_info, int indent) +{ static char spaces[] = " "; @@ -108,20 +109,16 @@ print_data_from_type_info(U8 **ptr_inout, U8 *opl, TypeInfo *type_info, int inde // decode single members if (member->array_count_member_index == -1) { - // save the offset of this member for later - U8 *ptr_og = *ptr_inout; - // decode this member + if (member_type_info == &U32_type_info && *ptr_inout + 4 <= opl) + { + member_value_memory[i] = *(U32*)*ptr_inout; + } fprintf(stdout, "%.*s%.*s: ", indent, spaces, member->name_length, member->name); if (!print_data_from_type_info(ptr_inout, opl, member_type_info, indent + 1)) { result = 0; goto finish; } - // if we see a U32 we want to remember it in case it's an array count - if (member_type_info == &U32_type_info) - { - member_value_memory[i] = *(U32*)ptr_og; - } } // decode arrays @@ -176,13 +173,14 @@ print_data_from_type_info(U8 **ptr_inout, U8 *opl, TypeInfo *type_info, int inde int main(int argc, char **argv) { - // decode the raw buffer + // decode the raw buffer of shape data U8 *ptr = raw_buffer; U8 *opl = ptr + sizeof(raw_buffer); for (;ptr < opl;) { // decode a shape discriminator - if (ptr + sizeof(Shape) > opl){ + if (ptr + sizeof(Shape) > opl) + { fprintf(stdout, "Could not decode shape discriminator\n"); break; } @@ -191,7 +189,8 @@ main(int argc, char **argv) // get type info TypeInfo *type_info = type_info_from_shape(shape); - if (type_info == 0){ + if (type_info == 0) + { fprintf(stdout, "Unrecognized shape discriminator\n"); break; } diff --git a/examples/type_metadata/type_metadata.c b/examples/type_metadata/type_metadata.c index ae6aa1f..53321e3 100644 --- a/examples/type_metadata/type_metadata.c +++ b/examples/type_metadata/type_metadata.c @@ -54,6 +54,18 @@ static MD_Arena *arena = 0; FILE *error_file = 0; // node maps + +// @notes As we analyze the Metadesk tree we create more data. In this example +// the new data is stored in two major types GEN_TypeInfo and GEN_MapInfo. +// We form a list for each type of these "processed" types holds a pointer +// back to the original MD_Node that generated it, and room for information +// that will be equiped to the "processed" type in later stages of analysis. +// We also use the MD_Map helper to create a string -> pointer mapping so that +// we can look up the "processed" info pointers by name after the initial +// gather stage. +// +// TODO notes on managing output files. + GEN_TypeInfo *first_type = 0; GEN_TypeInfo *last_type = 0; MD_Map type_map = {0}; @@ -77,6 +89,12 @@ GEN_TypeInfo* gen_resolve_type_info_from_string(MD_String8 name) { GEN_TypeInfo *result = 0; + // @notes The MD_Map helper is a "flexibly" typed hash table. It's keys can + // be a mix of strings and pointers. Here MD_MapKeyStr(name) is making the + // `name` string into a key for the map. The lookup function returns a + // "map slot" because the map is not restricted to storing just one value + // per key, if we were using it that way we could use MD_MapScan to + // iterate through the map slots. MD_MapSlot *slot = MD_MapLookup(&type_map, MD_MapKeyStr(name)); if (slot != 0) { @@ -136,6 +154,15 @@ gen_map_case_from_enumerant(GEN_MapInfo *map, GEN_TypeEnumerant *enumerant) //~ analyzers ///////////////////////////////////////////////////////////////// +// @notes The first stage of processing is to loop over the top level nodes +// from each parse. We are using the tags `@type` and `@map` to mark the nodes +// that this generator will process. Whenever we see one of those tags we +// create a GEN_TypeInfo or GEN_MapInfo to gather up information from the +// stages of analysis, and we insert the new info pointer into the appropriate +// map. On the types we do a little bit of the analysis right in this function +// to figure out which "type kind" it is, this lets us avoid ever having info +// where the kind field is not one of the expected values. + void gen_gather_types_and_maps(MD_Node *list) { @@ -149,6 +176,8 @@ gen_gather_types_and_maps(MD_Node *list) if (!MD_NodeIsNil(type_tag)) { + // TODO(allen): check for duplicates + GEN_TypeKind kind = GEN_TypeKind_Null; MD_Node *tag_arg_node = type_tag->first_child; MD_String8 tag_arg_str = tag_arg_node->string; @@ -185,6 +214,8 @@ gen_gather_types_and_maps(MD_Node *list) // gather map if (MD_NodeHasTag(node, MD_S8Lit("map"), 0)) { + // TODO(allen): check for duplicates + GEN_MapInfo *map_info = MD_PushArrayZero(arena, GEN_MapInfo, 1); map_info->node = node; MD_QueuePush(first_map, last_map, map_info); @@ -226,6 +257,10 @@ gen_check_duplicate_member_names(void) } } +// @notes In the next few stages of analysis we 'equip' the info nodes we +// gathered with further information by examining the sub-trees rooted at the +// metadesk nodes we saw durring the gather phase. + void gen_equip_basic_type_size(void) { @@ -745,9 +780,14 @@ gen_check_complete_map_cases(void) //~ generators //////////////////////////////////////////////////////////////// +// @notes Each generator function does all of the generation for one of the +// generated features we want. TODO keep going here. + void gen_type_definitions_from_types(FILE *out) { + // @notes This Metadesk helper generates a comment that points back here. + // Generating a comment like this can help a lot to with issues later. MD_PrintGenNoteCComment(out); for (GEN_TypeInfo *type = first_type; @@ -1163,6 +1203,13 @@ main(int argc, char **argv) gen_check_duplicate_cases(); gen_check_complete_map_cases(); + // @notes Here we explicitly use one block to generate each output file. + // This approach makes it a lot easier to understand where the contents + // of generated files come from, because it's all layed out it one place. + // However if the number of output files grows, this can get out of hand + // and the situation may start calling for more automation of the output + // files. There is a large amount of judgement calling in this part! + // generate header file { FILE *h = fopen("meta_types.h", "wb"); @@ -1177,20 +1224,22 @@ main(int argc, char **argv) // generate definitions file { - // open output file FILE *c = fopen("meta_types.c", "wb"); - gen_struct_member_tables_from_types(c); gen_enum_member_tables_from_types(c); gen_type_info_definitions_from_types(c); gen_function_definitions_from_maps(c); - - // close output file fclose(c); } + + // @notes The generated code doesn't go straight to stdout, and has a lot + // of transforms applied. When writing the analyzers, it's often useful to + // have a way to directly dump the results of analysis right to stdout to + // see what's going on. + // print diagnostics of the parse analysis -#if 0 +#if 1 for (GEN_TypeInfo *type = first_type; type != 0; type = type->next) diff --git a/examples/type_metadata/type_metadata.h b/examples/type_metadata/type_metadata.h index a2a3f79..353526b 100644 --- a/examples/type_metadata/type_metadata.h +++ b/examples/type_metadata/type_metadata.h @@ -120,6 +120,8 @@ void gen_equip_map_cases(void); void gen_check_duplicate_cases(void); void gen_check_complete_map_cases(void); +// TODO: check array member indexes point to members from before the array + //~ generators //////////////////////////////////////////////////////////////// void gen_type_definitions_from_types(FILE *out); void gen_function_declarations_from_maps(FILE *out);