const std = @import("std"); const chunk = @import("chunk.zig"); const value = @import("value.zig"); const Chunk = chunk.Chunk; const StdOut = *std.io.OutStream(std.fs.File.WriteError); pub const InterpretResult = enum { Ok, CompileError, RuntimeError, }; pub const VM = struct { chk: *Chunk, ip: usize, stdout: StdOut, pub fn init(stdout: StdOut, chk: *Chunk) VM { return VM{ .stdout = stdout, .chk = chk, .ip = 0, }; } fn readByte(self: *VM) u8 { var byte: u8 = self.chk.code[self.ip]; self.ip += 1; return byte; } fn readConst(self: *VM) value.Value { return self.chk.constants.values[self.readByte()]; } fn readConstLong(self: *VM) value.Value { const v3 = self.readByte(); const v2 = self.readByte(); const v1 = self.readByte(); const const_idx = (@intCast(u24, v3) << 16) | (@intCast(u24, v2) << 8) | v1; return self.chk.constants.values[const_idx]; } fn run(self: *VM) !InterpretResult { while (true) { var instruction = self.readByte(); switch (instruction) { chunk.OpCode.Constant => blk: { var constant = self.readConst(); try value.printValue(self.stdout, constant); break :blk; }, chunk.OpCode.ConstantLong => blk: { var constant = self.readConstLong(); try value.printValue(self.stdout, constant); break :blk; }, chunk.OpCode.Return => blk: { return InterpretResult.Ok; }, else => blk: { std.debug.warn("Unknown instruction: {x}\n", instruction); return InterpretResult.RuntimeError; }, } } } pub fn interpret(self: *VM) !InterpretResult { self.ip = 0; return try self.run(); } };