const std = @import("std"); const scanner = @import("new_scanner.zig"); const vm = @import("vm.zig"); const chunks = @import("chunk.zig"); const tokens = @import("token.zig"); const Allocator = std.mem.Allocator; const Scanner = scanner.Scanner; const Chunk = chunks.Chunk; const Token = tokens.Token; const TokenType = tokens.TokenType; pub const Parser = struct { previous: Token = undefined, current: Token = undefined, // TODO are those needed hadError: bool = false, panicMode: bool = false, }; pub const Compiler = struct { src: []const u8, stdout: vm.StdOut, allocator: *Allocator, parser: Parser, scanr: Scanner = undefined, chunk: *chunks.Chunk, pub fn init( allocator: *Allocator, chunk: *chunks.Chunk, stdout: vm.StdOut, source: []const u8, ) Compiler { return Compiler{ .src = source, .chunk = chunk, .allocator = allocator, .stdout = stdout, .parser = Parser{}, }; } fn errorAt(self: *Compiler, token: Token, msg: []const u8) void { if (self.parser.panicMode) return; self.parser.panicMode = true; std.debug.warn("[line {}] Error", token.line); if (token.ttype == TokenType.EOF) { std.debug.warn(" at end"); } else { std.debug.warn(" at '{}'", token.lexeme); } std.debug.warn(": {}\n", msg); self.parser.hadError = true; } fn errorCurrent(self: *Compiler, msg: []const u8) void { self.errorAt(self.parser.current, msg); } fn errorPrevious(self: *Compiler, msg: []const u8) void { self.errorAt(self.parser.previous, msg); } fn advance(self: *Compiler) !void { self.parser.previous = self.parser.current; while (true) { var token_opt = try self.scanr.scanToken(); if (token_opt) |token| { self.parser.current = token; break; } else { self.errorCurrent(self.parser.current.lexeme); } } } fn consume(self: *Compiler, ttype: TokenType, msg: []const u8) !void { if (self.parser.current.ttype == ttype) { try self.advance(); return; } self.errorCurrent(msg); } fn currentChunk(self: *Compiler) *chunks.Chunk { return self.chunk; } fn emitByte(self: *Compiler, byte: u8) !void { try self.currentChunk().write(byte, self.parser.previous.line); } fn emitBytes(self: *Compiler, byte1: u8, byte2: u82) !void { try self.emitByte(byte1); try self.emitByte(byte2); } fn writeReturn(self: *Compiler) !void { try self.emitByte(chunks.OpCode.Return); } fn end(self: *Compiler) !void { try self.writeReturn(); } /// Compile the source given when initializing the compiler /// into the given chunk. pub fn compile(self: *Compiler, chunk: *Chunk) !bool { self.scanr = try scanner.Scanner.init(self.allocator, self.src); try self.advance(); //try self.expression(); try self.consume(.EOF, "Expect end of expression."); try self.end(); return !self.parser.hadError; } };