const std = @import("std"); const ArenaAllocator = std.heap.ArenaAllocator; const Allocator = std.mem.Allocator; const ArrayList = std.ArrayList; const Token = @import("Token.zig"); const Parser = @This(); const Stmt = @import("stmt.zig").Stmt; 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) ![]const *const Stmt { self.allocator = self.arena.allocator(); var statements: ArrayList(*const Stmt) = .empty; while (!self.isAtEnd()) { try statements.append(self.allocator, try self.statement()); } return statements.toOwnedSlice(self.allocator); } fn expression(self: *Parser) (Allocator.Error || std.Io.Writer.Error || error{ParseError})!*const Expr { return self.equality(); } fn statement(self: *Parser) !*const Stmt { if (self.match(&.{.print})) { return self.printStatement(); } return self.expressionStatement(); } fn printStatement(self: *Parser) !*const Stmt { const value = try self.expression(); _ = try self.consume(.semicolon, "Expect ';' after value."); const stmt = try self.allocator.create(Stmt); stmt.* = .{ .print = .init(value) }; return stmt; } fn expressionStatement(self: *Parser) !*const Stmt { const expr = try self.expression(); _ = try self.consume(.semicolon, "Expect ';' after expression."); const stmt = try self.allocator.create(Stmt); stmt.* = .{ .expression = .init(expr) }; return stmt; } fn equality(self: *Parser) !*const 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) !*const 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) !*const 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) !*const 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) !*const 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 self.primary(); } fn primary(self: *Parser) !*const 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.err(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.err(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 err(self: *Parser, token: Token, message: []const u8) !noreturn { try lox.parseError(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(); } }