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 token = @import("token.zig");
pub var hasError: bool = false;
@ -6,7 +7,20 @@ pub fn err(line: u64, message: []const u8) void {
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 });
hasError = true;
}

View File

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

View File

@ -13,6 +13,12 @@ const Token = token_zig.Token;
const errors_zig = @import("error.zig");
const err = errors_zig.err;
const errToken = errors_zig.errToken;
const ParseError = error{
UnmatchedParen,
UnexpectedToken,
};
pub const Parser = struct {
const Self = @This();
@ -20,11 +26,20 @@ pub const Parser = struct {
allocator: std.mem.Allocator,
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();
}
pub fn equality(self: *Self) !*Expr {
fn equality(self: *Self) !*Expr {
var expr = try self.comparison();
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);
const token = self.advance();
switch (token.token_type) {
@ -143,12 +158,13 @@ pub const Parser = struct {
};
var next_token = self.advance();
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 => {
err(token.line, "Unexpected primary token type.");
expr.* = Expr{ .literal = LiteralExpr{ .nil = false } };
errToken(token, "Unexpected token.");
return ParseError.UnexpectedToken;
},
}
return expr;