Self referential struct

This commit is contained in:
David Gonzalez Martin 2024-04-05 14:49:20 -06:00
parent 2343a1ff4e
commit 84c279aa3d
6 changed files with 73 additions and 28 deletions

1
.gitignore vendored
View File

@ -4,3 +4,4 @@ nat/
*.o *.o
*.out *.out
*.obj *.obj
Nativity/

View File

@ -4069,6 +4069,7 @@ pub const Debug = struct {
pub const Global = struct { pub const Global = struct {
scope: Scope, scope: Scope,
type: Type.Index = .null,
}; };
pub const Function = struct { pub const Function = struct {
@ -4107,7 +4108,10 @@ pub const Debug = struct {
compilation_unit, compilation_unit,
file, file,
file_container, file_container,
container, struct_type,
enum_type,
bitfield,
error_type,
function, // Arguments function, // Arguments
block, block,
}; };
@ -4127,7 +4131,6 @@ pub const Debug = struct {
lexer: lexer.Result = undefined, lexer: lexer.Result = undefined,
parser: parser.Result = undefined, parser: parser.Result = undefined,
// value: Value.Index = .null, // value: Value.Index = .null,
type: Type.Index = .null,
scope: Scope.Global, scope: Scope.Global,
pub const List = BlockList(@This(), enum {}); pub const List = BlockList(@This(), enum {});
@ -4428,7 +4431,7 @@ pub const Builder = struct {
return .{ return .{
.value = .{ .value = .{
.@"comptime" = .{ .@"comptime" = .{
.type = file.type, .type = file.scope.type,
}, },
}, },
.type = .type, .type = .type,
@ -4910,7 +4913,7 @@ pub const Builder = struct {
// File type already assigned // File type already assigned
_ = try builder.resolveContainerType(unit, context, main_node_index, .@"struct", null); _ = try builder.resolveContainerType(unit, context, main_node_index, .@"struct", null);
file.status = .analyzed; file.status = .analyzed;
assert(file.type != .null); assert(file.scope.type != .null);
} }
const CastResult = enum { const CastResult = enum {
@ -5178,7 +5181,7 @@ pub const Builder = struct {
try builder.analyzeFile(unit, context, file_index); try builder.analyzeFile(unit, context, file_index);
} }
assert(file.type != .null); assert(file.scope.type != .null);
return file_index; return file_index;
} }
@ -5503,7 +5506,7 @@ pub const Builder = struct {
const v: V = switch (lookup.scope.kind) { const v: V = switch (lookup.scope.kind) {
.file_container, .file_container,
.file, .file,
.container, .struct_type,
=> b: { => b: {
const global = try builder.referenceGlobalDeclaration(unit, context, lookup.scope, lookup.declaration, global_attributes); const global = try builder.referenceGlobalDeclaration(unit, context, lookup.scope, lookup.declaration, global_attributes);
const pointer_to_global = try unit.getPointerType(context, .{ const pointer_to_global = try unit.getPointerType(context, .{
@ -6356,6 +6359,7 @@ pub const Builder = struct {
.array_type, .array_type,
.usize_type, .usize_type,
.pointer_type, .pointer_type,
.self,
=> { => {
if (element_type_index != .null) { if (element_type_index != .null) {
unreachable; unreachable;
@ -6503,7 +6507,7 @@ pub const Builder = struct {
.file = builder.current_file, .file = builder.current_file,
.line = token_debug_info.line, .line = token_debug_info.line,
.column = token_debug_info.column, .column = token_debug_info.column,
.kind = .container, .kind = .error_type,
.local = false, .local = false,
.level = builder.current_scope.level + 1, .level = builder.current_scope.level + 1,
.parent = &unit.scope.scope, .parent = &unit.scope.scope,
@ -6534,6 +6538,19 @@ pub const Builder = struct {
const instantiated_type_index = try builder.instantiate_polymorphic_type(unit, context, parameterized_type_index, parameter_types.slice(), parameterized_type_index); const instantiated_type_index = try builder.instantiate_polymorphic_type(unit, context, parameterized_type_index, parameter_types.slice(), parameterized_type_index);
break :b instantiated_type_index; break :b instantiated_type_index;
}, },
.self => {
var scope = builder.current_scope;
while (true) {
const global_scope: *Debug.Scope.Global = switch (scope.kind) {
.struct_type => @fieldParentPtr("scope", scope),
else => |t| @panic(@tagName(t)),
};
_ = &scope;
const type_index = global_scope.type;
assert(type_index != .null);
return type_index;
}
},
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}; };
@ -6641,7 +6658,7 @@ pub const Builder = struct {
fn get_builtin_declaration(builder: *Builder, unit: *Unit, context: *const Context, name: []const u8) !*Debug.Declaration.Global { fn get_builtin_declaration(builder: *Builder, unit: *Unit, context: *const Context, name: []const u8) !*Debug.Declaration.Global {
const std_file_index = try builder.resolveImportStringLiteral(unit, context, Type.Expect{ .type = .type }, "std"); const std_file_index = try builder.resolveImportStringLiteral(unit, context, Type.Expect{ .type = .type }, "std");
const std_file = unit.files.get(std_file_index); const std_file = unit.files.get(std_file_index);
const std_file_struct_index = unit.types.get(std_file.type).@"struct"; const std_file_struct_index = unit.types.get(std_file.scope.type).@"struct";
const std_file_struct = unit.structs.get(std_file_struct_index); const std_file_struct = unit.structs.get(std_file_struct_index);
const builtin_hash = try unit.processIdentifier(context, "builtin"); const builtin_hash = try unit.processIdentifier(context, "builtin");
@ -7629,7 +7646,7 @@ pub const Builder = struct {
.scope = .{ .scope = .{
.kind = switch (builder.current_scope.kind) { .kind = switch (builder.current_scope.kind) {
.file => .file_container, .file => .file_container,
else => .container, else => .struct_type,
}, },
.line = token_debug_info.line, .line = token_debug_info.line,
.column = token_debug_info.column, .column = token_debug_info.column,
@ -7728,20 +7745,17 @@ pub const Builder = struct {
}; };
} }
// Save file type // Assign the struct type to the upper file scope
switch (builder.current_scope.kind) { switch (builder.current_scope.kind) {
.file => { .file => {
const global_scope: *Debug.Scope.Global = @fieldParentPtr("scope", builder.current_scope); const global_scope: *Debug.Scope.Global = @fieldParentPtr("scope", builder.current_scope);
const file: *Debug.File = @fieldParentPtr("scope", global_scope); const file: *Debug.File = @fieldParentPtr("scope", global_scope);
file.type = type_index; file.scope.type = type_index;
try unit.scope_container_map.put_no_clobber(context.my_allocator, &struct_type.kind.@"struct".scope.scope, type_index);
}, },
.file_container => {}, .file_container => {},
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} }
try unit.struct_type_map.put_no_clobber(context.my_allocator, struct_index, type_index);
break :b .{ break :b .{
.scope = &struct_type.kind.@"struct".scope, .scope = &struct_type.kind.@"struct".scope,
.type = type_index, .type = type_index,
@ -7778,7 +7792,7 @@ pub const Builder = struct {
.@"enum" = .{ .@"enum" = .{
.scope = .{ .scope = .{
.scope = .{ .scope = .{
.kind = .container, .kind = .enum_type,
.line = token_debug_info.line, .line = token_debug_info.line,
.column = token_debug_info.column, .column = token_debug_info.column,
.level = builder.current_scope.level + 1, .level = builder.current_scope.level + 1,
@ -7814,6 +7828,7 @@ pub const Builder = struct {
}; };
}, },
}; };
const bitfield_type_index = try unit.types.append(context.my_allocator, .{ const bitfield_type_index = try unit.types.append(context.my_allocator, .{
.integer = .{ .integer = .{
.bit_count = integer.bit_count, .bit_count = integer.bit_count,
@ -7822,10 +7837,7 @@ pub const Builder = struct {
.bitfield = .{ .bitfield = .{
.scope = .{ .scope = .{
.scope = .{ .scope = .{
.kind = switch (builder.current_scope.kind) { .kind = .bitfield,
.file => .file_container,
else => .container,
},
.line = token_debug_info.line, .line = token_debug_info.line,
.column = token_debug_info.column, .column = token_debug_info.column,
.level = builder.current_scope.level + 1, .level = builder.current_scope.level + 1,
@ -7847,6 +7859,8 @@ pub const Builder = struct {
const scope = data.scope; const scope = data.scope;
const type_index = data.type; const type_index = data.type;
scope.type = type_index;
if (maybe_global) |global| { if (maybe_global) |global| {
global.declaration.type = .type; global.declaration.type = .type;
global.initial_value = .{ global.initial_value = .{
@ -8313,7 +8327,6 @@ pub const Builder = struct {
const function = unit.function_definitions.get(builder.current_function); const function = unit.function_definitions.get(builder.current_function);
builder.last_check_point = .{}; builder.last_check_point = .{};
assert(builder.current_scope.kind == .file_container or builder.current_scope.kind == .file or builder.current_scope.kind == .container);
try builder.pushScope(unit, context, &function.scope.scope); try builder.pushScope(unit, context, &function.scope.scope);
defer builder.popScope(unit, context) catch unreachable; defer builder.popScope(unit, context) catch unreachable;
@ -8822,7 +8835,7 @@ pub const Builder = struct {
const file_index = try builder.resolveImport(unit, context, type_expect, argument_node_list); const file_index = try builder.resolveImport(unit, context, type_expect, argument_node_list);
const file = unit.files.get(file_index); const file = unit.files.get(file_index);
return .{ return .{
.type = file.type, .type = file.scope.type,
}; };
}, },
.@"error" => { .@"error" => {
@ -9028,7 +9041,7 @@ pub const Builder = struct {
.file = builder.current_file, .file = builder.current_file,
.line = token_debug_info.line, .line = token_debug_info.line,
.column = token_debug_info.column, .column = token_debug_info.column,
.kind = .container, .kind = .error_type,
.local = false, .local = false,
.level = builder.current_scope.level + 1, .level = builder.current_scope.level + 1,
.parent = builder.current_scope, .parent = builder.current_scope,
@ -15002,7 +15015,7 @@ pub const Builder = struct {
const builtin_package = try unit.importPackage(context, unit.root_package.dependencies.get("builtin").?); const builtin_package = try unit.importPackage(context, unit.root_package.dependencies.get("builtin").?);
const builtin_file_index = builtin_package.file.index; const builtin_file_index = builtin_package.file.index;
const builtin_file = unit.files.get(builtin_file_index); const builtin_file = unit.files.get(builtin_file_index);
const builtin_file_struct_index = unit.types.get(builtin_file.type).@"struct"; const builtin_file_struct_index = unit.types.get(builtin_file.scope.type).@"struct";
const builtin_file_struct = unit.structs.get(builtin_file_struct_index); const builtin_file_struct = unit.structs.get(builtin_file_struct_index);
const test_functions_name = "test_functions"; const test_functions_name = "test_functions";
const test_functions_name_hash = try unit.processIdentifier(context, test_functions_name); const test_functions_name_hash = try unit.processIdentifier(context, test_functions_name);
@ -15218,7 +15231,6 @@ pub const Unit = struct {
data_to_emit: UnpinnedArray(*Debug.Declaration.Global) = .{}, data_to_emit: UnpinnedArray(*Debug.Declaration.Global) = .{},
external_functions: MyHashMap(Type.Index, *Debug.Declaration.Global) = .{}, external_functions: MyHashMap(Type.Index, *Debug.Declaration.Global) = .{},
type_declarations: MyHashMap(Type.Index, *Debug.Declaration.Global) = .{}, type_declarations: MyHashMap(Type.Index, *Debug.Declaration.Global) = .{},
struct_type_map: MyHashMap(Struct.Index, Type.Index) = .{},
test_functions: MyHashMap(*Debug.Declaration.Global, *Debug.Declaration.Global) = .{}, test_functions: MyHashMap(*Debug.Declaration.Global, *Debug.Declaration.Global) = .{},
scope: Debug.Scope.Global = .{ scope: Debug.Scope.Global = .{
.scope = .{ .scope = .{
@ -15230,7 +15242,6 @@ pub const Unit = struct {
.local = false, .local = false,
}, },
}, },
scope_container_map: MyHashMap(*Debug.Scope, Type.Index) = .{},
root_package: *Package = undefined, root_package: *Package = undefined,
main_package: ?*Package = null, main_package: ?*Package = null,
all_errors: Type.Index = .null, all_errors: Type.Index = .null,
@ -16062,6 +16073,7 @@ pub const FixedKeyword = enum {
@"and", @"and",
@"or", @"or",
bitfield, bitfield,
Self,
}; };
pub const Descriptor = struct { pub const Descriptor = struct {
@ -16273,6 +16285,7 @@ pub const Token = struct {
fixed_keyword_and, fixed_keyword_and,
fixed_keyword_or, fixed_keyword_or,
fixed_keyword_bitfield, fixed_keyword_bitfield,
fixed_keyword_Self,
unused1, unused1,
unused2, unused2,
unused3, unused3,

View File

@ -1952,8 +1952,8 @@ pub const LLVM = struct {
if (true) unreachable; if (true) unreachable;
return scope; return scope;
} else { } else {
const sema_struct_type = unit.scope_container_map.get(sema_scope).?; const global_scope: *Compilation.Debug.Scope.Global = @fieldParentPtr("scope", sema_scope);
const struct_type = try llvm.getDebugType(unit, context, sema_struct_type); const struct_type = try llvm.getDebugType(unit, context, global_scope.type);
return struct_type.toScope(); return struct_type.toScope();
} }
}, },

View File

@ -197,6 +197,7 @@ pub const Node = struct {
catch_payload, catch_payload,
bitfield_type, bitfield_type,
comptime_expression, comptime_expression,
self,
}; };
}; };
@ -1873,6 +1874,15 @@ const Analyzer = struct {
const token = analyzer.peekToken(); const token = analyzer.peekToken();
return try switch (token) { return try switch (token) {
.fixed_keyword_Self => try analyzer.addNode(.{
.id = .self,
.token = b: {
analyzer.consumeToken();
break :b token_i;
},
.left = .null,
.right = .null,
}),
.fixed_keyword_fn => blk: { .fixed_keyword_fn => blk: {
analyzer.consumeToken(); analyzer.consumeToken();
break :blk analyzer.functionPrototype(); break :blk analyzer.functionPrototype();

View File

@ -1,6 +1,16 @@
const std = #import("std"); const std = #import("std");
const expect = std.testing.expect;
const PinnedArray = std.data_structures.PinnedArray; const PinnedArray = std.data_structures.PinnedArray;
const main = fn () *!void { const main = fn () *!void {
var pinned_array = PinnedArray(u32){}; var array = [1]u32{0};
var pinned_array = PinnedArray(u32){
.pointer = array.&,
.length = 0,
.capacity = 1,
};
//const n = 5;
//pinned_array.append_with_capacity(n);
//try expect(pinned_array.length == 1);
//try expect(pinned_array[0] == n);
} }

View File

@ -0,0 +1,11 @@
const Struct = struct {
previous: ?&Struct,
next: ?&Self,
};
const main = fn () *!void {
var s = Struct{
.previous = null,
.next = null,
};
}