From 9f6b1414009d9887969e1294df199876693b9702 Mon Sep 17 00:00:00 2001 From: David Gonzalez Martin Date: Tue, 29 Apr 2025 06:29:32 -0600 Subject: [PATCH] wip --- src/bootstrap.zig | 41 +++++-- src/compiler.bbb | 176 ++++++++++++++++++++++++++++++ src/main.zig | 1 + tests/self_referential_struct.bbb | 11 ++ 4 files changed, 217 insertions(+), 12 deletions(-) create mode 100644 tests/self_referential_struct.bbb diff --git a/src/bootstrap.zig b/src/bootstrap.zig index 53df3a0..9905aa2 100644 --- a/src/bootstrap.zig +++ b/src/bootstrap.zig @@ -396,7 +396,7 @@ pub const Type = struct { }; } - fn resolve(ty: *Type, module: *Module) void { + fn resolve_abi(ty: *Type, module: *Module) void { if (ty.llvm.abi == null) { const abi_type = switch (ty.bb) { .void, .noreturn => module.llvm.void_type, @@ -439,7 +439,11 @@ pub const Type = struct { else => @trap(), }; ty.llvm.abi = abi_type; + } + } + fn resolve_memory(ty: *Type, module: *Module) void { + if (ty.llvm.memory == null) { const memory_type = switch (ty.bb) { .void, .noreturn, @@ -447,7 +451,7 @@ pub const Type = struct { .array, .structure, .@"union", - => abi_type, + => ty.llvm.abi.?, .integer => module.llvm.context.get_integer_type(@intCast(ty.get_byte_size() * 8)).to_type(), .enumerator => |enumerator| enumerator.backing_type.llvm.memory.?, .bits => |bits| bits.backing_type.llvm.memory.?, // TODO: see assert below @@ -456,8 +460,12 @@ pub const Type = struct { }; ty.llvm.memory = memory_type; if (ty.bb == .bits) assert(ty.llvm.memory == ty.llvm.abi); + } + } - if (module.has_debug_info) { + fn resolve_debug(ty: *Type, module: *Module) void { + if (module.has_debug_info) { + if (ty.llvm.debug == null) { const debug_type = switch (ty.bb) { .void, .noreturn => module.llvm.di_builder.create_basic_type(ty.name, 0, .void, .{ .no_return = ty.bb == .noreturn }), .integer => |integer| module.llvm.di_builder.create_basic_type(ty.name, @max(lib.next_power_of_two(integer.bit_count), 8), switch (integer.bit_count) { @@ -467,9 +475,10 @@ pub const Type = struct { false => .unsigned, }, }, .{}), - .pointer => |pointer| b: { - pointer.type.resolve(module); - break :b module.llvm.di_builder.create_pointer_type(pointer.type.llvm.debug.?, 64, 64, 0, ty.name).to_type(); + .pointer => |pointer| if (pointer.type.llvm.debug) |t| t else b: { + pointer.type.resolve_debug(module); + const pointer_type = module.llvm.di_builder.create_pointer_type(pointer.type.llvm.debug.?, 64, 64, 0, ty.name).to_type(); + break :b pointer_type; }, .array => |array| module.llvm.di_builder.create_array_type(array.element_count, 0, array.element_type.llvm.debug.?, &.{}).to_type(), .enumerator => |enumerator| blk: { @@ -483,21 +492,22 @@ pub const Type = struct { break :blk enumeration_type.to_type(); }, .structure => |structure| blk: { - const struct_type = module.llvm.di_builder.create_replaceable_composite_type(module.llvm.debug_tag, ty.name, module.scope.llvm.?, module.llvm.file, structure.line); - ty.llvm.debug = struct_type.to_type(); + assert(ty.llvm.debug == null); + const fwd = module.llvm.di_builder.create_replaceable_composite_type(module.llvm.debug_tag, ty.name, module.scope.llvm.?, module.llvm.file, structure.line); + ty.llvm.debug = fwd.to_type(); module.llvm.debug_tag += 1; var llvm_debug_member_type_buffer: [64]*llvm.DI.Type.Derived = undefined; const llvm_debug_member_types = llvm_debug_member_type_buffer[0..structure.fields.len]; for (structure.fields, llvm_debug_member_types) |field, *llvm_debug_member_type| { - field.type.resolve(module); + field.type.resolve_debug(module); const member_type = module.llvm.di_builder.create_member_type(module.scope.llvm.?, field.name, module.llvm.file, field.line, field.type.get_byte_size() * 8, @intCast(field.type.get_byte_alignment() * 8), field.bit_offset, .{}, field.type.llvm.debug.?); llvm_debug_member_type.* = member_type; } const debug_struct_type = module.llvm.di_builder.create_struct_type(module.scope.llvm.?, ty.name, module.llvm.file, structure.line, structure.bit_size, @intCast(structure.bit_alignment), .{}, llvm_debug_member_types); - const forward_declared: *llvm.DI.Type.Composite = @ptrCast(ty.llvm.debug); + const forward_declared: *llvm.DI.Type.Composite = @ptrCast(fwd); forward_declared.replace_all_uses_with(debug_struct_type); break :blk debug_struct_type.to_type(); }, @@ -524,7 +534,7 @@ pub const Type = struct { const llvm_debug_member_types = llvm_debug_member_type_buffer[0..union_type.fields.len]; for (union_type.fields, llvm_debug_member_types) |field, *llvm_debug_member_type| { - field.type.resolve(module); + field.type.resolve_debug(module); const member_type = module.llvm.di_builder.create_member_type(module.scope.llvm.?, field.name, module.llvm.file, field.line, field.type.get_byte_size() * 8, @intCast(field.type.get_byte_alignment() * 8), 0, .{}, field.type.llvm.debug.?); llvm_debug_member_type.* = member_type; } @@ -536,11 +546,18 @@ pub const Type = struct { }, else => @trap(), }; + ty.llvm.debug = debug_type; } } } + fn resolve(ty: *Type, module: *Module) void { + ty.resolve_abi(module); + ty.resolve_memory(module); + ty.resolve_debug(module); + } + const Bits = struct { fields: []const Struct.Field, backing_type: *Type, @@ -1569,7 +1586,7 @@ pub const Module = struct { pub fn get_pointer_type(module: *Module, pointer: Pointer) *Type { const p = Type.Pointer{ .type = pointer.type, - .alignment = if (pointer.alignment) |a| a else if (pointer.type.bb != .unresolved) pointer.type.get_byte_alignment() else null, + .alignment = if (pointer.alignment) |a| a else if (pointer.type.bb != .unresolved and pointer.type.bb != .forward_declaration) pointer.type.get_byte_alignment() else null, }; const all_types = module.types.get_slice(); const pointer_type = for (module.pointer_types.get_slice()) |pointer_type_index| { diff --git a/src/compiler.bbb b/src/compiler.bbb index c30f9a3..93efee1 100644 --- a/src/compiler.bbb +++ b/src/compiler.bbb @@ -586,6 +586,24 @@ CompileOptions = struct silent: u1, } +ScopeKind = enum +{ + global, + function, + local, + for_each, + macro_declaration, + macro_instantiation_function, +} + +Scope = struct +{ + parent: &Scope, + line: u32, + column: u32, + kind: ScopeKind, +} + TypeId = enum { void, @@ -655,6 +673,13 @@ module_noreturn_type = fn (module: &Module) &Type return module_void_type(module) + 1; } +left_bracket: u8 = '['; +right_bracket: u8 = '['; +left_parenthesis: u8 = '('; +right_parenthesis: u8 = ')'; +left_brace: u8 = '{'; +right_brace: u8 = '}'; + is_space = fn (ch: u8) u1 { return ch == ' ' or ch == '\n' or ch == '\t' or ch == '\r'; @@ -817,8 +842,159 @@ parse_identifier = fn (module: &Module) []u8 return result; } +parse_type = fn (module: &Module) &Type +{ +} + +ValueBuilder = struct +{ + foo: u32, +} + +parse_value = fn (module: &Module, scope: &Scope, v: ValueBuilder) &Value +{ +} + +GlobalKeyword = enum +{ + export, + extern, +} + +GlobalKind = enum +{ + bits, + enum, + fn, + macro, + struct, + typealias, + union, +} + parse = fn (module: &Module) void { + while (1) + { + skip_space(module); + + if (module.offset == module.content.length) + { + break; + } + + >is_export: u1 = 0; + >is_extern: u1 = 0; + + >global_line = get_line(module); + >global_column = get_column(module); + + if (consume_character_if_match(module, left_bracket)) + { + while (module.offset < module.content.length) + { + >global_keyword_string = parse_identifier(module); + >global_keyword_s2e = #string_to_enum(GlobalKeyword, global_keyword_string); + if (!global_keyword_s2e.is_valid) + { + report_error(); + } + + >global_keyword = global_keyword_s2e.enum_value; + switch (global_keyword) + { + .export => { is_export = 1; } + .extern => { is_extern = 1; } + } + + if (consume_character_if_match(module, right_bracket)) + { + break; + } + + report_error(); + } + + skip_space(module); + } + + >global_name = parse_identifier(module); + + // TODO: check if the name is repeated in global namespace + + skip_space(module); + + >global_type: &Type = zero; + + if (consume_character_if_match(module, ':')) + { + skip_space(module); + + global_type = parse_type(module); + + skip_space(module); + } + + expect_character(module, '='); + + skip_space(module); + + >has_global_keyword: u1 = 0; + + if (is_identifier_start(module.content[module.offset])) + { + >identifier_offset = module.offset; + + >global_string = parse_identifier(module); + + skip_space(module); + + >global_kind_s2e = #string_to_enum(GlobalKind, global_string); + + if (global_kind_s2e.is_valid) + { + >global_kind = global_kind_s2e.enum_value; + + switch (global_kind) + { + .bits => { + #trap(); + }, + .enum => { + #trap(); + }, + .fn => { + #trap(); + }, + .macro => { + #trap(); + }, + .struct => { + #trap(); + }, + .typealias => { + #trap(); + }, + .union => { + #trap(); + }, + } + } + else + { + module.offset = identifier_offset; + } + } + + if (!has_global_keyword) + { + >v = parse_value(&module.scope, zero); + skip_space(module); + expect_character(module, ';'); + + #trap(); + } + } } emit = fn (module: &Module) void diff --git a/src/main.zig b/src/main.zig index 1f23525..c207f41 100644 --- a/src/main.zig +++ b/src/main.zig @@ -332,4 +332,5 @@ const names = &[_][]const u8{ "generic_pointer_macro", "break_continue", "noreturn_macro", + "self_referential_struct", }; diff --git a/tests/self_referential_struct.bbb b/tests/self_referential_struct.bbb new file mode 100644 index 0000000..f2f5463 --- /dev/null +++ b/tests/self_referential_struct.bbb @@ -0,0 +1,11 @@ +S = struct +{ + self: &S, +} + +[export] main = fn [cc(c)] () s32 +{ + >s: S = zero; + s.self = &s; + return 0; +}