+const std = @import("std");
+const ArenaAllocator = std.heap.ArenaAllocator;
+const Allocator = std.mem.Allocator;
+const Token = @import("Token.zig");
+const Parser = @This();
+const Expr = @import("expr.zig").Expr;
+const TokenType = @import("token_type.zig").TokenType;
+const lox = @import("main.zig");
+
+arena: ArenaAllocator,
+allocator: Allocator,
+tokens: []const Token,
+current: u32 = 0,
+
+pub fn init(child_allocator: Allocator, tokens: []const Token) !Parser {
+ return .{
+ .arena = .init(child_allocator),
+ .allocator = undefined,
+ .tokens = tokens,
+ };
+}
+
+pub fn deinit(self: *Parser) void {
+ self.arena.deinit();
+}
+
+pub fn parse(self: *Parser) !?*Expr {
+ self.allocator = self.arena.allocator();
+
+ return self.expression() catch |err| switch (err) {
+ error.ParseError => return null,
+ else => return err,
+ };
+}
+
+fn expression(self: *Parser) (Allocator.Error || std.Io.Writer.Error || error{ParseError})!*Expr {
+ return self.equality();
+}
+
+fn equality(self: *Parser) !*Expr {
+ var expr = try self.comparison();
+
+ while (self.match(&.{ .bang_equal, .equal_equal })) {
+ const operator = self.previous();
+ const right = try self.comparison();
+ const binary = try self.allocator.create(Expr);
+ binary.* = .{ .binary = .init(expr, operator, right) };
+ expr = binary;
+ }
+
+ return expr;
+}
+
+fn comparison(self: *Parser) !*Expr {
+ var expr = try self.term();
+
+ while (self.match(&.{ .greater, .greater_equal, .less, .less_equal })) {
+ const operator = self.previous();
+ const right = try self.term();
+ const binary = try self.allocator.create(Expr);
+ binary.* = .{ .binary = .init(expr, operator, right) };
+ expr = binary;
+ }
+
+ return expr;
+}
+
+fn term(self: *Parser) !*Expr {
+ var expr = try self.factor();
+
+ while (self.match(&.{ .plus, .minus })) {
+ const operator = self.previous();
+ const right = try self.factor();
+ const binary = try self.allocator.create(Expr);
+ binary.* = .{ .binary = .init(expr, operator, right) };
+ expr = binary;
+ }
+
+ return expr;
+}
+
+fn factor(self: *Parser) !*Expr {
+ var expr = try self.unary();
+
+ while (self.match(&.{ .slash, .star })) {
+ const operator = self.previous();
+ const right = try self.unary();
+ const binary = try self.allocator.create(Expr);
+ binary.* = .{ .binary = .init(expr, operator, right) };
+ expr = binary;
+ }
+
+ return expr;
+}
+
+fn unary(self: *Parser) !*Expr {
+ if (self.match(&.{ .bang, .minus })) {
+ const operator = self.previous();
+ const right = try self.unary();
+ const expr = try self.allocator.create(Expr);
+ expr.* = .{ .unary = .init(operator, right) };
+ return expr;
+ }
+
+ return try self.primary();
+}
+
+fn primary(self: *Parser) !*Expr {
+ if (self.match(&.{.false})) {
+ const expr = try self.allocator.create(Expr);
+ expr.* = .{ .literal = .init(.{ .boolean = false }) };
+ return expr;
+ }
+
+ if (self.match(&.{.true})) {
+ const expr = try self.allocator.create(Expr);
+ expr.* = .{ .literal = .init(.{ .boolean = true }) };
+ return expr;
+ }
+
+ if (self.match(&.{.nil})) {
+ const expr = try self.allocator.create(Expr);
+ expr.* = .{ .literal = .init(.{ .nil = {} }) };
+ return expr;
+ }
+
+ if (self.match(&.{ .number, .string })) {
+ const expr = try self.allocator.create(Expr);
+ expr.* = .{ .literal = .init(self.previous().literal.?) };
+ return expr;
+ }
+
+ if (self.match(&.{.left_paren})) {
+ const expr = try self.expression();
+ _ = try self.consume(.right_paren, "Expect ')' after expression.");
+ const grouping = try self.allocator.create(Expr);
+ grouping.* = .{ .grouping = .init(expr) };
+ return grouping;
+ }
+
+ try self.@"error"(self.peek(), "Expect expression.");
+}
+
+fn match(self: *Parser, types: []const TokenType) bool {
+ for (types) |@"type"| {
+ if (self.check(@"type")) {
+ _ = self.advance();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+fn consume(self: *Parser, @"type": TokenType, message: []const u8) !Token {
+ if (self.check(@"type")) return self.advance();
+
+ try self.@"error"(self.peek(), message);
+}
+
+fn check(self: *Parser, @"type": TokenType) bool {
+ if (self.isAtEnd()) return false;
+ return self.peek().type == @"type";
+}
+
+fn advance(self: *Parser) Token {
+ if (!self.isAtEnd()) self.current += 1;
+ return self.previous();
+}
+
+fn isAtEnd(self: *Parser) bool {
+ return self.peek().type == .eof;
+}
+
+fn peek(self: *Parser) Token {
+ return self.tokens[self.current];
+}
+
+fn previous(self: *Parser) Token {
+ return self.tokens[self.current - 1];
+}
+
+fn @"error"(self: *Parser, token: Token, message: []const u8) !noreturn {
+ try lox.parse_error(self.allocator, token, message);
+ return error.ParseError;
+}
+
+fn synchronize(self: *Parser) !void {
+ _ = self.advance();
+
+ while (!self.isAtEnd()) {
+ if (self.previous().type == .semicolon) return;
+
+ switch (self.peek().type) {
+ .class,
+ .fun,
+ .@"var",
+ .@"for",
+ .@"if",
+ .@"while",
+ .print,
+ .@"return",
+ => return,
+ }
+
+ _ = self.advance();
+ }
+}