From 4acf1c36f1f3014a6fbfd382a04cae84fee2766d Mon Sep 17 00:00:00 2001 From: David Gonzalez Martin Date: Tue, 21 Nov 2023 10:44:36 -0600 Subject: [PATCH] add named arguments --- bootstrap/Compilation.zig | 6 --- bootstrap/frontend/semantic_analyzer.zig | 60 +++++++++++++++++++++-- bootstrap/frontend/syntactic_analyzer.zig | 28 +++++++---- lib/std/start.nat | 2 +- test/hello_world/main.nat | 2 +- 5 files changed, 76 insertions(+), 22 deletions(-) diff --git a/bootstrap/Compilation.zig b/bootstrap/Compilation.zig index dd705ac..b19ebea 100644 --- a/bootstrap/Compilation.zig +++ b/bootstrap/Compilation.zig @@ -887,12 +887,6 @@ pub const Module = struct { fn addString(map: *StringKeyMap([]const u8), allocator: Allocator, string: []const u8) !u32 { const lookup_result = try map.getOrPut(allocator, string, string); - - { - const lookup_name = map.getValue(lookup_result.key) orelse unreachable; - assert(equal(u8, lookup_name, string)); - } - return lookup_result.key; } diff --git a/bootstrap/frontend/semantic_analyzer.zig b/bootstrap/frontend/semantic_analyzer.zig index 62466d6..bf57480 100644 --- a/bootstrap/frontend/semantic_analyzer.zig +++ b/bootstrap/frontend/semantic_analyzer.zig @@ -302,14 +302,66 @@ const Analyzer = struct { const argument_declarations = function_prototype.arguments.?; logln(.sema, .call, "Argument declaration count: {}. Argument node list count: {}\n", .{ argument_declarations.len, call_argument_node_list.len }); var argument_array = ArrayList(Value.Index){}; + if (argument_declarations.len == call_argument_node_list.len) { - for (argument_declarations, call_argument_node_list) |argument_declaration_index, argument_node_index| { + for (argument_declarations, call_argument_node_list, 0..) |argument_declaration_index, argument_node_index, index| { const argument_declaration = analyzer.module.declarations.get(argument_declaration_index); - // const argument_declaration_type = analyzer.module.types.get(argument_declaration.type); - // assert(argument_declaration.type.valid); + const argument_node = analyzer.getScopeNode(scope_index, argument_node_index); + const value_node_index = switch (argument_node.id) { + .identifier => blk: { + const identifier = analyzer.tokenIdentifier(scope_index, argument_node.token); + const identifier_hash = try analyzer.processIdentifier(identifier); + + if (identifier_hash == argument_declaration.name) { + break :blk argument_node_index; + } else { + const call_site_name = analyzer.module.getName(identifier_hash).?; + const definition_site_name = analyzer.module.getName(argument_declaration.name).?; + const function_name = analyzer.module.getName(analyzer.module.function_name_map.get(function_index).?).?; + std.debug.panic("At function '{s}' call, argument #{} must be named the same way. Call site was name '{s}' while function definition has it named as '{s}'", .{ function_name, index, call_site_name, definition_site_name }); + } + }, + .named_argument => blk: { + const identifier_node = analyzer.getScopeNode(scope_index, argument_node.left); + if (identifier_node.id != .identifier) { + @panic("expected identifier"); + } + const identifier = analyzer.tokenIdentifier(scope_index, identifier_node.token); + const identifier_hash = try analyzer.processIdentifier(identifier); + + if (identifier_hash == argument_declaration.name) { + break :blk argument_node.right; + } else { + const call_site_name = analyzer.module.getName(identifier_hash).?; + const definition_site_name = analyzer.module.getName(argument_declaration.name).?; + const function_name = analyzer.module.getName(analyzer.module.function_name_map.get(function_index).?).?; + std.debug.panic("At function '{s}' call, argument #{} must be named the same way. Call site was name '{s}' while function definition has it named as '{s}'", .{ function_name, index, call_site_name, definition_site_name }); + } + }, + else => |node_id| { + const definition_site_name = analyzer.module.getName(argument_declaration.name).?; + const function_name = analyzer.module.getName(analyzer.module.function_name_map.get(function_index).?).?; + + std.debug.panic("Argument #{} of call to function '{s}' of type {s} must be named as '{s}'", .{ index, function_name, @tagName(node_id), definition_site_name }); + }, + }; const call_argument_allocation = try analyzer.unresolvedAllocate(scope_index, ExpectType{ .type_index = argument_declaration.type, - }, argument_node_index); + }, value_node_index); + // switch (call_argument_allocation.ptr.*) { + // .integer, + // .string_literal, + // => {}, + // .declaration_reference => |declaration_reference| { + // if (call_argument_declaration.name != argument_declaration.name) { + // const call_site_name = analyzer.module.getName(call_argument_declaration.name).?; + // const definition_site_name = analyzer.module.getName(argument_declaration.name).?; + // const function_name = analyzer.module.getName(analyzer.module.function_name_map.get(function_index).?).?; + // std.debug.panic("At function '{s}' call, argument #{} must be named the same way. Call site was name '{s}' while function definition has it named as '{s}'", .{ function_name, index, call_site_name, definition_site_name }); + // } + // }, + // else => |t| @panic(@tagName(t)), + // } try call_argument_allocation.ptr.typeCheck(analyzer.module, argument_declaration.type); // const call_argument_type_index = call_argument_allocation.ptr.getType(analyzer.module); // const call_argument_type = analyzer.module.types.get(call_argument_type_index); diff --git a/bootstrap/frontend/syntactic_analyzer.zig b/bootstrap/frontend/syntactic_analyzer.zig index 0b398e6..86fc611 100644 --- a/bootstrap/frontend/syntactic_analyzer.zig +++ b/bootstrap/frontend/syntactic_analyzer.zig @@ -163,6 +163,7 @@ pub const Node = packed struct(u128) { shift_left = 69, shift_right = 70, bool_type = 71, + named_argument = 72, }; }; @@ -1082,20 +1083,27 @@ const Analyzer = struct { var expression_list = ArrayList(Node.Index){}; while (analyzer.tokens[analyzer.token_i].id != .right_parenthesis) { - const current_token = analyzer.tokens[analyzer.token_i]; - logln(.parser, .suffix, "Current token: {s}\n", .{@tagName(current_token.id)}); - const parameter = try analyzer.expression(); - try expression_list.append(analyzer.allocator, parameter); + const current_token = analyzer.token_i; + var parameter = try analyzer.expression(); const parameter_node = analyzer.nodes.items[parameter.unwrap()]; logln(.parser, .suffix, "Paremeter node: {s}\n", .{@tagName(parameter_node.id)}); - const next_token = analyzer.tokens[analyzer.token_i]; - logln(.parser, .suffix, "next token: {s}\n", .{@tagName(next_token.id)}); - analyzer.token_i += @intFromBool(switch (next_token.id) { - .comma => true, + if (analyzer.tokens[analyzer.token_i].id == .equal) { + analyzer.token_i += 1; + + parameter = try analyzer.addNode(.{ + .id = .named_argument, + .token = current_token, + .left = parameter, + .right = try analyzer.expression(), + }); + } + try expression_list.append(analyzer.allocator, parameter); + switch (analyzer.tokens[analyzer.token_i].id) { + .comma => analyzer.token_i += 1, + .right_parenthesis => {}, .colon, .right_brace, .right_bracket => unreachable, - .right_parenthesis => false, else => |t| @panic(@tagName(t)), - }); + } } _ = try analyzer.expectToken(.right_parenthesis); diff --git a/lib/std/start.nat b/lib/std/start.nat index 3a2c6c3..f169441 100644 --- a/lib/std/start.nat +++ b/lib/std/start.nat @@ -5,5 +5,5 @@ comptime { const _start = fn () noreturn { const result = #import("main").main(); - std.os.exit(result); + std.os.exit(exit_code = result); } diff --git a/test/hello_world/main.nat b/test/hello_world/main.nat index 595a9f5..dc3444f 100644 --- a/test/hello_world/main.nat +++ b/test/hello_world/main.nat @@ -1,6 +1,6 @@ const std = #import("std"); const main = fn() s32 { - std.print("Hello world!\n", 13); + std.print(bytes_ptr = "Hello world!\n", bytes_len = 13); return 0; }