2019-06-01 19:12:39 +00:00
|
|
|
const std = @import("std");
|
|
|
|
const scanner = @import("new_scanner.zig");
|
2019-06-01 19:37:24 +00:00
|
|
|
const vm = @import("vm.zig");
|
2019-06-01 23:33:43 +00:00
|
|
|
const chunks = @import("chunk.zig");
|
|
|
|
const tokens = @import("token.zig");
|
2019-06-01 23:48:26 +00:00
|
|
|
const values = @import("value.zig");
|
2019-06-01 19:12:39 +00:00
|
|
|
|
|
|
|
const Allocator = std.mem.Allocator;
|
2019-06-01 23:33:43 +00:00
|
|
|
const Scanner = scanner.Scanner;
|
|
|
|
const Chunk = chunks.Chunk;
|
|
|
|
const Token = tokens.Token;
|
|
|
|
const TokenType = tokens.TokenType;
|
2019-06-01 23:48:26 +00:00
|
|
|
const Value = values.Value;
|
|
|
|
const OpCode = chunks.OpCode;
|
2019-06-01 23:33:43 +00:00
|
|
|
|
|
|
|
pub const Parser = struct {
|
|
|
|
previous: Token = undefined,
|
|
|
|
current: Token = undefined,
|
|
|
|
|
|
|
|
// TODO are those needed
|
|
|
|
hadError: bool = false,
|
|
|
|
panicMode: bool = false,
|
|
|
|
};
|
2019-06-01 04:20:06 +00:00
|
|
|
|
|
|
|
pub const Compiler = struct {
|
2019-06-01 19:12:39 +00:00
|
|
|
src: []const u8,
|
2019-06-01 19:37:24 +00:00
|
|
|
stdout: vm.StdOut,
|
2019-06-01 19:12:39 +00:00
|
|
|
allocator: *Allocator,
|
2019-06-01 23:33:43 +00:00
|
|
|
parser: Parser,
|
|
|
|
scanr: Scanner = undefined,
|
|
|
|
chunk: *chunks.Chunk,
|
2019-06-01 04:20:06 +00:00
|
|
|
|
2019-06-01 19:37:24 +00:00
|
|
|
pub fn init(
|
|
|
|
allocator: *Allocator,
|
2019-06-01 23:33:43 +00:00
|
|
|
chunk: *chunks.Chunk,
|
2019-06-01 19:37:24 +00:00
|
|
|
stdout: vm.StdOut,
|
|
|
|
source: []const u8,
|
|
|
|
) Compiler {
|
|
|
|
return Compiler{
|
|
|
|
.src = source,
|
2019-06-01 23:33:43 +00:00
|
|
|
.chunk = chunk,
|
2019-06-01 19:37:24 +00:00
|
|
|
.allocator = allocator,
|
|
|
|
.stdout = stdout,
|
2019-06-01 23:33:43 +00:00
|
|
|
.parser = Parser{},
|
2019-06-01 19:37:24 +00:00
|
|
|
};
|
2019-06-01 04:20:06 +00:00
|
|
|
}
|
|
|
|
|
2019-06-01 23:33:43 +00:00
|
|
|
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;
|
|
|
|
}
|
2019-06-01 19:37:24 +00:00
|
|
|
|
2019-06-01 23:33:43 +00:00
|
|
|
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();
|
2019-06-01 20:07:22 +00:00
|
|
|
if (token_opt) |token| {
|
2019-06-01 23:33:43 +00:00
|
|
|
self.parser.current = token;
|
2019-06-01 20:07:22 +00:00
|
|
|
break;
|
2019-06-01 23:33:43 +00:00
|
|
|
} else {
|
|
|
|
self.errorCurrent(self.parser.current.lexeme);
|
2019-06-01 19:37:24 +00:00
|
|
|
}
|
|
|
|
}
|
2019-06-01 19:21:36 +00:00
|
|
|
}
|
2019-06-01 23:33:43 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-06-01 23:48:26 +00:00
|
|
|
fn emitReturn(self: *Compiler) !void {
|
|
|
|
try self.emitByte(OpCode.Return);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn emitConstant(self: *Compiler, value: Value) !void {
|
|
|
|
try self.currentChunk().writeConstant(
|
|
|
|
value,
|
|
|
|
self.parser.previous.line,
|
|
|
|
);
|
2019-06-01 23:33:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn end(self: *Compiler) !void {
|
2019-06-01 23:48:26 +00:00
|
|
|
try self.emitReturn();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn grouping(self: *Compiler) !void {
|
|
|
|
try self.expression();
|
|
|
|
try self.consume(.RIGHT_PAREN, "Expect ')' after expression.");
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Emits bytecode for a number being loaded into the code.
|
|
|
|
fn number(self: *Compiler) !void {
|
|
|
|
var value: f64 = try std.fmt.parseFloat(f64, parser.previous.lexeme);
|
|
|
|
try self.emitConstant(value);
|
2019-06-01 23:33:43 +00:00
|
|
|
}
|
|
|
|
|
2019-06-01 23:48:26 +00:00
|
|
|
/// Emits bytecode for a given unary.
|
|
|
|
fn unary(self: *Compiler) !void {
|
|
|
|
var ttype = self.parser.previous.ttype;
|
|
|
|
try self.expression();
|
|
|
|
switch (ttype) {
|
|
|
|
.MINUS => try self.emitByte(OpCode.Negate),
|
|
|
|
else => unreachable,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn expression(self: *Compiler) !void {}
|
|
|
|
|
2019-06-01 23:33:43 +00:00
|
|
|
/// 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;
|
|
|
|
}
|
2019-06-01 04:20:06 +00:00
|
|
|
};
|