refactor: return null on utils match fail

This commit is contained in:
Fernando Araoz 2025-01-27 19:43:25 -05:00
parent 1a3bdc7592
commit 5f75392d6b
3 changed files with 34 additions and 23 deletions

View File

@ -16,7 +16,12 @@ pub const Statement = struct {
},
/// Parses a Statement and return the position of the next token
pub fn init(target: *Statement, tokens: *const TokenStream, pos: usize, allocator: std.mem.Allocator) ParseError!usize {
pub fn init(
target: *Statement,
tokens: *const TokenStream,
pos: usize,
allocator: std.mem.Allocator,
) ParseError!usize {
// try to parse a variable definition
var vardef = allocator.create(variable.VariableBinding) catch {
@ -34,13 +39,15 @@ pub const Statement = struct {
return err;
},
};
if (!parse_failed) {
// return the parsed variable definition
target.* = .{
.alloc = allocator,
.value = .{ .variableBinding = vardef },
};
return vardef_end;
if (vardef_end) |v| {
if (!parse_failed) {
// return the parsed variable definition
target.* = .{
.alloc = allocator,
.value = .{ .variableBinding = vardef },
};
return v;
}
}
// fail

View File

@ -4,18 +4,18 @@ const lexic = @import("lexic");
/// Expects that the given token `t` has type `value`.
/// If it fails returns `error.Unmatched`, otherwise
/// returns the same token passed (`t`)
pub inline fn expect_token_type(comptime value: lexic.TokenType, t: *lexic.Token) error{Unmatched}!*lexic.Token {
pub inline fn expect_token_type(comptime value: lexic.TokenType, t: *lexic.Token) ?*lexic.Token {
if (t.token_type == value) {
return t;
} else {
return error.Unmatched;
return null;
}
}
pub inline fn expect_operator(comptime value: []const u8, t: *lexic.Token) error{Unmatched}!*lexic.Token {
pub inline fn expect_operator(comptime value: []const u8, t: *lexic.Token) ?*lexic.Token {
if (t.token_type == lexic.TokenType.Operator and std.mem.eql(u8, value, t.value)) {
return t;
} else {
return error.Unmatched;
return null;
}
}

View File

@ -16,11 +16,18 @@ pub const VariableBinding = struct {
alloc: std.mem.Allocator,
/// Parses a variable binding and returns the position of the next token
pub fn init(target: *VariableBinding, tokens: *const TokenStream, pos: usize, allocator: std.mem.Allocator) ParseError!usize {
pub fn init(
target: *VariableBinding,
tokens: *const TokenStream,
pos: usize,
allocator: std.mem.Allocator,
) ParseError!?usize {
std.debug.assert(pos < tokens.items.len);
// try to parse a var keyword
const var_keyword = try utils.expect_token_type(lexic.TokenType.K_Var, &tokens.items[pos]);
const var_keyword = if (utils.expect_token_type(lexic.TokenType.K_Var, &tokens.items[pos])) |t| t else {
return null;
};
_ = var_keyword;
// check there is still input
@ -30,13 +37,13 @@ pub const VariableBinding = struct {
}
// try to parse an identifier
const identifier = utils.expect_token_type(lexic.TokenType.Identifier, &tokens.items[pos + 1]) catch {
const identifier = if (utils.expect_token_type(lexic.TokenType.Identifier, &tokens.items[pos + 1])) |i| i else {
return ParseError.Error;
};
// parse equal sign
if (pos + 2 >= tokens.items.len) return ParseError.Error;
const equal_sign = utils.expect_operator("=", &tokens.items[pos + 2]) catch {
const equal_sign = if (utils.expect_operator("=", &tokens.items[pos + 2])) |x| x else {
return ParseError.Error;
};
_ = equal_sign;
@ -92,7 +99,7 @@ test "should parse a minimal var" {
}
}
test "should fail is it doesnt start with var" {
test "should return null if stream doesnt start with var" {
const input = "different_token_stream()";
var error_list = std.ArrayList(errors.ErrorData).init(std.testing.allocator);
defer error_list.deinit();
@ -100,12 +107,9 @@ test "should fail is it doesnt start with var" {
defer tokens.deinit();
var binding: VariableBinding = undefined;
_ = binding.init(&tokens, 0, std.testing.allocator) catch |err| {
try std.testing.expectEqual(ParseError.Unmatched, err);
return;
};
try std.testing.expect(false);
if (try binding.init(&tokens, 0, std.testing.allocator)) |_| {
try std.testing.expect(false);
}
}
test "should fail if the identifier is missing" {