Compare commits

..

No commits in common. "74e6beda671b6006848f6c967ae437715416e9b7" and "9a9008247fded846b4c027f019a8156f80f3b5d0" have entirely different histories.

8 changed files with 249 additions and 235 deletions

View file

@ -30,5 +30,5 @@ fn add(a: i32, b: i32) i32 {
} }
fn main() i32 { fn main() i32 {
return 123; return 1;
} }

View file

@ -25,7 +25,7 @@ pub const Analyzer = struct {
}; };
} }
fn setErrContext(self: *@This(), comptime fmt: ?[]const u8, args: var) void { fn setErrContext(self: *@This(), comptime fmt: ?[]const u8, args: ...) void {
if (fmt == null) { if (fmt == null) {
self.err_ctx = null; self.err_ctx = null;
return; return;
@ -42,21 +42,21 @@ pub const Analyzer = struct {
self.err_tok = tok; self.err_tok = tok;
} }
fn doError(self: *@This(), comptime fmt: []const u8, args: var) void { fn doError(self: *@This(), comptime fmt: []const u8, args: ...) void {
self.hadError = true; self.hadError = true;
std.debug.warn("analysis error", .{}); std.debug.warn("analysis error");
if (self.err_tok) |tok| { if (self.err_tok) |tok| {
std.debug.warn(" at line {}", .{tok.line}); std.debug.warn(" at line {}", tok.line);
} }
if (self.err_ctx) |ctx| { if (self.err_ctx) |ctx| {
std.debug.warn(" on {}", .{ctx}); std.debug.warn(" on {}", ctx);
} }
std.debug.warn("\n\t", .{}); std.debug.warn("\n\t");
std.debug.warn(fmt, args); std.debug.warn(fmt, args);
std.debug.warn("\n", .{}); std.debug.warn("\n");
} }
/// Resolve a type in global scope /// Resolve a type in global scope
@ -76,7 +76,7 @@ pub const Analyzer = struct {
var sym = ctx.symbol_table.get(val); var sym = ctx.symbol_table.get(val);
if (sym == null) { if (sym == null) {
self.doError("Unknown type: '{}'", .{val}); self.doError("Unknown type: '{}'", val);
return null; return null;
} }
@ -85,10 +85,11 @@ pub const Analyzer = struct {
.Enum => SymbolUnderlyingType{ .Enum = val }, .Enum => SymbolUnderlyingType{ .Enum = val },
else => blk: { else => blk: {
self.doError("expected struct or enum for '{}', got {}", .{ self.doError(
"expected struct or enum for '{}', got {}",
val, val,
@tagName(@as(comp.SymbolType, sym.?.value.*)), @tagName(@as(comp.SymbolType, sym.?.value.*)),
}); );
break :blk null; break :blk null;
}, },
}; };
@ -107,7 +108,7 @@ pub const Analyzer = struct {
) !void { ) !void {
var actual_enum = @as(comp.SymbolUnderlyingTypeEnum, symbol_type); var actual_enum = @as(comp.SymbolUnderlyingTypeEnum, symbol_type);
if (actual_enum != wanted_type_enum) { if (actual_enum != wanted_type_enum) {
std.debug.warn("Expected {}, got {}\n", .{ wanted_type_enum, actual_enum }); std.debug.warn("Expected {}, got {}\n", wanted_type_enum, actual_enum);
return CompileError.TypeError; return CompileError.TypeError;
} }
} }
@ -121,7 +122,7 @@ pub const Analyzer = struct {
.Integer32, .Integer64, .Double => {}, .Integer32, .Integer64, .Double => {},
else => { else => {
var actual_enum = @as(comp.SymbolUnderlyingTypeEnum, symbol_type); var actual_enum = @as(comp.SymbolUnderlyingTypeEnum, symbol_type);
std.debug.warn("Expected numeric, got {}\n", .{actual_enum}); std.debug.warn("Expected numeric, got {}\n", actual_enum);
return CompileError.TypeError; return CompileError.TypeError;
}, },
} }
@ -135,11 +136,12 @@ pub const Analyzer = struct {
expected_ident: []const u8, expected_ident: []const u8,
) !void { ) !void {
if (!std.mem.eql(u8, sym_ident, expected_ident)) { if (!std.mem.eql(u8, sym_ident, expected_ident)) {
self.doError("Expected {} {}, got {}", .{ self.doError(
"Expected {} {}, got {}",
@tagName(typ_enum), @tagName(typ_enum),
expected_ident, expected_ident,
sym_ident, sym_ident,
}); );
return CompileError.TypeError; return CompileError.TypeError;
} }
@ -156,7 +158,7 @@ pub const Analyzer = struct {
const expected_enum = @as(comp.SymbolUnderlyingTypeEnum, expected_type); const expected_enum = @as(comp.SymbolUnderlyingTypeEnum, expected_type);
if (symbol_enum != expected_enum) { if (symbol_enum != expected_enum) {
std.debug.warn("Expected {}, got {}\n", .{ expected_enum, symbol_enum }); std.debug.warn("Expected {}, got {}\n", expected_enum, symbol_enum);
return CompileError.TypeError; return CompileError.TypeError;
} }
@ -242,7 +244,7 @@ pub const Analyzer = struct {
const name = struc.name.lexeme; const name = struc.name.lexeme;
var typ = self.resolveGlobalType(ctx, name); var typ = self.resolveGlobalType(ctx, name);
if (typ == null) { if (typ == null) {
self.doError("Unknown struct name '{}'\n", .{name}); self.doError("Unknown struct name '{}'\n", name);
return CompileError.TypeError; return CompileError.TypeError;
} }
@ -265,11 +267,12 @@ pub const Analyzer = struct {
const param_type_val = @as(comp.SymbolUnderlyingTypeEnum, param_type); const param_type_val = @as(comp.SymbolUnderlyingTypeEnum, param_type);
const arg_type_val = @as(comp.SymbolUnderlyingTypeEnum, arg_type); const arg_type_val = @as(comp.SymbolUnderlyingTypeEnum, arg_type);
self.doError("Expected parameter {} to be {}, got {}", .{ self.doError(
"Expected parameter {} to be {}, got {}",
idx, idx,
@tagName(param_type_val), @tagName(param_type_val),
@tagName(arg_type_val), @tagName(arg_type_val),
}); );
return CompileError.TypeError; return CompileError.TypeError;
}; };
@ -289,7 +292,7 @@ pub const Analyzer = struct {
var target = get.target.*; var target = get.target.*;
const target_type = @as(ast.ExprType, target); const target_type = @as(ast.ExprType, target);
if (target_type != .Variable) { if (target_type != .Variable) {
std.debug.warn("Expected Variable as get target, got {}\n", .{target_type}); std.debug.warn("Expected Variable as get target, got {}\n", target_type);
return CompileError.TypeError; return CompileError.TypeError;
} }
@ -319,10 +322,11 @@ pub const Analyzer = struct {
var kv = map.get(name); var kv = map.get(name);
if (kv == null) { if (kv == null) {
self.doError("Field {} not found in enum {}", .{ self.doError(
"Field {} not found in enum {}",
name, name,
lexeme, lexeme,
}); );
return CompileError.TypeError; return CompileError.TypeError;
} }
@ -330,9 +334,10 @@ pub const Analyzer = struct {
}, },
else => { else => {
self.doError("Expected Struct/Enum as get target, got {}", .{ self.doError(
"Expected Struct/Enum as get target, got {}",
@as(comp.SymbolUnderlyingTypeEnum, global_typ), @as(comp.SymbolUnderlyingTypeEnum, global_typ),
}); );
return CompileError.TypeError; return CompileError.TypeError;
}, },
@ -341,7 +346,7 @@ pub const Analyzer = struct {
.Assign => |assign| { .Assign => |assign| {
if (ctx.current_scope == null) { if (ctx.current_scope == null) {
self.doError("Can't assign without a scope", .{}); self.doError("Can't assign without a scope");
return CompileError.Invalid; return CompileError.Invalid;
} }
@ -350,7 +355,7 @@ pub const Analyzer = struct {
); );
if (var_type == null) { if (var_type == null) {
self.doError("Assign target variable not found", .{}); self.doError("Assign target variable not found");
return CompileError.Invalid; return CompileError.Invalid;
} }
@ -388,7 +393,7 @@ pub const Analyzer = struct {
var var_type = try self.resolveExprType(ctx, vardecl.value); var var_type = try self.resolveExprType(ctx, vardecl.value);
if (ctx.current_scope == null) { if (ctx.current_scope == null) {
self.doError("Can't declare without a scope", .{}); self.doError("Can't declare without a scope");
return CompileError.Invalid; return CompileError.Invalid;
} }
@ -457,7 +462,7 @@ pub const Analyzer = struct {
node: *ast.Node, node: *ast.Node,
) !void { ) !void {
self.setErrToken(null); self.setErrToken(null);
self.setErrContext(null, .{}); self.setErrContext(null);
// always reset the contexts' current function // always reset the contexts' current function
ctx.cur_function = null; ctx.cur_function = null;
@ -467,13 +472,10 @@ pub const Analyzer = struct {
.FnDecl => |decl| { .FnDecl => |decl| {
self.setErrToken(decl.return_type); self.setErrToken(decl.return_type);
const name = decl.func_name.lexeme; const name = decl.func_name.lexeme;
self.setErrContext("function {}", .{name}); self.setErrContext("function {}", name);
var ret_type = self.resolveGlobalType(ctx, decl.return_type.lexeme); var ret_type = self.resolveGlobalType(ctx, decl.return_type.lexeme);
std.debug.warn("start analysis of fn {}, ret type: {}\n", .{ std.debug.warn("start analysis of fn {}, ret type: {}\n", decl.func_name.lexeme, ret_type);
decl.func_name.lexeme,
ret_type,
});
var parameters = comp.TypeList.init(self.allocator); var parameters = comp.TypeList.init(self.allocator);
for (decl.params.toSlice()) |param| { for (decl.params.toSlice()) |param| {
@ -494,10 +496,10 @@ pub const Analyzer = struct {
try ctx.insertFn(decl, ret_type.?, parameters, scope); try ctx.insertFn(decl, ret_type.?, parameters, scope);
} else { } else {
if (ret_type != null) if (ret_type != null)
self.doError("Return type was not fully resolved", .{}); self.doError("Return type was not fully resolved");
if (parameters.len != decl.params.len) if (parameters.len != decl.params.len)
self.doError("Fully analyzed {} parameters, wanted {}", .{ parameters.len, decl.params.len }); self.doError("Fully analyzed {} parameters, wanted {}", parameters.len, decl.params.len);
return CompileError.TypeError; return CompileError.TypeError;
} }
@ -518,7 +520,7 @@ pub const Analyzer = struct {
.Struct => |struc| { .Struct => |struc| {
self.setErrToken(struc.name); self.setErrToken(struc.name);
self.setErrContext("struct {}", .{struc.name.lexeme}); self.setErrContext("struct {}", struc.name.lexeme);
var types = comp.TypeList.init(self.allocator); var types = comp.TypeList.init(self.allocator);
@ -541,7 +543,7 @@ pub const Analyzer = struct {
// TODO change enums to u32 // TODO change enums to u32
.Enum => |enu| { .Enum => |enu| {
self.setErrToken(enu.name); self.setErrToken(enu.name);
self.setErrContext("enum {}", .{enu.name.lexeme}); self.setErrContext("enum {}", enu.name.lexeme);
try ctx.insertEnum(enu); try ctx.insertEnum(enu);
}, },
@ -549,7 +551,7 @@ pub const Analyzer = struct {
.ConstDecl => |constlist| { .ConstDecl => |constlist| {
for (constlist.toSlice()) |constdecl| { for (constlist.toSlice()) |constdecl| {
self.setErrToken(constdecl.name); self.setErrToken(constdecl.name);
self.setErrContext("const {}", .{constdecl.name.lexeme}); self.setErrContext("const {}", constdecl.name.lexeme);
var expr_type = try self.resolveExprType(ctx, constdecl.expr); var expr_type = try self.resolveExprType(ctx, constdecl.expr);
try ctx.insertConst(constdecl, expr_type); try ctx.insertConst(constdecl, expr_type);
@ -557,7 +559,7 @@ pub const Analyzer = struct {
}, },
.Block => { .Block => {
self.doError("Block can't be found at root", .{}); self.doError("Block can't be found at root");
return CompileError.Invalid; return CompileError.Invalid;
}, },
} }

View file

@ -10,28 +10,28 @@ const warn = std.debug.warn;
fn printIdent(ident: usize) void { fn printIdent(ident: usize) void {
var i: usize = 0; var i: usize = 0;
while (i < ident) : (i += 1) { while (i < ident) : (i += 1) {
std.debug.warn("\t", .{}); std.debug.warn("\t");
} }
} }
fn print(ident: usize, comptime fmt: []const u8, args: var) void { fn print(ident: usize, comptime fmt: []const u8, args: ...) void {
printIdent(ident); printIdent(ident);
std.debug.warn(fmt, args); std.debug.warn(fmt, args);
} }
fn printBlock(ident: usize, block: var, endNewline: bool) void { fn printBlock(ident: usize, block: var, endNewline: bool) void {
std.debug.warn("(\n", .{}); std.debug.warn("(\n");
for (block.toSlice()) |stmt| { for (block.toSlice()) |stmt| {
printIdent(ident); printIdent(ident);
printStmt(ident, &stmt); printStmt(ident, &stmt);
std.debug.warn("\n", .{}); std.debug.warn("\n");
} }
if (endNewline) { if (endNewline) {
print(ident - 1, ")\n", .{}); print(ident - 1, ")\n");
} else { } else {
print(ident - 1, ")", .{}); print(ident - 1, ")");
} }
} }
@ -48,45 +48,49 @@ pub fn printNode(node: *const Node, ident: usize) void {
const vari = method.variable.lexeme; const vari = method.variable.lexeme;
const typ = method.typ.lexeme; const typ = method.typ.lexeme;
warn("(method {} {} {} {} (", .{ vari, typ, name, ret_type }); warn("(method {} {} {} {} (", vari, typ, name, ret_type);
} else { } else {
warn("(fn {} {} (", .{ name, ret_type }); warn("(fn {} {} (", name, ret_type);
} }
for (decl.params.toSlice()) |param| { for (decl.params.toSlice()) |param| {
warn(" ({} {})", .{ param.name.lexeme, param.typ.lexeme }); warn(" ({} {})", param.name.lexeme, param.typ.lexeme);
} }
warn(") ", .{}); warn(") ");
printBlock(ident + 1, decl.body, false); printBlock(ident + 1, decl.body, false);
warn("\n", .{}); warn("\n");
}, },
.ConstDecl => |consts| { .ConstDecl => |consts| {
print(ident, "(const (\n", .{}); print(ident, "(const (\n");
for (consts.toSlice()) |const_decl| { for (consts.toSlice()) |const_decl| {
print(ident + 1, "({} ", .{ print(
ident + 1,
"({} ",
const_decl.name.lexeme, const_decl.name.lexeme,
}); );
printExpr(const_decl.expr); printExpr(const_decl.expr);
std.debug.warn(")\n", .{}); std.debug.warn(")\n");
} }
print(ident, "))\n", .{}); print(ident, "))\n");
}, },
.Enum => |decl| { .Enum => |decl| {
print(ident, "(enum {} (\n", .{decl.name.lexeme}); print(ident, "(enum {} (\n", decl.name.lexeme);
for (decl.fields.toSlice()) |field| { for (decl.fields.toSlice()) |field| {
print(ident + 1, "{}\n", .{ print(
ident + 1,
"{}\n",
field.lexeme, field.lexeme,
}); );
} }
print(ident, "))\n", .{}); print(ident, "))\n");
}, },
.Root => { .Root => {
@ -96,34 +100,34 @@ pub fn printNode(node: *const Node, ident: usize) void {
}, },
.Struct => |struc| { .Struct => |struc| {
print(ident, "(struct {} (\n", .{struc.name.lexeme}); print(ident, "(struct {} (\n", struc.name.lexeme);
for (struc.fields.toSlice()) |field| { for (struc.fields.toSlice()) |field| {
print(ident + 1, "({} {})\n", .{ field.name.lexeme, field.typ.lexeme }); print(ident + 1, "({} {})\n", field.name.lexeme, field.typ.lexeme);
} }
print(ident, "))\n", .{}); print(ident, "))\n");
}, },
else => { else => {
print(ident, "unknown node: {}\n", .{node}); print(ident, "unknown node: {}\n", node);
}, },
} }
} }
fn parenthetize(name: []const u8, exprs: []const Expr) void { fn parenthetize(name: []const u8, exprs: []const Expr) void {
std.debug.warn("({}", .{name}); std.debug.warn("({}", name);
for (exprs) |expr| { for (exprs) |expr| {
std.debug.warn(" ", .{}); std.debug.warn(" ");
printExpr(&expr); printExpr(&expr);
} }
std.debug.warn(")", .{}); std.debug.warn(")");
} }
fn printTwoExprs(expr_a: *const Expr, expr_b: *const Expr) void { fn printTwoExprs(expr_a: *const Expr, expr_b: *const Expr) void {
std.debug.warn(" ", .{}); std.debug.warn(" ");
printExpr(expr_a); printExpr(expr_a);
std.debug.warn(" ", .{}); std.debug.warn(" ");
printExpr(expr_b); printExpr(expr_b);
} }
@ -157,9 +161,9 @@ fn binOpToStr(op: BinaryOperator) ?[]const u8 {
} }
fn printBinOp(inner: var) void { fn printBinOp(inner: var) void {
std.debug.warn("({}", .{binOpToStr(inner.op)}); std.debug.warn("({}", binOpToStr(inner.op));
printTwoExprs(inner.left, inner.right); printTwoExprs(inner.left, inner.right);
std.debug.warn(")", .{}); std.debug.warn(")");
} }
const unary_operator_tokens = [_][]const u8{ const unary_operator_tokens = [_][]const u8{
@ -183,9 +187,9 @@ fn printSingleOp(op: UnaryOperator, applied: *const Expr) void {
} }
fn printSimpleOp(op: ?[]const u8, applied: *const Expr) void { fn printSimpleOp(op: ?[]const u8, applied: *const Expr) void {
std.debug.warn("({}", .{op}); std.debug.warn("({}", op);
printExpr(applied); printExpr(applied);
std.debug.warn(")", .{}); std.debug.warn(")");
} }
pub fn printExpr(expr: *const Expr) void { pub fn printExpr(expr: *const Expr) void {
@ -197,66 +201,66 @@ pub fn printExpr(expr: *const Expr) void {
.Literal => |literal| { .Literal => |literal| {
switch (literal) { switch (literal) {
.Bool => |val| std.debug.warn("{}", .{val}), .Bool => |val| std.debug.warn("{}", val),
.Integer32 => |val| std.debug.warn("{}", .{val}), .Integer32 => |val| std.debug.warn("{}", val),
.Integer64 => |val| std.debug.warn("{}", .{val}), .Integer64 => |val| std.debug.warn("{}", val),
.Float => |val| std.debug.warn("{}", .{val}), .Float => |val| std.debug.warn("{}", val),
.String => |val| std.debug.warn("'{}'", .{val}), .String => |val| std.debug.warn("'{}'", val),
.Array => |exprs| { .Array => |exprs| {
parenthetize("array", exprs.toSlice()); parenthetize("array", exprs.toSlice());
}, },
else => |typ| std.debug.warn("UnknownLiteral-{}", .{typ}), else => |typ| std.debug.warn("UnknownLiteral-{}", typ),
} }
}, },
.Variable => |token| std.debug.warn("{}", .{token.lexeme}), .Variable => |token| std.debug.warn("{}", token.lexeme),
.Assign => |assign| { .Assign => |assign| {
std.debug.warn("(set ", .{}); std.debug.warn("(set ");
std.debug.warn("{} ", .{assign.name.lexeme}); std.debug.warn("{} ", assign.name.lexeme);
printExpr(assign.value); printExpr(assign.value);
std.debug.warn(")", .{}); std.debug.warn(")");
}, },
.Call => |call| { .Call => |call| {
std.debug.warn("(", .{}); std.debug.warn("(");
printExpr(call.callee); printExpr(call.callee);
for (call.arguments.toSlice()) |arg| { for (call.arguments.toSlice()) |arg| {
std.debug.warn(" ", .{}); std.debug.warn(" ");
printExpr(&arg); printExpr(&arg);
} }
std.debug.warn(")", .{}); std.debug.warn(")");
}, },
.Struct => |val| { .Struct => |val| {
std.debug.warn("({} (", .{val.name.lexeme}); std.debug.warn("({} (", val.name.lexeme);
for (val.inits.toSlice()) |init| { for (val.inits.toSlice()) |init| {
std.debug.warn(" ({} ", .{init.field.lexeme}); std.debug.warn(" ({} ", init.field.lexeme);
printExpr(init.expr); printExpr(init.expr);
std.debug.warn(")", .{}); std.debug.warn(")");
} }
std.debug.warn("))", .{}); std.debug.warn("))");
}, },
.Get => |get| { .Get => |get| {
warn("(", .{}); warn("(");
printExpr(get.target); printExpr(get.target);
warn(".{})", .{get.name.lexeme}); warn(".{})", get.name.lexeme);
}, },
.Set => |set| { .Set => |set| {
warn("(set ", .{}); warn("(set ");
printExpr(set.struc); printExpr(set.struc);
warn(" {} ", .{set.field.lexeme}); warn(" {} ", set.field.lexeme);
printExpr(set.value); printExpr(set.value);
warn(")", .{}); warn(")");
}, },
else => std.debug.warn("UnknownExpr-{}", .{@tagName(expr.*)}), else => std.debug.warn("UnknownExpr-{}", @tagName(expr.*)),
} }
} }
@ -266,67 +270,67 @@ pub fn printStmt(ident: usize, stmt: *const Stmt) void {
.Expr => |expr| printExpr(expr), .Expr => |expr| printExpr(expr),
.VarDecl => |decl| { .VarDecl => |decl| {
std.debug.warn("(let {} ", .{decl.name.lexeme}); std.debug.warn("(let {} ", decl.name.lexeme);
printExpr(decl.value); printExpr(decl.value);
std.debug.warn(")", .{}); std.debug.warn(")");
}, },
.If => |ifstmt| { .If => |ifstmt| {
std.debug.warn("(if ", .{}); std.debug.warn("(if ");
printExpr(ifstmt.condition); printExpr(ifstmt.condition);
std.debug.warn(" ", .{}); std.debug.warn(" ");
printBlock(ident + 1, ifstmt.then_branch, false); printBlock(ident + 1, ifstmt.then_branch, false);
if (ifstmt.else_branch) |else_branch| { if (ifstmt.else_branch) |else_branch| {
std.debug.warn(" else ", .{}); std.debug.warn(" else ");
printBlock(ident + 1, else_branch, false); printBlock(ident + 1, else_branch, false);
} }
std.debug.warn(")\n", .{}); std.debug.warn(")\n");
}, },
.Loop => |loop| { .Loop => |loop| {
std.debug.warn("(loop ", .{}); std.debug.warn("(loop ");
if (loop.condition) |cond| { if (loop.condition) |cond| {
printExpr(cond); printExpr(cond);
} else { } else {
std.debug.warn("true", .{}); std.debug.warn("true");
} }
std.debug.warn(" ", .{}); std.debug.warn(" ");
printBlock(ident + 1, loop.then_branch, false); printBlock(ident + 1, loop.then_branch, false);
std.debug.warn(")\n", .{}); std.debug.warn(")\n");
}, },
.For => |forstmt| { .For => |forstmt| {
std.debug.warn("(for ", .{}); std.debug.warn("(for ");
if (forstmt.index) |index| { if (forstmt.index) |index| {
std.debug.warn("({} {}) ", .{ index.lexeme, forstmt.value.lexeme }); std.debug.warn("({} {}) ", index.lexeme, forstmt.value.lexeme);
} else { } else {
std.debug.warn("{} ", .{forstmt.value.lexeme}); std.debug.warn("{} ", forstmt.value.lexeme);
} }
std.debug.warn("{} ", .{forstmt.array.lexeme}); std.debug.warn("{} ", forstmt.array.lexeme);
printBlock(ident + 1, forstmt.block, false); printBlock(ident + 1, forstmt.block, false);
std.debug.warn(")\n", .{}); std.debug.warn(")\n");
}, },
.Return => |ret| { .Return => |ret| {
std.debug.warn("(return ", .{}); std.debug.warn("(return ");
printExpr(ret.value); printExpr(ret.value);
std.debug.warn(")\n", .{}); std.debug.warn(")\n");
}, },
else => std.debug.warn("UnknownStmt-{}", .{@tagName(stmt.*)}), else => std.debug.warn("UnknownStmt-{}", @tagName(stmt.*)),
} }
} }
// very bad but be like that // very bad but be like that
fn retWithName(prefix: []const u8, inner: []const u8) []const u8 { fn retWithName(prefix: []const u8, inner: []const u8) []const u8 {
var ret_nam_buf = std.heap.page_allocator.alloc(u8, 256) catch unreachable; var ret_nam_buf = std.heap.direct_allocator.alloc(u8, 256) catch unreachable;
return std.fmt.bufPrint(ret_nam_buf[0..], "{}({})", .{ prefix, inner }) catch unreachable; return std.fmt.bufPrint(ret_nam_buf[0..], "{}({})", prefix, inner) catch unreachable;
} }
fn prettyType(typ: SymbolUnderlyingType) []const u8 { fn prettyType(typ: SymbolUnderlyingType) []const u8 {
@ -343,11 +347,11 @@ fn prettyType(typ: SymbolUnderlyingType) []const u8 {
} }
pub fn printScope(scope: *Scope, ident: usize) void { pub fn printScope(scope: *Scope, ident: usize) void {
print(ident, "scope '{}' at addr {}\n", .{ scope.id, @ptrToInt(scope) }); print(ident, "scope '{}' at addr {}\n", scope.id, @ptrToInt(scope));
var it = scope.env.iterator(); var it = scope.env.iterator();
while (it.next()) |kv| { while (it.next()) |kv| {
print(ident + 1, "sym: {}, typ: {}\n", .{ kv.key, prettyType(kv.value) }); print(ident + 1, "sym: {}, typ: {}\n", kv.key, prettyType(kv.value));
} }
for (scope.children.toSlice()) |child| { for (scope.children.toSlice()) |child| {
@ -361,56 +365,60 @@ pub fn printContext(ctx: CompilationContext) void {
while (it.next()) |kv| { while (it.next()) |kv| {
switch (kv.value.*) { switch (kv.value.*) {
.Function => |fn_sym| { .Function => |fn_sym| {
std.debug.warn("function {} returns {}\n", .{ std.debug.warn(
"function {} returns {}\n",
kv.key, kv.key,
prettyType(fn_sym.return_type), prettyType(fn_sym.return_type),
}); );
for (fn_sym.decl.params.toSlice()) |param| { for (fn_sym.decl.params.toSlice()) |param| {
var param_kv = fn_sym.parameters.get(param.name.lexeme).?; var param_kv = fn_sym.parameters.get(param.name.lexeme).?;
std.debug.warn("\tparameter {} typ {}\n", .{ std.debug.warn(
"\tparameter {} typ {}\n",
param_kv.key, param_kv.key,
prettyType(param_kv.value.typ), prettyType(param_kv.value.typ),
}); );
} }
// go through scopes // go through scopes
std.debug.warn("scope info:\n", .{}); std.debug.warn("scope info:\n");
printScope(fn_sym.scope, 1); printScope(fn_sym.scope, 1);
}, },
.Struct => |typemap| { .Struct => |typemap| {
std.debug.warn("struct '{}'\n", .{kv.key}); std.debug.warn("struct '{}'\n", kv.key);
var map_it = typemap.iterator(); var map_it = typemap.iterator();
while (map_it.next()) |map_kv| { while (map_it.next()) |map_kv| {
std.debug.warn("\tfield {} type {}\n", .{ std.debug.warn(
"\tfield {} type {}\n",
map_kv.key, map_kv.key,
prettyType(map_kv.value), prettyType(map_kv.value),
}); );
} }
}, },
.Variable => std.debug.warn("variable {} type {}\n", .{ .Variable => std.debug.warn(
"variable {} type {}\n",
kv.key, kv.key,
kv.value, kv.value,
}), ),
.Enum => |identmap| { .Enum => |identmap| {
std.debug.warn("enum {}:", .{kv.key}); std.debug.warn("enum {}:", kv.key);
var mapit = identmap.iterator(); var mapit = identmap.iterator();
while (mapit.next()) |field_kv| { while (mapit.next()) |field_kv| {
std.debug.warn("\t{} => {}\n", .{ field_kv.key, field_kv.value }); std.debug.warn("\t{} => {}\n", field_kv.key, field_kv.value);
} }
}, },
.Const => |typ| { .Const => |typ| {
std.debug.warn("const '{}', typ={}\n", .{ kv.key, prettyType(typ) }); std.debug.warn("const '{}', typ={}\n", kv.key, prettyType(typ));
}, },
else => { else => {
std.debug.warn("TODO handle print of {}\n", .{kv.value}); std.debug.warn("TODO handle print of {}\n", kv.value);
unreachable; unreachable;
}, },
} }

View file

@ -4,8 +4,9 @@ const llvm = @import("../llvm.zig");
const comp = @import("../comp_ctx.zig"); const comp = @import("../comp_ctx.zig");
const CompileError = @import("../codegen.zig").CompileError; const CompileError = @import("../codegen.zig").CompileError;
fn sliceify(non_slice: ?[*:0]const u8) []const u8 { fn sliceify(non_slice: ?[*]const u8) []const u8 {
return non_slice.?[0..std.mem.len(non_slice.?)]; if (non_slice == null) return "";
return non_slice.?[0..std.mem.len(u8, non_slice.?)];
} }
fn mkLLVMBool(val: bool) llvm.LLVMValueRef { fn mkLLVMBool(val: bool) llvm.LLVMValueRef {
@ -41,7 +42,7 @@ pub const Codegen = struct {
.Bool => llvm.LLVMInt1Type(), .Bool => llvm.LLVMInt1Type(),
.OpaqueType => |val| { .OpaqueType => |val| {
std.debug.warn("Invalid return type: {}\n", .{val}); std.debug.warn("Invalid return type: {}\n", val);
return CompileError.TypeError; return CompileError.TypeError;
}, },
@ -51,14 +52,14 @@ pub const Codegen = struct {
.Struct => unreachable, .Struct => unreachable,
.Enum => llvm.LLVMInt32Type(), .Enum => llvm.LLVMInt32Type(),
else => { else => {
std.debug.warn("Function {} is not a type\n", .{lex}); std.debug.warn("Function {} is not a type\n", lex);
return CompileError.TypeError; return CompileError.TypeError;
}, },
}; };
}, },
else => { else => {
std.debug.warn("TODO handle {}\n", .{typ}); std.debug.warn("TODO handle {}\n", typ);
return CompileError.TypeError; return CompileError.TypeError;
}, },
}; };
@ -71,17 +72,18 @@ pub const Codegen = struct {
.Enum => |map| { .Enum => |map| {
var val = map.get(get.name.lexeme); var val = map.get(get.name.lexeme);
if (val == null) { if (val == null) {
std.debug.warn("enum {} does not have field {}\n", .{ std.debug.warn(
"enum {} does not have field {}\n",
vari.lexeme, vari.lexeme,
get.name.lexeme, get.name.lexeme,
}); );
} }
return llvm.LLVMConstInt(llvm.LLVMInt32Type(), val.?.value, 1); return llvm.LLVMConstInt(llvm.LLVMInt32Type(), val.?.value, 1);
}, },
.Struct => @panic("TODO handle struct"), .Struct => @panic("TODO handle struct"),
else => { else => {
std.debug.warn("Invalid get target: {}\n", .{@as(comp.SymbolType, sym.*)}); std.debug.warn("Invalid get target: {}\n", @as(comp.SymbolType, sym.*));
return CompileError.EmitError; return CompileError.EmitError;
}, },
} }
@ -124,8 +126,8 @@ pub const Codegen = struct {
var right = try self.emitExpr(builder, unary.right); var right = try self.emitExpr(builder, unary.right);
return switch (unary.op) { return switch (unary.op) {
.Negate => llvm.LLVMBuildNeg(builder, right, "neg_tmp"), .Negate => llvm.LLVMBuildNeg(builder, right, c"neg_tmp"),
.Not => llvm.LLVMBuildNot(builder, right, "neg_tmp"), .Not => llvm.LLVMBuildNot(builder, right, c"neg_tmp"),
}; };
}, },
@ -134,16 +136,16 @@ pub const Codegen = struct {
var right = try self.emitExpr(builder, binary.right); var right = try self.emitExpr(builder, binary.right);
return switch (binary.op) { return switch (binary.op) {
.Add => llvm.LLVMBuildAdd(builder, left, right, "addtmp"), .Add => llvm.LLVMBuildAdd(builder, left, right, c"addtmp"),
.Sub => llvm.LLVMBuildSub(builder, left, right, "subtmp"), .Sub => llvm.LLVMBuildSub(builder, left, right, c"subtmp"),
.Mul => llvm.LLVMBuildMul(builder, left, right, "multmp"), .Mul => llvm.LLVMBuildMul(builder, left, right, c"multmp"),
//.Div => llvm.LLVMBuildDiv(builder, left, right, "divtmp"), //.Div => llvm.LLVMBuildDiv(builder, left, right, c"divtmp"),
.And => llvm.LLVMBuildAnd(builder, left, right, "andtmp"), .And => llvm.LLVMBuildAnd(builder, left, right, c"andtmp"),
.Or => llvm.LLVMBuildOr(builder, left, right, "ortmp"), .Or => llvm.LLVMBuildOr(builder, left, right, c"ortmp"),
else => { else => {
std.debug.warn("Unexpected binary operator: '{}'\n", .{binary.op}); std.debug.warn("Unexpected binary operator: '{}'\n", binary.op);
return CompileError.EmitError; return CompileError.EmitError;
}, },
}; };
@ -167,7 +169,7 @@ pub const Codegen = struct {
}, },
else => { else => {
std.debug.warn("Invalid get target: {}\n", .{@as(ast.ExprType, target)}); std.debug.warn("Invalid get target: {}\n", @as(ast.ExprType, target));
return CompileError.EmitError; return CompileError.EmitError;
}, },
} }
@ -178,7 +180,7 @@ pub const Codegen = struct {
var llvm_func = self.llvm_table.get(name); var llvm_func = self.llvm_table.get(name);
if (llvm_func == null) { if (llvm_func == null) {
std.debug.warn("Function '{}' not found\n", .{name}); std.debug.warn("Function '{}' not found\n", name);
return CompileError.EmitError; return CompileError.EmitError;
} }
@ -197,7 +199,7 @@ pub const Codegen = struct {
llvm_func.?.value, llvm_func.?.value,
args_slice.ptr, args_slice.ptr,
@intCast(c_uint, args_slice.len), @intCast(c_uint, args_slice.len),
"call", c"call",
); );
}, },
@ -217,7 +219,7 @@ pub const Codegen = struct {
var kv_opt = self.ctx.current_scope.?.meta_map.get(vari.lexeme); var kv_opt = self.ctx.current_scope.?.meta_map.get(vari.lexeme);
if (kv_opt == null) { if (kv_opt == null) {
std.debug.warn("variable {} not fully analyzed\n", .{vari.lexeme}); std.debug.warn("variable {} not fully analyzed\n", vari.lexeme);
return CompileError.EmitError; return CompileError.EmitError;
} }
@ -225,12 +227,12 @@ pub const Codegen = struct {
// is coming from the scope or from the function // is coming from the scope or from the function
var metadata = kv_opt.?.value; var metadata = kv_opt.?.value;
std.debug.warn("!! LOAD FROM VAR META {}\n", .{@ptrToInt(metadata)}); std.debug.warn("!! LOAD FROM VAR META {}\n", @ptrToInt(metadata));
var buf = try self.allocator.alloc(u8, 512); var buf = try self.allocator.alloc(u8, 512);
errdefer self.allocator.free(buf); errdefer self.allocator.free(buf);
var load_str = try std.fmt.bufPrint(buf, "{}_loaded", .{vari.lexeme}); var load_str = try std.fmt.bufPrint(buf, "{}_loaded", vari.lexeme);
var load_cstr = try std.cstr.addNullByte(self.allocator, load_str); var load_cstr = try std.cstr.addNullByte(self.allocator, load_str);
errdefer self.allocator.free(load_cstr); errdefer self.allocator.free(load_cstr);
@ -254,14 +256,14 @@ pub const Codegen = struct {
}, },
else => { else => {
std.debug.warn("Got unexpected expr {}\n", .{@as(ast.ExprType, expr.*)}); std.debug.warn("Got unexpected expr {}\n", @as(ast.ExprType, expr.*));
return CompileError.EmitError; return CompileError.EmitError;
}, },
}; };
} }
fn emitStmt(self: *Codegen, builder: var, stmt: *ast.Stmt) anyerror!void { fn emitStmt(self: *Codegen, builder: var, stmt: *ast.Stmt) anyerror!void {
std.debug.warn("cgen: emitting stmt {}\n", .{@as(ast.StmtType, stmt.*)}); std.debug.warn("cgen: emitting stmt {}\n", @as(ast.StmtType, stmt.*));
switch (stmt.*) { switch (stmt.*) {
.Expr => |expr| _ = try self.emitExpr(builder, expr), .Expr => |expr| _ = try self.emitExpr(builder, expr),
@ -274,14 +276,14 @@ pub const Codegen = struct {
.If => |ifstmt| { .If => |ifstmt| {
var cond = try self.emitExpr(builder, ifstmt.condition); var cond = try self.emitExpr(builder, ifstmt.condition);
var zero = mkLLVMBool(false); var zero = mkLLVMBool(false);
var icmp = llvm.LLVMBuildICmp(builder, llvm.LLVMIntPredicate.LLVMIntNE, cond, zero, "ifcond"); var icmp = llvm.LLVMBuildICmp(builder, llvm.LLVMIntPredicate.LLVMIntNE, cond, zero, c"ifcond");
var insert = llvm.LLVMGetInsertBlock(builder); var insert = llvm.LLVMGetInsertBlock(builder);
var function = llvm.LLVMGetBasicBlockParent(insert); var function = llvm.LLVMGetBasicBlockParent(insert);
var then_bb = llvm.LLVMAppendBasicBlock(function, "then"); var then_bb = llvm.LLVMAppendBasicBlock(function, c"then");
var else_bb = llvm.LLVMAppendBasicBlock(function, "else"); var else_bb = llvm.LLVMAppendBasicBlock(function, c"else");
var merge_bb = llvm.LLVMAppendBasicBlock(function, "ifcont"); var merge_bb = llvm.LLVMAppendBasicBlock(function, c"ifcont");
var condbr = llvm.LLVMBuildCondBr(builder, icmp, then_bb, else_bb); var condbr = llvm.LLVMBuildCondBr(builder, icmp, then_bb, else_bb);
@ -378,14 +380,14 @@ pub const Codegen = struct {
var_metadata.*.llvm_alloca = variable; var_metadata.*.llvm_alloca = variable;
std.debug.warn("!! DECL VAR {} => {}\n", .{ @ptrToInt(var_metadata), variable }); std.debug.warn("!! DECL VAR {} => {}\n", @ptrToInt(var_metadata), variable);
var llvm_expr = try self.emitExpr(builder, vardecl.value); var llvm_expr = try self.emitExpr(builder, vardecl.value);
_ = llvm.LLVMBuildStore(builder, llvm_expr, variable); _ = llvm.LLVMBuildStore(builder, llvm_expr, variable);
}, },
else => { else => {
std.debug.warn("Got unexpected stmt {}\n", .{stmt.*}); std.debug.warn("Got unexpected stmt {}\n", stmt.*);
return CompileError.EmitError; return CompileError.EmitError;
}, },
} }
@ -408,7 +410,7 @@ pub const Codegen = struct {
.FnDecl => |decl| { .FnDecl => |decl| {
const name = decl.func_name.lexeme; const name = decl.func_name.lexeme;
self.current_function_name = name; self.current_function_name = name;
std.debug.warn("cgen: genning function '{}'\n", .{name}); std.debug.warn("cgen: genning function '{}'\n", name);
var fn_sym = self.getFnSymbol(name); var fn_sym = self.getFnSymbol(name);
@ -435,7 +437,7 @@ pub const Codegen = struct {
_ = try self.llvm_table.put(name, func); _ = try self.llvm_table.put(name, func);
var buf = try self.allocator.alloc(u8, 512); var buf = try self.allocator.alloc(u8, 512);
var entry_lbl = try std.fmt.bufPrint(buf, "fn_{}_entry", .{name}); var entry_lbl = try std.fmt.bufPrint(buf, "fn_{}_entry", name);
var entry_lbl_cstr = try std.cstr.addNullByte(self.allocator, entry_lbl); var entry_lbl_cstr = try std.cstr.addNullByte(self.allocator, entry_lbl);
var entry = llvm.LLVMAppendBasicBlock(func, entry_lbl_cstr.ptr); var entry = llvm.LLVMAppendBasicBlock(func, entry_lbl_cstr.ptr);
@ -453,7 +455,7 @@ pub const Codegen = struct {
var alloca = llvm.LLVMBuildAlloca(builder, try self.typeToLLVM(param.typ), param_name_cstr.ptr); var alloca = llvm.LLVMBuildAlloca(builder, try self.typeToLLVM(param.typ), param_name_cstr.ptr);
std.debug.warn("SET PARAM LLVM ALLOCA {} to {}\n", .{ param_node.name.lexeme, alloca }); std.debug.warn("SET PARAM LLVM ALLOCA {} to {}\n", param_node.name.lexeme, alloca);
param.llvm_alloca = alloca; param.llvm_alloca = alloca;
_ = llvm.LLVMBuildStore( _ = llvm.LLVMBuildStore(
@ -473,7 +475,7 @@ pub const Codegen = struct {
} }
self.ctx.dumpScope(); self.ctx.dumpScope();
std.debug.warn("cgen: generated function '{}'\n", .{name}); std.debug.warn("cgen: generated function '{}'\n", name);
}, },
// NOTE: enums don't have specific llvm ir code generated for them // NOTE: enums don't have specific llvm ir code generated for them
@ -502,17 +504,17 @@ pub const Codegen = struct {
}, },
else => { else => {
std.debug.warn("TODO handle node type {}\n", .{@tagName(node.*)}); std.debug.warn("TODO handle node type {}\n", @tagName(node.*));
return; return;
}, },
} }
} }
pub fn gen(self: *Codegen, root: *ast.Node) !void { pub fn gen(self: *Codegen, root: *ast.Node) !void {
std.debug.warn("cgen: start gen\n", .{}); std.debug.warn("cgen: start gen\n");
_ = llvm.LLVMInitializeNativeTarget(); _ = llvm.LLVMInitializeNativeTarget();
var mod = llvm.LLVMModuleCreateWithName("awoo").?; var mod = llvm.LLVMModuleCreateWithName(c"awoo").?;
defer llvm.LLVMDisposeModule(mod); defer llvm.LLVMDisposeModule(mod);
var root_slice = root.Root.toSlice(); var root_slice = root.Root.toSlice();
@ -520,20 +522,20 @@ pub const Codegen = struct {
try self.genNode(mod, &root_slice[idx]); try self.genNode(mod, &root_slice[idx]);
} }
var err: ?[*:0]u8 = null; var err: ?[*]u8 = null;
defer llvm.LLVMDisposeMessage(err); defer llvm.LLVMDisposeMessage(err);
if (llvm.LLVMPrintModuleToFile(mod, "output.ll", &err) != 0) { if (llvm.LLVMPrintModuleToFile(mod, c"output.ll", &err) != 0) {
std.debug.warn("error printing module to file: {}\n", .{sliceify(err)}); std.debug.warn("error printing module to file: {}\n", sliceify(err));
return CompileError.BackendError; return CompileError.BackendError;
} }
//if (llvm.LLVMWriteBitcodeToFile(mod, "awoo.bc") != 0) { //if (llvm.LLVMWriteBitcodeToFile(mod, c"awoo.bc") != 0) {
// std.debug.warn("error writing bitcode to file: {}\n" , .{ sliceify(err) }); // std.debug.warn("error writing bitcode to file: {}\n", sliceify(err));
// return CompileError.BackendError; // return CompileError.BackendError;
//} //}
std.debug.warn("cgen: verify llvm module\n", .{}); std.debug.warn("cgen: verify llvm module\n");
_ = llvm.LLVMVerifyModule( _ = llvm.LLVMVerifyModule(
mod, mod,
llvm.LLVMVerifierFailureAction.LLVMAbortProcessAction, llvm.LLVMVerifierFailureAction.LLVMAbortProcessAction,
@ -548,7 +550,7 @@ pub const Codegen = struct {
var engine: llvm.LLVMExecutionEngineRef = undefined; var engine: llvm.LLVMExecutionEngineRef = undefined;
if (llvm.LLVMCreateExecutionEngineForModule(&engine, mod, &err) != 0) { if (llvm.LLVMCreateExecutionEngineForModule(&engine, mod, &err) != 0) {
std.debug.warn("failed to create execution engine: {}\n", .{sliceify(err)}); std.debug.warn("failed to create execution engine: {}\n", sliceify(err));
return CompileError.BackendError; return CompileError.BackendError;
} }
@ -568,9 +570,9 @@ pub const Codegen = struct {
var features = llvm.LLVMGetTargetMachineFeatureString(machine); var features = llvm.LLVMGetTargetMachineFeatureString(machine);
var triple = llvm.LLVMGetTargetMachineTriple(machine); var triple = llvm.LLVMGetTargetMachineTriple(machine);
std.debug.warn("target: {}\n", .{sliceify(desc)}); std.debug.warn("target: {}\n", sliceify(desc));
std.debug.warn("triple: {}\n", .{sliceify(triple)}); std.debug.warn("triple: {}\n", sliceify(triple));
std.debug.warn("features: {}\n", .{sliceify(features)}); std.debug.warn("features: {}\n", sliceify(features));
//if (llvm.LLVMTargetMachineEmitToFile( //if (llvm.LLVMTargetMachineEmitToFile(
// machine, // machine,
@ -579,7 +581,7 @@ pub const Codegen = struct {
// llvm.LLVMCodeGenFileType.LLVMAssemblyFile, // llvm.LLVMCodeGenFileType.LLVMAssemblyFile,
// &err, // &err,
//) != 0) { //) != 0) {
// std.debug.warn("failed to emit to assembly file: {}\n" , .{ sliceify(err) }); // std.debug.warn("failed to emit to assembly file: {}\n", sliceify(err));
// return CompileError.BackendError; // return CompileError.BackendError;
//} //}
@ -590,7 +592,7 @@ pub const Codegen = struct {
llvm.LLVMCodeGenFileType.LLVMObjectFile, llvm.LLVMCodeGenFileType.LLVMObjectFile,
&err, &err,
) != 0) { ) != 0) {
std.debug.warn("failed to emit to file: {}\n", .{sliceify(err)}); std.debug.warn("failed to emit to file: {}\n", sliceify(err));
return CompileError.BackendError; return CompileError.BackendError;
} }
} }

View file

@ -158,7 +158,7 @@ pub const VariableMetadata = struct {
typ: SymbolUnderlyingType, typ: SymbolUnderlyingType,
) !*VariableMetadata { ) !*VariableMetadata {
var meta = try allocator.create(VariableMetadata); var meta = try allocator.create(VariableMetadata);
std.debug.warn("VARMETA create from scope={}, meta={}\n", .{ @ptrToInt(scope), @ptrToInt(meta) }); std.debug.warn("VARMETA create from scope={}, meta={}\n", @ptrToInt(scope), @ptrToInt(meta));
meta.* = VariableMetadata{ .typ = typ, .from_scope = scope, .using = .Scope }; meta.* = VariableMetadata{ .typ = typ, .from_scope = scope, .using = .Scope };
return meta; return meta;
} }
@ -169,7 +169,7 @@ pub const VariableMetadata = struct {
typ: SymbolUnderlyingType, typ: SymbolUnderlyingType,
) !*VariableMetadata { ) !*VariableMetadata {
var meta = try allocator.create(VariableMetadata); var meta = try allocator.create(VariableMetadata);
std.debug.warn("VARMETA create from fndecl={}, meta={}\n", .{ @ptrToInt(func), @ptrToInt(meta) }); std.debug.warn("VARMETA create from fndecl={}, meta={}\n", @ptrToInt(func), @ptrToInt(meta));
meta.* = VariableMetadata{ .typ = typ, .from_function = func, .using = .Function }; meta.* = VariableMetadata{ .typ = typ, .from_function = func, .using = .Function };
return meta; return meta;
} }
@ -204,7 +204,7 @@ pub const CompilationContext = struct {
@panic("can't bump scope from null"); @panic("can't bump scope from null");
} }
std.debug.warn("==scope bump== '{}'\n", .{scope_id}); std.debug.warn("==scope bump== '{}'\n", scope_id);
var child = try self.current_scope.?.createChild(scope_id); var child = try self.current_scope.?.createChild(scope_id);
self.current_scope = child; self.current_scope = child;
@ -212,7 +212,7 @@ pub const CompilationContext = struct {
/// Set a given scope as the current scope. /// Set a given scope as the current scope.
pub fn setScope(self: *@This(), scope: *Scope) void { pub fn setScope(self: *@This(), scope: *Scope) void {
std.debug.warn("==set== set scope to {}\n", .{scope.id}); std.debug.warn("==set== set scope to {}\n", scope.id);
self.current_scope = scope; self.current_scope = scope;
} }
@ -224,10 +224,11 @@ pub const CompilationContext = struct {
const parent_id: ?[]const u8 = if (self.current_scope.?.parent == null) null else self.current_scope.?.parent.?.id; const parent_id: ?[]const u8 = if (self.current_scope.?.parent == null) null else self.current_scope.?.parent.?.id;
std.debug.warn("==scope dump== {} to {}\n", .{ std.debug.warn(
"==scope dump== {} to {}\n",
self.current_scope.?.id, self.current_scope.?.id,
parent_id, parent_id,
}); );
self.current_scope = self.current_scope.?.parent; self.current_scope = self.current_scope.?.parent;
} }
@ -348,7 +349,7 @@ pub const CompilationContext = struct {
) !*SymbolData { ) !*SymbolData {
var sym_kv = self.symbol_table.get(identifier); var sym_kv = self.symbol_table.get(identifier);
if (sym_kv == null) { if (sym_kv == null) {
std.debug.warn("Unknown {} '{}'\n", .{ typ, identifier }); std.debug.warn("Unknown {} '{}'\n", typ, identifier);
return CompilationError.TypeError; return CompilationError.TypeError;
} }
@ -356,7 +357,7 @@ pub const CompilationContext = struct {
var sym_typ = @as(SymbolType, value.*); var sym_typ = @as(SymbolType, value.*);
if (sym_typ != typ) { if (sym_typ != typ) {
std.debug.warn("Expected {}, got {}\n", .{ sym_typ, typ }); std.debug.warn("Expected {}, got {}\n", sym_typ, typ);
return CompilationError.TypeError; return CompilationError.TypeError;
} }
@ -416,7 +417,7 @@ pub const CompilationContext = struct {
} }
} }
std.debug.warn("Unknown name {}\n", .{name}); std.debug.warn("Unknown name {}\n", name);
return CompilationError.UnknownName; return CompilationError.UnknownName;
} }

View file

@ -2,9 +2,9 @@ const std = @import("std");
pub fn report(line: usize, where: []const u8, ctx_opt: ?[]const u8, message: []const u8) void { pub fn report(line: usize, where: []const u8, ctx_opt: ?[]const u8, message: []const u8) void {
if (ctx_opt) |ctx| { if (ctx_opt) |ctx| {
std.debug.warn("[line {}] Error{} on {}: {}", .{ line, where, ctx, message }); std.debug.warn("[line {}] Error{} on {}: {}", line, where, ctx, message);
} else { } else {
std.debug.warn("[line {}] Error{}: {}", .{ line, where, message }); std.debug.warn("[line {}] Error{}: {}", line, where, message);
} }
} }
@ -12,13 +12,13 @@ pub fn reportN(line: usize, message: []const u8) void {
report(line, "", message); report(line, "", message);
} }
pub fn reportFmt(line: usize, ctx_opt: ?[]const u8, comptime fmt: []const u8, args: var) void { pub fn reportFmt(line: usize, ctx_opt: ?[]const u8, comptime fmt: []const u8, args: ...) void {
if (ctx_opt) |ctx| { if (ctx_opt) |ctx| {
std.debug.warn("[line {}] Error on {}", .{ line, ctx }); std.debug.warn("[line {}] Error on {}", line, ctx);
} else { } else {
std.debug.warn("[line {}] Error", .{line}); std.debug.warn("[line {}] Error", line);
} }
std.debug.warn(fmt, args); std.debug.warn(fmt, args);
std.debug.warn("\n", .{}); std.debug.warn("\n");
} }

View file

@ -19,10 +19,11 @@ pub fn run(allocator: *std.mem.Allocator, slice: []const u8) !Result {
// do a full scan pass, then reset, then do it again (with parser) // do a full scan pass, then reset, then do it again (with parser)
while (true) { while (true) {
var tok_opt = scan.nextToken() catch |err| { var tok_opt = scan.nextToken() catch |err| {
std.debug.warn("error at '{}': {}\n", .{ std.debug.warn(
"error at '{}': {}\n",
scan.currentLexeme(), scan.currentLexeme(),
err, err,
}); );
return Result.TokenizeError; return Result.TokenizeError;
}; };
@ -31,7 +32,7 @@ pub fn run(allocator: *std.mem.Allocator, slice: []const u8) !Result {
if (tok.typ == .EOF) break; if (tok.typ == .EOF) break;
// TODO remove // TODO remove
std.debug.warn("{x}\n", .{tok}); std.debug.warn("{x}\n", tok);
} }
} }
@ -46,20 +47,20 @@ pub fn run(allocator: *std.mem.Allocator, slice: []const u8) !Result {
var root = root_opt.?; var root = root_opt.?;
std.debug.warn("parse tree\n", .{}); std.debug.warn("parse tree\n");
printer.printNode(root, 0); printer.printNode(root, 0);
var solver = try analysis.Analyzer.init(allocator); var solver = try analysis.Analyzer.init(allocator);
var ctx = try solver.pass(root); var ctx = try solver.pass(root);
std.debug.warn("symbol table\n", .{}); std.debug.warn("symbol table\n");
printer.printContext(ctx); printer.printContext(ctx);
var cgen = codegen.llvm.Codegen.init(allocator, &ctx); var cgen = codegen.llvm.Codegen.init(allocator, &ctx);
try cgen.gen(root); try cgen.gen(root);
var child = try std.ChildProcess.init( var child = try std.ChildProcess.init(
&[_][]const u8{ "gcc", "src/entry.c", "outpath.o", "-o", "a.out" }, [_][]const u8{ "gcc", "src/entry.c", "outpath.o", "-o", "a.out" },
allocator, allocator,
); );
try child.spawn(); try child.spawn();
@ -69,13 +70,13 @@ pub fn run(allocator: *std.mem.Allocator, slice: []const u8) !Result {
} }
pub fn main() anyerror!void { pub fn main() anyerror!void {
const allocator = std.heap.page_allocator; const allocator = std.heap.direct_allocator;
var args_it = std.process.args(); var args_it = std.process.args();
_ = args_it.skip(); _ = args_it.skip();
const filepath = try (args_it.next(allocator) orelse @panic("expected file path")); const filepath = try (args_it.next(allocator) orelse @panic("expected file path"));
var file = try std.fs.cwd().openFile(filepath, .{}); var file = try std.fs.File.openRead(filepath);
defer file.close(); defer file.close();
const total_bytes = try file.getEndPos(); const total_bytes = try file.getEndPos();
@ -93,7 +94,7 @@ pub fn main() anyerror!void {
.ParseError, .ParseError,
.CompileError, .CompileError,
=> { => {
std.debug.warn("error: {}\n", .{result}); std.debug.warn("error: {}\n", result);
std.os.exit(1); std.os.exit(1);
}, },
} }

View file

@ -94,7 +94,7 @@ pub const Parser = struct {
self.tokens.deinit(); self.tokens.deinit();
} }
fn setErrContext(self: *Parser, comptime fmt: ?[]const u8, args: var) void { fn setErrContext(self: *Parser, comptime fmt: ?[]const u8, args: ...) void {
if (fmt == null) { if (fmt == null) {
self.err_ctx = null; self.err_ctx = null;
return; return;
@ -104,18 +104,18 @@ pub const Parser = struct {
self.err_ctx = std.fmt.bufPrint(buf, fmt.?, args) catch unreachable; self.err_ctx = std.fmt.bufPrint(buf, fmt.?, args) catch unreachable;
} }
fn doError(self: *Parser, comptime fmt: []const u8, args: var) ParseError { fn doError(self: *Parser, comptime fmt: []const u8, args: ...) ParseError {
self.hadError = true; self.hadError = true;
std.debug.warn("parser error at line {}", .{self.scanner.line}); std.debug.warn("parser error at line {}", self.scanner.line);
if (self.err_ctx) |ctx| { if (self.err_ctx) |ctx| {
std.debug.warn(" on {}", .{ctx}); std.debug.warn(" on {}", ctx);
} }
std.debug.warn("\n\t", .{}); std.debug.warn("\n\t");
std.debug.warn(fmt, args); std.debug.warn(fmt, args);
std.debug.warn("\n", .{}); std.debug.warn("\n");
return ParseError.CompileError; return ParseError.CompileError;
} }
@ -146,14 +146,11 @@ pub const Parser = struct {
} }
fn tokenError(self: *Parser, token: Token, msg: []const u8) ParseError { fn tokenError(self: *Parser, token: Token, msg: []const u8) ParseError {
std.debug.warn("ctx: '{}'\n", .{self.err_ctx}); std.debug.warn("ctx: '{}'\n", self.err_ctx);
if (token.typ == .EOF) { if (token.typ == .EOF) {
ereport.report(token.line, " at end", self.err_ctx, msg); ereport.report(token.line, " at end", self.err_ctx, msg);
} else { } else {
ereport.reportFmt(token.line, self.err_ctx, " at '{}': {}", .{ ereport.reportFmt(token.line, self.err_ctx, " at '{}': {}", token.lexeme, msg);
token.lexeme,
msg,
});
} }
return ParseError.CompileError; return ParseError.CompileError;
@ -180,7 +177,7 @@ pub const Parser = struct {
} }
try self.tokens.append(token); try self.tokens.append(token);
std.debug.warn("skip to {}\n", .{token}); std.debug.warn("skip to {}\n", token);
return token; return token;
} }
@ -206,10 +203,12 @@ pub const Parser = struct {
// TODO maybe this could be entirely comptime? // TODO maybe this could be entirely comptime?
var buf_main: [1000]u8 = undefined; var buf_main: [1000]u8 = undefined;
var buf = try std.fmt.bufPrint(&buf_main, "expected {}, got {}", .{ var buf = try std.fmt.bufPrint(
buf_main[0..],
"expected {}, got {}",
ttype, ttype,
self.peek().typ, self.peek().typ,
}); );
return self.tokenError(self.peek(), buf); return self.tokenError(self.peek(), buf);
} }
@ -467,7 +466,7 @@ pub const Parser = struct {
break :blk orig_name; break :blk orig_name;
}; };
self.setErrContext("function {}", .{name.lexeme}); self.setErrContext("function {}", name.lexeme);
_ = try self.consumeSingle(.LeftParen); _ = try self.consumeSingle(.LeftParen);
@ -530,14 +529,14 @@ pub const Parser = struct {
var consts = ast.ConstList.init(self.allocator); var consts = ast.ConstList.init(self.allocator);
errdefer consts.deinit(); errdefer consts.deinit();
self.setErrContext("const", .{}); self.setErrContext("const");
_ = try self.consumeSingle(.Const); _ = try self.consumeSingle(.Const);
_ = try self.consumeSingle(.LeftParen); _ = try self.consumeSingle(.LeftParen);
while (self.peek().typ != .RightParen) { while (self.peek().typ != .RightParen) {
const const_name = try self.consumeSingle(.Identifier); const const_name = try self.consumeSingle(.Identifier);
self.setErrContext("const {}", .{const_name}); self.setErrContext("const {}", const_name);
_ = try self.consumeSingle(.Equal); _ = try self.consumeSingle(.Equal);
@ -559,18 +558,18 @@ pub const Parser = struct {
fn parseStructDecl(self: *@This()) !*Node { fn parseStructDecl(self: *@This()) !*Node {
var fields = ast.FieldList.init(self.allocator); var fields = ast.FieldList.init(self.allocator);
errdefer fields.deinit(); errdefer fields.deinit();
self.setErrContext("struct", .{}); self.setErrContext("struct");
_ = try self.consumeSingle(.Struct); _ = try self.consumeSingle(.Struct);
var name = try self.consumeSingle(.Identifier); var name = try self.consumeSingle(.Identifier);
self.setErrContext("struct {}", .{name}); self.setErrContext("struct {}", name);
_ = try self.consumeSingle(.LeftBrace); _ = try self.consumeSingle(.LeftBrace);
while (!self.check(.RightBrace)) { while (!self.check(.RightBrace)) {
const field_name = try self.consumeSingle(.Identifier); const field_name = try self.consumeSingle(.Identifier);
self.setErrContext("struct {} field {}", .{ name, field_name }); self.setErrContext("struct {} field {}", name, field_name);
const field_type = try self.consumeSingle(.Identifier); const field_type = try self.consumeSingle(.Identifier);
try fields.append(ast.StructField{ try fields.append(ast.StructField{
@ -588,12 +587,12 @@ pub const Parser = struct {
var fields = ast.TokenList.init(self.allocator); var fields = ast.TokenList.init(self.allocator);
errdefer fields.deinit(); errdefer fields.deinit();
self.setErrContext("enum", .{}); self.setErrContext("enum");
_ = try self.consumeSingle(.Enum); _ = try self.consumeSingle(.Enum);
const name = try self.consumeSingle(.Identifier); const name = try self.consumeSingle(.Identifier);
self.setErrContext("enum {}", .{name}); self.setErrContext("enum {}", name);
_ = try self.consumeSingle(.LeftBrace); _ = try self.consumeSingle(.LeftBrace);
@ -607,7 +606,7 @@ pub const Parser = struct {
} }
fn parseTopDecl(self: *@This()) !*Node { fn parseTopDecl(self: *@This()) !*Node {
self.setErrContext(null, .{}); self.setErrContext(null);
return switch (self.peek().typ) { return switch (self.peek().typ) {
.Fn => try self.parseFnDecl(), .Fn => try self.parseFnDecl(),
@ -616,7 +615,7 @@ pub const Parser = struct {
.Enum => try self.parseEnumDecl(), .Enum => try self.parseEnumDecl(),
else => |typ| blk: { else => |typ| blk: {
return self.doError("expected Fn, Const, Struct, got {}\n", .{typ}); return self.doError("expected Fn, Const, Struct, got {}\n", typ);
}, },
}; };
} }
@ -838,7 +837,7 @@ pub const Parser = struct {
switch (op_tok.typ) { switch (op_tok.typ) {
// TODO remove .ColonEqual from language // TODO remove .ColonEqual from language
.ColonEqual => { .ColonEqual => {
return self.doError("can not initialize struct field", .{}); return self.doError("can not initialize struct field");
}, },
.Equal => return try self.mkSet(get.target, get.name, value), .Equal => return try self.mkSet(get.target, get.name, value),
@ -856,7 +855,7 @@ pub const Parser = struct {
}, },
else => |expr_typ| { else => |expr_typ| {
return self.doError("Invalid assignment target {}", .{expr_typ}); return self.doError("Invalid assignment target {}", expr_typ);
}, },
} }
} }
@ -1029,7 +1028,7 @@ pub const Parser = struct {
// for this to work properly, <expr> must be Variable, since its a type. // for this to work properly, <expr> must be Variable, since its a type.
const expr_type = @as(ast.ExprType, expr.*); const expr_type = @as(ast.ExprType, expr.*);
if (expr_type != .Variable) { if (expr_type != .Variable) {
return self.doError("Expected variable for struct type, got {}", .{expr_type}); return self.doError("Expected variable for struct type, got {}", expr_type);
} }
var inits = ast.StructInitList.init(self.allocator); var inits = ast.StructInitList.init(self.allocator);
@ -1066,10 +1065,11 @@ pub const Parser = struct {
// parseInt(i64) on the catch block of parseInt(i32) // parseInt(i64) on the catch block of parseInt(i32)
var i32_num_opt: ?i32 = std.fmt.parseInt(i32, lexeme, 10) catch null; var i32_num_opt: ?i32 = std.fmt.parseInt(i32, lexeme, 10) catch null;
var i64_num: i64 = std.fmt.parseInt(i64, lexeme, 10) catch |err| { var i64_num: i64 = std.fmt.parseInt(i64, lexeme, 10) catch |err| {
return self.doError("Invalid integer (not 32bit or 64bit) '{}': {}", .{ return self.doError(
"Invalid integer (not 32bit or 64bit) '{}': {}",
lexeme, lexeme,
err, err,
}); );
}; };
if (i32_num_opt) |i32_num| { if (i32_num_opt) |i32_num| {
@ -1124,7 +1124,7 @@ pub const Parser = struct {
}, },
else => blk: { else => blk: {
return self.doError("expected literal, got {}", .{curtype}); return self.doError("expected literal, got {}", curtype);
}, },
}; };