feat: minimal error handling
This commit is contained in:
parent
fb30e1195e
commit
75002582ba
16
build.zig
16
build.zig
@ -22,6 +22,16 @@ pub fn build(b: *std.Build) void {
|
|||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//
|
||||||
|
// Error handling module
|
||||||
|
//
|
||||||
|
const error_module = b.addModule("errors", .{
|
||||||
|
.root_source_file = b.path("src/errors/root.zig"),
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
exe.root_module.addImport("errors", error_module);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Lexic module
|
// Lexic module
|
||||||
//
|
//
|
||||||
@ -31,6 +41,7 @@ pub fn build(b: *std.Build) void {
|
|||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
exe.root_module.addImport("lexic", lexic_module);
|
exe.root_module.addImport("lexic", lexic_module);
|
||||||
|
lexic_module.addImport("errors", error_module);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Syntax module
|
// Syntax module
|
||||||
@ -40,8 +51,9 @@ pub fn build(b: *std.Build) void {
|
|||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
syntax_module.addImport("lexic", lexic_module);
|
|
||||||
exe.root_module.addImport("syntax", syntax_module);
|
exe.root_module.addImport("syntax", syntax_module);
|
||||||
|
syntax_module.addImport("lexic", lexic_module);
|
||||||
|
syntax_module.addImport("errors", error_module);
|
||||||
|
|
||||||
// This declares intent for the executable to be installed into the
|
// This declares intent for the executable to be installed into the
|
||||||
// standard location when the user invokes the "install" step (the default
|
// standard location when the user invokes the "install" step (the default
|
||||||
@ -80,6 +92,7 @@ pub fn build(b: *std.Build) void {
|
|||||||
});
|
});
|
||||||
exe_unit_tests.root_module.addImport("lexic", lexic_module);
|
exe_unit_tests.root_module.addImport("lexic", lexic_module);
|
||||||
exe_unit_tests.root_module.addImport("syntax", syntax_module);
|
exe_unit_tests.root_module.addImport("syntax", syntax_module);
|
||||||
|
exe_unit_tests.root_module.addImport("errors", error_module);
|
||||||
|
|
||||||
const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
|
const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
|
||||||
|
|
||||||
@ -102,6 +115,7 @@ pub fn build(b: *std.Build) void {
|
|||||||
});
|
});
|
||||||
file_unit_test.root_module.addImport("lexic", lexic_module);
|
file_unit_test.root_module.addImport("lexic", lexic_module);
|
||||||
file_unit_test.root_module.addImport("syntax", syntax_module);
|
file_unit_test.root_module.addImport("syntax", syntax_module);
|
||||||
|
file_unit_test.root_module.addImport("errors", error_module);
|
||||||
|
|
||||||
var test_artifact = b.addRunArtifact(file_unit_test);
|
var test_artifact = b.addRunArtifact(file_unit_test);
|
||||||
test_step.dependOn(&test_artifact.step);
|
test_step.dependOn(&test_artifact.step);
|
||||||
|
@ -100,7 +100,6 @@ pub fn tokenize(input: []const u8, alloc: std.mem.Allocator) !std.ArrayList(Toke
|
|||||||
// TODO: check if this is a good error recovery strategy
|
// TODO: check if this is a good error recovery strategy
|
||||||
else {
|
else {
|
||||||
// no lexer matched
|
// no lexer matched
|
||||||
std.debug.print("unmatched args: anytype:c\n", .{});
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const lexic = @import("lexic");
|
const lexic = @import("lexic");
|
||||||
|
const errors = @import("errors");
|
||||||
|
|
||||||
const expression = @import("./expression.zig");
|
const expression = @import("./expression.zig");
|
||||||
const variable = @import("./variable.zig");
|
const variable = @import("./variable.zig");
|
||||||
const types = @import("./types.zig");
|
const types = @import("./types.zig");
|
||||||
@ -14,7 +16,19 @@ pub const Module = struct {
|
|||||||
statements: std.ArrayList(*statement.Statement),
|
statements: std.ArrayList(*statement.Statement),
|
||||||
alloc: std.mem.Allocator,
|
alloc: std.mem.Allocator,
|
||||||
|
|
||||||
pub fn init(target: *@This(), tokens: *const TokenStream, pos: usize, allocator: std.mem.Allocator) ParseError!void {
|
/// Parses a module.
|
||||||
|
///
|
||||||
|
/// If this function fails an error will be returned, and additionally the out parameter
|
||||||
|
/// `error_target` will be populated. If the error returned is OOM, nothing will be there.
|
||||||
|
/// In that case, the caller is responsible for calling the error `deinit` method,
|
||||||
|
/// which will clean it.
|
||||||
|
pub fn init(
|
||||||
|
target: *@This(),
|
||||||
|
tokens: *const TokenStream,
|
||||||
|
pos: usize,
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
error_target: *errors.ErrorData,
|
||||||
|
) ParseError!void {
|
||||||
var arrl = std.ArrayList(*statement.Statement).init(allocator);
|
var arrl = std.ArrayList(*statement.Statement).init(allocator);
|
||||||
errdefer arrl.deinit();
|
errdefer arrl.deinit();
|
||||||
errdefer for (arrl.items) |i| {
|
errdefer for (arrl.items) |i| {
|
||||||
@ -30,7 +44,20 @@ pub const Module = struct {
|
|||||||
var stmt = try allocator.create(statement.Statement);
|
var stmt = try allocator.create(statement.Statement);
|
||||||
errdefer allocator.destroy(stmt);
|
errdefer allocator.destroy(stmt);
|
||||||
|
|
||||||
const next_pos = try stmt.init(tokens, current_pos, allocator);
|
const next_pos = stmt.init(tokens, current_pos, allocator) catch |e| {
|
||||||
|
switch (e) {
|
||||||
|
error.Unmatched => {
|
||||||
|
// create the error value
|
||||||
|
try error_target.init(
|
||||||
|
"No statement found",
|
||||||
|
current_pos,
|
||||||
|
current_pos + 1,
|
||||||
|
);
|
||||||
|
return error.Unmatched;
|
||||||
|
},
|
||||||
|
else => return e,
|
||||||
|
}
|
||||||
|
};
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
try arrl.append(stmt);
|
try arrl.append(stmt);
|
||||||
@ -60,8 +87,11 @@ test "should parse a single statement" {
|
|||||||
const tokens = try lexic.tokenize(input, std.testing.allocator);
|
const tokens = try lexic.tokenize(input, std.testing.allocator);
|
||||||
defer tokens.deinit();
|
defer tokens.deinit();
|
||||||
|
|
||||||
|
const error_target = try std.testing.allocator.create(errors.ErrorData);
|
||||||
|
defer std.testing.allocator.destroy(error_target);
|
||||||
|
|
||||||
var module: Module = undefined;
|
var module: Module = undefined;
|
||||||
_ = try module.init(&tokens, 0, std.testing.allocator);
|
_ = try module.init(&tokens, 0, std.testing.allocator, error_target);
|
||||||
|
|
||||||
defer module.deinit();
|
defer module.deinit();
|
||||||
}
|
}
|
||||||
@ -71,8 +101,11 @@ test "should clean memory if a statement parsing fails after one item has been i
|
|||||||
const tokens = try lexic.tokenize(input, std.testing.allocator);
|
const tokens = try lexic.tokenize(input, std.testing.allocator);
|
||||||
defer tokens.deinit();
|
defer tokens.deinit();
|
||||||
|
|
||||||
|
const error_target = try std.testing.allocator.create(errors.ErrorData);
|
||||||
|
defer std.testing.allocator.destroy(error_target);
|
||||||
|
|
||||||
var module: Module = undefined;
|
var module: Module = undefined;
|
||||||
_ = module.init(&tokens, 0, std.testing.allocator) catch {
|
_ = module.init(&tokens, 0, std.testing.allocator, error_target) catch {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
defer module.deinit();
|
defer module.deinit();
|
||||||
|
34
src/errors/root.zig
Normal file
34
src/errors/root.zig
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub const ErrorData = struct {
|
||||||
|
reason: []const u8,
|
||||||
|
start_position: usize,
|
||||||
|
end_position: usize,
|
||||||
|
|
||||||
|
pub fn init(
|
||||||
|
target: *@This(),
|
||||||
|
reason: []const u8,
|
||||||
|
start_position: usize,
|
||||||
|
end_position: usize,
|
||||||
|
) !void {
|
||||||
|
target.* = .{
|
||||||
|
.reason = reason,
|
||||||
|
.start_position = start_position,
|
||||||
|
.end_position = end_position,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print(self: *@This()) void {
|
||||||
|
std.debug.print("Error: {s}\n", .{self.reason});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// When called, this struct will clean its resources and then
|
||||||
|
/// clean itself.
|
||||||
|
pub fn deinit(self: *@This()) void {
|
||||||
|
_ = self;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
test {
|
||||||
|
std.testing.refAllDecls(@This());
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user