Compare commits

...

2 commits

Author SHA1 Message Date
ec652b29d9 remove print debug 2019-06-01 23:35:13 -03:00
589413488c move towards dynamically typed values
- remove InterpretResult as an enum, replace by error.
 - scanner: fix peekNext()
 - vm: add runtime errors, add VM.peek()
2019-06-01 23:33:53 -03:00
5 changed files with 111 additions and 31 deletions

View file

@ -167,8 +167,6 @@ pub const Compiler = struct {
if (token_opt) |token| { if (token_opt) |token| {
self.parser.current = token; self.parser.current = token;
break; break;
} else {
self.errorCurrent(self.parser.current.lexeme);
} }
} }
} }
@ -221,11 +219,12 @@ pub const Compiler = struct {
/// Emits bytecode for a number being loaded into the code. /// Emits bytecode for a number being loaded into the code.
fn number(self: *Compiler) !void { fn number(self: *Compiler) !void {
std.debug.warn("parsing number: '{}'\n", self.parser.previous.lexeme);
var value: f64 = try std.fmt.parseFloat( var value: f64 = try std.fmt.parseFloat(
f64, f64,
self.parser.previous.lexeme, self.parser.previous.lexeme,
); );
try self.emitConstant(value); try self.emitConstant(values.NumberVal(value));
} }
/// Emits bytecode for a given unary. /// Emits bytecode for a given unary.

View file

@ -12,12 +12,12 @@ const InterpretResult = vm.InterpretResult;
pub var hadError = false; pub var hadError = false;
fn run(allocator: *Allocator, data: []u8) !InterpretResult { fn run(allocator: *Allocator, data: []u8) !void {
var stdout_file = try std.io.getStdOut(); var stdout_file = try std.io.getStdOut();
const stdout = &stdout_file.outStream().stream; const stdout = &stdout_file.outStream().stream;
var vmach = try vm.VM.init(allocator, stdout, data, true); var vmach = try vm.VM.init(allocator, stdout, data, true);
return try vmach.interpret(); try vmach.interpret();
} }
pub fn doError(line: usize, message: []const u8) !void { pub fn doError(line: usize, message: []const u8) !void {
@ -40,9 +40,14 @@ fn runFile(allocator: *Allocator, path: []const u8) !void {
var slice = try allocator.alloc(u8, total_bytes); var slice = try allocator.alloc(u8, total_bytes);
_ = try lox_file.read(slice); _ = try lox_file.read(slice);
var res = try run(allocator, slice); run(allocator, slice) catch |err| {
if (res == vm.InterpretResult.CompileError) std.os.exit(65); switch (err) {
if (res == vm.InterpretResult.RuntimeError) std.os.exit(70); InterpretResult.Ok => {},
InterpretResult.CompileError => std.os.exit(65),
InterpretResult.RuntimeError => std.os.exit(70),
else => return err,
}
};
} }
fn runPrompt(allocator: *Allocator) !void { fn runPrompt(allocator: *Allocator) !void {
@ -59,7 +64,15 @@ fn runPrompt(allocator: *Allocator) !void {
return err; return err;
}; };
_ = try run(allocator, line); run(allocator, line) catch |err| {
switch (err) {
InterpretResult.Ok => {},
InterpretResult.CompileError, InterpretResult.RuntimeError => blk: {
try stdout.print("compile/runtime error.\n");
},
else => return err,
}
};
} }
} }

View file

@ -147,8 +147,8 @@ pub const Scanner = struct {
} }
fn peekNext(self: *Scanner) u8 { fn peekNext(self: *Scanner) u8 {
if (self.isAtEnd()) return 0; if (self.current + 1 >= self.source.len) return 0;
return self.source[self.current - 1]; return self.source[self.current + 1];
} }
fn skipWhitespace(self: *Scanner) void { fn skipWhitespace(self: *Scanner) void {
@ -259,6 +259,7 @@ pub const Scanner = struct {
while (self.peek() != '\n' and !self.isAtEnd()) { while (self.peek() != '\n' and !self.isAtEnd()) {
_ = self.advance(); _ = self.advance();
} }
break :blk null; break :blk null;
} else { } else {
break :blk self.makeToken(.SLASH); break :blk self.makeToken(.SLASH);

View file

@ -3,10 +3,42 @@ const std = @import("std");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
// NOTE: right now, only numbers. // NOTE: right now, only numbers.
pub const Value = f64;
pub const ValueType = enum(u8) {
Bool,
Nil,
Number,
};
pub const ValueValue = union(ValueType) {
Bool: bool,
Nil: void,
Number: f64,
};
pub const Value = struct {
vtype: ValueType,
as: ValueValue,
};
// helper functions
pub fn BoolVal(val: bool) Value {
return Value{ .vtype = .Bool, .as = ValueValue{ .Bool = val } };
}
pub fn NilVal() Value {
return Value{ .vtype = .Nil, .as = ValueValue{ .Nil = {} } };
}
pub fn NumberVal(val: f64) Value {
return Value{ .vtype = .Number, .as = ValueValue{ .Number = val } };
}
pub fn printValue(stdout: var, value: Value) !void { pub fn printValue(stdout: var, value: Value) !void {
try stdout.print("{}", value); switch (value.as) {
.Number => try stdout.print("{}", value.as.Number),
else => unreachable,
}
} }
pub const ValueList = struct { pub const ValueList = struct {

View file

@ -1,6 +1,7 @@
const std = @import("std"); const std = @import("std");
const chunk = @import("chunk.zig"); const chunk = @import("chunk.zig");
const value = @import("value.zig"); const value = @import("value.zig");
const values = value;
const compiler = @import("compiler.zig"); const compiler = @import("compiler.zig");
const Chunk = chunk.Chunk; const Chunk = chunk.Chunk;
@ -9,7 +10,7 @@ const Compiler = compiler.Compiler;
pub const StdOut = *std.io.OutStream(std.fs.File.WriteError); pub const StdOut = *std.io.OutStream(std.fs.File.WriteError);
pub const InterpretResult = enum { pub const InterpretResult = error{
Ok, Ok,
CompileError, CompileError,
RuntimeError, RuntimeError,
@ -91,35 +92,50 @@ pub const VM = struct {
} }
/// gets a f64 out of a value on the top of the stack. /// gets a f64 out of a value on the top of the stack.
fn popNum(self: *VM) f64 { fn popNum(self: *VM) !f64 {
return self.pop(); var val: Value = self.pop();
switch (val.vtype) {
.Number => return val.as.Number,
else => |vtype| blk: {
self.runtimeError("Expected number, got {x}", vtype);
return InterpretResult.RuntimeError;
},
}
} }
fn doAdd(self: *VM) !void { fn doAdd(self: *VM) !void {
var b = self.popNum(); var b = try self.popNum();
var a = self.popNum(); var a = try self.popNum();
try self.push(a + b); try self.push(values.NumberVal(a + b));
} }
fn doSub(self: *VM) !void { fn doSub(self: *VM) !void {
var b = self.popNum(); var b = try self.popNum();
var a = self.popNum(); var a = try self.popNum();
try self.push(a * b); try self.push(values.NumberVal(a - b));
} }
fn doMul(self: *VM) !void { fn doMul(self: *VM) !void {
var b = self.popNum(); var b = try self.popNum();
var a = self.popNum(); var a = try self.popNum();
try self.push(a * b); try self.push(values.NumberVal(a * b));
} }
fn doDiv(self: *VM) !void { fn doDiv(self: *VM) !void {
var b = self.popNum(); var b = try self.popNum();
var a = self.popNum(); var a = try self.popNum();
try self.push(a / b); try self.push(values.NumberVal(a / b));
} }
fn run(self: *VM) !InterpretResult { fn runtimeError(self: *VM, comptime fmt: []const u8, args: ...) void {
std.debug.warn(fmt, args);
std.debug.warn("\n[line {}] in script\n", self.chk.lines[self.ip]);
self.resetStack();
}
fn run(self: *VM) !void {
while (true) { while (true) {
if (self.debug_flag) { if (self.debug_flag) {
try self.debugStack(); try self.debugStack();
@ -150,7 +166,22 @@ pub const VM = struct {
chunk.OpCode.Subtract => try self.doSub(), chunk.OpCode.Subtract => try self.doSub(),
chunk.OpCode.Multiply => try self.doMul(), chunk.OpCode.Multiply => try self.doMul(),
chunk.OpCode.Divide => try self.doDiv(), chunk.OpCode.Divide => try self.doDiv(),
chunk.OpCode.Negate => try self.push(-self.pop()), chunk.OpCode.Negate => blk: {
var val = self.peek(0);
if (val.vtype != .Bool) {
self.runtimeError("Operand must be a number.");
return InterpretResult.RuntimeError;
}
val = self.pop();
switch (val.as) {
.Number => |num| {
try self.push(values.NumberVal(-num));
},
else => unreachable,
}
},
else => blk: { else => blk: {
std.debug.warn("Unknown instruction: {x}\n", instruction); std.debug.warn("Unknown instruction: {x}\n", instruction);
return InterpretResult.RuntimeError; return InterpretResult.RuntimeError;
@ -159,7 +190,7 @@ pub const VM = struct {
} }
} }
pub fn interpret(self: *VM) !InterpretResult { pub fn interpret(self: *VM) !void {
//self.ip = 0; //self.ip = 0;
//self.debug("VM start\n"); //self.debug("VM start\n");
//var res = try self.run(); //var res = try self.run();
@ -196,4 +227,8 @@ pub const VM = struct {
self.stackTop -= 1; self.stackTop -= 1;
return self.stack[self.stackTop]; return self.stack[self.stackTop];
} }
pub fn peek(self: *VM, distance: usize) Value {
return self.stack[self.stackTop - 1 - distance];
}
}; };