Compare commits

...

1 Commits

Author SHA1 Message Date
David Gonzalez Martin
fab147eacc Polymorphic function 2024-06-19 18:26:09 +02:00
3 changed files with 853 additions and 753 deletions

View File

@ -241,12 +241,9 @@ const Parser = struct{
while (parser.i < file.len) : (parser.i += 1) { while (parser.i < file.len) : (parser.i += 1) {
const is_line_feed = file[parser.i] == '\n'; const is_line_feed = file[parser.i] == '\n';
if (is_line_feed) { if (is_line_feed) {
parser.line += 1;
break; break;
} }
} }
if (parser.i == file.len) break;
} }
} }
} }
@ -258,6 +255,65 @@ const Parser = struct{
column: u32, column: u32,
}; };
fn parse_polymorphic_arguments(parser: *Parser, thread: *Thread, file: *File, scope: *Scope) []const *Type{
const src = file.source_code;
parser.expect_character(src, polymorphic_start_token);
var polymorphic_parameters = PinnedArray(*Type){};
while (true) {
parser.skip_space(src);
if (src[parser.i] == polymorphic_end_token) {
break;
}
const line = parser.get_debug_line();
const column = parser.get_debug_column();
parser.expect_character(src, '$');
const name = parser.parse_identifier(thread, src);
const polymorphic_name = thread.polymorphic_names.append(.{
.type = .{
.sema = .{
.id = .polymorphic_name,
.thread = thread.get_index(),
.resolved = false,
},
.size = 0,
.bit_size = 0,
.alignment = 1,
},
.type_declaration = .{
.declaration = .{
.id = .type,
.name = name,
.line = line,
.column = column,
.scope = scope,
},
.id = .polymorphic_name,
},
.index = polymorphic_parameters.length,
});
switch (src[parser.i]) {
',' => parser.i += 1,
polymorphic_end_token => {},
else => fail(),
}
_ = polymorphic_parameters.append(&polymorphic_name.type);
_ = scope.declarations.put_no_clobber(name, &polymorphic_name.type_declaration.declaration);
}
parser.i += 1;
return polymorphic_parameters.slice();
}
fn parse_field(parser: *Parser, thread: *Thread, file: *File, scope: *Scope) ?ParseFieldData{ fn parse_field(parser: *Parser, thread: *Thread, file: *File, scope: *Scope) ?ParseFieldData{
const src = file.source_code; const src = file.source_code;
parser.skip_space(src); parser.skip_space(src);
@ -725,14 +781,14 @@ const Parser = struct{
const polymorphic_struct = declaration.get_payload(.polymorphic_struct); const polymorphic_struct = declaration.get_payload(.polymorphic_struct);
parser.skip_space(src); parser.skip_space(src);
// Expect parameters for the struct (all polymorphic structs have polymorphic parameters) // Expect parameters for the struct (all polymorphic structs have polymorphic parameters)
parser.expect_character(src, '['); parser.expect_character(src, polymorphic_start_token);
var instantiation_types = PinnedArray(*Type){}; var instantiation_types = PinnedArray(*Type){};
while (true) { while (true) {
parser.skip_space(src); parser.skip_space(src);
if (src[parser.i] == ']') { if (src[parser.i] == polymorphic_end_token) {
break; break;
} }
@ -742,7 +798,7 @@ const Parser = struct{
switch (src[parser.i]) { switch (src[parser.i]) {
',' => parser.i += 1, ',' => parser.i += 1,
']' => {}, polymorphic_end_token => {},
else => fail(), else => fail(),
} }
@ -766,7 +822,7 @@ const Parser = struct{
var struct_name = PinnedArray(u8){}; var struct_name = PinnedArray(u8){};
_ = struct_name.append_slice(struct_polymorphic_name); _ = struct_name.append_slice(struct_polymorphic_name);
_ = struct_name.append('['); _ = struct_name.append(polymorphic_start_token);
for (instantiation_types.slice()) |ty| { for (instantiation_types.slice()) |ty| {
_ = struct_name.append_slice(ty.get_name()); _ = struct_name.append_slice(ty.get_name());
@ -774,7 +830,7 @@ const Parser = struct{
} }
struct_name.length -= 2; struct_name.length -= 2;
_ = struct_name.append(']'); _ = struct_name.append(polymorphic_end_token);
const struct_name_hash = intern_identifier(&thread.identifiers, struct_name.slice()); const struct_name_hash = intern_identifier(&thread.identifiers, struct_name.slice());
@ -3010,7 +3066,6 @@ const Type = struct {
alignment: u32, alignment: u32,
const Id = enum(u8){ const Id = enum(u8){
unresolved,
void, void,
noreturn, noreturn,
integer, integer,
@ -3118,7 +3173,6 @@ const Type = struct {
}; };
const id_to_type_map = std.EnumArray(Id, type).init(.{ const id_to_type_map = std.EnumArray(Id, type).init(.{
.unresolved = void,
.void = void, .void = void,
.noreturn = void, .noreturn = void,
.integer = Integer, .integer = Integer,
@ -3231,7 +3285,6 @@ const Type = struct {
fn is_aggregate(ty: *Type) bool { fn is_aggregate(ty: *Type) bool {
return switch (ty.sema.id) { return switch (ty.sema.id) {
.unresolved => unreachable,
.array => unreachable, .array => unreachable,
.function => unreachable, .function => unreachable,
.void, .void,
@ -3394,6 +3447,7 @@ const Scope = struct {
function, function,
local, local,
polymorphic_struct, polymorphic_struct,
polymorphic_function,
}; };
}; };
@ -3412,7 +3466,6 @@ const ArgumentDeclaration = struct {
const TypeDeclaration = struct{ const TypeDeclaration = struct{
declaration: Declaration, declaration: Declaration,
parent: *Type,
id: Id, id: Id,
const Id = enum{ const Id = enum{
@ -3520,12 +3573,18 @@ const Declaration = struct {
} }
}; };
const PolymorphicFunction = struct{
declaration: GlobalDeclaration,
scope: Function.Scope,
polymorphic_parameters: []const *Type,
};
const Function = struct{ const Function = struct{
declaration: Function.Declaration, declaration: Function.Declaration,
entry_block: *BasicBlock,
stack_slots: PinnedArray(*LocalSymbol) = .{},
scope: Function.Scope, scope: Function.Scope,
arguments: PinnedArray(*ArgumentSymbol) = .{}, stack_slots: PinnedArray(*LocalSymbol) = .{},
arguments: []const *ArgumentSymbol,
entry_block: *BasicBlock,
const Attributes = struct{ const Attributes = struct{
}; };
@ -4159,6 +4218,7 @@ const Thread = struct{
bitfields: PinnedArray(Type.Bitfield) = .{}, bitfields: PinnedArray(Type.Bitfield) = .{},
cloned_types: PinnedHashMap(*Type, *Type) = .{}, cloned_types: PinnedHashMap(*Type, *Type) = .{},
polymorphic_names: PinnedArray(Type.PolymorphicName) = .{}, polymorphic_names: PinnedArray(Type.PolymorphicName) = .{},
polymorphic_functions: PinnedArray(PolymorphicFunction) = .{},
constant_strings: PinnedHashMap(u32, String) = .{}, constant_strings: PinnedHashMap(u32, String) = .{},
global_strings: PinnedHashMap(u32, String) = .{}, global_strings: PinnedHashMap(u32, String) = .{},
string_buffer: PinnedArray(u8) = .{}, string_buffer: PinnedArray(u8) = .{},
@ -5278,6 +5338,8 @@ const brace_open = '{';
const brace_close = '}'; const brace_close = '}';
const pointer_token = '*'; const pointer_token = '*';
const polymorphic_start_token = '\'';
const polymorphic_end_token = '\'';
const cache_line_size = switch (builtin.os.tag) { const cache_line_size = switch (builtin.os.tag) {
.macos => 128, .macos => 128,
@ -5651,7 +5713,7 @@ fn worker_thread(thread_index: u32, cpu_count: *u32) void {
var last_block = basic_block_node; var last_block = basic_block_node;
if (emit_allocas) { if (emit_allocas) {
for (nat_function.arguments.slice(), nat_function.declaration.get_function_type().abi.argument_types_abi) |argument, abi| { for (nat_function.arguments, nat_function.declaration.get_function_type().abi.argument_types_abi) |argument, abi| {
_ = abi; // autofix _ = abi; // autofix
switch (argument.instruction.id) { switch (argument.instruction.id) {
.argument_storage => { .argument_storage => {
@ -8782,6 +8844,81 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
function_declaration_data.global_symbol.attributes.@"export" = true; function_declaration_data.global_symbol.attributes.@"export" = true;
} }
const has_polymorphic_parameters = src[parser.i] == polymorphic_start_token;
if (has_polymorphic_parameters) {
const polymorphic_function = thread.polymorphic_functions.append(.{
.declaration = function_declaration_data.global_symbol.global_declaration,
.scope = .{
.scope = .{
.parent = &file.scope.scope,
.line = declaration_line + 1,
.column = declaration_column + 1,
.file = file.get_index(),
.id = .polymorphic_function,
},
},
.polymorphic_parameters = &.{},
});
_ = file.scope.scope.declarations.put_no_clobber(polymorphic_function.declaration.declaration.name, &polymorphic_function.declaration.declaration);
polymorphic_function.polymorphic_parameters = parser.parse_polymorphic_arguments(thread, file, &polymorphic_function.scope.scope);
parser.skip_space(src);
parser.expect_character(src, '(');
while (true) {
parser.skip_space(src);
if (src[parser.i] == ')') {
break;
}
_ = parser.parse_identifier(thread, src);
parser.skip_space(src);
parser.expect_character(src, ':');
parser.skip_space(src);
_ = parser.parse_type_expression(thread, file, &polymorphic_function.scope.scope);
parser.skip_space(src);
switch (src[parser.i]) {
',' => parser.i += 1,
')' => {},
else => fail(),
}
}
parser.i += 1;
parser.skip_space(src);
_ = parser.parse_type_expression(thread, file, &polymorphic_function.scope.scope);
parser.skip_space(src);
parser.expect_character(src, brace_open);
// var open_brace_count: usize = 1;
// while (parser.i < src.len) {
// if (open_brace_count == 0) {
// break;
// }
// const is_open_brace = src[parser.i] == brace_open;
// const is_close_brace = src[parser.i] == brace_close;
// const is_comment = src[parser.i] == '/' and Parser.get_next_ch_safe(src, parser.i) == '/';
// const is_new_line = src[parser.i] == '\n';
// open_brace_count += @intFromBool(is_open_brace);
// open_brace_count -= @intFromBool(is_close_brace);
// if (is_comment) {
// while (src[parser.i] != '\n') {
// parser.i += 1;
// }
// } else if (is_new_line) {
// } else {
// parser.i += 1;
// }
// }
// parser.parse_polymorphic_arguments(thread, file, scope);
unreachable;
} else {
parser.expect_character(src, '('); parser.expect_character(src, '(');
const ArgumentData = struct{ const ArgumentData = struct{
@ -9266,7 +9403,7 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
}; };
}, },
} else { } else {
unreachable; fail();
}; };
const function_type = thread.function_types.append(.{ const function_type = thread.function_types.append(.{
@ -9296,7 +9433,6 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
fail(); fail();
} }
const function = thread.functions.add_one(); const function = thread.functions.add_one();
const entry_block = create_basic_block(thread); const entry_block = create_basic_block(thread);
function.* = .{ function.* = .{
@ -9311,6 +9447,7 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
}, },
}, },
.entry_block = entry_block, .entry_block = entry_block,
.arguments = &.{},
}; };
_ = file.scope.scope.declarations.put_no_clobber(function.declaration.global_symbol.global_declaration.declaration.name, &function.declaration.global_symbol.global_declaration.declaration); _ = file.scope.scope.declarations.put_no_clobber(function.declaration.global_symbol.global_declaration.declaration.name, &function.declaration.global_symbol.global_declaration.declaration);
var analyzer = Analyzer{ var analyzer = Analyzer{
@ -9340,6 +9477,7 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
} }
if (original_arguments.length > 0) { if (original_arguments.length > 0) {
var arguments = PinnedArray(*ArgumentSymbol){};
// var runtime_parameter_count: u64 = 0; // var runtime_parameter_count: u64 = 0;
for (original_arguments.const_slice(), function_abi.argument_types_abi, 0..) |argument, argument_abi, argument_index| { for (original_arguments.const_slice(), function_abi.argument_types_abi, 0..) |argument, argument_abi, argument_index| {
if (analyzer.current_scope.declarations.get(argument.name) != null) { if (analyzer.current_scope.declarations.get(argument.name) != null) {
@ -9359,6 +9497,7 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
.index = @intCast(argument_index), .index = @intCast(argument_index),
.indirect_argument = argument_abi.indices[0], .indirect_argument = argument_abi.indices[0],
}); });
_ = arguments.append(argument_symbol);
argument_symbol.instruction.id = .abi_indirect_argument; argument_symbol.instruction.id = .abi_indirect_argument;
break :blk argument_symbol; break :blk argument_symbol;
} else blk: { } else blk: {
@ -9400,6 +9539,7 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
.column = argument.column, .column = argument.column,
.index = @intCast(argument_index), .index = @intCast(argument_index),
}); });
_ = arguments.append(argument_symbol);
_ = emit_store(&analyzer, thread, .{ _ = emit_store(&analyzer, thread, .{
.destination = &argument_symbol.instruction.value, .destination = &argument_symbol.instruction.value,
.source = &argument_abi_instructions.slice()[0].value, .source = &argument_abi_instructions.slice()[0].value,
@ -9420,6 +9560,7 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
.column = argument.column, .column = argument.column,
.index = @intCast(argument_index), .index = @intCast(argument_index),
}); });
_ = arguments.append(argument_symbol);
switch (argument.type.sema.id) { switch (argument.type.sema.id) {
.@"struct" => { .@"struct" => {
@ -9485,6 +9626,7 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
.column = argument.column, .column = argument.column,
.index = @intCast(argument_index), .index = @intCast(argument_index),
}); });
_ = arguments.append(argument_symbol);
_ = emit_store(&analyzer, thread, .{ _ = emit_store(&analyzer, thread, .{
.destination = &argument_symbol.instruction.value, .destination = &argument_symbol.instruction.value,
@ -9533,6 +9675,8 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
} }
} }
} }
function.arguments = arguments.slice();
} }
const result = analyze_local_block(thread, &analyzer, &parser, file); const result = analyze_local_block(thread, &analyzer, &parser, file);
@ -9581,6 +9725,7 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
}, },
else => fail_message("Unexpected character to close function declaration"), else => fail_message("Unexpected character to close function declaration"),
} }
}
} else { } else {
fail(); fail();
} }
@ -9658,9 +9803,8 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
parser.skip_space(src); parser.skip_space(src);
if (src[parser.i] == '[') { const has_polymorphic_parameters = src[parser.i] == polymorphic_start_token;
parser.i += 1; if (has_polymorphic_parameters) {
const polymorphic_struct = thread.polymorphic_structs.append(.{ const polymorphic_struct = thread.polymorphic_structs.append(.{
.type = .{ .type = .{
.sema = .{ .sema = .{
@ -9691,57 +9835,7 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
}); });
_ = file.scope.scope.declarations.put_no_clobber(struct_name, &polymorphic_struct.declaration); _ = file.scope.scope.declarations.put_no_clobber(struct_name, &polymorphic_struct.declaration);
var struct_parameters = PinnedArray(*Type){}; polymorphic_struct.parameters = parser.parse_polymorphic_arguments(thread, file, &polymorphic_struct.scope);
while (true) {
parser.skip_space(src);
if (src[parser.i] == ']') {
break;
}
const line = parser.get_debug_line();
const column = parser.get_debug_column();
parser.i += 1;
const name = parser.parse_identifier(thread, src);
const polymorphic_name = thread.polymorphic_names.append(.{
.type = .{
.sema = .{
.id = .polymorphic_name,
.thread = thread.get_index(),
.resolved = false,
},
.size = 0,
.bit_size = 0,
.alignment = 1,
},
.type_declaration = .{
.declaration = .{
.id = .type,
.name = name,
.line = line,
.column = column,
.scope = &polymorphic_struct.scope,
},
.parent = &polymorphic_struct.type,
.id = .polymorphic_name,
},
.index = struct_parameters.length,
});
switch (src[parser.i]) {
',' => parser.i += 1,
']' => {},
else => fail(),
}
_ = struct_parameters.append(&polymorphic_name.type);
_ = polymorphic_struct.scope.declarations.put_no_clobber(name, &polymorphic_name.type_declaration.declaration);
}
parser.i += 1;
polymorphic_struct.parameters = struct_parameters.slice();
parser.skip_space(src); parser.skip_space(src);
@ -10079,7 +10173,6 @@ fn emit_argument_symbol(analyzer: *Analyzer, thread: *Thread, args: struct{
.column = args.column, .column = args.column,
}), }),
}); });
_ = analyzer.current_function.arguments.append(argument_symbol);
return argument_symbol; return argument_symbol;
} }

View File

@ -1,9 +1,9 @@
struct SimplePolymorphic[$T] { struct SimplePolymorphic'$T' {
member: T, member: T,
} }
fn[cc(.c)] main[export]() s32 { fn[cc(.c)] main[export]() s32 {
>s: SimplePolymorphic[s32] = { >s: SimplePolymorphic's32' = {
.member = 0, .member = 0,
}; };
return s.member; return s.member;

View File

@ -0,0 +1,7 @@
fn polymorphic'$T'(arg: T) T {
return arg;
}
fn[cc(.c)] main[export]() s32 {
return polymorphic's32'(0);
}