vm: add dynamically-sized growing stack

This commit is contained in:
Luna 2019-06-01 15:45:30 -03:00
parent 3377d1675c
commit 088674bf0b
2 changed files with 36 additions and 26 deletions

View file

@ -123,6 +123,6 @@ pub fn main() !void {
try chk.write(chunk.OpCode.Divide, 123); try chk.write(chunk.OpCode.Divide, 123);
try chk.write(chunk.OpCode.Return, 123); try chk.write(chunk.OpCode.Return, 123);
var vmach = vm.VM.init(stdout, &chk, true); var vmach = try vm.VM.init(allocator, stdout, &chk, true);
_ = try vmach.interpret(); _ = try vmach.interpret();
} }

View file

@ -3,9 +3,9 @@ const chunk = @import("chunk.zig");
const value = @import("value.zig"); const value = @import("value.zig");
const Chunk = chunk.Chunk; const Chunk = chunk.Chunk;
const StdOut = *std.io.OutStream(std.fs.File.WriteError); const Value = value.Value;
pub const STACK_MAX = 256; const StdOut = *std.io.OutStream(std.fs.File.WriteError);
pub const InterpretResult = enum { pub const InterpretResult = enum {
Ok, Ok,
@ -17,24 +17,30 @@ pub const VM = struct {
chk: *Chunk, chk: *Chunk,
ip: usize = 0, ip: usize = 0,
stack: [STACK_MAX]value.Value, stack: []Value,
stackTop: usize = 0, stackTop: usize = 0,
stdout: StdOut, stdout: StdOut,
debug_flag: bool, debug_flag: bool,
allocator: *std.mem.Allocator,
fn resetStack(self: *VM) void { fn resetStack(self: *VM) void {
self.stackTop = 0; self.stackTop = 0;
} }
pub fn init(stdout: StdOut, chk: *Chunk, debug_flag: bool) VM { pub fn init(
allocator: *std.mem.Allocator,
stdout: StdOut,
chk: *Chunk,
debug_flag: bool,
) !VM {
var self = VM{ var self = VM{
.chk = chk, .chk = chk,
// TODO move this to a nil value or something. .stack = try allocator.alloc(Value, 256),
.stack = []value.Value{0} ** STACK_MAX,
.stdout = stdout, .stdout = stdout,
.debug_flag = debug_flag, .debug_flag = debug_flag,
.allocator = allocator,
}; };
self.resetStack(); self.resetStack();
@ -54,11 +60,11 @@ pub const VM = struct {
return byte; return byte;
} }
fn readConst(self: *VM) value.Value { fn readConst(self: *VM) Value {
return self.chk.constants.values[self.readByte()]; return self.chk.constants.values[self.readByte()];
} }
fn readConstLong(self: *VM) value.Value { fn readConstLong(self: *VM) Value {
const v3 = self.readByte(); const v3 = self.readByte();
const v2 = self.readByte(); const v2 = self.readByte();
const v1 = self.readByte(); const v1 = self.readByte();
@ -86,28 +92,28 @@ pub const VM = struct {
return self.pop(); return self.pop();
} }
fn doAdd(self: *VM) void { fn doAdd(self: *VM) !void {
var b = self.popNum(); var b = self.popNum();
var a = self.popNum(); var a = self.popNum();
self.push(a + b); try self.push(a + b);
} }
fn doSub(self: *VM) void { fn doSub(self: *VM) !void {
var b = self.popNum(); var b = self.popNum();
var a = self.popNum(); var a = self.popNum();
self.push(a * b); try self.push(a * b);
} }
fn doMul(self: *VM) void { fn doMul(self: *VM) !void {
var b = self.popNum(); var b = self.popNum();
var a = self.popNum(); var a = self.popNum();
self.push(a * b); try self.push(a * b);
} }
fn doDiv(self: *VM) void { fn doDiv(self: *VM) !void {
var b = self.popNum(); var b = self.popNum();
var a = self.popNum(); var a = self.popNum();
self.push(a / b); try self.push(a / b);
} }
fn run(self: *VM) !InterpretResult { fn run(self: *VM) !InterpretResult {
@ -122,12 +128,12 @@ pub const VM = struct {
switch (instruction) { switch (instruction) {
chunk.OpCode.Constant => blk: { chunk.OpCode.Constant => blk: {
var constant = self.readConst(); var constant = self.readConst();
self.push(constant); try self.push(constant);
break :blk; break :blk;
}, },
chunk.OpCode.ConstantLong => blk: { chunk.OpCode.ConstantLong => blk: {
var constant = self.readConstLong(); var constant = self.readConstLong();
self.push(constant); try self.push(constant);
break :blk; break :blk;
}, },
@ -137,11 +143,11 @@ pub const VM = struct {
return InterpretResult.Ok; return InterpretResult.Ok;
}, },
chunk.OpCode.Add => self.doAdd(), chunk.OpCode.Add => try self.doAdd(),
chunk.OpCode.Subtract => self.doSub(), chunk.OpCode.Subtract => try self.doSub(),
chunk.OpCode.Multiply => self.doMul(), chunk.OpCode.Multiply => try self.doMul(),
chunk.OpCode.Divide => self.doDiv(), chunk.OpCode.Divide => try self.doDiv(),
chunk.OpCode.Negate => self.push(-self.pop()), chunk.OpCode.Negate => try self.push(-self.pop()),
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,12 +165,16 @@ pub const VM = struct {
return res; return res;
} }
pub fn push(self: *VM, val: value.Value) void { pub fn push(self: *VM, val: Value) !void {
if (self.stackTop > 0 and self.stackTop - 1 > self.stack.len) {
self.stack = try self.allocator.realloc(self.stack, self.stack.len + 1);
}
self.stack[self.stackTop] = val; self.stack[self.stackTop] = val;
self.stackTop += 1; self.stackTop += 1;
} }
pub fn pop(self: *VM) value.Value { pub fn pop(self: *VM) Value {
self.stackTop -= 1; self.stackTop -= 1;
return self.stack[self.stackTop]; return self.stack[self.stackTop];
} }