From b1ad4a1c280d25f92fdb1103edf2faa5e3e1daac Mon Sep 17 00:00:00 2001 From: Nic Gaffney Date: Tue, 13 Aug 2024 17:28:34 -0500 Subject: Added type checking on function calls --- examples/helloWorld.nya | 6 ++++++ examples/test.nya | 6 ------ src/codegen.zig | 8 +++++++- src/main.zig | 2 +- src/symtable.zig | 36 +++++++++++++++++++++++------------- 5 files changed, 37 insertions(+), 21 deletions(-) create mode 100644 examples/helloWorld.nya delete mode 100644 examples/test.nya diff --git a/examples/helloWorld.nya b/examples/helloWorld.nya new file mode 100644 index 0000000..0b8c59b --- /dev/null +++ b/examples/helloWorld.nya @@ -0,0 +1,6 @@ +import fn puts(str: [u8]) -> i32; + +fn main(argc: i32) -> i32 { + puts("Hello World!"); + return 0; +} diff --git a/examples/test.nya b/examples/test.nya deleted file mode 100644 index 0b8c59b..0000000 --- a/examples/test.nya +++ /dev/null @@ -1,6 +0,0 @@ -import fn puts(str: [u8]) -> i32; - -fn main(argc: i32) -> i32 { - puts("Hello World!"); - return 0; -} diff --git a/src/codegen.zig b/src/codegen.zig index 3922a75..cdcffdd 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -10,6 +10,7 @@ const types = llvm.types; const CodegenError = error{ Immutable, OutOfMemory, + IncorrectType, }; fn toLLVMtype(typ: parse.TypeIdent, sym: *symb.SymbolTable, expr: ?parse.NodeExpr) types.LLVMTypeRef { @@ -232,11 +233,16 @@ pub const Generator = struct { }, .call => |call| blk: { + std.debug.print("Function {s} requested\n", .{call.ident.ident}); + + const functype = expr.symtable.getValue(call.ident.ident).?.typ.Function; const ident = try self.allocator.dupeZ(u8, call.ident.ident); const function = core.LLVMGetNamedFunction(self.module, ident); var args = std.ArrayList(types.LLVMValueRef).init(self.allocator); - for (call.args) |arg| + for (call.args, functype.input) |arg, intype| { + if (!std.meta.eql(expr.symtable.getType(arg.typ.?).?, intype)) return CodegenError.IncorrectType; try args.append(try self.genExpr(arg)); + } const funcType = core.LLVMGlobalGetValueType(function); // std.debug.print("FUNCTYPE: {s}\n", .{call.ident.ident}); diff --git a/src/main.zig b/src/main.zig index a326685..05dde7d 100644 --- a/src/main.zig +++ b/src/main.zig @@ -67,7 +67,7 @@ pub fn main() !void { var generator = gen.Generator.init(arena.allocator(), tree, @ptrCast(fname)); defer generator.deinit(); const code = try generator.generate(); - std.debug.print("{s}\n", .{code}); + // std.debug.print("{s}\n", .{code}); try outWriter.writeAll(code); const binFile = try getFileName(allocator, out_name, ""); diff --git a/src/symtable.zig b/src/symtable.zig index 6ddee01..5da6081 100644 --- a/src/symtable.zig +++ b/src/symtable.zig @@ -23,10 +23,21 @@ pub const SymbType = union(enum) { pub fn toSymb(self: SymbType) Symbol { return Symbol{ .Type = self }; } - pub fn toString(self: SymbType) []const u8 { + pub fn toString(self: SymbType, allocator: std.mem.Allocator) ![]const u8 { return switch (self) { .Integer => "i32", .Character => "u8", + .String => "[u8]", + .Function => |fun| blk: { + const output = try fun.output.toString(allocator); + var argstring: []const u8 = ""; + if (fun.input.len != 0) { + argstring = try fun.input[0].toString(allocator); + for (1..fun.input.len) |i| + argstring = try std.mem.join(allocator, ", ", &[_][]const u8{ argstring, try fun.input[i].toString(allocator) }); + } + break :blk try std.fmt.allocPrint(allocator, "fn({s})->{s}", .{ argstring, output }); + }, else => "void", }; } @@ -105,7 +116,7 @@ pub const SymbolTable = struct { } pub fn get(self: SymbolTable, ident: []const u8) ?Symbol { - if (self.scope) |scope| return scope.symbs.get(ident); + if (self.scope) |scope| return scope.symbs.get(ident) orelse if (self.parent()) |par| par.get(ident) else null; return null; } @@ -193,20 +204,12 @@ pub const Populator = struct { fun.args, fun.retType, ); + if (!try table.insert(fun.ident.ident, symbol)) return error.FailedToInsert; + std.debug.print("Function {s} inserted\n", .{fun.ident.ident}); if (fun.block == null) return; - // var iter = fun.block.?.symtable.scope.?.symbs.iterator(); - // while (iter.next()) |val| { - // // std.debug.print("{s}\n", .{val.key_ptr.*}); - // } - const block = fun.block.?.asNode(); try self.populateSymtable(&block); - - // var iterTable = bodyTable.scope.?.symbs.iterator(); - // while (iterTable.next()) |entry| { - // // std.debug.print("{s} -> {any}\n", .{ entry.key_ptr.*, entry.value_ptr.* }); - // } }, else => {}, @@ -243,8 +246,15 @@ pub const Populator = struct { }, }; const id = self.reserveId(); + var argstring: []const u8 = ""; + if (input.len != 0) { + argstring = try input[0].toString(self.allocator); + for (1..input.len) |i| + argstring = try std.mem.join(self.allocator, ",", &[_][]const u8{ argstring, try input[i].toString(self.allocator) }); + } - const name = try std.fmt.allocPrint(self.allocator, "func_{d}", .{id}); + const name = try std.fmt.allocPrint(self.allocator, "fn({s})->{s}", .{ argstring, try output.toString(self.allocator) }); + std.debug.print("Function type => \"{s}\"\n", .{name}); _ = try table.insert(name, typ.toSymb()); return Symbol{ -- cgit v1.2.3