A decent union type with common fields and variants

This commit is contained in:
Ginger Bill
2017-02-21 21:21:54 +00:00
parent a94dfdf21d
commit 047c0e4bcc
10 changed files with 678 additions and 389 deletions
+83 -25
View File
@@ -89,12 +89,15 @@ typedef struct TypeRecord {
// All record types
// Theses are arrays
// Entity_Variable - struct/raw_union
// Entity_TypeName - union
// Entity_Constant - enum
Entity **fields;
i32 field_count; // == struct_offsets count
AstNode *node;
// Entity_TypeName - union
Entity **variants;
i32 variant_count;
i64 * struct_offsets;
bool struct_are_offsets_set;
bool struct_is_packed;
@@ -301,8 +304,8 @@ gb_global Type *t_type_info_slice = NULL;
gb_global Type *t_type_info_vector = NULL;
gb_global Type *t_type_info_tuple = NULL;
gb_global Type *t_type_info_struct = NULL;
gb_global Type *t_type_info_union = NULL;
gb_global Type *t_type_info_raw_union = NULL;
gb_global Type *t_type_info_union = NULL;
gb_global Type *t_type_info_enum = NULL;
gb_global Type *t_type_info_map = NULL;
@@ -320,8 +323,8 @@ gb_global Type *t_type_info_slice_ptr = NULL;
gb_global Type *t_type_info_vector_ptr = NULL;
gb_global Type *t_type_info_tuple_ptr = NULL;
gb_global Type *t_type_info_struct_ptr = NULL;
gb_global Type *t_type_info_union_ptr = NULL;
gb_global Type *t_type_info_raw_union_ptr = NULL;
gb_global Type *t_type_info_union_ptr = NULL;
gb_global Type *t_type_info_enum_ptr = NULL;
gb_global Type *t_type_info_map_ptr = NULL;
@@ -858,6 +861,7 @@ bool are_types_identical(Type *x, Type *y) {
case TypeRecord_RawUnion:
case TypeRecord_Union:
if (x->Record.field_count == y->Record.field_count &&
x->Record.variant_count == y->Record.variant_count &&
x->Record.struct_is_packed == y->Record.struct_is_packed &&
x->Record.struct_is_ordered == y->Record.struct_is_ordered &&
x->Record.custom_align == y->Record.custom_align) {
@@ -870,9 +874,18 @@ bool are_types_identical(Type *x, Type *y) {
return false;
}
}
for (isize i = 1; i < x->Record.variant_count; i++) {
if (!are_types_identical(x->Record.variants[i]->type, y->Record.variants[i]->type)) {
return false;
}
if (str_ne(x->Record.variants[i]->token.string, y->Record.variants[i]->token.string)) {
return false;
}
}
return true;
}
break;
case TypeRecord_Enum:
return x == y; // NOTE(bill): All enums are unique
}
@@ -1331,14 +1344,12 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
}
if (is_type_union(type)) {
// NOTE(bill): The subtype for a union are stored in the fields
// as they are "kind of" like variables but not
for (isize i = 0; i < type->Record.field_count; i++) {
Entity *f = type->Record.fields[i];
for (isize i = 1; i < type->Record.variant_count; i++) {
Entity *f = type->Record.variants[i];
GB_ASSERT(f->kind == Entity_TypeName);
String str = f->token.string;
if (str_eq(field_name, str)) {
if (str_eq(str, field_name)) {
sel.entity = f;
// selection_add_index(&sel, i);
return sel;
@@ -1373,7 +1384,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
}
}
}
} else if (!is_type_union(type)) {
} else {
for (isize i = 0; i < type->Record.field_count; i++) {
Entity *f = type->Record.fields[i];
if (f->kind != Entity_Variable || (f->flags & EntityFlag_Field) == 0) {
@@ -1605,13 +1616,13 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
case TypeRecord_Union: {
i64 max = 1;
// NOTE(bill): field zero is null
for (isize i = 1; i < t->Record.field_count; i++) {
Type *field_type = t->Record.fields[i]->type;
type_path_push(path, field_type);
for (isize i = 1; i < t->Record.variant_count; i++) {
Type *variant = t->Record.variants[i]->type;
type_path_push(path, variant);
if (path->failure) {
return FAILURE_ALIGNMENT;
}
i64 align = type_align_of_internal(allocator, field_type, path);
i64 align = type_align_of_internal(allocator, variant, path);
type_path_pop(path);
if (max < align) {
max = align;
@@ -1620,7 +1631,7 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
return max;
} break;
case TypeRecord_RawUnion: {
i64 max = 1;
i64 max = build_context.word_size;
for (isize i = 0; i < t->Record.field_count; i++) {
Type *field_type = t->Record.fields[i]->type;
type_path_push(path, field_type);
@@ -1653,7 +1664,6 @@ i64 *type_set_offsets_of(gbAllocator allocator, Entity **fields, isize field_cou
offsets[i] = curr_offset;
curr_offset += type_size_of(allocator, fields[i]->type);
}
} else {
for (isize i = 0; i < field_count; i++) {
i64 align = type_align_of(allocator, fields[i]->type);
@@ -1673,7 +1683,13 @@ bool type_set_offsets(gbAllocator allocator, Type *t) {
t->Record.struct_are_offsets_set = true;
return true;
}
} else if (is_type_tuple(t)) {
} else if (is_type_union(t)) {
if (!t->Record.struct_are_offsets_set) {
t->Record.struct_offsets = type_set_offsets_of(allocator, t->Record.fields, t->Record.field_count, false);
t->Record.struct_are_offsets_set = true;
return true;
}
} else if (is_type_tuple(t)) {
if (!t->Tuple.are_offsets_set) {
t->Tuple.offsets = type_set_offsets_of(allocator, t->Tuple.variables, t->Tuple.variable_count, false);
t->Tuple.are_offsets_set = true;
@@ -1801,7 +1817,7 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
} break;
case TypeRecord_Union: {
i64 count = t->Record.field_count;
i64 count = t->Record.variant_count;
i64 align = type_align_of_internal(allocator, t, path);
if (path->failure) {
return FAILURE_SIZE;
@@ -1809,13 +1825,13 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
i64 max = 0;
// NOTE(bill): Zeroth field is invalid
for (isize i = 1; i < count; i++) {
i64 size = type_size_of_internal(allocator, t->Record.fields[i]->type, path);
i64 size = type_size_of_internal(allocator, t->Record.variants[i]->type, path);
if (max < size) {
max = size;
}
}
// NOTE(bill): Align to int
isize size = align_formula(max, build_context.word_size);
i64 size = align_formula(max, build_context.word_size);
size += type_size_of_internal(allocator, t_int, path);
return align_formula(size, align);
} break;
@@ -1983,8 +1999,9 @@ gbString write_type_to_string(gbString str, Type *type) {
for (isize i = 0; i < type->Record.field_count; i++) {
Entity *f = type->Record.fields[i];
GB_ASSERT(f->kind == Entity_Variable);
if (i > 0)
str = gb_string_appendc(str, "; ");
if (i > 0) {
str = gb_string_appendc(str, ", ");
}
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
str = gb_string_appendc(str, ": ");
str = write_type_to_string(str, f->type);
@@ -1994,16 +2011,38 @@ gbString write_type_to_string(gbString str, Type *type) {
case TypeRecord_Union:
str = gb_string_appendc(str, "union{");
for (isize i = 1; i < type->Record.field_count; i++) {
for (isize i = 0; i < type->Record.field_count; i++) {
Entity *f = type->Record.fields[i];
GB_ASSERT(f->kind == Entity_TypeName);
if (i > 1) {
str = gb_string_appendc(str, "; ");
GB_ASSERT(f->kind == Entity_Variable);
if (i > 0) {
str = gb_string_appendc(str, ", ");
}
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
str = gb_string_appendc(str, ": ");
str = write_type_to_string(str, base_type(f->type));
}
for (isize i = 1; i < type->Record.variant_count; i++) {
Entity *f = type->Record.variants[i];
GB_ASSERT(f->kind == Entity_TypeName);
if (i > 1 || type->Record.field_count > 1) {
str = gb_string_appendc(str, ", ");
}
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
str = gb_string_appendc(str, "{");
Type *variant = base_type(f->type);
for (isize i = 0; i < variant->Record.field_count; i++) {
Entity *f = variant->Record.fields[i];
GB_ASSERT(f->kind == Entity_Variable);
if (i > 0) {
str = gb_string_appendc(str, ", ");
}
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
str = gb_string_appendc(str, ": ");
str = write_type_to_string(str, f->type);
}
str = gb_string_appendc(str, "{");
}
str = gb_string_appendc(str, "}");
break;
@@ -2021,6 +2060,25 @@ gbString write_type_to_string(gbString str, Type *type) {
}
str = gb_string_appendc(str, "}");
break;
case TypeRecord_Enum:
str = gb_string_appendc(str, "enum");
if (type->Record.enum_base_type != NULL) {
str = gb_string_appendc(str, " ");
str = write_type_to_string(str, type->Record.enum_base_type);
}
str = gb_string_appendc(str, " {");
for (isize i = 0; i < type->Record.field_count; i++) {
Entity *f = type->Record.fields[i];
GB_ASSERT(f->kind == Entity_Constant);
if (i > 0) {
str = gb_string_appendc(str, ", ");
}
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
// str = gb_string_appendc(str, " = ");
}
str = gb_string_appendc(str, "}");
break;
}
} break;