refactor: generate simple error on variable parse

This commit is contained in:
Fernando Araoz 2025-01-27 21:45:57 -05:00
parent 6a194d4065
commit 7c95e669a4
2 changed files with 30 additions and 10 deletions

View File

@ -28,7 +28,7 @@ pub const Statement = struct {
errdefer allocator.destroy(vardef); errdefer allocator.destroy(vardef);
// TODO: handle other errors of vardef parsing // TODO: handle other errors of vardef parsing
if (try vardef.init(tokens, pos, allocator)) |vardef_end| { if (try vardef.init(tokens, pos, undefined, allocator)) |vardef_end| {
// variable definition parsed // variable definition parsed
// return the parsed variable definition // return the parsed variable definition
target.* = .{ target.* = .{

View File

@ -20,6 +20,7 @@ pub const VariableBinding = struct {
target: *VariableBinding, target: *VariableBinding,
tokens: *const TokenStream, tokens: *const TokenStream,
pos: usize, pos: usize,
err: *errors.ErrorData,
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
) ParseError!?usize { ) ParseError!?usize {
std.debug.assert(pos < tokens.items.len); std.debug.assert(pos < tokens.items.len);
@ -28,12 +29,22 @@ pub const VariableBinding = struct {
const var_keyword = if (utils.expect_token_type(lexic.TokenType.K_Var, &tokens.items[pos])) |t| t else { const var_keyword = if (utils.expect_token_type(lexic.TokenType.K_Var, &tokens.items[pos])) |t| t else {
return null; return null;
}; };
_ = var_keyword;
// check there is still input // check there is still input
if (pos + 1 >= tokens.items.len) { if (pos + 1 >= tokens.items.len) {
// return error // return error
// TODO: populate error information try err.init(
"Incomplete variable declaration",
var_keyword.start_pos,
var_keyword.start_pos + var_keyword.value.len,
allocator,
);
try err.add_label(
"This variable declaration is incomplete",
var_keyword.start_pos,
var_keyword.start_pos + var_keyword.value.len,
);
return ParseError.Error; return ParseError.Error;
} }
@ -84,7 +95,7 @@ test "should parse a minimal var" {
defer tokens.deinit(); defer tokens.deinit();
var binding: VariableBinding = undefined; var binding: VariableBinding = undefined;
_ = try binding.init(&tokens, 0, std.testing.allocator); _ = try binding.init(&tokens, 0, undefined, std.testing.allocator);
defer binding.deinit(); defer binding.deinit();
try std.testing.expectEqual(true, binding.is_mutable); try std.testing.expectEqual(true, binding.is_mutable);
@ -106,7 +117,7 @@ test "should return null if stream doesnt start with var" {
defer tokens.deinit(); defer tokens.deinit();
var binding: VariableBinding = undefined; var binding: VariableBinding = undefined;
if (try binding.init(&tokens, 0, std.testing.allocator)) |_| { if (try binding.init(&tokens, 0, undefined, std.testing.allocator)) |_| {
try std.testing.expect(false); try std.testing.expect(false);
} }
} }
@ -118,9 +129,18 @@ test "should fail if the identifier is missing" {
const tokens = try lexic.tokenize(input, std.testing.allocator, &error_list); const tokens = try lexic.tokenize(input, std.testing.allocator, &error_list);
defer tokens.deinit(); defer tokens.deinit();
var error_data: errors.ErrorData = undefined;
var binding: VariableBinding = undefined; var binding: VariableBinding = undefined;
_ = binding.init(&tokens, 0, std.testing.allocator) catch |err| { _ = binding.init(&tokens, 0, &error_data, std.testing.allocator) catch |err| {
defer error_data.deinit();
try std.testing.expectEqual(ParseError.Error, err); try std.testing.expectEqual(ParseError.Error, err);
try std.testing.expectEqualStrings("Incomplete variable declaration", error_data.reason);
try std.testing.expectEqual(0, error_data.start_position);
try std.testing.expectEqual(3, error_data.end_position);
try std.testing.expectEqual(1, error_data.labels.items.len);
const l = error_data.labels.items[0];
try std.testing.expectEqual(0, l.start);
try std.testing.expectEqual(3, l.end);
return; return;
}; };
@ -135,7 +155,7 @@ test "should fail if there is not an identifier after var" {
defer tokens.deinit(); defer tokens.deinit();
var binding: VariableBinding = undefined; var binding: VariableBinding = undefined;
_ = binding.init(&tokens, 0, std.testing.allocator) catch |err| { _ = binding.init(&tokens, 0, undefined, std.testing.allocator) catch |err| {
try std.testing.expectEqual(ParseError.Error, err); try std.testing.expectEqual(ParseError.Error, err);
return; return;
}; };
@ -151,7 +171,7 @@ test "should fail if the equal sign is missing" {
defer tokens.deinit(); defer tokens.deinit();
var binding: VariableBinding = undefined; var binding: VariableBinding = undefined;
_ = binding.init(&tokens, 0, std.testing.allocator) catch |err| { _ = binding.init(&tokens, 0, undefined, std.testing.allocator) catch |err| {
try std.testing.expectEqual(ParseError.Error, err); try std.testing.expectEqual(ParseError.Error, err);
return; return;
}; };
@ -167,7 +187,7 @@ test "should fail if the equal sign is not found" {
defer tokens.deinit(); defer tokens.deinit();
var binding: VariableBinding = undefined; var binding: VariableBinding = undefined;
_ = binding.init(&tokens, 0, std.testing.allocator) catch |err| { _ = binding.init(&tokens, 0, undefined, std.testing.allocator) catch |err| {
try std.testing.expectEqual(ParseError.Error, err); try std.testing.expectEqual(ParseError.Error, err);
return; return;
}; };
@ -183,7 +203,7 @@ test "should fail if the expression parsing fails" {
defer tokens.deinit(); defer tokens.deinit();
var binding: VariableBinding = undefined; var binding: VariableBinding = undefined;
_ = binding.init(&tokens, 0, std.testing.allocator) catch |err| { _ = binding.init(&tokens, 0, undefined, std.testing.allocator) catch |err| {
try std.testing.expectEqual(ParseError.Error, err); try std.testing.expectEqual(ParseError.Error, err);
return; return;
}; };