add basic compiler code

This commit is contained in:
Luna 2019-06-01 20:33:43 -03:00
parent 7d7aabbdd7
commit e1d0e3ec0b
3 changed files with 109 additions and 28 deletions

View File

@ -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;
}
};

View File

@ -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();

View File

@ -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 {