Improve parser error handling

This commit is contained in:
Drew Galbraith 2023-08-29 15:57:09 -07:00
parent 7236c0b43a
commit cb5d7c7798
3 changed files with 42 additions and 10 deletions

View File

@ -1,4 +1,5 @@
const std = @import("std"); const std = @import("std");
const token = @import("token.zig");
pub var hasError: bool = false; pub var hasError: bool = false;
@ -6,7 +7,20 @@ pub fn err(line: u64, message: []const u8) void {
report(line, "", message); report(line, "", message);
} }
pub fn report(line: u64, where: []u8, message: []const u8) void { pub fn errToken(tok: token.Token, message: []const u8) void {
if (tok.token_type == token.TokenType.EOF) {
report(tok.line, " at end", message);
} else {
var buffer = [_]u8{0} ** 100;
const where = std.fmt.bufPrint(&buffer, " at '{s}'", .{tok.lexeme}) catch {
std.debug.print("Format error: buffer empty", .{});
std.process.exit(1);
};
report(tok.line, where, message);
}
}
pub fn report(line: u64, where: []const u8, message: []const u8) void {
std.debug.print("[line {}] Error{s}: {s}\n", .{ line, where, message }); std.debug.print("[line {}] Error{s}: {s}\n", .{ line, where, message });
hasError = true; hasError = true;
} }

View File

@ -67,8 +67,10 @@ fn run(allocator: std.mem.Allocator, bytes: []u8) !void {
.allocator = alloc, .allocator = alloc,
}; };
const expression = try parse.expression(); const expression = parse.parse();
// std.debug.print("AST: {}", .{expression.*}); if (err.hasError) {
expr.AstPrint(expression.*); return;
}
expr.AstPrint(expression);
std.debug.print("\n", .{}); std.debug.print("\n", .{});
} }

View File

@ -13,6 +13,12 @@ const Token = token_zig.Token;
const errors_zig = @import("error.zig"); const errors_zig = @import("error.zig");
const err = errors_zig.err; const err = errors_zig.err;
const errToken = errors_zig.errToken;
const ParseError = error{
UnmatchedParen,
UnexpectedToken,
};
pub const Parser = struct { pub const Parser = struct {
const Self = @This(); const Self = @This();
@ -20,11 +26,20 @@ pub const Parser = struct {
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
current: u64 = 0, current: u64 = 0,
pub fn expression(self: *Self) !*Expr { pub fn parse(self: *Self) Expr {
var expr = self.expression() catch blk: {
break :blk &Expr{ .literal = LiteralExpr{
.nil = false,
} };
};
return expr.*;
}
fn expression(self: *Self) !*Expr {
return self.equality(); return self.equality();
} }
pub fn equality(self: *Self) !*Expr { fn equality(self: *Self) !*Expr {
var expr = try self.comparison(); var expr = try self.comparison();
while (true) { while (true) {
@ -128,7 +143,7 @@ pub const Parser = struct {
} }
} }
fn primary(self: *Self) error{OutOfMemory}!*Expr { fn primary(self: *Self) error{ OutOfMemory, UnmatchedParen, UnexpectedToken }!*Expr {
var expr = try self.allocator.create(Expr); var expr = try self.allocator.create(Expr);
const token = self.advance(); const token = self.advance();
switch (token.token_type) { switch (token.token_type) {
@ -143,12 +158,13 @@ pub const Parser = struct {
}; };
var next_token = self.advance(); var next_token = self.advance();
if (next_token.token_type != TokenType.RIGHT_PAREN) { if (next_token.token_type != TokenType.RIGHT_PAREN) {
err(next_token.line, "Unclosed left paren."); errToken(next_token, "Unclosed left paren.");
return ParseError.UnmatchedParen;
} }
}, },
else => { else => {
err(token.line, "Unexpected primary token type."); errToken(token, "Unexpected token.");
expr.* = Expr{ .literal = LiteralExpr{ .nil = false } }; return ParseError.UnexpectedToken;
}, },
} }
return expr; return expr;