mirror of
https://github.com/odin-lang/Odin.git
synced 2026-02-16 08:04:07 +00:00
Merge raw_union into struct as a memory layout tag #raw_union
This commit is contained in:
@@ -130,18 +130,16 @@ get_hash :: proc(s: string) -> u32 {
|
||||
|
||||
|
||||
|
||||
Vector :: struct(N: int, T: type) {
|
||||
using _: raw_union {
|
||||
using e: [N]T;
|
||||
when 0 < N && N <= 4 {
|
||||
using v: struct {
|
||||
when N >= 1 do x: T;
|
||||
when N >= 2 do y: T;
|
||||
when N >= 3 do z: T;
|
||||
when N >= 4 do w: T;
|
||||
};
|
||||
|
||||
} };
|
||||
Vector :: struct(N: int, T: type) #raw_union {
|
||||
using e: [N]T;
|
||||
when 0 < N && N <= 4 {
|
||||
using v: struct {
|
||||
when N >= 1 do x: T;
|
||||
when N >= 2 do y: T;
|
||||
when N >= 3 do z: T;
|
||||
when N >= 4 do w: T;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 :: Vector(3, f32);
|
||||
@@ -161,17 +159,17 @@ foo3 :: proc(a: type/Vector(3, $T)) { fmt.println("foo3", a{}); }
|
||||
|
||||
|
||||
main :: proc() {
|
||||
Foo :: struct {
|
||||
a := 123;
|
||||
b := true;
|
||||
}
|
||||
v1 := Foo{};
|
||||
fmt.println(v1);
|
||||
// Foo :: struct {
|
||||
// a := 123;
|
||||
// b := true;
|
||||
// }
|
||||
// v1 := Foo{};
|
||||
// fmt.println(v1);
|
||||
|
||||
foo1(Vector(3, f32));
|
||||
foo1(Vector3);
|
||||
foo3(Vector(3, f32));
|
||||
foo3(Vector3);
|
||||
// foo1(Vector(3, f32));
|
||||
// foo1(Vector3);
|
||||
// foo3(Vector(3, f32));
|
||||
// foo3(Vector3);
|
||||
|
||||
|
||||
a, b: Vector3;
|
||||
@@ -184,17 +182,18 @@ main :: proc() {
|
||||
b.z = 5;
|
||||
|
||||
v := add(a, b);
|
||||
fmt.println(v.v);
|
||||
fmt.println(size_of(Vector3));
|
||||
fmt.println(v.e, v.v);
|
||||
|
||||
table: Table(string, int);
|
||||
// table: Table(string, int);
|
||||
|
||||
for i in 0..36 do put(&table, "Hellope", i);
|
||||
for i in 0..42 do put(&table, "World!", i);
|
||||
// for i in 0..36 do put(&table, "Hellope", i);
|
||||
// for i in 0..42 do put(&table, "World!", i);
|
||||
|
||||
|
||||
found, _ := find(&table, "Hellope");
|
||||
fmt.printf("found is %v\n", found);
|
||||
// found, _ := find(&table, "Hellope");
|
||||
// fmt.printf("found is %v\n", found);
|
||||
|
||||
found, _ = find(&table, "World!");
|
||||
fmt.printf("found is %v\n", found);
|
||||
// found, _ = find(&table, "World!");
|
||||
// fmt.printf("found is %v\n", found);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ CallingConvention :: enum {
|
||||
// The compiler relies upon this _exact_ order
|
||||
TypeInfo :: struct #ordered {
|
||||
// Core Types
|
||||
EnumValue :: raw_union {
|
||||
EnumValue :: struct #raw_union {
|
||||
f: f64;
|
||||
i: i128;
|
||||
}
|
||||
|
||||
@@ -6,12 +6,12 @@ __multi3 :: proc(a, b: u128) -> u128 #cc_c #link_name "__multi3" {
|
||||
|
||||
|
||||
when ODIN_ENDIAN == "bit" {
|
||||
TWords :: raw_union {
|
||||
TWords :: struct #raw_union {
|
||||
all: u128;
|
||||
using _: struct {lo, hi: u64;};
|
||||
};
|
||||
} else {
|
||||
TWords :: raw_union {
|
||||
TWords :: struct #raw_union {
|
||||
all: u128;
|
||||
using _: struct {hi, lo: u64;};
|
||||
};
|
||||
@@ -106,7 +106,7 @@ __u128_quo_mod :: proc(a, b: u128, rem: ^u128) -> (quo: u128) #cc_c #link_name "
|
||||
__f16_to_f32 :: proc(f: f16) -> f32 #cc_c #no_inline #link_name "__gnu_h2f_ieee" {
|
||||
when true {
|
||||
// Source: https://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/
|
||||
FP32 :: raw_union {u: u32, f: f32};
|
||||
FP32 :: struct #raw_union {u: u32, f: f32};
|
||||
|
||||
magic, was_infnan: FP32;
|
||||
magic.u = (254-15) << 23;
|
||||
@@ -130,8 +130,8 @@ __f16_to_f32 :: proc(f: f16) -> f32 #cc_c #no_inline #link_name "__gnu_h2f_ieee"
|
||||
__f32_to_f16 :: proc(f_: f32) -> f16 #cc_c #no_inline #link_name "__gnu_f2h_ieee" {
|
||||
when false {
|
||||
// Source: https://gist.github.com/rygorous/2156668
|
||||
FP16 :: raw_union {u: u16, f: f16};
|
||||
FP32 :: raw_union {u: u32, f: f32};
|
||||
FP16 :: struct #raw_union {u: u16, f: f16};
|
||||
FP32 :: struct #raw_union {u: u32, f: f32};
|
||||
|
||||
f32infty, f16infty, magic: FP32;
|
||||
f32infty.u = 255<<23;
|
||||
|
||||
@@ -1055,6 +1055,8 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
|
||||
GB_ASSERT(is_type_struct(struct_type));
|
||||
ast_node(st, StructType, node);
|
||||
|
||||
String context = str_lit("struct");
|
||||
|
||||
isize min_field_count = 0;
|
||||
for_array(field_index, st->fields) {
|
||||
AstNode *field = st->fields[field_index];
|
||||
@@ -1066,6 +1068,11 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
|
||||
}
|
||||
struct_type->Record.names = make_names_field_for_record(c, c->context.scope);
|
||||
|
||||
if (st->is_raw_union) {
|
||||
struct_type->Record.is_raw_union = true;
|
||||
context = str_lit("struct #raw_union");
|
||||
}
|
||||
|
||||
Type *polymorphic_params = nullptr;
|
||||
bool is_polymorphic = false;
|
||||
bool can_check_fields = true;
|
||||
@@ -1218,7 +1225,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
|
||||
Array<Entity *> fields = {};
|
||||
|
||||
if (!is_polymorphic) {
|
||||
fields = check_fields(c, node, st->fields, min_field_count, str_lit("struct"));
|
||||
fields = check_fields(c, node, st->fields, min_field_count, context);
|
||||
}
|
||||
|
||||
struct_type->Record.scope = c->context.scope;
|
||||
@@ -1232,35 +1239,36 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
|
||||
struct_type->Record.is_poly_specialized = is_poly_specialized;
|
||||
|
||||
|
||||
type_set_offsets(c->allocator, struct_type);
|
||||
if (!struct_type->Record.is_raw_union) {
|
||||
type_set_offsets(c->allocator, struct_type);
|
||||
|
||||
if (!struct_type->failure && !st->is_packed && !st->is_ordered) {
|
||||
struct_type->failure = false;
|
||||
struct_type->Record.are_offsets_set = false;
|
||||
struct_type->Record.offsets = nullptr;
|
||||
// NOTE(bill): Reorder fields for reduced size/performance
|
||||
|
||||
if (!struct_type->failure && !st->is_packed && !st->is_ordered) {
|
||||
struct_type->failure = false;
|
||||
struct_type->Record.are_offsets_set = false;
|
||||
struct_type->Record.offsets = nullptr;
|
||||
// NOTE(bill): Reorder fields for reduced size/performance
|
||||
Entity **reordered_fields = gb_alloc_array(c->allocator, Entity *, fields.count);
|
||||
for (isize i = 0; i < fields.count; i++) {
|
||||
reordered_fields[i] = struct_type->Record.fields_in_src_order[i];
|
||||
}
|
||||
|
||||
Entity **reordered_fields = gb_alloc_array(c->allocator, Entity *, fields.count);
|
||||
for (isize i = 0; i < fields.count; i++) {
|
||||
reordered_fields[i] = struct_type->Record.fields_in_src_order[i];
|
||||
// NOTE(bill): Hacky thing
|
||||
// TODO(bill): Probably make an inline sorting procedure rather than use global variables
|
||||
__checker_allocator = c->allocator;
|
||||
// NOTE(bill): compound literal order must match source not layout
|
||||
gb_sort_array(reordered_fields, fields.count, cmp_reorder_struct_fields);
|
||||
|
||||
for (isize i = 0; i < fields.count; i++) {
|
||||
reordered_fields[i]->Variable.field_index = i;
|
||||
}
|
||||
|
||||
struct_type->Record.fields = reordered_fields;
|
||||
}
|
||||
|
||||
// NOTE(bill): Hacky thing
|
||||
// TODO(bill): Probably make an inline sorting procedure rather than use global variables
|
||||
__checker_allocator = c->allocator;
|
||||
// NOTE(bill): compound literal order must match source not layout
|
||||
gb_sort_array(reordered_fields, fields.count, cmp_reorder_struct_fields);
|
||||
|
||||
for (isize i = 0; i < fields.count; i++) {
|
||||
reordered_fields[i]->Variable.field_index = i;
|
||||
}
|
||||
|
||||
struct_type->Record.fields = reordered_fields;
|
||||
type_set_offsets(c->allocator, struct_type);
|
||||
}
|
||||
|
||||
type_set_offsets(c->allocator, struct_type);
|
||||
|
||||
|
||||
if (st->align != nullptr) {
|
||||
if (st->is_packed) {
|
||||
@@ -1353,29 +1361,29 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
|
||||
union_type->Union.variant_count = variants.count;
|
||||
}
|
||||
|
||||
void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
|
||||
GB_ASSERT(node->kind == AstNode_RawUnionType);
|
||||
GB_ASSERT(is_type_raw_union(union_type));
|
||||
ast_node(ut, RawUnionType, node);
|
||||
// void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
|
||||
// GB_ASSERT(node->kind == AstNode_RawUnionType);
|
||||
// GB_ASSERT(is_type_raw_union(union_type));
|
||||
// ast_node(ut, RawUnionType, node);
|
||||
|
||||
isize min_field_count = 0;
|
||||
for_array(i, ut->fields) {
|
||||
AstNode *field = ut->fields[i];
|
||||
switch (field->kind) {
|
||||
case_ast_node(f, ValueDecl, field);
|
||||
min_field_count += f->names.count;
|
||||
case_end;
|
||||
}
|
||||
}
|
||||
// isize min_field_count = 0;
|
||||
// for_array(i, ut->fields) {
|
||||
// AstNode *field = ut->fields[i];
|
||||
// switch (field->kind) {
|
||||
// case_ast_node(f, ValueDecl, field);
|
||||
// min_field_count += f->names.count;
|
||||
// case_end;
|
||||
// }
|
||||
// }
|
||||
|
||||
union_type->Record.names = make_names_field_for_record(c, c->context.scope);
|
||||
// union_type->Record.names = make_names_field_for_record(c, c->context.scope);
|
||||
|
||||
auto fields = check_fields(c, node, ut->fields, min_field_count, str_lit("raw_union"));
|
||||
// auto fields = check_fields(c, node, ut->fields, min_field_count, str_lit("raw_union"));
|
||||
|
||||
union_type->Record.scope = c->context.scope;
|
||||
union_type->Record.fields = fields.data;
|
||||
union_type->Record.field_count = fields.count;
|
||||
}
|
||||
// union_type->Record.scope = c->context.scope;
|
||||
// union_type->Record.fields = fields.data;
|
||||
// union_type->Record.field_count = fields.count;
|
||||
// }
|
||||
|
||||
|
||||
void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *node) {
|
||||
@@ -3018,7 +3026,7 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
|
||||
return true;
|
||||
case_end;
|
||||
|
||||
case_ast_node(rut, RawUnionType, e);
|
||||
/* case_ast_node(rut, RawUnionType, e);
|
||||
*type = make_type_raw_union(c->allocator);
|
||||
set_base_type(named_type, *type);
|
||||
check_open_scope(c, e);
|
||||
@@ -3027,7 +3035,7 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
|
||||
(*type)->Record.node = e;
|
||||
return true;
|
||||
case_end;
|
||||
|
||||
*/
|
||||
case_ast_node(et, EnumType, e);
|
||||
*type = make_type_enum(c->allocator);
|
||||
set_base_type(named_type, *type);
|
||||
@@ -6482,7 +6490,7 @@ CallArgumentError check_polymorphic_struct_type(Checker *c, Operand *operand, As
|
||||
|
||||
Type *original_type = operand->type;
|
||||
Type *struct_type = base_type(operand->type);
|
||||
GB_ASSERT(is_type_struct(struct_type));
|
||||
GB_ASSERT(struct_type->kind == Type_Record);
|
||||
TypeRecord *st = &struct_type->Record;
|
||||
GB_ASSERT(st->is_polymorphic);
|
||||
|
||||
@@ -7738,7 +7746,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (!valid && (is_type_struct(t) || is_type_raw_union(t))) {
|
||||
if (!valid && t->kind == Type_Record) {
|
||||
Entity *found = find_using_index_expr(t);
|
||||
if (found != nullptr) {
|
||||
valid = check_set_index_data(o, found->type, is_type_pointer(found->type), &max_count);
|
||||
@@ -7937,7 +7945,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
|
||||
case AstNode_VectorType:
|
||||
case AstNode_StructType:
|
||||
case AstNode_UnionType:
|
||||
case AstNode_RawUnionType:
|
||||
// case AstNode_RawUnionType:
|
||||
case AstNode_EnumType:
|
||||
case AstNode_MapType:
|
||||
o->mode = Addressing_Type;
|
||||
@@ -8351,19 +8359,20 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
|
||||
|
||||
case_ast_node(st, StructType, node);
|
||||
str = gb_string_appendc(str, "struct ");
|
||||
if (st->is_packed) str = gb_string_appendc(str, "#packed ");
|
||||
if (st->is_ordered) str = gb_string_appendc(str, "#ordered ");
|
||||
if (st->is_packed) str = gb_string_appendc(str, "#packed ");
|
||||
if (st->is_ordered) str = gb_string_appendc(str, "#ordered ");
|
||||
if (st->is_raw_union) str = gb_string_appendc(str, "#raw_union ");
|
||||
str = gb_string_appendc(str, "{");
|
||||
str = write_record_fields_to_string(str, st->fields);
|
||||
str = gb_string_appendc(str, "}");
|
||||
case_end;
|
||||
|
||||
case_ast_node(st, RawUnionType, node);
|
||||
str = gb_string_appendc(str, "raw_union ");
|
||||
str = gb_string_appendc(str, "{");
|
||||
str = write_record_fields_to_string(str, st->fields);
|
||||
str = gb_string_appendc(str, "}");
|
||||
case_end;
|
||||
// case_ast_node(st, RawUnionType, node);
|
||||
// str = gb_string_appendc(str, "raw_union ");
|
||||
// str = gb_string_appendc(str, "{");
|
||||
// str = write_record_fields_to_string(str, st->fields);
|
||||
// str = gb_string_appendc(str, "}");
|
||||
// case_end;
|
||||
|
||||
case_ast_node(st, UnionType, node);
|
||||
str = gb_string_appendc(str, "union ");
|
||||
|
||||
@@ -472,7 +472,6 @@ void check_open_scope(Checker *c, AstNode *node) {
|
||||
case AstNode_StructType:
|
||||
case AstNode_EnumType:
|
||||
case AstNode_UnionType:
|
||||
case AstNode_RawUnionType:
|
||||
scope->is_record = true;
|
||||
break;
|
||||
}
|
||||
|
||||
64
src/ir.cpp
64
src/ir.cpp
@@ -662,7 +662,7 @@ bool ir_type_has_default_values(Type *t) {
|
||||
return ir_type_has_default_values(t->Array.elem);
|
||||
|
||||
case Type_Record:
|
||||
if (t->Record.kind == TypeRecord_Struct) {
|
||||
if (!t->Record.is_raw_union) {
|
||||
for (isize i = 0; i < t->Record.field_count; i++) {
|
||||
Entity *f = t->Record.fields_in_src_order[i];
|
||||
if (f->kind != Entity_Variable) continue;
|
||||
@@ -7355,12 +7355,7 @@ void ir_init_module(irModule *m, Checker *c) {
|
||||
count += t->Union.variant_count;
|
||||
break;
|
||||
case Type_Record:
|
||||
switch (t->Record.kind) {
|
||||
case TypeRecord_Struct:
|
||||
case TypeRecord_RawUnion:
|
||||
count += t->Record.field_count;
|
||||
break;
|
||||
}
|
||||
count += t->Record.field_count;
|
||||
break;
|
||||
case Type_Tuple:
|
||||
count += t->Tuple.variable_count;
|
||||
@@ -8193,8 +8188,32 @@ void ir_gen_tree(irGen *s) {
|
||||
} break;
|
||||
|
||||
case Type_Record: {
|
||||
switch (t->Record.kind) {
|
||||
case TypeRecord_Struct: {
|
||||
if (t->Record.is_raw_union) {
|
||||
ir_emit_comment(proc, str_lit("TypeInfoRawUnion"));
|
||||
tag = ir_emit_conv(proc, variant_ptr, t_type_info_raw_union_ptr);
|
||||
|
||||
irValue *memory_types = ir_type_info_member_types_offset(proc, t->Record.field_count);
|
||||
irValue *memory_names = ir_type_info_member_names_offset(proc, t->Record.field_count);
|
||||
irValue *memory_offsets = ir_type_info_member_offsets_offset(proc, t->Record.field_count);
|
||||
|
||||
for (isize i = 0; i < t->Record.field_count; i++) {
|
||||
Entity *f = t->Record.fields[i];
|
||||
irValue *index = ir_const_int(a, i);
|
||||
irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index);
|
||||
// NOTE(bill): Offsets are always 0
|
||||
|
||||
ir_emit_store(proc, type_info, ir_type_info(proc, f->type));
|
||||
if (f->token.string.len > 0) {
|
||||
irValue *name = ir_emit_ptr_offset(proc, memory_names, index);
|
||||
ir_emit_store(proc, name, ir_const_string(a, f->token.string));
|
||||
}
|
||||
}
|
||||
|
||||
irValue *count = ir_const_int(a, t->Record.field_count);
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 0), memory_types, count, count);
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names, count, count);
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, count, count);
|
||||
} else {
|
||||
ir_emit_comment(proc, str_lit("TypeInfoStruct"));
|
||||
tag = ir_emit_conv(proc, variant_ptr, t_type_info_struct_ptr);
|
||||
|
||||
@@ -8239,33 +8258,6 @@ void ir_gen_tree(irGen *s) {
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names, count, count);
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, count, count);
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 3), memory_usings, count, count);
|
||||
} break;
|
||||
case TypeRecord_RawUnion: {
|
||||
ir_emit_comment(proc, str_lit("TypeInfoRawUnion"));
|
||||
tag = ir_emit_conv(proc, variant_ptr, t_type_info_raw_union_ptr);
|
||||
|
||||
irValue *memory_types = ir_type_info_member_types_offset(proc, t->Record.field_count);
|
||||
irValue *memory_names = ir_type_info_member_names_offset(proc, t->Record.field_count);
|
||||
irValue *memory_offsets = ir_type_info_member_offsets_offset(proc, t->Record.field_count);
|
||||
|
||||
for (isize i = 0; i < t->Record.field_count; i++) {
|
||||
Entity *f = t->Record.fields[i];
|
||||
irValue *index = ir_const_int(a, i);
|
||||
irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index);
|
||||
// NOTE(bill): Offsets are always 0
|
||||
|
||||
ir_emit_store(proc, type_info, ir_type_info(proc, f->type));
|
||||
if (f->token.string.len > 0) {
|
||||
irValue *name = ir_emit_ptr_offset(proc, memory_names, index);
|
||||
ir_emit_store(proc, name, ir_const_string(a, f->token.string));
|
||||
}
|
||||
}
|
||||
|
||||
irValue *count = ir_const_int(a, t->Record.field_count);
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 0), memory_types, count, count);
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names, count, count);
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, count, count);
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
case Type_Map: {
|
||||
|
||||
@@ -300,8 +300,14 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
||||
} return;
|
||||
|
||||
case Type_Record: {
|
||||
switch (t->Record.kind) {
|
||||
case TypeRecord_Struct:
|
||||
if (t->Record.is_raw_union) {
|
||||
// NOTE(bill): The zero size array is used to fix the alignment used in a structure as
|
||||
// LLVM takes the first element's alignment as the entire alignment (like C)
|
||||
i64 size_of_union = type_size_of(heap_allocator(), t);
|
||||
i64 align_of_union = type_align_of(heap_allocator(), t);
|
||||
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8]}", align_of_union, size_of_union);
|
||||
return;
|
||||
} else {
|
||||
if (t->Record.is_packed) {
|
||||
ir_fprintf(f, "<");
|
||||
}
|
||||
@@ -323,13 +329,6 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
||||
ir_fprintf(f, ">");
|
||||
}
|
||||
return;
|
||||
case TypeRecord_RawUnion: {
|
||||
// NOTE(bill): The zero size array is used to fix the alignment used in a structure as
|
||||
// LLVM takes the first element's alignment as the entire alignment (like C)
|
||||
i64 size_of_union = type_size_of(heap_allocator(), t);
|
||||
i64 align_of_union = type_align_of(heap_allocator(), t);
|
||||
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8]}", align_of_union, size_of_union);
|
||||
} return;
|
||||
}
|
||||
} break;
|
||||
|
||||
|
||||
@@ -423,17 +423,13 @@ AST_NODE_KIND(_TypeBegin, "", i32) \
|
||||
AstNode * polymorphic_params; \
|
||||
bool is_packed; \
|
||||
bool is_ordered; \
|
||||
bool is_raw_union; \
|
||||
AstNode * align; \
|
||||
}) \
|
||||
AST_NODE_KIND(UnionType, "union type", struct { \
|
||||
Token token; \
|
||||
Array<AstNode *> variants; \
|
||||
}) \
|
||||
AST_NODE_KIND(RawUnionType, "raw union type", struct { \
|
||||
Token token; \
|
||||
Array<AstNode *> fields; \
|
||||
isize field_count; \
|
||||
}) \
|
||||
AST_NODE_KIND(EnumType, "enum type", struct { \
|
||||
Token token; \
|
||||
AstNode * base_type; \
|
||||
@@ -599,7 +595,6 @@ Token ast_node_token(AstNode *node) {
|
||||
case AstNode_VectorType: return node->VectorType.token;
|
||||
case AstNode_StructType: return node->StructType.token;
|
||||
case AstNode_UnionType: return node->UnionType.token;
|
||||
case AstNode_RawUnionType: return node->RawUnionType.token;
|
||||
case AstNode_EnumType: return node->EnumType.token;
|
||||
case AstNode_BitFieldType: return node->BitFieldType.token;
|
||||
case AstNode_MapType: return node->MapType.token;
|
||||
@@ -868,9 +863,6 @@ AstNode *clone_ast_node(gbAllocator a, AstNode *node) {
|
||||
case AstNode_UnionType:
|
||||
n->UnionType.variants = clone_ast_node_array(a, n->UnionType.variants);
|
||||
break;
|
||||
case AstNode_RawUnionType:
|
||||
n->RawUnionType.fields = clone_ast_node_array(a, n->RawUnionType.fields);
|
||||
break;
|
||||
case AstNode_EnumType:
|
||||
n->EnumType.base_type = clone_ast_node(a, n->EnumType.base_type);
|
||||
n->EnumType.fields = clone_ast_node_array(a, n->EnumType.fields);
|
||||
@@ -1451,7 +1443,8 @@ AstNode *ast_vector_type(AstFile *f, Token token, AstNode *count, AstNode *elem)
|
||||
}
|
||||
|
||||
AstNode *ast_struct_type(AstFile *f, Token token, Array<AstNode *> fields, isize field_count,
|
||||
AstNode *polymorphic_params, bool is_packed, bool is_ordered, AstNode *align) {
|
||||
AstNode *polymorphic_params, bool is_packed, bool is_ordered, bool is_raw_union,
|
||||
AstNode *align) {
|
||||
AstNode *result = make_ast_node(f, AstNode_StructType);
|
||||
result->StructType.token = token;
|
||||
result->StructType.fields = fields;
|
||||
@@ -1459,6 +1452,7 @@ AstNode *ast_struct_type(AstFile *f, Token token, Array<AstNode *> fields, isize
|
||||
result->StructType.polymorphic_params = polymorphic_params;
|
||||
result->StructType.is_packed = is_packed;
|
||||
result->StructType.is_ordered = is_ordered;
|
||||
result->StructType.is_raw_union = is_raw_union;
|
||||
result->StructType.align = align;
|
||||
return result;
|
||||
}
|
||||
@@ -1471,14 +1465,6 @@ AstNode *ast_union_type(AstFile *f, Token token, Array<AstNode *> variants) {
|
||||
return result;
|
||||
}
|
||||
|
||||
AstNode *ast_raw_union_type(AstFile *f, Token token, Array<AstNode *> fields, isize field_count) {
|
||||
AstNode *result = make_ast_node(f, AstNode_RawUnionType);
|
||||
result->RawUnionType.token = token;
|
||||
result->RawUnionType.fields = fields;
|
||||
result->RawUnionType.field_count = field_count;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
AstNode *ast_enum_type(AstFile *f, Token token, AstNode *base_type, Array<AstNode *> fields) {
|
||||
AstNode *result = make_ast_node(f, AstNode_EnumType);
|
||||
@@ -1837,7 +1823,6 @@ bool is_semicolon_optional_for_node(AstFile *f, AstNode *s) {
|
||||
|
||||
case AstNode_StructType:
|
||||
case AstNode_UnionType:
|
||||
case AstNode_RawUnionType:
|
||||
case AstNode_EnumType:
|
||||
case AstNode_BitFieldType:
|
||||
return true;
|
||||
@@ -2424,8 +2409,9 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
|
||||
case Token_struct: {
|
||||
Token token = expect_token(f, Token_struct);
|
||||
AstNode *polymorphic_params = nullptr;
|
||||
bool is_packed = false;
|
||||
bool is_ordered = false;
|
||||
bool is_packed = false;
|
||||
bool is_ordered = false;
|
||||
bool is_raw_union = false;
|
||||
AstNode *align = nullptr;
|
||||
|
||||
if (allow_token(f, Token_OpenParen)) {
|
||||
@@ -2458,6 +2444,11 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
|
||||
syntax_error(tag, "Duplicate struct tag `#%.*s`", LIT(tag.string));
|
||||
}
|
||||
align = parse_expr(f, true);
|
||||
} else if (tag.string == "raw_union") {
|
||||
if (is_raw_union) {
|
||||
syntax_error(tag, "Duplicate struct tag `#%.*s`", LIT(tag.string));
|
||||
}
|
||||
is_raw_union = true;
|
||||
} else {
|
||||
syntax_error(tag, "Invalid struct tag `#%.*s`", LIT(tag.string));
|
||||
}
|
||||
@@ -2468,6 +2459,14 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
|
||||
if (is_packed && is_ordered) {
|
||||
syntax_error(token, "`#ordered` is not needed with `#packed` which implies ordering");
|
||||
}
|
||||
if (is_raw_union && is_packed) {
|
||||
is_packed = false;
|
||||
syntax_error(token, "`#raw_union` cannot also be `#packed`");
|
||||
}
|
||||
if (is_raw_union && is_ordered) {
|
||||
is_ordered = false;
|
||||
syntax_error(token, "`#raw_union` cannot also be `#ordered`");
|
||||
}
|
||||
|
||||
Token open = expect_token_after(f, Token_OpenBrace, "struct");
|
||||
|
||||
@@ -2481,7 +2480,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
|
||||
decls = fields->FieldList.list;
|
||||
}
|
||||
|
||||
return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_ordered, align);
|
||||
return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_ordered, is_raw_union, align);
|
||||
} break;
|
||||
|
||||
case Token_union: {
|
||||
@@ -2510,23 +2509,6 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
|
||||
return ast_union_type(f, token, variants);
|
||||
} break;
|
||||
|
||||
case Token_raw_union: {
|
||||
Token token = expect_token(f, Token_raw_union);
|
||||
Token open = expect_token_after(f, Token_OpenBrace, "raw_union");
|
||||
|
||||
isize decl_count = 0;
|
||||
AstNode *fields = parse_record_field_list(f, &decl_count);
|
||||
Token close = expect_token(f, Token_CloseBrace);
|
||||
|
||||
Array<AstNode *> decls = {};
|
||||
if (fields != nullptr) {
|
||||
GB_ASSERT(fields->kind == AstNode_FieldList);
|
||||
decls = fields->FieldList.list;
|
||||
}
|
||||
|
||||
return ast_raw_union_type(f, token, decls, decl_count);
|
||||
} break;
|
||||
|
||||
case Token_enum: {
|
||||
Token token = expect_token(f, Token_enum);
|
||||
AstNode *base_type = nullptr;
|
||||
|
||||
@@ -652,7 +652,7 @@ bool can_ssa_type(Type *t) {
|
||||
return false;
|
||||
|
||||
case Type_Record:
|
||||
if (t->Record.kind == TypeRecord_Struct) {
|
||||
if (!t->Record.is_raw_union) {
|
||||
if (t->Record.field_count > SSA_MAX_STRUCT_FIELD_COUNT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
||||
TOKEN_KIND(Token_macro, "macro"), \
|
||||
TOKEN_KIND(Token_struct, "struct"), \
|
||||
TOKEN_KIND(Token_union, "union"), \
|
||||
TOKEN_KIND(Token_raw_union, "raw_union"), \
|
||||
/* TOKEN_KIND(Token_raw_union, "raw_union"), */ \
|
||||
TOKEN_KIND(Token_enum, "enum"), \
|
||||
TOKEN_KIND(Token_bit_field, "bit_field"), \
|
||||
TOKEN_KIND(Token_vector, "vector"), \
|
||||
|
||||
200
src/types.cpp
200
src/types.cpp
@@ -68,17 +68,7 @@ struct BasicType {
|
||||
String name;
|
||||
};
|
||||
|
||||
enum TypeRecordKind {
|
||||
TypeRecord_Invalid,
|
||||
|
||||
TypeRecord_Struct,
|
||||
TypeRecord_RawUnion,
|
||||
|
||||
TypeRecord_Count,
|
||||
};
|
||||
|
||||
struct TypeRecord {
|
||||
TypeRecordKind kind;
|
||||
|
||||
// All record types
|
||||
// Theses are arrays
|
||||
@@ -94,6 +84,7 @@ struct TypeRecord {
|
||||
bool are_offsets_being_processed;
|
||||
bool is_packed;
|
||||
bool is_ordered;
|
||||
bool is_raw_union;
|
||||
bool is_polymorphic;
|
||||
bool is_poly_specialized;
|
||||
Type * polymorphic_params; // Type_Tuple
|
||||
@@ -523,7 +514,6 @@ Type *make_type_slice(gbAllocator a, Type *elem) {
|
||||
|
||||
Type *make_type_struct(gbAllocator a) {
|
||||
Type *t = alloc_type(a, Type_Record);
|
||||
t->Record.kind = TypeRecord_Struct;
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -532,12 +522,6 @@ Type *make_type_union(gbAllocator a) {
|
||||
return t;
|
||||
}
|
||||
|
||||
Type *make_type_raw_union(gbAllocator a) {
|
||||
Type *t = alloc_type(a, Type_Record);
|
||||
t->Record.kind = TypeRecord_RawUnion;
|
||||
return t;
|
||||
}
|
||||
|
||||
Type *make_type_enum(gbAllocator a) {
|
||||
Type *t = alloc_type(a, Type_Enum);
|
||||
return t;
|
||||
@@ -847,7 +831,7 @@ Type *base_complex_elem_type(Type *t) {
|
||||
|
||||
bool is_type_struct(Type *t) {
|
||||
t = base_type(t);
|
||||
return (t->kind == Type_Record && t->Record.kind == TypeRecord_Struct);
|
||||
return (t->kind == Type_Record && !t->Record.is_raw_union);
|
||||
}
|
||||
bool is_type_union(Type *t) {
|
||||
t = base_type(t);
|
||||
@@ -856,7 +840,7 @@ bool is_type_union(Type *t) {
|
||||
|
||||
bool is_type_raw_union(Type *t) {
|
||||
t = base_type(t);
|
||||
return (t->kind == Type_Record && t->Record.kind == TypeRecord_RawUnion);
|
||||
return (t->kind == Type_Record && t->Record.is_raw_union);
|
||||
}
|
||||
bool is_type_enum(Type *t) {
|
||||
t = base_type(t);
|
||||
@@ -932,8 +916,7 @@ bool is_type_indexable(Type *t) {
|
||||
|
||||
bool is_type_polymorphic_struct(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Record &&
|
||||
t->Record.kind == TypeRecord_Struct) {
|
||||
if (t->kind == Type_Record) {
|
||||
return t->Record.is_polymorphic;
|
||||
}
|
||||
return false;
|
||||
@@ -941,8 +924,7 @@ bool is_type_polymorphic_struct(Type *t) {
|
||||
|
||||
bool is_type_polymorphic_struct_specialized(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Record &&
|
||||
t->Record.kind == TypeRecord_Struct) {
|
||||
if (t->kind == Type_Record) {
|
||||
return t->Record.is_polymorphic && t->Record.is_poly_specialized;
|
||||
}
|
||||
return false;
|
||||
@@ -1158,34 +1140,28 @@ bool are_types_identical(Type *x, Type *y) {
|
||||
|
||||
case Type_Record:
|
||||
if (y->kind == Type_Record) {
|
||||
if (x->Record.kind == y->Record.kind) {
|
||||
switch (x->Record.kind) {
|
||||
case TypeRecord_Struct:
|
||||
case TypeRecord_RawUnion:
|
||||
if (x->Record.field_count == y->Record.field_count &&
|
||||
x->Record.is_packed == y->Record.is_packed &&
|
||||
x->Record.is_ordered == y->Record.is_ordered &&
|
||||
x->Record.custom_align == y->Record.custom_align) {
|
||||
// TODO(bill); Fix the custom alignment rule
|
||||
for (isize i = 0; i < x->Record.field_count; i++) {
|
||||
Entity *xf = x->Record.fields[i];
|
||||
Entity *yf = y->Record.fields[i];
|
||||
if (!are_types_identical(xf->type, yf->type)) {
|
||||
return false;
|
||||
}
|
||||
if (xf->token.string != yf->token.string) {
|
||||
return false;
|
||||
}
|
||||
bool xf_is_using = (xf->flags&EntityFlag_Using) != 0;
|
||||
bool yf_is_using = (yf->flags&EntityFlag_Using) != 0;
|
||||
if (xf_is_using ^ yf_is_using) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
if (x->Record.is_raw_union == y->Record.is_raw_union &&
|
||||
x->Record.field_count == y->Record.field_count &&
|
||||
x->Record.is_packed == y->Record.is_packed &&
|
||||
x->Record.is_ordered == y->Record.is_ordered &&
|
||||
x->Record.custom_align == y->Record.custom_align) {
|
||||
// TODO(bill); Fix the custom alignment rule
|
||||
for (isize i = 0; i < x->Record.field_count; i++) {
|
||||
Entity *xf = x->Record.fields[i];
|
||||
Entity *yf = y->Record.fields[i];
|
||||
if (!are_types_identical(xf->type, yf->type)) {
|
||||
return false;
|
||||
}
|
||||
if (xf->token.string != yf->token.string) {
|
||||
return false;
|
||||
}
|
||||
bool xf_is_using = (xf->flags&EntityFlag_Using) != 0;
|
||||
bool yf_is_using = (yf->flags&EntityFlag_Using) != 0;
|
||||
if (xf_is_using ^ yf_is_using) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1310,7 +1286,7 @@ bool is_type_cte_safe(Type *type) {
|
||||
return false;
|
||||
|
||||
case Type_Record: {
|
||||
if (type->Record.kind != TypeRecord_Struct) {
|
||||
if (type->Record.is_raw_union) {
|
||||
return false;
|
||||
}
|
||||
for (isize i = 0; i < type->Record.field_count; i++) {
|
||||
@@ -1619,7 +1595,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
||||
return lookup_field_with_selection(a, specialized, field_name, is_type, sel);
|
||||
}
|
||||
|
||||
} else if (type->Record.kind == Type_Union) {
|
||||
} else if (type->kind == Type_Union) {
|
||||
if (field_name == "__tag") {
|
||||
Entity *e = type->Union.union__tag;
|
||||
GB_ASSERT(e != nullptr);
|
||||
@@ -1868,8 +1844,22 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
} break;
|
||||
|
||||
case Type_Record: {
|
||||
switch (t->Record.kind) {
|
||||
case TypeRecord_Struct:
|
||||
if (t->Record.is_raw_union) {
|
||||
i64 max = 1;
|
||||
for (isize i = 0; i < t->Record.field_count; i++) {
|
||||
Type *field_type = t->Record.fields[i]->type;
|
||||
type_path_push(path, field_type);
|
||||
if (path->failure) {
|
||||
return FAILURE_ALIGNMENT;
|
||||
}
|
||||
i64 align = type_align_of_internal(allocator, field_type, path);
|
||||
type_path_pop(path);
|
||||
if (max < align) {
|
||||
max = align;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
} else {
|
||||
if (t->Record.custom_align > 0) {
|
||||
return gb_clamp(t->Record.custom_align, 1, build_context.max_align);
|
||||
}
|
||||
@@ -1892,23 +1882,6 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
}
|
||||
return max;
|
||||
}
|
||||
break;
|
||||
case TypeRecord_RawUnion: {
|
||||
i64 max = 1;
|
||||
for (isize i = 0; i < t->Record.field_count; i++) {
|
||||
Type *field_type = t->Record.fields[i]->type;
|
||||
type_path_push(path, field_type);
|
||||
if (path->failure) {
|
||||
return FAILURE_ALIGNMENT;
|
||||
}
|
||||
i64 align = type_align_of_internal(allocator, field_type, path);
|
||||
type_path_pop(path);
|
||||
if (max < align) {
|
||||
max = align;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
|
||||
@@ -1927,10 +1900,14 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
return gb_clamp(next_pow2(type_size_of_internal(allocator, t, path)), 1, build_context.word_size);
|
||||
}
|
||||
|
||||
i64 *type_set_offsets_of(gbAllocator allocator, Entity **fields, isize field_count, bool is_packed) {
|
||||
i64 *type_set_offsets_of(gbAllocator allocator, Entity **fields, isize field_count, bool is_packed, bool is_raw_union) {
|
||||
i64 *offsets = gb_alloc_array(allocator, i64, field_count);
|
||||
i64 curr_offset = 0;
|
||||
if (is_packed) {
|
||||
if (is_raw_union) {
|
||||
for (isize i = 0; i < field_count; i++) {
|
||||
offsets[i] = 0;
|
||||
}
|
||||
} else if (is_packed) {
|
||||
for (isize i = 0; i < field_count; i++) {
|
||||
i64 size = type_size_of(allocator, fields[i]->type);
|
||||
offsets[i] = curr_offset;
|
||||
@@ -1950,17 +1927,17 @@ i64 *type_set_offsets_of(gbAllocator allocator, Entity **fields, isize field_cou
|
||||
|
||||
bool type_set_offsets(gbAllocator allocator, Type *t) {
|
||||
t = base_type(t);
|
||||
if (is_type_struct(t)) {
|
||||
if (t->kind == Type_Record) {
|
||||
if (!t->Record.are_offsets_set) {
|
||||
t->Record.are_offsets_being_processed = true;
|
||||
t->Record.offsets = type_set_offsets_of(allocator, t->Record.fields, t->Record.field_count, t->Record.is_packed);
|
||||
t->Record.offsets = type_set_offsets_of(allocator, t->Record.fields, t->Record.field_count, t->Record.is_packed, t->Record.is_raw_union);
|
||||
t->Record.are_offsets_set = true;
|
||||
return true;
|
||||
}
|
||||
} else if (is_type_tuple(t)) {
|
||||
if (!t->Tuple.are_offsets_set) {
|
||||
t->Record.are_offsets_being_processed = true;
|
||||
t->Tuple.offsets = type_set_offsets_of(allocator, t->Tuple.variables, t->Tuple.variable_count, false);
|
||||
t->Tuple.offsets = type_set_offsets_of(allocator, t->Tuple.variables, t->Tuple.variable_count, false, false);
|
||||
t->Tuple.are_offsets_set = true;
|
||||
return true;
|
||||
}
|
||||
@@ -2114,9 +2091,22 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
|
||||
|
||||
case Type_Record: {
|
||||
switch (t->Record.kind) {
|
||||
|
||||
case TypeRecord_Struct: {
|
||||
if (t->Record.is_raw_union) {
|
||||
i64 count = t->Record.field_count;
|
||||
i64 align = type_align_of_internal(allocator, t, path);
|
||||
if (path->failure) {
|
||||
return FAILURE_SIZE;
|
||||
}
|
||||
i64 max = 0;
|
||||
for (isize i = 0; i < count; i++) {
|
||||
i64 size = type_size_of_internal(allocator, t->Record.fields[i]->type, path);
|
||||
if (max < size) {
|
||||
max = size;
|
||||
}
|
||||
}
|
||||
// TODO(bill): Is this how it should work?
|
||||
return align_formula(max, align);
|
||||
} else {
|
||||
i64 count = t->Record.field_count;
|
||||
if (count == 0) {
|
||||
return 0;
|
||||
@@ -2132,24 +2122,6 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
type_set_offsets(allocator, t);
|
||||
i64 size = t->Record.offsets[count-1] + type_size_of_internal(allocator, t->Record.fields[count-1]->type, path);
|
||||
return align_formula(size, align);
|
||||
} break;
|
||||
|
||||
case TypeRecord_RawUnion: {
|
||||
i64 count = t->Record.field_count;
|
||||
i64 align = type_align_of_internal(allocator, t, path);
|
||||
if (path->failure) {
|
||||
return FAILURE_SIZE;
|
||||
}
|
||||
i64 max = 0;
|
||||
for (isize i = 0; i < count; i++) {
|
||||
i64 size = type_size_of_internal(allocator, t->Record.fields[i]->type, path);
|
||||
if (max < size) {
|
||||
max = size;
|
||||
}
|
||||
}
|
||||
// TODO(bill): Is this how it should work?
|
||||
return align_formula(max, align);
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
|
||||
@@ -2172,7 +2144,7 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
|
||||
i64 type_offset_of(gbAllocator allocator, Type *t, i32 index) {
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Record && (t->Record.kind == TypeRecord_Struct)) {
|
||||
if (t->kind == Type_Record && !t->Record.is_raw_union) {
|
||||
type_set_offsets(allocator, t);
|
||||
if (gb_is_between(index, 0, t->Record.field_count-1)) {
|
||||
return t->Record.offsets[index];
|
||||
@@ -2221,7 +2193,7 @@ i64 type_offset_of_from_selection(gbAllocator allocator, Type *type, Selection s
|
||||
isize index = sel.index[i];
|
||||
t = base_type(t);
|
||||
offset += type_offset_of(allocator, t, index);
|
||||
if (t->kind == Type_Record && t->Record.kind == TypeRecord_Struct) {
|
||||
if (t->kind == Type_Record && !t->Record.is_raw_union) {
|
||||
t = t->Record.fields[index]->type;
|
||||
} else {
|
||||
// NOTE(bill): No need to worry about custom types, just need the alignment
|
||||
@@ -2339,8 +2311,20 @@ gbString write_type_to_string(gbString str, Type *type) {
|
||||
break;
|
||||
|
||||
case Type_Record: {
|
||||
switch (type->Record.kind) {
|
||||
case TypeRecord_Struct:
|
||||
if (type->Record.is_raw_union) {
|
||||
str = gb_string_appendc(str, "raw_union{");
|
||||
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, ", ");
|
||||
}
|
||||
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, "}");
|
||||
} else {
|
||||
str = gb_string_appendc(str, "struct");
|
||||
if (type->Record.is_packed) {
|
||||
str = gb_string_appendc(str, " #packed");
|
||||
@@ -2360,22 +2344,6 @@ gbString write_type_to_string(gbString str, Type *type) {
|
||||
str = write_type_to_string(str, f->type);
|
||||
}
|
||||
str = gb_string_appendc(str, "}");
|
||||
break;
|
||||
|
||||
case TypeRecord_RawUnion:
|
||||
str = gb_string_appendc(str, "raw_union{");
|
||||
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, ", ");
|
||||
}
|
||||
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, "}");
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user