changed struct generation internals
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 16 Mar 2022 03:17:12 +0000 (22:17 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 16 Mar 2022 03:17:12 +0000 (22:17 -0500)
include/astnodes.h
include/types.h
src/checker.c
src/symres.c
src/types.c

index 068bafe7ab2ceb1d0e8aadf34580bc32d6b028f4..b43869ed101bbb325b1cc06fea1bb3cfd9d17bd1 100644 (file)
@@ -888,6 +888,11 @@ struct AstStructType {
     // a struct type is kind of complicated and should
     // only happen once.
     Type *stcache;
+
+    // NOTE: This type is used when the structure has not been
+    // completely generated, but is a valid pointer to where the
+    // type will be generated to.
+    Type *pending_type;
     
     // NOTE: Used to store statically bound expressions in the struct.
     Scope* scope;
@@ -898,8 +903,8 @@ struct AstStructType {
     OnyxFilePos polymorphic_error_loc;
     ConstraintContext constraints;
 
-    b32 stcache_is_valid : 1;
-    b32 is_union         : 1;
+    b32 pending_type_is_valid : 1;
+    b32 is_union              : 1;
 };
 struct AstStructMember {
     AstTyped_base;
index fa03138dec32d81d7ec388e851d7b626375f883f..9ed77e5343e92b81e2b770df135e64c572242f15 100644 (file)
@@ -76,6 +76,7 @@ typedef struct StructMember {
     // be many struct members, and iterating through an array would be
     // easier and less costly.                  - brendanfh 2020/09/17
     char *name;
+    struct OnyxToken* token;
 
     struct AstTyped** initial_value;
     i32 use_through_pointer_index;
@@ -91,6 +92,12 @@ struct TypeWithOffset {
     u32   offset;
 };
 
+typedef enum StructProcessingStatus {
+    SPS_Start,
+    SPS_Members_Done,
+    SPS_Uses_Done,
+} StructProcessingStatus;
+
 #define TYPE_KINDS \
     TYPE_KIND(Basic, TypeBasic)                                   \
     TYPE_KIND(Pointer, struct { TypeBasic base; Type *elem; })    \
@@ -105,12 +112,13 @@ struct TypeWithOffset {
         char* name;                                               \
         u32 size;                                                 \
         u16 alignment, mem_count;                                 \
-        Table(StructMember) members;                              \
+        Table(StructMember *) members;                            \
         bh_arr(StructMember *) memarr;                            \
         bh_arr(struct AstPolySolution) poly_sln;                  \
         bh_arr(TypeWithOffset) linear_members;                    \
         struct AstType *constructed_from;                         \
         bh_arr(struct AstTyped *) meta_tags;                      \
+        StructProcessingStatus status;                            \
     })                                                            \
     TYPE_KIND(PolyStruct, struct {                                \
         char* name;                                               \
@@ -199,6 +207,7 @@ Type* type_make_dynarray(bh_allocator alloc, Type* of);
 Type* type_make_varargs(bh_allocator alloc, Type* of);
 
 void build_linear_types_with_offset(Type* type, bh_arr(TypeWithOffset)* pdest, u32 offset);
+b32  type_struct_member_apply_use(bh_allocator alloc, Type *s_type, StructMember *smem);
 
 const char* type_get_unique_name(Type* type);
 const char* type_get_name(Type* type);
index 5712060a5262f56941bc8c51281f4db67565c262..88de40aed49306541dff072577765902b259770a 100644 (file)
@@ -2163,17 +2163,26 @@ CheckStatus check_struct(AstStructType* s_node) {
         }
     }
 
-    // NOTE: fills in the stcache
+    // NOTE: fills in the pending_type.
     type_build_from_ast(context.ast_alloc, (AstType *) s_node);
-    if (s_node->stcache == NULL || !s_node->stcache_is_valid)
+    if (s_node->pending_type == NULL || !s_node->pending_type_is_valid)
         YIELD(s_node->token->pos, "Waiting for type to be constructed.");
 
-    bh_arr_each(StructMember *, smem, s_node->stcache->Struct.memarr) {
+    bh_arr_each(StructMember *, smem, s_node->pending_type->Struct.memarr) {
         if ((*smem)->type->kind == Type_Kind_Compound) {
             ERROR(s_node->token->pos, "Compound types are not allowed as struct member types.");
         }
+
+        if ((*smem)->used) {
+            if (!type_struct_member_apply_use(context.ast_alloc, s_node->pending_type, *smem)) {
+                YIELD((*smem)->token->pos, "Waiting for use to be applied.");
+            }
+        }
     }
 
+    s_node->stcache = s_node->pending_type;
+    s_node->stcache->Struct.status = SPS_Uses_Done;
+
     return Check_Success;
 }
 
index bf173503acf76d3c00f7c681db8e5a65d6667299..88b7e5b8291ef037c39d8116d0d975b3c5ed15a5 100644 (file)
@@ -770,9 +770,9 @@ static SymresStatus symres_use(AstUse* use) {
             st = st->Pointer.elem;
 
         fori (i, 0, shlen(st->Struct.members)) {
-            StructMember value = st->Struct.members[i].value;
-            AstFieldAccess* fa = make_field_access(context.ast_alloc, use->expr, value.name);
-            symbol_raw_introduce(curr_scope, value.name, use->token->pos, (AstNode *) fa);
+            StructMember* value = st->Struct.members[i].value;
+            AstFieldAccess* fa = make_field_access(context.ast_alloc, use->expr, value->name);
+            symbol_raw_introduce(curr_scope, value->name, use->token->pos, (AstNode *) fa);
         }
 
         return Symres_Success;
@@ -1045,10 +1045,12 @@ SymresStatus symres_function(AstFunction* func) {
                         st = param->local->type->Pointer.elem;
                     }
 
+                    if (st->Struct.status != SPS_Uses_Done) return Symres_Yield_Macro;
+
                     fori (i, 0, shlen(st->Struct.members)) {
-                        StructMember value = st->Struct.members[i].value;
-                        AstFieldAccess* fa = make_field_access(context.ast_alloc, (AstTyped *) param->local, value.name);
-                        symbol_raw_introduce(curr_scope, value.name, param->local->token->pos, (AstNode *) fa);
+                        StructMember* value = st->Struct.members[i].value;
+                        AstFieldAccess* fa = make_field_access(context.ast_alloc, (AstTyped *) param->local, value->name);
+                        symbol_raw_introduce(curr_scope, value->name, param->local->token->pos, (AstNode *) fa);
                     }
 
                     param->use_processed = 1;
index cd913e5e0523f49921815309b39640e6d91c6748..daf88fc8e64ba7a500ba378ec16c670eb79bffe9 100644 (file)
@@ -337,18 +337,20 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
 
         case Ast_Kind_Struct_Type: {
             AstStructType* s_node = (AstStructType *) type_node;
-            if (s_node->stcache != NULL && s_node->stcache_is_valid) return s_node->stcache;
+            if (s_node->stcache != NULL) return s_node->stcache;
+            if (s_node->pending_type != NULL && s_node->pending_type_is_valid) return s_node->pending_type;
 
             Type* s_type;
-            if (s_node->stcache == NULL) {
+            if (s_node->pending_type == NULL) {
                 s_type = type_create(Type_Kind_Struct, alloc, 0);
-                s_node->stcache = s_type;
+                s_node->pending_type = s_type;
 
                 s_type->ast_type = type_node;
                 s_type->Struct.name = s_node->name;
                 s_type->Struct.mem_count = bh_arr_length(s_node->members);
                 s_type->Struct.meta_tags = s_node->meta_tags;
                 s_type->Struct.constructed_from = NULL;
+                s_type->Struct.status = SPS_Start;
                 type_register(s_type);
 
                 s_type->Struct.memarr = NULL;
@@ -356,17 +358,16 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
                 bh_arr_new(global_heap_allocator, s_type->Struct.memarr, s_type->Struct.mem_count);
 
             } else {
-                s_type = s_node->stcache;
+                s_type = s_node->pending_type;
             }
 
             s_type->Struct.poly_sln = NULL;
 
             bh_arr_clear(s_type->Struct.memarr);
-            // bh_table_clear(s_type->Struct.members);
             shfree(s_type->Struct.members);
             sh_new_arena(s_type->Struct.members);
 
-            s_node->stcache_is_valid = 1;
+            s_node->pending_type_is_valid = 1;
 
             b32 is_union = s_node->is_union;
             u32 size = 0;
@@ -378,7 +379,7 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
                     (*member)->type = type_build_from_ast(alloc, (*member)->type_node);
 
                 if ((*member)->type == NULL) {
-                    s_node->stcache_is_valid = 0;
+                    s_node->pending_type_is_valid = 0;
                     return NULL;
                 }
 
@@ -397,64 +398,22 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
                     return NULL;
                 }
 
-                StructMember smem = {
-                    .offset = offset,
-                    .type = (*member)->type,
-                    .idx = idx,
-                    .name = bh_strdup(alloc, (*member)->token->text),
-                    .initial_value = &(*member)->initial_value,
-                    .meta_tags = (*member)->meta_tags,
-
-                    .included_through_use = 0,
-                    .used = (*member)->is_used,
-                    .use_through_pointer_index = -1,
-                };
+                StructMember* smem = bh_alloc_item(alloc, StructMember);
+                smem->offset = offset;
+                smem->type = (*member)->type;
+                smem->idx = idx;
+                smem->name = bh_strdup(alloc, (*member)->token->text);
+                smem->token = (*member)->token;
+                smem->initial_value = &(*member)->initial_value;
+                smem->meta_tags = (*member)->meta_tags;
+
+                smem->included_through_use = 0;
+                smem->used = (*member)->is_used;
+                smem->use_through_pointer_index = -1;
                 shput(s_type->Struct.members, (*member)->token->text, smem);
+                bh_arr_push(s_type->Struct.memarr, smem);
                 token_toggle_end((*member)->token);
 
-                if (smem.used) {
-                    Type* used_type = (*member)->type;
-
-                    b32 type_is_pointer = 0;
-                    if (used_type->kind == Type_Kind_Pointer) {
-                        type_is_pointer = 1;
-                        used_type = type_get_contained_type(used_type);
-                    }
-
-                    if (used_type->kind != Type_Kind_Struct) {
-                        onyx_report_error((*member)->token->pos, Error_Critical, "Can only use things of structure, or pointer to structure type.");
-                        return NULL;
-                    }
-
-                    bh_arr_each(StructMember*, psmem, used_type->Struct.memarr) {
-                        if (shgeti(s_type->Struct.members, (*psmem)->name) != -1) {
-                            onyx_report_error((*member)->token->pos, Error_Critical, "Used name '%s' conflicts with existing struct member.", (*psmem)->name);
-                            return NULL;
-                        }
-
-                        StructMember new_smem;
-                        new_smem.type   = (*psmem)->type;
-                        new_smem.name   = (*psmem)->name;
-                        new_smem.meta_tags = (*psmem)->meta_tags;
-                        new_smem.used = 0;
-                        new_smem.included_through_use = 1;
-
-                        if (type_is_pointer) {
-                            new_smem.offset = (*psmem)->offset;
-                            new_smem.idx = (*psmem)->idx;
-                            new_smem.initial_value = NULL;
-                            new_smem.use_through_pointer_index = idx;
-                        } else {
-                            new_smem.offset = offset + (*psmem)->offset;
-                            new_smem.idx    = -1; // Dummy value because I don't think this is needed.
-                            new_smem.initial_value = (*psmem)->initial_value;
-                            new_smem.use_through_pointer_index = -1;
-                        }
-
-                        shput(s_type->Struct.members, (*psmem)->name, new_smem);
-                    }
-                }
-
                 u32 type_size = type_size_of((*member)->type);
 
                 if (!is_union) {
@@ -467,15 +426,6 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
                 idx++;
             }
 
-            // NOTE: Need to do a second pass because the references to the
-            // elements of the table may change if the internal arrays of the
-            // table need to be resized.
-            bh_arr_each(AstStructMember *, member, s_node->members) {
-                token_toggle_end((*member)->token);
-                bh_arr_push(s_type->Struct.memarr, &s_type->Struct.members[shgeti(s_type->Struct.members, (*member)->token->text)].value);
-                token_toggle_end((*member)->token);
-            }
-
             alignment = bh_max(s_node->min_alignment, alignment);
             bh_align(size, alignment);
             size = bh_max(s_node->min_size, size);
@@ -487,6 +437,7 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
             bh_arr_new(global_heap_allocator, s_type->Struct.linear_members, s_type->Struct.mem_count);
             build_linear_types_with_offset(s_type, &s_type->Struct.linear_members, 0);
 
+            s_type->Struct.status = SPS_Members_Done;
             return s_type;
         }
 
@@ -867,6 +818,53 @@ void build_linear_types_with_offset(Type* type, bh_arr(TypeWithOffset)* pdest, u
     }
 }
 
+b32 type_struct_member_apply_use(bh_allocator alloc, Type *s_type, StructMember *smem) {
+    Type* used_type = smem->type;
+
+    b32 type_is_pointer = 0;
+    if (used_type->kind == Type_Kind_Pointer) {
+        type_is_pointer = 1;
+        used_type = type_get_contained_type(used_type);
+    }
+
+    if (used_type->kind != Type_Kind_Struct) {
+        onyx_report_error(smem->token->pos, Error_Critical, "Can only use things of structure, or pointer to structure type.");
+        return 0;
+    }
+
+    if (used_type->Struct.status == SPS_Start) return 0;
+
+    bh_arr_each(StructMember*, psmem, used_type->Struct.memarr) {
+        if (shgeti(s_type->Struct.members, (*psmem)->name) != -1) {
+            onyx_report_error(smem->token->pos, Error_Critical, "Used name '%s' conflicts with existing struct member.", (*psmem)->name);
+            return 0;
+        }
+
+        StructMember* new_smem = bh_alloc_item(alloc, StructMember);
+        new_smem->type   = (*psmem)->type;
+        new_smem->name   = (*psmem)->name;
+        new_smem->meta_tags = (*psmem)->meta_tags;
+        new_smem->used = 0;
+        new_smem->included_through_use = 1;
+
+        if (type_is_pointer) {
+            new_smem->offset = (*psmem)->offset;
+            new_smem->idx = (*psmem)->idx;
+            new_smem->initial_value = NULL;
+            new_smem->use_through_pointer_index = smem->idx;
+        } else {
+            new_smem->offset = smem->offset + (*psmem)->offset;
+            new_smem->idx    = -1; // Dummy value because I don't think this is needed.
+            new_smem->initial_value = (*psmem)->initial_value;
+            new_smem->use_through_pointer_index = -1;
+        }
+
+        shput(s_type->Struct.members, (*psmem)->name, new_smem);
+    }
+
+    return 1;
+}
+
 const char* type_get_unique_name(Type* type) {
     if (type == NULL) return "unknown";
 
@@ -1018,15 +1016,15 @@ Type* type_get_contained_type(Type* type) {
 }
 
 static const StructMember slice_members[] = {
-    { 0,            0, NULL,                         "data",  NULL, -1, 0, 0 },
-    { POINTER_SIZE, 1, &basic_types[Basic_Kind_U32], "count", NULL, -1, 0, 0 },
+    { 0,            0, NULL,                         "data",  NULL, NULL, -1, 0, 0 },
+    { POINTER_SIZE, 1, &basic_types[Basic_Kind_U32], "count", NULL, NULL, -1, 0, 0 },
 };
 
 static const StructMember array_members[] = {
-    { 0,                0, NULL,                         "data",      NULL, -1, 0, 0 },
-    { POINTER_SIZE,     1, &basic_types[Basic_Kind_U32], "count",     NULL, -1, 0, 0 },
-    { POINTER_SIZE + 4, 2, &basic_types[Basic_Kind_U32], "capacity",  NULL, -1, 0, 0 },
-    { POINTER_SIZE + 8, 3, NULL,                         "allocator", NULL, -1, 0, 0 },
+    { 0,                0, NULL,                         "data",      NULL, NULL, -1, 0, 0 },
+    { POINTER_SIZE,     1, &basic_types[Basic_Kind_U32], "count",     NULL, NULL, -1, 0, 0 },
+    { POINTER_SIZE + 4, 2, &basic_types[Basic_Kind_U32], "capacity",  NULL, NULL, -1, 0, 0 },
+    { POINTER_SIZE + 8, 3, NULL,                         "allocator", NULL, NULL, -1, 0, 0 },
 };
 
 b32 type_lookup_member(Type* type, char* member, StructMember* smem) {
@@ -1038,7 +1036,7 @@ b32 type_lookup_member(Type* type, char* member, StructMember* smem) {
 
             i32 index = shgeti(stype->members, member);
             if (index == -1) return 0;
-            *smem = stype->members[index].value;
+            *smem = *stype->members[index].value;
             return 1;
         }