Skip to content

Commit

Permalink
Simplify error coollector API.
Browse files Browse the repository at this point in the history
  • Loading branch information
wmedrano committed Sep 11, 2024
1 parent 45dfd0e commit 0a20002
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 77 deletions.
4 changes: 2 additions & 2 deletions src/Ast.zig
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ fn initImpl(allocator: std.mem.Allocator, errors: *ErrorCollector, t: *Tokenizer
},
.closeParen => {
if (!want_close) {
try errors.addError(.{ .msg = "Unmatched close parenthesis" });
try errors.addError("Unmatched close parenthesis", .{});
return SyntaxError.UnmatchedCloseParenthesis;
}
has_close = true;
Expand All @@ -87,7 +87,7 @@ fn initImpl(allocator: std.mem.Allocator, errors: *ErrorCollector, t: *Tokenizer
}
}
if (want_close and !has_close) {
try errors.addError(.{ .msg = "Unclosed parenthesis" });
try errors.addError("Unclosed parenthesis", .{});
return SyntaxError.UnclosedParenthesis;
}
return try result.toOwnedSlice();
Expand Down
37 changes: 11 additions & 26 deletions src/Vm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,10 @@ pub fn toZig(self: *Vm, T: type, alloc: std.mem.Allocator, val: Val) !T {
errdefer toZigClean(field.type, alloc, field_zig_val, null);
@field(ret, field.name) = field_zig_val;
} else {
const msg: []const u8 = std.fmt.allocPrint(
self.env.errors.allocator(),
try self.env.errors.addError(
"field {s} not found in Fizz struct",
.{fizz_field_name},
) catch return Error.OutOfMemory;
try self.env.errors.addErrorOwned(.{ .msg = msg });
);
return Error.TypeError;
}
}
Expand Down Expand Up @@ -412,7 +410,7 @@ fn executeGetArg(self: *Vm, frame: *const Env.Frame, idx: usize) !void {

fn executeMove(self: *Vm, frame: *const Env.Frame, idx: usize) !void {
const v = self.env.stack.popOrNull() orelse {
try self.env.errors.addError(.{ .msg = "unexpected code branch reached, file a GitHub issue" });
try self.env.errors.addError("unexpected code branch reached, file a GitHub issue", .{});
return error.RuntimeError;
};
self.env.stack.items[frame.stack_start + idx] = v;
Expand All @@ -430,12 +428,10 @@ fn executeEval(self: *Vm, frame: *const Env.Frame, n: usize) !void {
switch (func) {
.bytecode => |bc| {
if (bc.arg_count != arg_count) {
const msg = try std.fmt.allocPrint(
self.env.errors.allocator(),
try self.env.errors.addError(
"Function {s} received {d} arguments but expected {d}",
.{ bc.name, arg_count, bc.arg_count },
);
try self.env.errors.addErrorOwned(.{ .msg = msg });
return error.ArrityError;
}
try self.env.stack.appendNTimes(self.valAllocator(), .none, bc.locals_count);
Expand All @@ -452,12 +448,10 @@ fn executeEval(self: *Vm, frame: *const Env.Frame, n: usize) !void {
self.env.stack.items = self.env.stack.items[0..stack_start];
},
else => {
const msg = try std.fmt.allocPrint(
self.env.errors.allocator(),
try self.env.errors.addError(
"Expected to evaluate value of type function but got {any}",
.{func.tag()},
);
try self.env.errors.addErrorOwned(.{ .msg = msg });
return error.TypeError;
},
}
Expand All @@ -481,24 +475,20 @@ fn executeDefine(self: *Vm, module: *Module, symbol_id: Symbol) Error!void {

fn executeImportModule(self: *Vm, module: *Module, module_path: []const u8) Error!void {
errdefer {
self.env.errors.addError(ErrorCollector.Error{ .msg = "failed to import module" }) catch {};
self.env.errors.addError("failed to import module", .{}) catch {};
}
const base_dir = module.directory() catch {
const msg = try std.fmt.allocPrint(
self.env.errors.allocator(),
try self.env.errors.addError(
"could not determine working directory for module {s}",
.{module.name},
);
try self.env.errors.addErrorOwned(.{ .msg = msg });
return Error.FileError;
};
const full_path = base_dir.realpathAlloc(self.valAllocator(), module_path) catch {
const msg = try std.fmt.allocPrint(
self.env.errors.allocator(),
try self.env.errors.addError(
"could not determine path for {s}",
.{module_path},
);
try self.env.errors.addErrorOwned(.{ .msg = msg });
return Error.FileError;
};
defer self.valAllocator().free(full_path);
Expand All @@ -512,12 +502,10 @@ fn executeImportModule(self: *Vm, module: *Module, module_path: []const u8) Erro
defer arena.deinit();
const file_size_limit = 64 * 1024 * 1024;
const contents = std.fs.cwd().readFileAlloc(arena.allocator(), full_path, file_size_limit) catch {
const msg = try std.fmt.allocPrint(
self.env.errors.allocator(),
try self.env.errors.addError(
"could not read file {any}",
.{full_path},
);
try self.env.errors.addErrorOwned(.{ .msg = msg });
return Error.FileError;
};
const ast = Ast.initWithStr(arena.allocator(), &self.env.errors, contents) catch return Error.SyntaxError;
Expand All @@ -535,19 +523,16 @@ fn executeImportModule(self: *Vm, module: *Module, module_path: []const u8) Erro
fn errSymbolNotFound(self: *Vm, module: *const Module, sym: Symbol) Error {
@setCold(true);
const name = self.env.memory_manager.symbols.getName(sym) orelse "*unknown-symbol*";
const msg = try std.fmt.allocPrint(
self.env.errors.allocator(),
try self.env.errors.addError(
"Symbol {s} (id={d}) not found in module {s}",
.{ name, sym.id, module.name },
);
try self.env.errors.addErrorOwned(.{ .msg = msg });
return Error.SymbolNotFound;
}

fn errModuleNotFound(self: *Vm, module_name: []const u8) Error {
@setCold(true);
const msg = try std.fmt.allocPrint(self.env.errors.allocator(), "Module {s} not found", .{module_name});
try self.env.errors.addErrorOwned(.{ .msg = msg });
try self.env.errors.addError("Module {s} not found", .{module_name});
return Error.SymbolNotFound;
}

Expand Down
31 changes: 7 additions & 24 deletions src/datastructures/ErrorCollector.zig
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
const ErrorCollector = @This();
const std = @import("std");

errors: std.ArrayList(Error),

pub const Error = union(enum) {
msg: []const u8,

pub fn format(self: *const Error, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
try writer.print("{s}\n", .{self.msg});
}
};
errors: std.ArrayList([]const u8),

pub fn init(alloc: std.mem.Allocator) ErrorCollector {
@setCold(true);
return .{
.errors = std.ArrayList(Error).init(alloc),
.errors = std.ArrayList([]const u8).init(alloc),
};
}

Expand All @@ -31,25 +23,16 @@ pub fn allocator(self: *ErrorCollector) std.mem.Allocator {

pub fn clear(self: *ErrorCollector) void {
@setCold(true);
for (self.errors.items) |err| {
switch (err) {
.msg => |msg| self.errors.allocator.free(msg),
}
for (self.errors.items) |msg| {
self.errors.allocator.free(msg);
}
self.errors.clearRetainingCapacity();
}

pub fn addError(self: *ErrorCollector, err: Error) !void {
@setCold(true);
const err_copy = Error{
.msg = try self.errors.allocator.dupe(u8, err.msg),
};
try self.addErrorOwned(err_copy);
}

pub fn addErrorOwned(self: *ErrorCollector, err: Error) !void {
pub fn addError(self: *ErrorCollector, comptime fmt: []const u8, args: anytype) !void {
@setCold(true);
try self.errors.append(err);
const msg = try std.fmt.allocPrint(self.allocator(), fmt, args);
try self.errors.append(msg);
}

pub fn format(self: *const ErrorCollector, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
Expand Down
45 changes: 20 additions & 25 deletions src/ir.zig
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ const IrBuilder = struct {
.leaf => return self.buildLeaf(&ast.leaf),
.tree => |asts| {
if (asts.len == 0) {
try self.errors.addError(.{ .msg = "Got 0 expressions but expected at least 1." });
try self.errors.addError("Got 0 expressions but expected at least 1.", .{});
return Error.SyntaxError;
}
const first = &asts[0];
Expand All @@ -231,36 +231,36 @@ const IrBuilder = struct {
.if_expr => {
switch (rest.len) {
0 | 1 => {
try self.errors.addError(.{ .msg = "If expression expected at least 1 arg" });
try self.errors.addError("If expression expected at least 1 arg", .{});
return Error.SyntaxError;
},
2 => return self.buildIfExpression(&rest[0], &rest[1], null),
3 => return self.buildIfExpression(&rest[0], &rest[1], &rest[2]),
else => {
try self.errors.addError(.{ .msg = "If expression expected at most 3 args" });
try self.errors.addError("If expression expected at most 3 args", .{});
return Error.SyntaxError;
},
}
},
.lambda => {
if (rest.len < 2) {
try self.errors.addError(.{ .msg = "lambda expected form (lambda (<args>...) <exprs>...)" });
try self.errors.addError("lambda expected form (lambda (<args>...) <exprs>...)", .{});
return Error.SyntaxError;
}
return self.buildLambdaExpr(name, &rest[0], rest[1..]);
},
.define => {
switch (rest.len) {
0 | 1 => {
try self.errors.addError(.{ .msg = "define expected form (define <ident> <expr>)" });
try self.errors.addError("define expected form (define <ident> <expr>)", .{});
return Error.SyntaxError;
},
else => return self.buildDefine(&rest[0], rest[1..]),
}
},
.import => {
if (rest.len != 1) {
try self.errors.addError(.{ .msg = "import expected form (import \"<path>\")" });
try self.errors.addError("import expected form (import \"<path>\")", .{});
return Error.SyntaxError;
}
return self.buildImportModule(&rest[0]);
Expand All @@ -283,7 +283,7 @@ const IrBuilder = struct {
fn buildLeaf(self: *IrBuilder, leaf: *const Ast.Node.Leaf) Error!*Ir {
const v = switch (leaf.*) {
.keyword => {
try self.errors.addError(.{ .msg = "found unexpected keyword" });
try self.errors.addError("found unexpected keyword", .{});
return Error.SyntaxError;
},
.identifier => |ident| if (ident.len != 0 and ident[0] == 39)
Expand Down Expand Up @@ -318,7 +318,7 @@ const IrBuilder = struct {
.leaf => |l| switch (l) {
.identifier => |ident| ident,
else => {
try self.errors.addError(.{ .msg = "define expected form (define <ident> <expr>) but <ident> was malformed" });
try self.errors.addError("define expected form (define <ident> <expr>) but <ident> was malformed", .{});
return Error.SyntaxError;
},
},
Expand All @@ -340,9 +340,10 @@ const IrBuilder = struct {

fn buildDefineLambda(self: *IrBuilder, name_and_args: []const Ast.Node, exprs: []const Ast.Node) Error!*Ir {
if (name_and_args.len == 0) {
try self.errors.addError(.{
.msg = "define expected form (define (<ident> <args>...) <expr>) but <ident> was not found",
});
try self.errors.addError(
"define expected form (define (<ident> <args>...) <expr>) but <ident> was not found",
.{},
);
return Error.SyntaxError;
}
const name = switch (name_and_args[0]) {
Expand Down Expand Up @@ -382,15 +383,17 @@ const IrBuilder = struct {
const path = switch (path_expr.*) {
.tree => {
try self.errors.addError(
.{ .msg = "import expected form (import \"<path>\") but path was malformed" },
"import expected form (import \"<path>\") but path was malformed",
.{},
);
return Error.SyntaxError;
},
.leaf => |l| switch (l) {
.string => |ident| ident,
else => {
try self.errors.addError(
.{ .msg = "import expected form (import \"<path>\") but path was malformed" },
"import expected form (import \"<path>\") but path was malformed",
.{},
);
return Error.SyntaxError;
},
Expand Down Expand Up @@ -449,9 +452,7 @@ const IrBuilder = struct {
/// Build an Ir containing a lambda definition.
fn buildLambdaExpr(self: *IrBuilder, name: []const u8, arguments: *const Ast.Node, body: []const Ast.Node) Error!*Ir {
if (body.len == 0) {
try self.errors.addError(
.{ .msg = "lambda expected form (lambda (<args>...) <exprs>...) but found 0 exprs" },
);
try self.errors.addError("lambda expected form (lambda (<args>...) <exprs>...) but found 0 exprs", .{});
return Error.SyntaxError;
}
var lambda_builder = IrBuilder{
Expand All @@ -462,26 +463,20 @@ const IrBuilder = struct {
defer lambda_builder.deinit();
switch (arguments.*) {
.leaf => {
try self.errors.addError(.{
.msg = "lambda expected form (lambda (<args>...) <exprs>...) but found args were not enclosed in parenthesis",
});
try self.errors.addError("lambda expected form (lambda (<args>...) <exprs>...) but found args were not enclosed in parenthesis", .{});
return Error.SyntaxError;
},
.tree => |t| {
for (0.., t) |arg_idx, arg_name_ast| {
switch (arg_name_ast) {
.tree => {
try self.errors.addError(.{
.msg = "lambda expected form (lambda (<args>...) <exprs>...) but found args were not valid identifiers",
});
try self.errors.addError("lambda expected form (lambda (<args>...) <exprs>...) but found args were not valid identifiers", .{});
return Error.SyntaxError;
},
.leaf => |l| switch (l) {
.identifier => |ident| try lambda_builder.arg_to_idx.put(self.allocator, ident, arg_idx),
else => {
try self.errors.addError(.{
.msg = "lambda expected form (lambda (<args>...) <exprs>...) but found args were not valid identifiers",
});
try self.errors.addError("lambda expected form (lambda (<args>...) <exprs>...) but found args were not valid identifiers", .{});
return Error.SyntaxError;
},
},
Expand Down

0 comments on commit 0a20002

Please sign in to comment.