commit 8c31e681ffbeb80bcb45e631ba91cf43525bb39b
parent daa1a18c4fd26564453b1802f97ad10d1ab7a4c7
Author: Drew DeVault <sir@cmpwn.com>
Date: Fri, 15 Jan 2021 11:31:52 -0500
type store: initialize tagged union types
Diffstat:
3 files changed, 105 insertions(+), 2 deletions(-)
diff --git a/include/types.h b/include/types.h
@@ -102,6 +102,11 @@ struct type_struct_union {
struct struct_field *fields;
};
+struct type_tagged_union {
+ const struct type *type;
+ struct type_tagged_union *next;
+};
+
enum type_flags {
TYPE_CONST = 1 << 0,
};
@@ -117,6 +122,7 @@ struct type {
struct type_func func;
struct type_pointer pointer;
struct type_struct_union struct_union;
+ struct type_tagged_union tagged;
};
};
diff --git a/src/type_store.c b/src/type_store.c
@@ -351,6 +351,96 @@ struct_init_from_atype(struct type_store *store, enum type_storage storage,
}
}
+static size_t
+sum_atagged_memb(const struct ast_tagged_union_type *u)
+{
+ size_t nmemb = 0;
+ for (; u; u = u->next) {
+ if (u->type->storage == TYPE_STORAGE_TAGGED_UNION) {
+ nmemb += sum_atagged_memb(&u->type->tagged_union);
+ } else {
+ ++nmemb;
+ }
+ }
+ return nmemb;
+}
+
+static void
+collect_atagged_memb(struct type_store *store,
+ struct type_tagged_union **ta,
+ const struct ast_tagged_union_type *atu,
+ size_t *i)
+{
+ for (; atu; atu = atu->next) {
+ if (atu->type->storage == TYPE_STORAGE_TAGGED_UNION) {
+ collect_atagged_memb(store, ta, atu, i);
+ continue;
+ }
+ struct type_tagged_union *tu;
+ ta[*i] = tu = xcalloc(1, sizeof(struct type_tagged_union));
+ tu->type = type_store_lookup_atype(store, atu->type);
+ *i += 1;
+ }
+}
+
+static int
+tagged_cmp(const void *ptr_a, const void *ptr_b)
+{
+ const struct type_tagged_union **a =
+ (const struct type_tagged_union **)ptr_a;
+ const struct type_tagged_union **b =
+ (const struct type_tagged_union **)ptr_b;
+ return (*a)->type->id < (*b)->type->id ? -1
+ : (*a)->type->id > (*b)->type->id ? 1 : 0;
+}
+
+static void
+tagged_init_from_atype(struct type_store *store,
+ struct type *type, const struct ast_type *atype)
+{
+ size_t nmemb = sum_atagged_memb(&atype->tagged_union);
+ struct type_tagged_union **tu =
+ xcalloc(nmemb, sizeof(struct type_tagged_union *));
+ size_t i = 0;
+ collect_atagged_memb(store, tu, &atype->tagged_union, &i);
+
+ // Prune duplicates
+ for (i = 1; i < nmemb; ++i)
+ for (size_t j = 0; j < i; ++j) {
+ if (tu[j]->type->id == tu[i]->type->id) {
+ assert(0); // TODO: prune
+ }
+ }
+
+ // Sort by ID
+ qsort(tu, nmemb, sizeof(tu[0]), tagged_cmp);
+
+ // First one free
+ type->tagged = *tu[0];
+ free(tu[0]);
+
+ type->size = type->tagged.type->size;
+ type->align = type->tagged.type->align;
+
+ struct type_tagged_union **next = &type->tagged.next;
+ for (size_t i = 1; i < nmemb; ++i) {
+ if (tu[i]->type->size > type->size) {
+ type->size = tu[i]->type->size;
+ }
+ if (tu[i]->type->align > type->align) {
+ type->align = tu[i]->type->align;
+ }
+
+ *next = tu[i];
+ next = &tu[i]->next;
+ }
+
+ type->size += builtin_type_size.size;
+ if (builtin_type_size.align > type->align) {
+ type->align = builtin_type_size.align;
+ }
+}
+
static void
type_init_from_atype(struct type_store *store,
struct type *type,
@@ -450,7 +540,8 @@ type_init_from_atype(struct type_store *store,
&atype->struct_union);
break;
case TYPE_STORAGE_TAGGED_UNION:
- assert(0); // TODO
+ tagged_init_from_atype(store, type, atype);
+ break;
}
}
diff --git a/src/types.c b/src/types.c
@@ -306,7 +306,13 @@ type_hash(const struct type *type)
}
break;
case TYPE_STORAGE_TAGGED_UNION:
- assert(0); // TODO
+ // Invariant: subtypes must be sorted by ID and must not include
+ // any other tagged union types, nor any duplicates.
+ for (const struct type_tagged_union *tu = &type->tagged;
+ tu; tu = tu->next) {
+ hash = fnv1a_u64(hash, type_hash(tu->type));
+ }
+ break;
}
return hash;
}