summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNic Gaffney <gaffney_nic@protonmail.com>2024-08-13 20:36:31 -0500
committerNic Gaffney <gaffney_nic@protonmail.com>2024-08-13 20:36:31 -0500
commit760a9246618862b56bafe3dd5d95a77fdd668a6c (patch)
tree9e85eec354e98f6e6ab916956266438d54780573 /src
parentb1ad4a1c280d25f92fdb1103edf2faa5e3e1daac (diff)
downloadcalico-760a9246618862b56bafe3dd5d95a77fdd668a6c.tar.gz
Unit tests now pass
Diffstat (limited to 'src')
-rw-r--r--src/codegen.zig140
-rw-r--r--src/parser.zig27
-rw-r--r--src/symtable.zig9
-rw-r--r--src/tokenize.zig23
4 files changed, 137 insertions, 62 deletions
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{