refactor: use null to signal unmatch in parser
This commit is contained in:
parent
3671c221a9
commit
6a194d4065
@ -3,7 +3,6 @@ const lexic = @import("lexic");
|
||||
const errors = @import("errors");
|
||||
const Token = lexic.Token;
|
||||
const TokenType = lexic.TokenType;
|
||||
const ParseError = @import("./types.zig").ParseError;
|
||||
|
||||
pub const Expression = union(enum) {
|
||||
number: *const Token,
|
||||
|
@ -13,7 +13,7 @@ const ParseError = types.ParseError;
|
||||
const TokenStream = types.TokenStream;
|
||||
|
||||
pub const Module = struct {
|
||||
statements: std.ArrayList(*statement.Statement),
|
||||
statements: std.ArrayList(statement.Statement),
|
||||
alloc: std.mem.Allocator,
|
||||
|
||||
/// Parses a module.
|
||||
@ -29,11 +29,10 @@ pub const Module = struct {
|
||||
allocator: std.mem.Allocator,
|
||||
err_arrl: *std.ArrayList(errors.ErrorData),
|
||||
) ParseError!void {
|
||||
var arrl = std.ArrayList(*statement.Statement).init(allocator);
|
||||
var arrl = std.ArrayList(statement.Statement).init(allocator);
|
||||
errdefer arrl.deinit();
|
||||
errdefer for (arrl.items) |i| {
|
||||
i.deinit();
|
||||
allocator.destroy(i);
|
||||
};
|
||||
|
||||
const input_len = tokens.items.len;
|
||||
@ -41,30 +40,27 @@ pub const Module = struct {
|
||||
|
||||
// parse many statements
|
||||
while (current_pos < input_len) {
|
||||
var stmt = try allocator.create(statement.Statement);
|
||||
errdefer allocator.destroy(stmt);
|
||||
var stmt: statement.Statement = undefined;
|
||||
|
||||
const next_pos = stmt.init(tokens, current_pos, allocator) catch |e| {
|
||||
switch (e) {
|
||||
error.Unmatched => {
|
||||
// create the error value
|
||||
var error_target: errors.ErrorData = undefined;
|
||||
try error_target.init(
|
||||
"No statement found",
|
||||
// TODO: handle other errors of vardef parsing
|
||||
const next_pos = try stmt.init(tokens, current_pos, allocator);
|
||||
if (next_pos) |next_pos_actual| {
|
||||
current_pos = next_pos_actual;
|
||||
|
||||
try arrl.append(stmt);
|
||||
continue;
|
||||
}
|
||||
|
||||
// nothing matched, but there are tokens. this in an error
|
||||
var err: errors.ErrorData = undefined;
|
||||
try err.init(
|
||||
"No statement matched",
|
||||
current_pos,
|
||||
current_pos + 1,
|
||||
allocator,
|
||||
);
|
||||
defer error_target.deinit();
|
||||
try err_arrl.append(error_target);
|
||||
return error.Unmatched;
|
||||
},
|
||||
else => return e,
|
||||
}
|
||||
};
|
||||
current_pos = next_pos;
|
||||
|
||||
try arrl.append(stmt);
|
||||
try err_arrl.append(err);
|
||||
return error.Error;
|
||||
}
|
||||
|
||||
target.* = .{
|
||||
@ -76,7 +72,6 @@ pub const Module = struct {
|
||||
pub fn deinit(self: @This()) void {
|
||||
for (self.statements.items) |stmt| {
|
||||
stmt.deinit();
|
||||
self.alloc.destroy(stmt);
|
||||
}
|
||||
self.statements.deinit();
|
||||
}
|
||||
|
@ -21,14 +21,13 @@ pub const Statement = struct {
|
||||
tokens: *const TokenStream,
|
||||
pos: usize,
|
||||
allocator: std.mem.Allocator,
|
||||
) ParseError!usize {
|
||||
) ParseError!?usize {
|
||||
// try to parse a variable definition
|
||||
|
||||
var vardef = allocator.create(variable.VariableBinding) catch {
|
||||
return ParseError.OutOfMemory;
|
||||
};
|
||||
var vardef = try allocator.create(variable.VariableBinding);
|
||||
errdefer allocator.destroy(vardef);
|
||||
|
||||
// TODO: handle other errors of vardef parsing
|
||||
if (try vardef.init(tokens, pos, allocator)) |vardef_end| {
|
||||
// variable definition parsed
|
||||
// return the parsed variable definition
|
||||
@ -38,10 +37,10 @@ pub const Statement = struct {
|
||||
};
|
||||
return vardef_end;
|
||||
}
|
||||
// TODO: handle other errors of vardef parsing
|
||||
|
||||
// fail
|
||||
return ParseError.Unmatched;
|
||||
// manually deallocate
|
||||
allocator.destroy(vardef);
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn deinit(self: @This()) void {
|
||||
@ -81,15 +80,11 @@ test "should fail on other constructs" {
|
||||
defer tokens.deinit();
|
||||
|
||||
var statement: Statement = undefined;
|
||||
_ = statement.init(&tokens, 0, std.testing.allocator) catch |e| switch (e) {
|
||||
error.Unmatched => {
|
||||
const result = try statement.init(&tokens, 0, std.testing.allocator);
|
||||
if (result == null) {
|
||||
// good path
|
||||
return;
|
||||
},
|
||||
else => {
|
||||
try std.testing.expect(false);
|
||||
return;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
try std.testing.expect(false);
|
||||
}
|
||||
|
@ -3,9 +3,6 @@ const lexic = @import("lexic");
|
||||
|
||||
/// Respresents a failure of parsing.
|
||||
pub const ParseError = error{
|
||||
/// The parse operation failed, but it is recoverable.
|
||||
/// Other parsers should be considered.
|
||||
Unmatched,
|
||||
/// The parse operation parsed after a point of no return.
|
||||
/// For example, a `var` keyword was found, but then no identifier
|
||||
/// The parsing should stop
|
||||
|
Loading…
Reference in New Issue
Block a user