diff options
| -rw-r--r-- | build.zig | 54 | ||||
| -rw-r--r-- | examples/helloWorld.nya | 2 | ||||
| -rw-r--r-- | src/codegen.zig | 140 | ||||
| -rw-r--r-- | src/parser.zig | 27 | ||||
| -rw-r--r-- | src/symtable.zig | 9 | ||||
| -rw-r--r-- | src/tokenize.zig | 23 |
6 files changed, 161 insertions, 94 deletions
@@ -13,7 +13,8 @@ pub fn build(b: *std.Build) !void { }); const llvm = b.dependency("llvm-zig", .{}); - exe.root_module.addImport("llvm", llvm.module("llvm")); + _ = try b.modules.put("llvm", llvm.module("llvm")); + exe.root_module.addImport("llvm", b.modules.get("llvm").?); b.installArtifact(exe); @@ -28,38 +29,29 @@ pub fn build(b: *std.Build) !void { const run_step = b.step("run", "Run the compiler"); run_step.dependOn(&run_cmd.step); - const exe_unit_tests = b.addTest(.{ - .root_source_file = b.path("src/main.zig"), - .target = target, - .optimize = optimize, - }); - - const token_unit_tests = b.addTest(.{ - .root_source_file = b.path("src/tokenize.zig"), - .target = target, - .optimize = optimize, - }); - - const parse_unit_tests = b.addTest(.{ - .root_source_file = b.path("src/parser.zig"), - .target = target, - .optimize = optimize, - }); + const test_step = b.step("test", "Run unit tests"); + for ([_][]const u8{ + "src/main.zig", + "src/tokenize.zig", + "src/parser.zig", + "src/codegen.zig", + }) |file| + unit_test(b, target, optimize, test_step, file); +} - const codegen_unit_tests = b.addTest(.{ - .root_source_file = b.path("src/codegen.zig"), +fn unit_test( + b: *std.Build, + target: std.Build.ResolvedTarget, + optimize: std.builtin.OptimizeMode, + test_step: *std.Build.Step, + fname: []const u8, +) void { + const unit = b.addTest(.{ + .root_source_file = b.path(fname), .target = target, .optimize = optimize, }); - - const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests); - const run_token_unit_tests = b.addRunArtifact(token_unit_tests); - const run_parse_unit_tests = b.addRunArtifact(parse_unit_tests); - const run_codegen_unit_tests = b.addRunArtifact(codegen_unit_tests); - - const test_step = b.step("test", "Run unit tests"); - test_step.dependOn(&run_exe_unit_tests.step); - test_step.dependOn(&run_token_unit_tests.step); - test_step.dependOn(&run_parse_unit_tests.step); - test_step.dependOn(&run_codegen_unit_tests.step); + const unit_tests = b.addRunArtifact(unit); + test_step.dependOn(&unit_tests.step); + unit.root_module.addImport("llvm", b.modules.get("llvm").?); } diff --git a/examples/helloWorld.nya b/examples/helloWorld.nya index 0b8c59b..160d9d2 100644 --- a/examples/helloWorld.nya +++ b/examples/helloWorld.nya @@ -1,6 +1,6 @@ import fn puts(str: [u8]) -> i32; -fn main(argc: i32) -> i32 { +fn main() -> i32 { puts("Hello World!"); return 0; } diff --git a/src/codegen.zig b/src/codegen.zig index cdcffdd..c1fac76 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -80,7 +80,7 @@ pub const Generator = struct { const table = stmt.symtable; const symbol = table.getValue(nodeVar.ident.ident).?; const value = try self.genExpr(nodeVar.expr); - const ptr = try self.genAlloc(toLLVMtype(nodeVar.expr.typ.?, table, nodeVar.expr).?, nodeVar.ident.ident); + const ptr = try self.genAlloc(toLLVMtype(nodeVar.expr.typ orelse try nodeVar.expr.symtable.getValue(nodeVar.ident.ident).?.typ.toTypeIdent(self.allocator), table, nodeVar.expr).?, nodeVar.ident.ident); _ = core.LLVMBuildStore(self.builder, value, ptr); try self.references.put(symbol.id, ptr); } @@ -210,7 +210,16 @@ pub const Generator = struct { if (core.LLVMIsAArgument(ptr)) |_| break :blk ptr; - break :blk core.LLVMBuildLoad2(self.builder, toLLVMtype(expr.typ.?, table, expr), ptr, ""); + break :blk core.LLVMBuildLoad2( + self.builder, + toLLVMtype( + expr.typ orelse try table.getValue(id.ident).?.typ.toTypeIdent(self.allocator), + table, + expr, + ), + ptr, + "", + ); }, .intLit => |int| core.LLVMConstInt(core.LLVMInt32TypeInContext(self.context), @intCast(int.intLit), 1), .stringLit => |str| blk: { @@ -294,23 +303,22 @@ test "Codegen exit" { \\} \\ ; - var tokenizer = tok.Tokenizer.init(std.testing.allocator, src); - defer tokenizer.deinit(); - const toks = try tokenizer.tokenize(); - var symbTable: *symb.SymbolTable = try main.initSymbolTable(std.testing.allocator); - defer symbTable.deinit(); - var parser = parse.Parser.init(std.testing.allocator, toks, symbTable); - defer parser.deinit(); - const parseTree = try parser.parse(); - var pop = symb.Populator.init(std.testing.allocator); - var treeNode = parseTree.asNode(); - try pop.populateSymtable(&treeNode); var arena = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena.deinit(); - var gen = Generator.init(arena.allocator(), parseTree); - defer gen.deinit(); - const actual = try gen.generate(); - try expect(std.mem.eql(u8, actual, expected)); + const allocator = arena.allocator(); + var tokenizer = tok.Tokenizer.init(allocator, src); + defer tokenizer.deinit(); + const tokens = try tokenizer.tokenize(); + const symbTable = try main.initSymbolTable(arena.allocator()); + var parser = parse.Parser.init(arena.allocator(), tokens, symbTable); + const tree = try parser.parse(); + var treeNode = tree.asNode(); + var pop = symb.Populator.init(arena.allocator()); + try pop.populateSymtable(&treeNode); + var generator = Generator.init(arena.allocator(), tree, "_calico_start"); + defer generator.deinit(); + const code = try generator.generate(); + try expect(std.mem.eql(u8, code, expected)); } test "Codegen assign" { @@ -321,7 +329,7 @@ test "Codegen assign" { const src = \\fn main() -> i32 { \\ const testval = 6; - \\ var testvar = testval; + \\ varbl testvar = testval; \\ testvar = 5; \\ return testvar; \\} @@ -343,21 +351,22 @@ test "Codegen assign" { \\} \\ ; - var tokenizer = tok.Tokenizer.init(std.testing.allocator, src); + var arena = std.heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); + const allocator = arena.allocator(); + var tokenizer = tok.Tokenizer.init(allocator, src); defer tokenizer.deinit(); - const toks = try tokenizer.tokenize(); - var symbTable: *symb.SymbolTable = try main.initSymbolTable(std.testing.allocator); - defer symbTable.deinit(); - var parser = parse.Parser.init(std.testing.allocator, toks, symbTable); - defer parser.deinit(); - const parseTree = try parser.parse(); - var pop = symb.Populator.init(std.testing.allocator); - var treeNode = parseTree.asNode(); + const tokens = try tokenizer.tokenize(); + const symbTable = try main.initSymbolTable(arena.allocator()); + var parser = parse.Parser.init(arena.allocator(), tokens, symbTable); + const tree = try parser.parse(); + var treeNode = tree.asNode(); + var pop = symb.Populator.init(arena.allocator()); try pop.populateSymtable(&treeNode); - var gen = Generator.init(std.testing.allocator, parseTree); - defer gen.deinit(); - const actual = try gen.generate(); - try expect(std.mem.eql(u8, actual, expected)); + var generator = Generator.init(arena.allocator(), tree, "_calico_start"); + defer generator.deinit(); + const code = try generator.generate(); + try expect(std.mem.eql(u8, code, expected)); } test "Codegen assign constant" { @@ -372,19 +381,62 @@ test "Codegen assign constant" { \\ return testvar; \\} ; - var tokenizer = tok.Tokenizer.init(std.testing.allocator, src); + var arena = std.heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); + const allocator = arena.allocator(); + var tokenizer = tok.Tokenizer.init(allocator, src); + defer tokenizer.deinit(); + const tokens = try tokenizer.tokenize(); + const symbTable = try main.initSymbolTable(arena.allocator()); + var parser = parse.Parser.init(arena.allocator(), tokens, symbTable); + const tree = try parser.parse(); + var treeNode = tree.asNode(); + var pop = symb.Populator.init(arena.allocator()); + try pop.populateSymtable(&treeNode); + var generator = Generator.init(arena.allocator(), tree, "_calico_start"); + defer generator.deinit(); + const code = generator.generate(); + try std.testing.expectError(CodegenError.Immutable, code); +} +test "Codegen extern fn string" { + const tok = @import("tokenize.zig"); + const expect = std.testing.expect; + const main = @import("main.zig"); + + const src = + \\import fn puts(str: [u8]) -> i32; + \\fn main() -> i32 { + \\ puts("Hello World!"); + \\} + ; + const expected = + \\; ModuleID = '_calico_start' + \\source_filename = "_calico_start" + \\ + \\@.str.0 = private unnamed_addr constant [13 x i8] c"Hello World!\00" + \\ + \\declare i32 @puts(ptr) + \\ + \\define i32 @main() { + \\entry: + \\ %puts = call i32 @puts(ptr @.str.0) + \\} + \\ + ; + var arena = std.heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); + const allocator = arena.allocator(); + var tokenizer = tok.Tokenizer.init(allocator, src); defer tokenizer.deinit(); - const toks = try tokenizer.tokenize(); - var symbTable: *symb.SymbolTable = try main.initSymbolTable(std.testing.allocator); - defer symbTable.deinit(); - var parser = parse.Parser.init(std.testing.allocator, toks, symbTable); - defer parser.deinit(); - const parseTree = try parser.parse(); - var pop = symb.Populator.init(std.testing.allocator); - var treeNode = parseTree.asNode(); + const tokens = try tokenizer.tokenize(); + const symbTable = try main.initSymbolTable(arena.allocator()); + var parser = parse.Parser.init(arena.allocator(), tokens, symbTable); + const tree = try parser.parse(); + var treeNode = tree.asNode(); + var pop = symb.Populator.init(arena.allocator()); try pop.populateSymtable(&treeNode); - var gen = Generator.init(std.testing.allocator, parseTree); - defer gen.deinit(); - const actual = gen.generate(); - try std.testing.expectError(CodegenError.Immutable, actual); + var generator = Generator.init(arena.allocator(), tree, "_calico_start"); + defer generator.deinit(); + const code = try generator.generate(); + try expect(std.mem.eql(u8, code, expected)); } diff --git a/src/parser.zig b/src/parser.zig index 2e6bd85..d4bbfc0 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -315,6 +315,7 @@ pub const Parser = struct { } fn parseAssign(self: *Parser) ParsingError!NodeStmt { + std.debug.print("{any}\n", .{self.tokens.peek().?}); const ident = (try self.tokens.consume(.ident)).?; _ = try self.tokens.consume(.equal); const expr = try self.parseExpr(); @@ -346,7 +347,7 @@ pub const Parser = struct { fn parseVariable(self: *Parser) ParsingError!NodeStmt { _ = try self.tokens.consume(.variable); - var typ: TypeIdent = undefined; + var typ: ?TypeIdent = null; if (self.tokens.consume(.colon)) |_| { typ = .{ .ident = (try self.tokens.consume(.ident)).?.ident, @@ -509,20 +510,22 @@ pub const ExprKind = union(enum) { }; test "Parser" { + const main = @import("main.zig"); const expect = std.testing.expect; const src = "return 120;"; - var tokenizer = tok.Tokenizer.init(std.testing.allocator, src); + var arena = std.heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); + const allocator = arena.allocator(); + var tokenizer = tok.Tokenizer.init(allocator, src); defer tokenizer.deinit(); - const toks = try tokenizer.tokenize(); - - var symbTable = try symb.SymbolTable.init(std.testing.allocator); - defer symbTable.deinit(); - - var parser = Parser.init(std.testing.allocator, toks, symbTable); - defer parser.deinit(); - const parseTree = try parser.parse(); - const children = try parseTree.children(std.testing.allocator); - defer std.testing.allocator.free(children); + const tokens = try tokenizer.tokenize(); + const symbTable = try main.initSymbolTable(arena.allocator()); + var parser = Parser.init(arena.allocator(), tokens, symbTable); + const tree = try parser.parse(); + var treeNode = tree.asNode(); + var pop = symb.Populator.init(arena.allocator()); + try pop.populateSymtable(&treeNode); + const children = try treeNode.children(allocator); const exp: []const Node = &[_]Node{Node{ .Stmt = NodeStmt{ .id = 2, diff --git a/src/symtable.zig b/src/symtable.zig index 5da6081..2e6e86f 100644 --- a/src/symtable.zig +++ b/src/symtable.zig @@ -41,6 +41,15 @@ pub const SymbType = union(enum) { else => "void", }; } + pub fn toTypeIdent(self: SymbType, allocator: std.mem.Allocator) !pars.TypeIdent { + return pars.TypeIdent{ + .ident = try self.toString(allocator), + .list = switch (self) { + .String => true, + else => false, + }, + }; + } }; pub const SymbValue = struct { diff --git a/src/tokenize.zig b/src/tokenize.zig index aa3788c..b578b22 100644 --- a/src/tokenize.zig +++ b/src/tokenize.zig @@ -140,7 +140,6 @@ pub fn Iterator(comptime typ: type) type { pub fn consume(self: *Iterator(typ), comptime expected: TokenType) error{ ExpectedToken, TokenIteratorOnly }!?typ { if (typ != Token) return TokenizeError.TokenIteratorOnly; if (!checkType(self.peek().?, expected)) { - // std.debug.print("Got {}, expected {}\n", .{ self.peek().?, expected }); return TokenizeError.ExpectedToken; } return self.next(); @@ -235,7 +234,10 @@ pub const Tokenizer = struct { test "Tokenize Expression" { const expect = std.testing.expect; const testSource: []const u8 = "return 120 + 150 - 260 * 12 / 5 + variable;"; - var tokenizer = Tokenizer.init(std.testing.allocator, testSource); + var arena = std.heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); + const allocator = arena.allocator(); + var tokenizer = Tokenizer.init(allocator, testSource); defer tokenizer.deinit(); const tokens = try tokenizer.tokenize(); const expected = &[_]Token{ @@ -270,8 +272,11 @@ test "Tokenize Expression" { test "Tokenize variable" { const expect = std.testing.expect; - const testSource: []const u8 = "var five = 5;"; - var tokenizer = Tokenizer.init(std.testing.allocator, testSource); + const testSource: []const u8 = "varbl five = 5;"; + var arena = std.heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); + const allocator = arena.allocator(); + var tokenizer = Tokenizer.init(allocator, testSource); defer tokenizer.deinit(); const tokens = try tokenizer.tokenize(); const expected = &[_]Token{ @@ -296,7 +301,10 @@ test "Tokenize variable" { test "Tokenize constant" { const expect = std.testing.expect; const testSource: []const u8 = "const five = 5;"; - var tokenizer = Tokenizer.init(std.testing.allocator, testSource); + var arena = std.heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); + const allocator = arena.allocator(); + var tokenizer = Tokenizer.init(allocator, testSource); defer tokenizer.deinit(); const tokens = try tokenizer.tokenize(); const expected = &[_]Token{ @@ -325,7 +333,10 @@ test "Tokenize Function" { \\ return 7; \\} ; - var tokenizer = Tokenizer.init(std.testing.allocator, testSource); + var arena = std.heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); + const allocator = arena.allocator(); + var tokenizer = Tokenizer.init(allocator, testSource); defer tokenizer.deinit(); const tokens = try tokenizer.tokenize(); const expected = &[_]Token{ |
