diff --git a/src/compiler.bbb b/src/compiler.bbb index b9e2c35..6e0c6e8 100644 --- a/src/compiler.bbb +++ b/src/compiler.bbb @@ -1392,6 +1392,14 @@ TypeStruct = struct next: &Type, } +TypeBits = struct +{ + fields: []Field, + backing_type: &Type, + line: u32, + is_implicit_backing_type: u1, +} + TypeContent = union { integer: TypeInteger, @@ -1401,6 +1409,7 @@ TypeContent = union enum_array: TypeEnumArray, enum: TypeEnum, struct: TypeStruct, + bits: TypeBits, } TypeLLVM = struct @@ -5994,7 +6003,100 @@ parse = fn (module: &Module) void { .bits => { - #trap(); + >is_implicit_type = module.content[module.offset] == left_brace; + + >backing_type: &Type = zero; + + if (!is_implicit_type) + { + backing_type = parse_type(module, scope); + } + + skip_space(module); + expect_character(module, left_brace); + + >field_buffer: [64]Field = undefined; + >field_bit_offset: u64 = 0; + >field_count: u64 = 0; + + while (1) + { + skip_space(module); + + if (consume_character_if_match(module, right_brace)) + { + break; + } + + >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_bit_count = get_bit_size(field_type); + + skip_space(module); + + consume_character_if_match(module, ','); + + field_buffer[field_count] = { + .name = field_name, + .type = field_type, + .offset = field_bit_offset, + .line = field_line, + }; + + field_bit_offset += field_bit_count; + field_count += 1; + } + + consume_character_if_match(module, ';'); + + >fields = arena_allocate_slice[Field](module.arena, field_count); + memcpy(#pointer_cast(fields.pointer), #pointer_cast(&field_buffer), field_count * #byte_size(Field)); + + >needed_bit_count = #max(next_power_of_two(field_bit_offset), 8); + if (needed_bit_count > #integer_max(u32)) + { + report_error(); + } + + >bit_count = needed_bit_count; + + if (!backing_type) + { + backing_type = integer_type(module, { .bit_count = bit_count, .signed = 0 }); + } + + if (backing_type.id != .integer) + { + report_error(); + } + + >backing_type_bit_size = get_bit_size(backing_type); + if (backing_type_bit_size > 64) + { + report_error(); + } + + new_type(module, { + .content = { + .bits = { + .fields = fields, + .backing_type = backing_type, + .line = global_line, + .is_implicit_backing_type = is_implicit_type, + }, + }, + .id = .bits, + .name = global_name, + .scope = &module.scope, + zero, + }); }, .enum => { @@ -11869,6 +11971,7 @@ names: [_][]u8 = [ "argv", "assignment_operators", "not_pointer", + "bits", ]; [export] main = fn [cc(c)] (argument_count: u32, argv: &&u8, envp: &&u8) s32 diff --git a/src/parser.cpp b/src/parser.cpp index 13a51e3..e42590e 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -3365,7 +3365,8 @@ void parse(Module* module) { skip_space(module); - if (consume_character_if_match(module, right_brace)) { + if (consume_character_if_match(module, right_brace)) + { break; }