From cb5d7c7798f0a7b624d63b88d2ca4d4e692499a9 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Tue, 29 Aug 2023 15:57:09 -0700 Subject: [PATCH] Improve parser error handling --- src/error.zig | 16 +++++++++++++++- src/main.zig | 8 +++++--- src/parser.zig | 28 ++++++++++++++++++++++------ 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/src/error.zig b/src/error.zig index 46ee5ad..bcb8065 100644 --- a/src/error.zig +++ b/src/error.zig @@ -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; } diff --git a/src/main.zig b/src/main.zig index 22a7a2c..485388b 100644 --- a/src/main.zig +++ b/src/main.zig @@ -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", .{}); } diff --git a/src/parser.zig b/src/parser.zig index 849baa2..c1a538a 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -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;