diff --git a/src/compiler.zig b/src/compiler.zig index fd96032..a04fd1f 100644 --- a/src/compiler.zig +++ b/src/compiler.zig @@ -1,54 +1,124 @@ 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 TokenType = @import("token.zig").TokenType; +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{}, }; } - pub fn compile(self: *Compiler) !void { - var scanr = try scanner.Scanner.init(self.allocator, self.src); - var line: usize = 0; + 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 = scanr.scanToken() catch |err| { - std.debug.warn("Scan Error: {x}\n", err); - std.debug.warn( - "line: {}, cur lexeme: {}\n", - scanr.line, - scanr.currentLexeme(), - ); - break; - }; - + var token_opt = try self.scanr.scanToken(); if (token_opt) |token| { - if (token.line != line) { - try self.stdout.print("{} ", token.line); - line = token.line; - } else { - try self.stdout.print(" | "); - } - - try self.stdout.print("{} '{}'\n", token.ttype, token.lexeme); - if (token.ttype == TokenType.EOF) break; - } else { + 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; + } }; diff --git a/src/new_scanner.zig b/src/new_scanner.zig index 8a1c436..2b4020d 100644 --- a/src/new_scanner.zig +++ b/src/new_scanner.zig @@ -230,7 +230,11 @@ pub const Scanner = struct { pub fn scanToken(self: *Scanner) !?Token { self.skipWhitespace(); self.start = self.current; - if (self.isAtEnd()) return self.makeToken(TokenType.EOF); + + if (self.isAtEnd()) { + std.debug.warn("got at end\n"); + return self.makeToken(TokenType.EOF); + } var c = self.advance(); if (isAlpha(c)) return self.doIdentifier(); diff --git a/src/vm.zig b/src/vm.zig index 175414c..3375684 100644 --- a/src/vm.zig +++ b/src/vm.zig @@ -165,9 +165,16 @@ pub const VM = struct { //var res = try self.run(); //self.debug("VM end\n"); //return res; - var cmpr = Compiler.init(self.allocator, self.stdout, self.src); - try cmpr.compile(); - return InterpretResult.Ok; + var chk = try Chunk.init(self.allocator); + + var cmpr = Compiler.init(self.allocator, &chk, self.stdout, self.src); + if (!try cmpr.compile(&chk)) { + return InterpretResult.CompileError; + } + + self.chk = &chk; + self.ip = 0; + return try self.run(); } pub fn push(self: *VM, val: Value) !void {