DzLox

:)
git clone https://git.sr.ht/~ashymad/DzLox
Log | Files | Refs | Submodules | LICENSE

commit a5a57b943bcf842e45dbf99f72e5621e757594e9
parent d029753740ee504e49ac581cf101ea57c3a1534c
Author: Szymon Mikulicz <szymon.mikulicz@posteo.net>
Date:   Sat, 22 Oct 2022 18:04:22 +0200

Chunks of bytecode

Diffstat:
Mzlox/src/chunk.zig | 58+++++++++++++++++++++++++++++++++++++---------------------
Mzlox/src/debug.zig | 37+++++++++++++++++++++++++++----------
Mzlox/src/main.zig | 14++++++++++----
Azlox/src/rlearray.zig | 48++++++++++++++++++++++++++++++++++++++++++++++++
Azlox/src/value.zig | 37+++++++++++++++++++++++++++++++++++++
5 files changed, 159 insertions(+), 35 deletions(-)

diff --git a/zlox/src/chunk.zig b/zlox/src/chunk.zig @@ -1,35 +1,51 @@ const std = @import("std"); +const value = @import("value.zig"); +const ValueArray = value.ValueArray; +const RLEArray = @import("rlearray.zig").RLEArray; -pub const OP = enum(u8) { RETURN }; - -fn grow_capacity(capacity: usize) usize { - return if (capacity < 8) 8 else capacity * 2; -} - -fn grow_array(comptime T: type, allocator: std.mem.Allocator, ptr: ?[]T, new_count: usize) ![]T { - return if (ptr == null) - try allocator.alloc(T, new_count) - else - try allocator.reallocAtLeast(ptr.?, new_count); -} +pub const OP = enum(u8) { + CONSTANT, + RETURN, +}; pub const Chunk = struct { - pub fn init(allocator: std.mem.Allocator) Chunk { - return Chunk{ .count = 0, .capacity = 0, .code = null, .allocator = allocator }; + pub fn init(allocator: std.mem.Allocator) !@This() { + const cap = 8; + return @This() { + .count = 0, + .capacity = cap, + .code = try allocator.alloc(u8, cap), + .constants = try ValueArray.init(allocator), + .lines = try RLEArray(u32).init(allocator), + .allocator = allocator + }; } - pub fn write(self: *Chunk, byte: u8) !void { + + pub fn write(self: *@This(), byte: u8, line: u32) !void { if (self.capacity < self.count + 1) { - self.capacity = grow_capacity(self.capacity); - self.code = try grow_array(u8, self.allocator, self.code, self.capacity); + self.capacity = 2 * self.count; + self.code = try self.allocator.realloc(self.code, self.capacity); } - self.code.?[self.count] = byte; + self.code[self.count] = byte; + try self.lines.add(line); self.count += 1; } - pub fn free(self: *Chunk) void { - self.allocator.free(self.code.?); + + pub fn addConstant(self: *@This(), val: value.Value) !u8 { + try self.constants.write(val); + return self.constants.count - 1; + } + + pub fn deinit(self: *@This()) void { + self.constants.deinit(); + self.lines.deinit(); + self.allocator.free(self.code); } + count: usize, capacity: usize, - code: ?[]u8, + code: []u8, + constants: ValueArray, + lines: RLEArray(u32), allocator: std.mem.Allocator, }; diff --git a/zlox/src/debug.zig b/zlox/src/debug.zig @@ -1,29 +1,46 @@ const std = @import("std"); const chunk = @import("chunk.zig"); -const OP = chunk.OP; +const value = @import("value.zig"); +const print = std.debug.print; -pub fn disassembleChunk(ch: chunk.Chunk, name: []const u8) !void { - std.debug.print("== {s} ==\n", .{name}); +pub fn disassembleChunk(ch: chunk.Chunk, name: []const u8) void { + print("== {s} ==\n", .{name}); var offset: usize = 0; + while (offset < ch.count) { - offset = disassembleInstruction(ch.code.?, offset); + offset = disassembleInstruction(ch, offset); } } -pub fn disassembleInstruction(code: []u8, offset: usize) usize { - std.debug.print("{d:0>4} ", .{offset}); +pub fn disassembleInstruction(ch: chunk.Chunk, offset: usize) usize { + const OP = chunk.OP; + print("{d:0>4} ", .{offset}); + if (offset > 0 and ch.lines.get(offset) == ch.lines.get(offset-1)) { + print(" | ", .{}); + } else { + print("{d:4} ", .{ch.lines.get(offset)}); + } - return switch (code[offset]) { + return switch (ch.code[offset]) { @enumToInt(OP.RETURN) => simpleInstruction("OP_RETURN", offset), + @enumToInt(OP.CONSTANT) => constantInstruction("OP_CONSTANT", ch, offset), else => blk: { - std.debug.print("Unknown opcode {}\n", .{code[offset]}); + print("Unknown opcode {}\n", .{ch.code[offset]}); break :blk offset + 1; }, }; } -pub fn simpleInstruction(name: []const u8, offset: usize) usize { - std.debug.print("{s}\n", .{name}); +fn simpleInstruction(name: []const u8, offset: usize) usize { + print("{s}\n", .{name}); return offset + 1; } + +fn constantInstruction(name: []const u8, ch: chunk.Chunk, offset: usize) usize { + const constant = ch.code[offset + 1]; + print("{s:<16} {d:4} '", .{name, constant}); + value.printValue(ch.constants.values[constant]); + print("'\n", .{}); + return offset + 2; +} diff --git a/zlox/src/main.zig b/zlox/src/main.zig @@ -5,9 +5,15 @@ const debug = @import("debug.zig"); pub fn main() anyerror!u8 { var allocator = std.heap.GeneralPurposeAllocator(.{}){}; defer std.debug.assert(!allocator.deinit()); - var ch = chunk.Chunk.init(allocator.allocator()); - try ch.write(@enumToInt(chunk.OP.RETURN)); - try debug.disassembleChunk(ch, "test chunk"); - ch.free(); + var ch = try chunk.Chunk.init(allocator.allocator()); + + const constant = try ch.addConstant(1.2); + try ch.write(@enumToInt(chunk.OP.CONSTANT), 123); + try ch.write(constant, 123); + + try ch.write(@enumToInt(chunk.OP.RETURN), 123); + + debug.disassembleChunk(ch, "test chunk"); + ch.deinit(); return 0; } diff --git a/zlox/src/rlearray.zig b/zlox/src/rlearray.zig @@ -0,0 +1,48 @@ +const std = @import("std"); + +pub fn RLEArray(comptime T: type) type { + return struct { + count: usize, + capacity: usize, + elements: []element, + allocator: std.mem.Allocator, + + const element = struct {val: T, run: usize}; + + pub fn init(allocator: std.mem.Allocator) !@This() { + const cap = 8; + return @This() { + .count = 0, + .capacity = cap, + .elements = try allocator.alloc(element, cap), + .allocator = allocator + }; + } + + pub fn add(self: *@This(), val: T) !void { + if (self.capacity < self.count + 1) { + self.capacity = 2 * self.count; + self.elements = try self.allocator.realloc(self.elements, self.capacity); + } + if (val == self.elements[self.count].val) { + self.elements[self.count].run += 1; + } else { + self.elements[self.count] = .{.val = val, .run = 0}; + self.count += 1; + } + } + + pub fn get(self: *const @This(), idx: usize) T { + var i: usize = 0; + var sum: usize = 0; + while(idx > sum) : (i += 1) { + sum += self.elements[i].run; + } + return self.elements[i].val; + } + + pub fn deinit(self: *@This()) void { + self.allocator.free(self.elements); + } + }; +} diff --git a/zlox/src/value.zig b/zlox/src/value.zig @@ -0,0 +1,37 @@ +const std = @import("std"); + +pub const Value = f64; + +pub fn printValue(value: Value) void { + std.debug.print("{d}", .{value}); +} + +pub const ValueArray = struct { + pub fn init(allocator: std.mem.Allocator) !@This() { + const cap = 8; + return @This() { + .count = 0, + .capacity = cap, + .values = try allocator.alloc(Value, cap), + .allocator = allocator + }; + } + + pub fn write(self: *@This(), byte: Value) !void { + if (self.capacity < self.count + 1) { + self.capacity = 2 * self.count; + self.values = try self.allocator.realloc(self.values, self.capacity); + } + self.values[self.count] = byte; + self.count += 1; + } + + pub fn deinit(self: *@This()) void { + self.allocator.free(self.values); + } + + count: u8, + capacity: u8, + values: []Value, + allocator: std.mem.Allocator, +};