123 lines
4.9 KiB
Zig
123 lines
4.9 KiB
Zig
const std = @import("std");
|
|
const debug = std.debug;
|
|
const Allocator = std.mem.Allocator;
|
|
|
|
const Value = @import("./values.zig").Value;
|
|
const ValueArray = @import("./values.zig").ValueArray;
|
|
const OpCode = @import("./opcode.zig").OpCode;
|
|
|
|
const grow_capacity = @import("./utils.zig").grow_capacity;
|
|
const utils = @import("./utils.zig");
|
|
|
|
pub const Chunk = struct {
|
|
count: usize,
|
|
capacity: usize,
|
|
code: []u8,
|
|
lines: []usize,
|
|
constants: ValueArray,
|
|
allocator: Allocator,
|
|
|
|
pub fn new(allocator: Allocator) Chunk {
|
|
return Chunk{
|
|
.count = 0,
|
|
.capacity = 0,
|
|
.code = &.{},
|
|
.lines = &.{},
|
|
.constants = ValueArray.new(),
|
|
.allocator = allocator,
|
|
};
|
|
}
|
|
|
|
pub fn init(self: *Chunk) !void {
|
|
self.deinit(self.allocator);
|
|
|
|
self.count = 0;
|
|
self.capacity = 0;
|
|
self.code = &.{};
|
|
self.lines = &.{};
|
|
self.constants = ValueArray.new();
|
|
}
|
|
|
|
pub fn write(self: *Chunk, byte: u8, line: usize) !void {
|
|
if (self.capacity < self.count + 1) {
|
|
const old_capacity = self.capacity;
|
|
self.capacity = grow_capacity(old_capacity);
|
|
self.code = try self.allocator.realloc(self.code, self.capacity);
|
|
self.lines = try self.allocator.realloc(self.lines, self.capacity);
|
|
}
|
|
|
|
self.code[self.count] = byte;
|
|
self.lines[self.count] = line;
|
|
self.count += 1;
|
|
}
|
|
|
|
pub fn dump(self: Chunk) void {
|
|
debug.print("{any}\n", .{self});
|
|
}
|
|
|
|
pub fn dissassemble(self: Chunk, name: []const u8) void {
|
|
debug.print("== {s} ==\n", .{name});
|
|
|
|
var offset: usize = 0;
|
|
|
|
while (offset < self.count) {
|
|
offset = self.dissassemble_instruction(offset);
|
|
}
|
|
debug.print("== end of {s} ==\n\n", .{name});
|
|
}
|
|
|
|
pub fn dissassemble_instruction(self: Chunk, offset: usize) usize {
|
|
debug.print("{x:0>4} ", .{offset});
|
|
|
|
if (offset > 0 and self.lines[offset] == self.lines[offset - 1]) {
|
|
debug.print(" | ", .{});
|
|
} else {
|
|
debug.print("{d:4} ", .{self.lines[offset]});
|
|
}
|
|
|
|
const instruction = self.code[offset];
|
|
|
|
switch (instruction) {
|
|
@intFromEnum(OpCode.OP_RETURN) => return utils.simple_instruction("OP_RETURN", offset),
|
|
@intFromEnum(OpCode.OP_ADD) => return utils.simple_instruction("OP_ADD", offset),
|
|
@intFromEnum(OpCode.OP_SUBSTRACT) => return utils.simple_instruction("OP_SUBSTRACT", offset),
|
|
@intFromEnum(OpCode.OP_MULTIPLY) => return utils.simple_instruction("OP_MULTIPLY", offset),
|
|
@intFromEnum(OpCode.OP_DIVIDE) => return utils.simple_instruction("OP_DIVIDE", offset),
|
|
@intFromEnum(OpCode.OP_NEGATE) => return utils.simple_instruction("OP_NEGATE", offset),
|
|
@intFromEnum(OpCode.OP_CONSTANT) => return utils.constant_instruction("OP_CONSTANT", self, offset),
|
|
@intFromEnum(OpCode.OP_NIL) => return utils.simple_instruction("OP_NIL", offset),
|
|
@intFromEnum(OpCode.OP_TRUE) => return utils.simple_instruction("OP_TRUE", offset),
|
|
@intFromEnum(OpCode.OP_FALSE) => return utils.simple_instruction("OP_FALSE", offset),
|
|
@intFromEnum(OpCode.OP_NOT) => return utils.simple_instruction("OP_NOT", offset),
|
|
@intFromEnum(OpCode.OP_EQUAL) => return utils.simple_instruction("OP_EQUAL", offset),
|
|
@intFromEnum(OpCode.OP_GREATER) => return utils.simple_instruction("OP_GREATER", offset),
|
|
@intFromEnum(OpCode.OP_LESS) => return utils.simple_instruction("OP_LESS", offset),
|
|
@intFromEnum(OpCode.OP_PRINT) => return utils.simple_instruction("OP_PRINT", offset),
|
|
@intFromEnum(OpCode.OP_POP) => return utils.simple_instruction("OP_POP", offset),
|
|
@intFromEnum(OpCode.OP_DEFINE_GLOBAL) => return utils.constant_instruction("OP_DEFINE_GLOBAL", self, offset),
|
|
@intFromEnum(OpCode.OP_GET_GLOBAL) => return utils.constant_instruction("OP_GET_GLOBAL", self, offset),
|
|
@intFromEnum(OpCode.OP_SET_GLOBAL) => return utils.constant_instruction("OP_SET_GLOBAL", self, offset),
|
|
@intFromEnum(OpCode.OP_GET_LOCAL) => return utils.byte_instruction("OP_GET_LOCAL", self, offset),
|
|
@intFromEnum(OpCode.OP_SET_LOCAL) => return utils.byte_instruction("OP_SET_LOCAL", self, offset),
|
|
else => {
|
|
debug.print("unknown opcode {d}\n", .{instruction});
|
|
return offset + 1;
|
|
},
|
|
}
|
|
}
|
|
|
|
pub fn deinit(self: *Chunk) void {
|
|
self.constants.free(self.allocator);
|
|
|
|
if (self.capacity > 0) {
|
|
self.allocator.free(self.code);
|
|
self.allocator.free(self.lines);
|
|
}
|
|
}
|
|
|
|
pub fn add_constant(self: *Chunk, value: Value) !usize {
|
|
try self.constants.write(self.allocator, value);
|
|
return self.constants.count - 1;
|
|
}
|
|
};
|