rkgk/crates/haku2/src/bytecode.zig

81 lines
2.4 KiB
Zig
Raw Normal View History

const std = @import("std");
const mem = std.mem;
const log = std.log.scoped(.bytecode);
/// NOTE: This must be mirrored in bytecode.rs.
pub const Opcode = enum(u8) {
// Push literal values onto the stack.
nil,
false,
true,
tag,
number, // (float: f32)
rgba, // (r: u8, g: u8, b: u8, a: u8)
// Duplicate existing values.
local, // (index: u8) push a value relative to the bottom of the current stack window
set_local, // (index: u8) set the value of a value relative to the bottom of the current stack window
capture, // (index: u8) push a value captured by the current closure
def, // (index: u16) get the value of a definition
set_def, // (index: u16) set the value of a definition
// Create lists.
list, // (len: u16)
// Create literal functions.
function, // (params: u8, then: u16), at `then`: (local_count: u8, capture_count: u8, captures: [capture_count](source: u8, index: u8))
// Control flow.
jump, // (offset: u16)
jump_if_not, // (offset: u16)
field, // (count: u8, tags: [count]u16) look up a closure capture named by a tag. this is used to implement records with fields
// Function calls.
call, // (argc: u8)
system, // (index: u8, argc: u8) fast path for system calls
ret, // must be the last opcode; opcodes after .ret are treated as invalid
_, // invalid opcodes
};
// Constants used by the .function opcode to indicate capture sources.
pub const capture_local: u8 = 0;
pub const capture_capture: u8 = 1;
pub const Chunk = struct {
bytecode: []const u8,
};
pub const Loc = u16;
pub const Defs = struct {
num_defs: usize,
num_tags: usize,
// Unlike the Rust version, we currently do not store strings here, because we still don't
// support stack traces.
// The VM therefore never needs the names of Defs for any practical purposes.
pub fn parse(
a: mem.Allocator,
// These strings are expected to contain a list of names, where each name is terminated
// by a newline (LF).
defs_string: []const u8,
tags_string: []const u8,
) !*Defs {
const d = try a.create(Defs);
errdefer a.destroy(d);
d.* = .{
.num_defs = mem.count(u8, defs_string, "\n"),
.num_tags = mem.count(u8, tags_string, "\n"),
};
return d;
}
pub fn destroy(defs: *Defs, a: mem.Allocator) void {
a.destroy(defs);
}
};