diff options
| author | Ginger Bill <bill@gingerbill.org> | 2016-08-31 00:52:19 +0100 |
|---|---|---|
| committer | Ginger Bill <bill@gingerbill.org> | 2016-08-31 00:52:19 +0100 |
| commit | 5399463d9d9f94a20fb6b80814318e2b154b199a (patch) | |
| tree | c8508a4544f7292f00d4547fb5875aaa00e5307f /src/checker/type.cpp | |
| parent | cda0234d487ab73a1c87cbdcd74e300718ca7d0a (diff) | |
`down_cast`
Diffstat (limited to 'src/checker/type.cpp')
| -rw-r--r-- | src/checker/type.cpp | 118 |
1 files changed, 117 insertions, 1 deletions
diff --git a/src/checker/type.cpp b/src/checker/type.cpp index 2bec64615..cd11f3365 100644 --- a/src/checker/type.cpp +++ b/src/checker/type.cpp @@ -247,6 +247,8 @@ Type *make_type_proc(gbAllocator a, Scope *scope, Type *params, isize param_coun Type *type_deref(Type *t) { if (t != NULL) { Type *bt = get_base_type(t); + if (bt == NULL) + return NULL; if (bt != NULL && bt->kind == Type_Pointer) return bt->Pointer.elem; } @@ -595,6 +597,102 @@ gb_global i64 basic_type_sizes[] = { +struct Selection { + Entity *entity; + gbArray(isize) index; + b32 indirect; // Set if there was a pointer deref anywhere down the line +}; +Selection empty_selection = {}; + +Selection make_selection(Entity *entity, gbArray(isize) index, b32 indirect) { + Selection s = {entity, index, indirect}; + return s; +} + +void selection_add_index(Selection *s, isize index) { + if (s->index == NULL) { + gb_array_init(s->index, gb_heap_allocator()); + } + gb_array_append(s->index, index); +} + +Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection sel = empty_selection) { + GB_ASSERT(type_ != NULL); + + if (are_strings_equal(field_name, make_string("_"))) { + return empty_selection; + } + + Type *type = type_deref(type_); + b32 is_ptr = type != type_; + type = get_base_type(type); + + switch (type->kind) { + // HACK(bill): struct/union variable overlay from unsafe tagged union + case Type_Struct: + case Type_Union: + if (is_type) { + for (isize i = 0; i < type->Struct.other_field_count; i++) { + Entity *f = type->Struct.other_fields[i]; + GB_ASSERT(f->kind != Entity_Variable); + String str = f->token.string; + if (are_strings_equal(field_name, str)) { + selection_add_index(&sel, i); + sel.entity = f; + return sel; + } + } + } else { + for (isize i = 0; i < type->Struct.field_count; i++) { + Entity *f = type->Struct.fields[i]; + GB_ASSERT(f->kind == Entity_Variable && f->Variable.is_field); + String str = f->token.string; + if (are_strings_equal(field_name, str)) { + selection_add_index(&sel, i); + sel.entity = f; + return sel; + } + + if (f->Variable.anonymous) { + isize prev_count = 0; + if (sel.index != NULL) { + prev_count = gb_array_count(sel.index); + } + selection_add_index(&sel, i); // HACK(bill): Leaky memory + + sel = lookup_field(f->type, field_name, is_type, sel); + + if (sel.entity != NULL) { + if (is_type_pointer(f->type)) + sel.indirect = true; + return sel; + } + gb_array_count(sel.index) = prev_count; + } + } + } + break; + + case Type_Enum: + if (is_type) { + for (isize i = 0; i < type->Enum.field_count; i++) { + Entity *f = type->Enum.fields[i]; + GB_ASSERT(f->kind == Entity_Constant); + String str = f->token.string; + if (are_strings_equal(field_name, str)) { + // Enums are constant expression + return make_selection(f, NULL, i); + } + } + } + break; + } + + return sel; +} + + + i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t); i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t); i64 type_offset_of(BaseTypeSizes s, gbAllocator allocator, Type *t, i64 index); @@ -763,6 +861,24 @@ i64 type_offset_of(BaseTypeSizes s, gbAllocator allocator, Type *t, isize index) return 0; } +gbString type_to_string(Type *type, gbAllocator a = gb_heap_allocator()); + +i64 type_offset_of_from_selection(BaseTypeSizes s, gbAllocator allocator, Type *t, Selection sel) { + i64 offset = 0; + for (isize i = 0; i < gb_array_count(sel.index); i++) { + isize index = sel.index[i]; + t = get_base_type(t); + if (t->kind == Type_Struct) { + type_set_offsets(s, allocator, t); + GB_ASSERT(gb_is_between(index, 0, t->Struct.field_count-1)); + offset += t->Struct.offsets[index]; + t = t->Struct.fields[index]->type; + } + } + return offset; +} + + gbString write_type_to_string(gbString str, Type *type) { if (type == NULL) { @@ -866,7 +982,7 @@ gbString write_type_to_string(gbString str, Type *type) { } -gbString type_to_string(Type *type, gbAllocator a = gb_heap_allocator()) { +gbString type_to_string(Type *type, gbAllocator a) { gbString str = gb_string_make(a, ""); return write_type_to_string(str, type); } |