commit a5a57b943bcf842e45dbf99f72e5621e757594e9
parent d029753740ee504e49ac581cf101ea57c3a1534c
Author: Szymon Mikulicz <szymon.mikulicz@posteo.net>
Date: Sat, 22 Oct 2022 18:04:22 +0200
Chunks of bytecode
Diffstat:
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,
+};