Compare commits

..

4 Commits

Author SHA1 Message Date
Luna 3936b4a426 main: keep a long-running vm instance for REPL
enables us to declare variables and keep them going for as long as the
REPL goes.

 - vm: remove source arg from init(), move to interpret()
2019-06-03 00:02:07 -03:00
Luna 005981fbbd vm: add getglobal support 2019-06-02 23:57:28 -03:00
Luna 887cb1adea add emitting of GetGlobal/GetGlobalLong 2019-06-02 23:43:12 -03:00
Luna e3ac28d84e vm: deinit globals on vm deinit 2019-06-02 23:13:42 -03:00
4 changed files with 84 additions and 16 deletions

View File

@ -31,6 +31,8 @@ const AllOpcodes = struct {
pub DefineGlobal: u8 = 17, pub DefineGlobal: u8 = 17,
pub DefineGlobalLong: u8 = 18, pub DefineGlobalLong: u8 = 18,
pub GetGlobal: u8 = 19,
pub GetGlobalLong: u8 = 20,
}; };
pub const OpCode = AllOpcodes{}; pub const OpCode = AllOpcodes{};
@ -221,6 +223,10 @@ pub const Chunk = struct {
return try simpleInstruction(stdout, "OP_DEFGLOBAL", index); return try simpleInstruction(stdout, "OP_DEFGLOBAL", index);
} else if (instruction == OpCode.DefineGlobalLong) { } else if (instruction == OpCode.DefineGlobalLong) {
return try simpleInstruction(stdout, "OP_DEFGLOBAL_LONG", index); return try simpleInstruction(stdout, "OP_DEFGLOBAL_LONG", index);
} else if (instruction == OpCode.GetGlobal) {
return try simpleInstruction(stdout, "OP_GETGLOBAL", index);
} else if (instruction == OpCode.GetGlobalLong) {
return try simpleInstruction(stdout, "OP_GETGLOBAL_LONG", index);
} else { } else {
try stdout.print("Unknown opcode: {}\n", instruction); try stdout.print("Unknown opcode: {}\n", instruction);
return index + 1; return index + 1;

View File

@ -89,7 +89,7 @@ var rules = []ParseRule{
ParseRule{ .infix = Compiler.binary, .precedence = .Comparison }, ParseRule{ .infix = Compiler.binary, .precedence = .Comparison },
ParseRule{ .infix = Compiler.binary, .precedence = .Comparison }, ParseRule{ .infix = Compiler.binary, .precedence = .Comparison },
ParseRule{}, ParseRule{ .prefix = Compiler.variable },
ParseRule{ .prefix = Compiler.string }, ParseRule{ .prefix = Compiler.string },
ParseRule{ .prefix = Compiler.number }, ParseRule{ .prefix = Compiler.number },
ParseRule{ .precedence = .And }, ParseRule{ .precedence = .And },
@ -252,6 +252,19 @@ pub const Compiler = struct {
))); )));
} }
fn namedVariable(self: *Compiler, tok: *Token) !void {
var idx = try self.identifierConstant(tok);
try self.emitConstWithIndex(
chunks.OpCode.GetGlobal,
chunks.OpCode.GetGlobalLong,
idx,
);
}
fn variable(self: *Compiler) !void {
try self.namedVariable(&self.parser.previous);
}
/// Emits bytecode for a given unary. /// Emits bytecode for a given unary.
fn unary(self: *Compiler) !void { fn unary(self: *Compiler) !void {
var ttype = self.parser.previous.ttype; var ttype = self.parser.previous.ttype;
@ -368,11 +381,16 @@ pub const Compiler = struct {
return try self.identifierConstant(&self.parser.previous); return try self.identifierConstant(&self.parser.previous);
} }
fn defineVariable(self: *Compiler, global: chunks.ConstantIndex) !void { fn emitConstWithIndex(
switch (global) { self: *Compiler,
.Small => |val| try self.emitBytes(chunks.OpCode.DefineGlobal, val), op_short: u8,
op_long: u8,
idx: chunks.ConstantIndex,
) !void {
switch (idx) {
.Small => |val| try self.emitBytes(op_short, val),
.Long => |val| blk: { .Long => |val| blk: {
try self.emitByte(chunks.OpCode.DefineGlobalLong); try self.emitByte(op_long);
try self.emitByte(val[0]); try self.emitByte(val[0]);
try self.emitByte(val[1]); try self.emitByte(val[1]);
try self.emitByte(val[2]); try self.emitByte(val[2]);
@ -381,6 +399,14 @@ pub const Compiler = struct {
} }
} }
fn defineVariable(self: *Compiler, global: chunks.ConstantIndex) !void {
try self.emitConstWithIndex(
chunks.OpCode.DefineGlobal,
chunks.OpCode.DefineGlobalLong,
global,
);
}
fn varDecl(self: *Compiler) !void { fn varDecl(self: *Compiler) !void {
var global = try self.parseVariable("Expect variable name."); var global = try self.parseVariable("Expect variable name.");

View File

@ -16,9 +16,17 @@ 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, true);
defer vmach.deinit(); defer vmach.deinit();
try vmach.interpret(); try vmach.interpret(data);
}
fn runWithVM(vmach: *vm.VM, data: []u8) !void {
var stdout_file = try std.io.getStdOut();
const stdout = &stdout_file.outStream().stream;
defer vmach.deinit();
try vmach.interpret(data);
} }
pub fn doError(line: usize, message: []const u8) !void { pub fn doError(line: usize, message: []const u8) !void {
@ -55,6 +63,9 @@ fn runPrompt(allocator: *Allocator) !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, true);
defer vmach.deinit();
while (true) { while (true) {
try stdout.print(">"); try stdout.print(">");
var buffer = try std.Buffer.init(allocator, ""[0..]); var buffer = try std.Buffer.init(allocator, ""[0..]);
@ -65,7 +76,7 @@ fn runPrompt(allocator: *Allocator) !void {
return err; return err;
}; };
run(allocator, line) catch |err| { runWithVM(&vmach, line) catch |err| {
switch (err) { switch (err) {
InterpretResult.Ok => {}, InterpretResult.Ok => {},
InterpretResult.CompileError, InterpretResult.RuntimeError => blk: { InterpretResult.CompileError, InterpretResult.RuntimeError => blk: {

View File

@ -40,7 +40,6 @@ pub const ValueMap = std.AutoHashMap([]const u8, values.Value);
pub const VM = struct { pub const VM = struct {
chk: *Chunk = undefined, chk: *Chunk = undefined,
src: []const u8,
ip: usize = 0, ip: usize = 0,
stack: []Value, stack: []Value,
@ -60,12 +59,9 @@ pub const VM = struct {
pub fn init( pub fn init(
allocator: *std.mem.Allocator, allocator: *std.mem.Allocator,
stdout: StdOut, stdout: StdOut,
source: []const u8,
debug_flag: bool, debug_flag: bool,
) !VM { ) !VM {
var self = VM{ var self = VM{
.src = source,
.stack = try allocator.alloc(Value, 256), .stack = try allocator.alloc(Value, 256),
.stdout = stdout, .stdout = stdout,
.debug_flag = debug_flag, .debug_flag = debug_flag,
@ -106,6 +102,7 @@ pub const VM = struct {
} }
pub fn deinit(self: *VM) void { pub fn deinit(self: *VM) void {
self.globals.deinit();
self.deinitObjects(); self.deinitObjects();
} }
@ -229,6 +226,25 @@ pub const VM = struct {
_ = self.pop(); _ = self.pop();
} }
fn readString(self: *VM) []u8 {
return self.readConst().as.Object.value.String;
}
fn readStringLong(self: *VM) []u8 {
return self.readConstLong().as.Object.value.String;
}
fn doGetGlobal(self: *VM, name: []u8) !void {
var kv_opt = self.globals.get(name);
if (kv_opt) |kv| {
try self.push(kv.value);
} else {
self.runtimeError("Undefined variable '{}'.", name);
return InterpretResult.RuntimeError;
}
}
fn run(self: *VM) !void { fn run(self: *VM) !void {
while (true) { while (true) {
if (self.debug_flag) { if (self.debug_flag) {
@ -270,15 +286,24 @@ pub const VM = struct {
break :blk; break :blk;
}, },
chunk.OpCode.GetGlobal => blk: {
try self.doGetGlobal(self.readString());
break :blk;
},
chunk.OpCode.GetGlobalLong => blk: {
try self.doGetGlobal(self.readStringLong());
break :blk;
},
// extracting the name is different depending of the // extracting the name is different depending of the
// op code since one just uses a single byte, the other // op code since one just uses a single byte, the other
// uses three bytes since its a u24. // uses three bytes since its a u24.
chunk.OpCode.DefineGlobal => blk: { chunk.OpCode.DefineGlobal => blk: {
try self.defGlobal(self.readConst().as.Object.value.String); try self.defGlobal(self.readString());
break :blk; break :blk;
}, },
chunk.OpCode.DefineGlobalLong => blk: { chunk.OpCode.DefineGlobalLong => blk: {
try self.defGlobal(self.readConstLong().as.Object.value.String); try self.defGlobal(self.readStringLong());
break :blk; break :blk;
}, },
@ -323,7 +348,7 @@ pub const VM = struct {
} }
} }
pub fn interpret(self: *VM) !void { pub fn interpret(self: *VM, src: []const u8) !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();
@ -335,7 +360,7 @@ pub const VM = struct {
self.allocator, self.allocator,
&chk, &chk,
self.stdout, self.stdout,
self.src, src,
self.debug_flag, self.debug_flag,
self, self,
); );