Compare commits
4 Commits
3a6df2d9ea
...
3936b4a426
Author | SHA1 | Date |
---|---|---|
Luna | 3936b4a426 | |
Luna | 005981fbbd | |
Luna | 887cb1adea | |
Luna | e3ac28d84e |
|
@ -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;
|
||||||
|
|
|
@ -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.");
|
||||||
|
|
||||||
|
|
17
src/main.zig
17
src/main.zig
|
@ -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: {
|
||||||
|
|
41
src/vm.zig
41
src/vm.zig
|
@ -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,
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue