diff --git a/src/compiler.bbb b/src/compiler.bbb index 7449493..d087d37 100644 --- a/src/compiler.bbb +++ b/src/compiler.bbb @@ -1407,6 +1407,22 @@ TypeAlias = struct line: u32, } +UnionField = struct +{ + type: &Type, + name: []u8, + line: u32, +} + +TypeUnion = struct +{ + fields: []UnionField, + byte_size: u64, + biggest_field: u64, + byte_alignment: u32, + line: u32, +} + TypeContent = union { integer: TypeInteger, @@ -1418,6 +1434,7 @@ TypeContent = union struct: TypeStruct, bits: TypeBits, alias: TypeAlias, + union: TypeUnion, } TypeLLVM = struct @@ -7115,7 +7132,88 @@ parse = fn (module: &Module) void }, .union => { - #trap(); + skip_space(module); + expect_character(module, left_brace); + + >union_type: &Type = undefined; + + if (type_forward_declaration) + { + union_type = type_forward_declaration; + } + else + { + union_type = new_type(module, { + .id = .forward_declaration, + .name = global_name, + .scope = &module.scope, + zero, + }); + } + + >field_count: u64 = 0; + >biggest_field: u64 = 0; + >alignment: u32 = 1; + >byte_size: u64 = 0; + + >field_buffer: [64]UnionField = undefined; + + while (1) + { + skip_space(module); + + if (consume_character_if_match(module, right_brace)) + { + break; + } + + >field_index = field_count; + field_count += 1; + + >field_line = get_line(module); + >field_name = parse_identifier(module); + + skip_space(module); + expect_character(module, ':'); + skip_space(module); + + >field_type = parse_type(module, scope); + + >field_alignment = get_byte_alignment(field_type); + >field_size = get_byte_size(field_type); + + field_buffer[field_index] = { + .type = field_type, + .name = field_name, + .line = field_line, + }; + + biggest_field = #select(field_size > byte_size, field_index, biggest_field); + alignment = #max(alignment, field_alignment); + byte_size = #max(byte_size, field_size); + + skip_space(module); + + consume_character_if_match(module, ','); + } + + skip_space(module); + consume_character_if_match(module, ';'); + + >fields = arena_allocate_slice[UnionField](module.arena, field_count); + memcpy(#pointer_cast(fields.pointer), #pointer_cast(&field_buffer), field_count * #byte_size(UnionField)); + + >biggest_size = get_byte_size(fields[biggest_field].type); + assert(biggest_size == byte_size); + + union_type.content.union = { + .fields = fields, + .byte_size = byte_size, + .byte_alignment = alignment, + .line = global_line, + .biggest_field = biggest_field, + }; + union_type.id = .union; }, } } @@ -15903,6 +16001,7 @@ names: [_][]u8 = "integer_formats", "for_each_int", "bool_array", + "basic_union", ]; [export] main = fn [cc(c)] (argument_count: u32, argv: &&u8, envp: &&u8) s32