summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/codegen.zig54
-rw-r--r--src/main.zig13
-rw-r--r--src/parser.zig119
-rw-r--r--src/symtable.zig8
-rw-r--r--src/tokenize.zig28
5 files changed, 198 insertions, 24 deletions
diff --git a/src/codegen.zig b/src/codegen.zig
index 8f3160e..7aff0b6 100644
--- a/src/codegen.zig
+++ b/src/codegen.zig
@@ -81,6 +81,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.ident.ident);
const ptr = try self.genAlloc(
toLLVMtype(
nodeVar.expr.typ orelse try nodeVar.expr.symtable.getValue(nodeVar.ident.ident).?.typ.toTypeIdent(self.allocator),
@@ -98,9 +99,11 @@ pub const Generator = struct {
const table = stmt.symtable;
const symbol = table.getValue(nodeVar.ident.ident).?;
+ // const ptr = try self.genAlloc(toLLVMtype(nodeVar.expr.typ.?, table), nodeVar.ident.ident);
const ptr = try self.genAlloc(toLLVMtype(nodeVar.expr.typ orelse try nodeVar.expr.inferType(self.allocator, table), table, nodeVar.expr), nodeVar.ident.ident);
const value = try self.genExpr(nodeVar.expr);
_ = core.LLVMBuildStore(self.builder, value, ptr);
+ std.debug.print("\t\t\tGenerated Value {s}\n", .{nodeVar.ident.ident});
try self.references.put(symbol.id, ptr);
}
@@ -120,9 +123,9 @@ pub const Generator = struct {
return core.LLVMBuildAlloca(builder, typ, str);
}
- fn asBasicType(typ: symb.SymbType) ?types.LLVMTypeKind {
+ fn asBasicType(typ: symb.SymbType) ?types.LLVMTypeRef {
return switch (typ) {
- .Integer => types.LLVMTypeKind.LLVMIntegerTypeKind,
+ .Integer => core.LLVMInt32Type(),
else => null,
};
}
@@ -186,13 +189,39 @@ pub const Generator = struct {
}
}
+ fn genIf(self: *Generator, stmt: parse.NodeStmt) CodegenError!void {
+ const ifkind = stmt.kind.ifstmt;
+ const block = ifkind.body;
+ const expr = ifkind.expr;
+
+ const condition = try self.genExpr(expr);
+ const func = self.currentFunc.?;
+
+ const then = core.LLVMAppendBasicBlock(func, "then");
+ const elsebb = core.LLVMAppendBasicBlock(func, "elsebb");
+ const cont = core.LLVMAppendBasicBlock(func, "continue");
+
+ _ = core.LLVMBuildCondBr(self.builder, condition, then, elsebb);
+
+ _ = core.LLVMPositionBuilderAtEnd(self.builder, then);
+ try self.genStmt(block.*);
+ _ = core.LLVMBuildBr(self.builder, cont);
+
+ _ = core.LLVMPositionBuilderAtEnd(self.builder, elsebb);
+ _ = core.LLVMBuildBr(self.builder, cont);
+
+ _ = core.LLVMPositionBuilderAtEnd(self.builder, cont);
+ }
+
fn genStmt(self: *Generator, stmt: parse.NodeStmt) !void {
+ std.debug.print("======\n\tStmt: {any}\n======\n", .{stmt.kind});
try switch (stmt.kind) {
.exit => |expr| self.genExit(expr),
.function => self.genFunc(stmt),
.defValue => self.genValue(stmt),
.defVar => self.genVar(stmt),
.assignVar => self.genAssign(stmt),
+ .ifstmt => self.genIf(stmt),
.expr => |expression| {
_ = try self.genExpr(expression);
},
@@ -230,6 +259,20 @@ pub const Generator = struct {
);
},
.intLit => |int| core.LLVMConstInt(core.LLVMInt32TypeInContext(self.context), @intCast(int.intLit), 1),
+ .binaryOp => |exp| blk: {
+ const lhs = try self.genExpr(exp.lhs.*);
+ const rhs = try self.genExpr(exp.rhs.*);
+ std.debug.print("\n\n\tLHS: {any}\n\tRHS: {any}\n\tOP: {any}\n\n", .{ lhs, rhs, exp.op });
+
+ break :blk switch (exp.op) {
+ .plus => core.LLVMBuildAdd(self.builder, lhs, rhs, "add"),
+ .minus => core.LLVMBuildSub(self.builder, lhs, rhs, "sub"),
+ .star => core.LLVMBuildMul(self.builder, lhs, rhs, "mul"),
+ .slash => core.LLVMBuildSDiv(self.builder, lhs, rhs, "div"),
+ .eqleql => core.LLVMBuildICmp(self.builder, types.LLVMIntPredicate.LLVMIntEQ, lhs, rhs, "eql"),
+ else => core.LLVMBuildICmp(self.builder, types.LLVMIntPredicate.LLVMIntEQ, lhs, rhs, "eql"),
+ };
+ },
.stringLit => |str| blk: {
const vref = core.LLVMAddGlobal(
self.module,
@@ -254,7 +297,7 @@ pub const Generator = struct {
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, functype.input) |arg, intype| {
+ for (call.args.items, functype.input) |arg, intype| {
if (!std.meta.eql(expr.symtable.getType(arg.typ.?).?, intype)) return CodegenError.IncorrectType;
try args.append(try self.genExpr(arg));
}
@@ -266,7 +309,7 @@ pub const Generator = struct {
funcType,
function,
@ptrCast(args.items),
- @intCast(call.args.len),
+ @intCast(call.args.items.len),
ident,
);
// std.debug.print("CALL\n", .{});
@@ -279,8 +322,9 @@ pub const Generator = struct {
pub fn generate(self: *Generator) ![]const u8 {
try switch (self.root.kind) {
.block => |b| {
- for (b) |stmt|
+ for (b) |stmt| {
try self.genStmt(stmt);
+ }
},
else => error.InvalidTop,
};
diff --git a/src/main.zig b/src/main.zig
index 05dde7d..b51b170 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -5,6 +5,12 @@ const gen = @import("codegen.zig");
const symb = @import("symtable.zig");
pub fn main() !void {
+ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
+ const alc = gpa.allocator();
+ defer _ = gpa.deinit();
+ var arena = std.heap.ArenaAllocator.init(alc);
+ defer arena.deinit();
+ var allocator = arena.allocator();
if (std.os.argv.len < 2) {
std.debug.print(
\\info: Usage: calico [input file]
@@ -13,10 +19,6 @@ pub fn main() !void {
return;
}
- var gpa = std.heap.GeneralPurposeAllocator(.{}){};
- var allocator = gpa.allocator();
- defer _ = gpa.deinit();
-
var args = std.process.args();
_ = args.skip();
const inputFileName = args.next();
@@ -47,8 +49,7 @@ pub fn main() !void {
const tokens = try tokenizer.tokenize();
// Parse
- var arena = std.heap.ArenaAllocator.init(allocator);
- defer arena.deinit();
+ // var arena = std.heap.ArenaAllocator.init(allocator);
const symbTable = try initSymbolTable(arena.allocator());
var parser = parse.Parser.init(arena.allocator(), tokens, symbTable);
diff --git a/src/parser.zig b/src/parser.zig
index f2dba0a..66d02a2 100644
--- a/src/parser.zig
+++ b/src/parser.zig
@@ -68,6 +68,7 @@ pub const NodeExpr = struct {
.call => |call| if (table.getValue(call.ident.ident)) |symbol| try symbol.typ.Function.output.toTypeIdent(allocator) else TypeError.UnknownIdentifier,
.ident => |id| if (table.getValue(id.ident)) |symbol| try symbol.typ.toTypeIdent(allocator) else TypeError.UnknownIdentifier,
.intLit => TypeIdent{ .ident = "i32", .list = false },
+ .binaryOp => TypeIdent{ .ident = "i32", .list = false },
.stringLit => TypeIdent{ .ident = "[u8]", .list = true },
};
if (self.typ) |typ| {
@@ -107,6 +108,7 @@ pub const NodeStmt = struct {
const blockChildren = map(Node, NodeStmt, block, NodeStmt.asNode);
for (blockChildren) |child| try childrenArray.append(child);
},
+ .ifstmt => |ifstmt| try childrenArray.append(ifstmt.body.*.asNode()),
.function => |fun| if (fun.block == null) {} else try childrenArray.append(fun.block.?.asNode()),
.expr => |expr| try childrenArray.append(expr.asNode()),
}
@@ -167,9 +169,30 @@ pub const Parser = struct {
self.nodes.deinit();
}
+ fn parseCall(self: *Parser, typ: ?TypeIdent, expr: NodeExpr) ParsingError!NodeExpr {
+ if (self.tokens.peek().? != .openParen) return expr;
+ _ = try self.tokens.consume(.openParen);
+ var args = std.ArrayList(NodeExpr).init(self.allocator);
+ while (self.tokens.peek().? != .closeParen) {
+ try args.append(try self.parseExpr());
+ if (self.tokens.peek().? != .comma) break;
+ }
+ _ = try self.tokens.consume(.closeParen);
+
+ const kind = ExprKind{ .call = .{ .ident = expr.kind.ident, .args = args } };
+ return NodeExpr{
+ .kind = kind,
+ .isConst = false,
+ .typ = typ,
+ .id = self.reserveId(),
+ .symtable = self.top,
+ };
+ }
+
fn parseExpr(self: *Parser) !NodeExpr {
var typ: ?TypeIdent = null;
- const kind = try blk: {
+ var isIdent = false;
+ const kind: ExprKind = try blk: {
try switch (self.tokens.peek().?) {
.intLit => {
typ = TypeIdent{
@@ -179,6 +202,7 @@ pub const Parser = struct {
break :blk ExprKind{ .intLit = (try self.tokens.consume(.intLit)).? };
},
.ident => {
+ isIdent = true;
const ident = (try self.tokens.consume(.ident)).?;
if (tok.checkType(self.tokens.peek().?, .openParen)) {
_ = try self.tokens.consume(.openParen);
@@ -195,7 +219,7 @@ pub const Parser = struct {
}
_ = try self.tokens.consume(.closeParen);
- break :innerblk try argExprs.toOwnedSlice();
+ break :innerblk try argExprs.clone();
},
},
};
@@ -210,20 +234,66 @@ pub const Parser = struct {
};
break :blk ExprKind{ .stringLit = (try self.tokens.consume(.stringLit)).? };
},
- else => break :blk ParsingError.InvalidExpression,
+ else => |expr| break :blk errorblk: {
+ std.debug.print("Invalid Expression: {any}\n", .{expr});
+ break :errorblk ParsingError.InvalidExpression;
+ },
};
};
- return NodeExpr{
+
+ const lhs = NodeExpr{
.id = self.reserveId(),
+ .isConst = false,
.kind = kind,
- .isConst = kind.isConstant(),
- .typ = typ,
.symtable = self.top,
+ .typ = typ,
};
+
+ const lhsptr = try self.allocator.create(NodeExpr);
+ lhsptr.* = lhs;
+
+ const precTable: []const []const tok.TokenType = &.{
+ &.{ .plus, .minus },
+ &.{ .star, .slash },
+ &.{.eqleql},
+ };
+
+ return try self.genBinOp(precTable[0], typ, lhsptr) //.
+ orelse try self.genBinOp(precTable[1], typ, lhsptr) //.
+ orelse try self.genBinOp(precTable[2], typ, lhsptr) //.
+ orelse if (isIdent) blk: {
+ break :blk try self.parseCall(typ, lhsptr.*);
+ } //.
+ else lhs;
+ }
+
+ fn genBinOp(self: *Parser, comptime ops: []const tok.TokenType, typ: ?TypeIdent, lhs: *NodeExpr) ParsingError!?NodeExpr {
+ for (ops) |op|
+ if (self.tokens.peek().? == op) {
+ const oper = self.tokens.next();
+ const rhsptr = try self.allocator.create(NodeExpr);
+ rhsptr.* = try self.parseExpr();
+ const kind = ExprKind{
+ .binaryOp = .{
+ .lhs = lhs,
+ .rhs = rhsptr,
+ .op = oper.?,
+ },
+ };
+ return NodeExpr{
+ .id = self.reserveId(),
+ .isConst = false,
+ .kind = kind,
+ .symtable = self.top,
+ .typ = typ,
+ };
+ };
+ return null;
}
fn parseStmt(self: *Parser) ParsingError!NodeStmt {
return switch (self.tokens.peek().?) {
+ .ifstmt => try self.parseIf(),
.exit => try self.parseExit(),
.constant => try self.parseConstant(),
.variable => try self.parseVariable(),
@@ -232,6 +302,7 @@ pub const Parser = struct {
break :blk try self.parseAssign();
break :blk try self.parseExprStmt();
},
+ .openBrace => self.parseBlock(),
.fun => try self.parseFunc(false),
.import => try self.parseFunc(true),
else => self.parseExprStmt(),
@@ -248,6 +319,28 @@ pub const Parser = struct {
};
}
+ fn parseIf(self: *Parser) ParsingError!NodeStmt {
+ _ = try self.tokens.consume(.ifstmt); // if
+
+ _ = try self.tokens.consume(.openParen); // (
+ const expr = try self.parseExpr(); // EXPR
+ _ = try self.tokens.consume(.closeParen); // )
+
+ const body = try self.allocator.create(NodeStmt);
+ body.* = try self.parseStmt();
+
+ const kind = StmtKind{
+ .ifstmt = .{
+ .expr = expr,
+ .body = body,
+ },
+ };
+ return NodeStmt{
+ .id = self.reserveId(),
+ .kind = kind,
+ .symtable = self.top,
+ };
+ }
fn parseFunc(self: *Parser, external: bool) ParsingError!NodeStmt {
if (external) _ = try self.tokens.consume(.import);
var typ: ?TypeIdent = null;
@@ -485,18 +578,25 @@ pub const NodeVar = struct {
expr: NodeExpr,
};
+pub const NodeIf = struct {
+ expr: NodeExpr,
+ body: *NodeStmt,
+};
+
pub const NodeExit = NodeExpr;
pub const NodeIntlit = Token;
pub const NodeStringlit = Token;
pub const NodeIdent = Token;
pub const NodeBlock = []const NodeStmt;
+pub const NodeBinOp = Token;
pub const NodeCall = struct {
ident: Token,
- args: []const NodeExpr,
+ args: std.ArrayList(NodeExpr),
};
pub const StmtKind = union(enum) {
+ ifstmt: NodeIf,
function: NodeFunction,
exit: NodeExit,
defValue: NodeValue,
@@ -511,6 +611,11 @@ pub const ExprKind = union(enum) {
stringLit: NodeStringlit,
ident: NodeIdent,
call: NodeCall,
+ binaryOp: struct {
+ lhs: *NodeExpr,
+ rhs: *NodeExpr,
+ op: NodeBinOp,
+ },
pub fn isConstant(self: ExprKind) bool {
return switch (self) {
diff --git a/src/symtable.zig b/src/symtable.zig
index 71596e2..3017670 100644
--- a/src/symtable.zig
+++ b/src/symtable.zig
@@ -204,6 +204,7 @@ pub const Populator = struct {
try value.expr.inferType(self.allocator, table),
false,
);
+ std.debug.print("Value: {s}\nSymbol: {any}\n", .{ value.ident.ident, symbol });
if (!try table.insert(value.ident.ident, symbol)) return error.FailedToInsert;
},
.block => {
@@ -231,8 +232,12 @@ pub const Populator = struct {
},
.exit => |exit| _ = try exit.inferType(self.allocator, table),
.expr => {},
+ .ifstmt => for (try stmt.children(self.allocator)) |c| try self.populateSymtable(&c),
- // else => return error.Unimplemented,
+ // else => |unim| return errorblk: {
+ // std.debug.print("Error: Unimplemented: {any}\n", .{unim});
+ // break :errorblk error.Unimplemented;
+ // },
}
},
else => {
@@ -294,7 +299,6 @@ pub const Populator = struct {
};
return value.toSymb();
}
- // std.debug.print("{s}: ", .{typ.ident});
return error.UnknownType;
}
};
diff --git a/src/tokenize.zig b/src/tokenize.zig
index b578b22..2c536db 100644
--- a/src/tokenize.zig
+++ b/src/tokenize.zig
@@ -14,6 +14,7 @@ pub const TokenType = enum {
intLit,
charLit,
// Keywords
+ ifstmt,
constant,
variable,
exit,
@@ -26,6 +27,9 @@ pub const TokenType = enum {
slash,
semiCol,
equal,
+ eqleql,
+ lessthan,
+ greaterthan,
// Symbols
openBrace,
closeBrace,
@@ -33,9 +37,9 @@ pub const TokenType = enum {
closeParen,
openBracket,
closeBracket,
+ arrow,
colon,
comma,
- arrow,
};
pub const Token = union(TokenType) {
@@ -45,6 +49,7 @@ pub const Token = union(TokenType) {
intLit: i32,
charLit: u8,
// Keywords
+ ifstmt,
constant,
variable,
exit,
@@ -57,6 +62,9 @@ pub const Token = union(TokenType) {
slash,
semiCol,
equal,
+ eqleql,
+ lessthan,
+ greaterthan,
// Symbols
openBrace,
closeBrace,
@@ -64,12 +72,13 @@ pub const Token = union(TokenType) {
closeParen,
openBracket,
closeBracket,
+ arrow,
colon,
comma,
- arrow,
pub fn fromChar(char: u8) !Token {
return switch (char) {
+ ',' => .comma,
'+' => .plus,
'-' => .minus,
'*' => .star,
@@ -80,10 +89,11 @@ pub const Token = union(TokenType) {
'}' => .closeBrace,
'(' => .openParen,
')' => .closeParen,
+ '<' => .lessthan,
+ '>' => .greaterthan,
+ ':' => .colon,
'[' => .openBracket,
']' => .closeBracket,
- ':' => .colon,
- ',' => .comma,
else => {
// std.debug.print("{c}: ", .{char});
return TokenizeError.UnknownToken;
@@ -97,6 +107,7 @@ pub const Token = union(TokenType) {
if (eql(u8, str, "const")) return .constant;
if (eql(u8, str, "varbl")) return .variable;
if (eql(u8, str, "fn")) return .fun;
+ if (eql(u8, str, "if")) return .ifstmt;
if (eql(u8, str, "import")) return .import;
return Token{ .ident = str };
}
@@ -186,6 +197,15 @@ pub const Tokenizer = struct {
while (self.src.peek()) |char| {
try switch (char) {
+ '=' => {
+ self.src.skip();
+ if (self.src.peek().? != '=') {
+ try self.toks.append(.equal);
+ continue;
+ }
+ self.src.skip();
+ try self.toks.append(.eqleql);
+ },
'-' => {
self.src.skip();
if (self.src.peek().? != '>') {