const std = @import("std"); const scanners = @import("scanner.zig"); const main = @import("main.zig"); const ast = @import("ast.zig"); const tokens = @import("tokens.zig"); const Allocator = std.mem.Allocator; const Scanner = scanners.Scanner; const AstNode = ast.AstNode; const Token = tokens.Token; const TokenType = tokens.TokenType; const Result = main.Result; pub const Parser = struct { allocator: *Allocator, scanner: *Scanner, current: Token = undefined, root: AstNode = undefined, pub fn init(allocator: *Allocator, scanner: *Scanner) Parser { return Parser{ .allocator = allocator, .scanner = scanner }; } fn doError(self: *Parser, comptime fmt: []const u8, args: ...) !void { std.debug.warn("parser error at line {}\n\t", self.scanner.line); std.debug.warn(fmt, args); std.debug.warn("\n"); return Result.CompileError; } fn advance(self: *Parser) !void { var tok_opt = try self.scanner.nextToken(); if (tok_opt) |tok| { self.current = tok; } } fn accept(self: *Parser, ttype: TokenType) !bool { if (self.current.ttype == ttype) { try self.advance(); return true; } else { return false; } } fn expect(self: *Parser, ttype: TokenType) !void { if (!try self.accept(ttype)) { try self.doError("expected {x}, got {}", ttype, self.current.ttype); } } fn statement(self: *Parser) !void {} fn block(self: *Parser) !void {} fn program(self: *Parser) !void { try self.advance(); try self.block(); try self.expect(.EOF); } pub fn parse(self: *Parser) !AstNode { self.root = AstNode{ .Program = try self.allocator.alloc(AstNode, 0), }; try self.program(); return self.root; } };