DzLox

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

commit 887d23fcc9859fb6ab70003af88f7e4d25a96af1
parent 984223b8bd9855452cdc43920e27261c6b0d680a
Author: Szymon Mikulicz <szymon.mikulicz@posteo.net>
Date:   Tue, 11 Aug 2026 18:47:21 +0200

Update to 0.16

Diffstat:
Mzlox/.gitignore | 1+
Mzlox/build.zig | 33++++++++++++++++++++++++---------
Mzlox/build.zig.zon | 4++--
Mzlox/src/compiler.zig | 6+++---
Mzlox/src/comptime_utils.zig | 49++++++++++++++++++++++++++++++++++---------------
Mzlox/src/debug.zig | 12++++++------
Mzlox/src/gc.zig | 4+++-
Mzlox/src/main.zig | 32+++++++++++++-------------------
Mzlox/src/obj/closure.zig | 17+++++++++--------
Mzlox/src/obj/function.zig | 23++++++++++++++---------
Mzlox/src/obj/list.zig | 33++++++++++++++++++---------------
Mzlox/src/obj/native.zig | 18+++++++++++++-----
Mzlox/src/obj/table.zig | 23++++++++++++-----------
Mzlox/src/obj/upvalue.zig | 13+++++++------
Azlox/src/packed.zig | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mzlox/src/vm.zig | 24++++++++++++------------
Mzlox/src/vm/native.zig | 14++++++--------
17 files changed, 247 insertions(+), 129 deletions(-)

diff --git a/zlox/.gitignore b/zlox/.gitignore @@ -4,3 +4,4 @@ zig-out/ .envrc .tool-versions .zig-cache/ +zig-pkg diff --git a/zlox/build.zig b/zlox/build.zig @@ -15,12 +15,36 @@ pub fn build(b: *std.Build) void { // set a preferred release mode, allowing the user to decide how to optimize. const optimize = b.standardOptimizeOption(.{}); + const linenoise_dep = b.dependency("linenoise", .{ + .target = target, + .optimize = optimize, + }); + + const linenoise_tc = b.addTranslateC(.{ + .root_source_file = linenoise_dep.path("linenoise.h"), + .target = target, + .optimize = optimize, + }); + + const linenoise_mod = linenoise_tc.createModule(); + + linenoise_mod.addCSourceFile(.{ + .file = linenoise_dep.path("linenoise.c"), + .language = .c, + }); + const exe = b.addExecutable(.{ .name = "zlox", .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, + .imports = &.{ + .{ + .name = "linenoise", + .module = linenoise_mod, + }, + }, }), }); @@ -52,15 +76,6 @@ pub fn build(b: *std.Build) void { const run_step = b.step("run", "Run the app"); run_step.dependOn(&run_cmd.step); - const linenoise = b.dependency("linenoise", .{ - .target = target, - .optimize = optimize, - }); - - exe.addCSourceFile(.{ .file = linenoise.path("linenoise.c") }); - exe.addIncludePath(linenoise.path("")); - - exe.linkLibC(); // Creates a step for unit testing. This only builds the test executable // but does not run it. const unit_tests = b.addTest(.{ diff --git a/zlox/build.zig.zon b/zlox/build.zig.zon @@ -16,8 +16,8 @@ // internet connectivity. .dependencies = .{ .linenoise = .{ - .url = "https://github.com/antirez/linenoise/archive/refs/heads/master.tar.gz", - .hash = "1220129271545fccd186dd1ce05c9ee7fb52c97cd86884e70597a0eef254a909e320", + .url = "https://github.com/antirez/linenoise/archive/a473823d74b93eab2ba83480df16ed37617493f2.zip", + .hash = "N-V-__8AAOJ5AgChoMZ8F65t1NdLCUv2YLyHpCZ1ydGIfwbc", }, }, .paths = .{ diff --git a/zlox/src/compiler.zig b/zlox/src/compiler.zig @@ -137,7 +137,7 @@ pub fn Compiler(size: comptime_int) type { } fn currentChunk(self: *Self) *Chunk { - return self.currentFunction.chunk; + return self.currentFunction.chunk.ptr(); } fn emitByte(self: *Self, byte: u8) void { @@ -528,11 +528,11 @@ pub fn Compiler(size: comptime_int) type { self.lastError = err; return; }; - fun.name = self.objects.emplace(Obj.Type.String, &.{name}) catch |err| { + fun.set_name(self.objects.emplace(Obj.Type.String, &.{name}) catch |err| { self.errorAtPrevious("Couldn't allocate function name"); self.lastError = err; return; - }; + }); var compiler = Self.init_enclosed(self, fun); diff --git a/zlox/src/comptime_utils.zig b/zlox/src/comptime_utils.zig @@ -1,9 +1,19 @@ const std = @import("std"); pub fn copy_const(T: type, U: type) type { - comptime var info = @typeInfo(U); - info.pointer.is_const = @typeInfo(T).pointer.is_const; - return @Type(info); + const info = @typeInfo(U).pointer; + return @Pointer( + info.size, + std.builtin.Type.Pointer.Attributes{ + .@"const" = @typeInfo(T).pointer.is_const, + .@"volatile" = info.is_volatile, + .@"allowzero" = info.is_allowzero, + .@"addrspace" = info.address_space, + .@"align" = info.alignment + }, + info.child, + std.builtin.Type.Pointer.sentinel(info) + ); } pub fn typeFromTag(T: type, comptime tag: std.meta.Tag(T)) type { @@ -39,21 +49,30 @@ pub fn if_not_null(comptime fun: anytype) fn (?param_type(fun, 0)) void { } pub fn make_packed_t(s: type) type { - const oldFields = @typeInfo(s).@"struct".fields; - var newFields: [oldFields.len]std.builtin.Type.StructField = undefined; + const info = @typeInfo(s).@"struct"; + const Attributes = std.builtin.Type.StructField.Attributes; - for (oldFields, &newFields) |oldField, *newField| { - newField.* = oldField; - newField.alignment = 0; - newField.is_comptime = false; + const attr = Attributes{ + .@"align" = null, + .@"comptime" = false, + }; + + const attrs = [_]Attributes{attr} ** info.fields.len; + comptime var names: [info.fields.len][]const u8 = undefined; + comptime var types: [info.fields.len]type = undefined; + + inline for (info.fields, 0..) |field, i| { + names[i] = field.name; + types[i] = field.type; } - return @Type(std.builtin.Type{.@"struct" = .{ - .layout = std.builtin.Type.ContainerLayout.@"packed", - .fields = &newFields, - .decls = &[_]std.builtin.Type.Declaration{}, - .is_tuple = false - }}); + return @Struct( + std.builtin.Type.ContainerLayout.@"packed", + info.backing_integer, + &names, + &types, + &attrs + ); } pub fn make_packed(s: anytype) make_packed_t(@TypeOf(s)) { diff --git a/zlox/src/debug.zig b/zlox/src/debug.zig @@ -89,10 +89,10 @@ fn constantInstruction(name: []const u8, ch: *const chunk.Chunk, offset: usize, print("{s:<32} {d:4} '{f}'\n", .{ name, constant, constval}); if (print_fn and constval.is(Obj.Type.Function)) { const function = constval.obj.cast(.Function) catch unreachable; - if (function.name) |str| { - try disassembleChunk(function.chunk, str.slice()); + if (function.name.valid()) { + try disassembleChunk(function.chunk.ptr(), function.name.ptr().slice()); } else { - try disassembleChunk(function.chunk, "<anon>"); + try disassembleChunk(function.chunk.ptr(), "<anon>"); } } @@ -127,10 +127,10 @@ fn closureInstruction(name: []const u8, ch: *const chunk.Chunk, offset: usize, p off += 2; } if (print_fn) { - if (function.name) |str| { - try disassembleChunk(function.chunk, str.slice()); + if (function.name.valid()) { + try disassembleChunk(function.chunk.ptr(), function.name.ptr().slice()); } else { - try disassembleChunk(function.chunk, "<anon>"); + try disassembleChunk(function.chunk.ptr(), "<anon>"); } } diff --git a/zlox/src/gc.zig b/zlox/src/gc.zig @@ -14,6 +14,7 @@ pub const GC = struct { const DBG_LOG = true; allocator: std.mem.Allocator, + io: std.Io, table: Obj.String.Table, list: List, @@ -23,9 +24,10 @@ pub const GC = struct { } } - pub fn init(allocator: std.mem.Allocator) !Self { + pub fn init(allocator: std.mem.Allocator, io: std.Io) !Self { return Self{ .allocator = allocator, + .io = io, .table = Obj.String.Table.init(allocator), .list = List.init(allocator), }; diff --git a/zlox/src/main.zig b/zlox/src/main.zig @@ -1,26 +1,20 @@ const std = @import("std"); const vm = @import("vm.zig"); -const Linenoise = @cImport({ - @cInclude("stddef.h"); - @cInclude("linenoise.h"); -}); +const Linenoise = @import("linenoise"); -pub fn main() anyerror!u8 { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer std.debug.assert(gpa.deinit() == std.heap.Check.ok); +pub fn main(init: std.process.Init) anyerror!u8 { + const allocator = init.gpa; + const io = init.io; - const allocator = gpa.allocator(); - - const args = try std.process.argsAlloc(allocator); - defer std.process.argsFree(allocator, args); + const args = try init.minimal.args.toSlice(init.arena.allocator()); if (args.len == 1) { - try repl(allocator, false); + try repl(allocator, io, false); } else if (args.len == 2) { if (std.mem.eql(u8, args[1], "-d")) { - try repl(allocator, true); + try repl(allocator, io, true); } else { - try runFile(allocator, args[1]); + try runFile(allocator, io, args[1]); } } else { std.debug.print("Usage: {s} [path]\n", .{args[0]}); @@ -30,17 +24,17 @@ pub fn main() anyerror!u8 { return 0; } -pub fn runFile(allocator: std.mem.Allocator, path: []const u8) anyerror!void { - const text = try std.fs.cwd().readFileAlloc(allocator, path, 999999); +pub fn runFile(allocator: std.mem.Allocator, io: std.Io, path: []const u8) anyerror!void { + const text = try std.Io.Dir.cwd().readFileAlloc(io, path, allocator, std.Io.Limit.unlimited); defer allocator.free(text); - var VM = try vm.VM.init(allocator); + var VM = try vm.VM.init(allocator, io); defer VM.deinit(); try VM.interpret(text, false); } -pub fn repl(allocator: std.mem.Allocator, dbg: bool) anyerror!void { - var VM = try vm.VM.init(allocator); +pub fn repl(allocator: std.mem.Allocator, io: std.Io, dbg: bool) anyerror!void { + var VM = try vm.VM.init(allocator, io); defer VM.deinit(); _ = Linenoise.linenoiseHistorySetMaxLen(100); diff --git a/zlox/src/obj/closure.zig b/zlox/src/obj/closure.zig @@ -1,5 +1,6 @@ const std = @import("std"); const utils = @import("../comptime_utils.zig"); +const pack = @import("../packed.zig"); pub fn Closure(fields: anytype) type { const Super = @import("../obj.zig").Obj(fields); @@ -11,19 +12,19 @@ pub fn Closure(fields: anytype) type { pub const Error = error { OutOfMemory }; obj: Super, - function: *const Super.Function, - upvalues: [*]?*Super.Upvalue, + function: pack.Packed(*const Super.Function), + upvalues: pack.Packed([*]?*Super.Upvalue), upvalues_len: u8, pub fn init(arg: Arg, allocator: std.mem.Allocator) Error!*Self { const self: *Self = try allocator.create(Self); self.* = Self{ .obj = Super.make(Self), - .upvalues = (try allocator.alloc(?*Super.Upvalue, arg.upvalue_count)).ptr, + .upvalues = pack.Packed([*]?*Super.Upvalue).init((try allocator.alloc(?*Super.Upvalue, arg.upvalue_count)).ptr), .upvalues_len = arg.upvalue_count, - .function = arg, + .function = pack.Packed(*const Super.Function).init(arg), }; - for(self.upvalues[0..self.upvalues_len]) + for(self.upvalues.ptr()[0..self.upvalues_len]) |*upvalue| upvalue.* = null; return self; } @@ -34,8 +35,8 @@ pub fn Closure(fields: anytype) type { pub fn format(self: *const Self, writer: *std.Io.Writer) !void { _ = try writer.write("<C: "); - if (self.function.name) |name| { - _ = try writer.write(name.slice()); + if (self.function.ptr().name.valid()) { + _ = try writer.write(self.function.ptr().name.ptr().slice()); } else { _ = try writer.write("-"); } @@ -47,7 +48,7 @@ pub fn Closure(fields: anytype) type { } pub fn free(self: *const Self, allocator: std.mem.Allocator) void { - allocator.free(self.upvalues[0..self.upvalues_len]); + allocator.free(self.upvalues.ptr()[0..self.upvalues_len]); allocator.destroy(self); } }; diff --git a/zlox/src/obj/function.zig b/zlox/src/obj/function.zig @@ -1,6 +1,7 @@ const std = @import("std"); const chunk = @import("../chunk.zig"); const utils = @import("../comptime_utils.zig"); +const pack = @import("../packed.zig"); pub fn Function(fields: anytype) type { const Super = @import("../obj.zig").Obj(fields); @@ -18,8 +19,8 @@ pub fn Function(fields: anytype) type { obj: Super, arity: u8, - chunk: *chunk.Chunk, - name: ?*const String, + chunk: pack.Packed(*chunk.Chunk), + name: pack.Packed(?*const String), type: Type, upvalue_count: u8, @@ -27,16 +28,20 @@ pub fn Function(fields: anytype) type { const self: *Self = try allocator.create(Self); self.* = Self{ .obj = Super.make(Self), - .chunk = try allocator.create(chunk.Chunk), + .chunk = try pack.Packed(*chunk.Chunk).new(allocator), .arity = 0, - .name = null, + .name = pack.Packed(?*const String).nil(), .type = tp, .upvalue_count = 0, }; - self.chunk.* = try chunk.Chunk.init(allocator); + self.chunk.ptr().* = try chunk.Chunk.init(allocator); return self; } + pub fn set_name(self: *Self, name: *const String) void { + self.name = pack.Packed(?*const String).init(name); + } + pub fn cast(self: anytype) utils.copy_const(@TypeOf(self), *Super) { return @ptrCast(self); } @@ -46,8 +51,8 @@ pub fn Function(fields: anytype) type { .Function => _ = try writer.write("<F: "), .Script => _ = try writer.write("<S: "), } - if (self.name) |name| { - _ = try writer.write(name.slice()); + if (self.name.valid()) { + _ = try writer.write(self.name.ptr().slice()); } else { _ = try writer.write("-"); } @@ -59,8 +64,8 @@ pub fn Function(fields: anytype) type { } pub fn free(self: *const Self, allocator: std.mem.Allocator) void { - self.chunk.deinit(); - allocator.destroy(self.chunk); + self.chunk.ptr().deinit(); + self.chunk.free(allocator); allocator.destroy(self); } diff --git a/zlox/src/obj/list.zig b/zlox/src/obj/list.zig @@ -2,7 +2,8 @@ const std = @import("std"); const Value = @import("../value.zig").Value; const utils = @import("../comptime_utils.zig"); -const list = @import("../list.zig"); +const list_zig = @import("../list.zig"); +const pack = @import("../packed.zig"); pub fn List(fields: anytype) type { const Super = @import("../obj.zig").Obj(fields); @@ -10,20 +11,20 @@ pub fn List(fields: anytype) type { return packed struct { const Self = @This(); - pub const List = list.List(Value); + pub const List = list_zig.List(Value); pub const Arg = void; pub const Error = error { OutOfMemory, InvalidArgument } || Self.List.Error; obj: Super, - list: *Self.List, + list: pack.Packed(*Self.List), pub fn init(_: Arg, allocator: std.mem.Allocator) Error!*Self { const self: *Self = try allocator.create(Self); self.* = Self{ .obj = Super.make(Self), - .list = try allocator.create(Self.List) + .list = try pack.Packed(*Self.List).new(allocator) }; - self.list.* = Self.List.init(allocator); + self.list.ptr().* = Self.List.init(allocator); return self; } @@ -48,42 +49,44 @@ pub fn List(fields: anytype) type { }; - var printer = Printer{.writer = writer, .count = self.list.len}; + var printer = Printer{.writer = writer, .count = self.list.ptr().len}; _ = try writer.write("["); - try self.list.for_each_try(&printer, Printer.print); + try self.list.ptr().for_each_try(&printer, Printer.print); _ = try writer.writeAll("]"); } pub fn eql(self: *const Self, other: *const Self) bool { - return self.list.eql(other.list, Value.eql); + return self.list.ptr().eql(other.list.ptr(), Value.eql); } pub fn free(self: *Self, allocator: std.mem.Allocator) void { - self.list.free(); - allocator.destroy(self.list); + self.list.ptr().free(); + self.list.free(allocator); allocator.destroy(self); } pub fn delete(self: *Self, index: Value) void { - if (!index.is(Value.number) or index.number >= @as(Value.tagType(Value.number), @floatFromInt(self.list.len)) or index.number < 0) { + var list = self.list.ptr(); + if (!index.is(Value.number) or index.number >= @as(Value.tagType(Value.number), @floatFromInt(list.len)) or index.number < 0) { return; } - self.list.delete(@intFromFloat(index.number)); + list.delete(@intFromFloat(index.number)); } pub fn get(self: *const Self, index: Value) Error!Value { - if (!index.is(Value.number) or index.number >= @as(Value.tagType(Value.number), @floatFromInt(self.list.len)) or index.number < 0) { + var list = self.list.ptr(); + if (!index.is(Value.number) or index.number >= @as(Value.tagType(Value.number), @floatFromInt(list.len)) or index.number < 0) { return Error.InvalidArgument; } - return self.list.get(@intFromFloat(index.number)); + return list.get(@intFromFloat(index.number)); } pub fn set(self: *Self, index: Value, val: Value) Error!void { if (!index.is(Value.number) or index.number < 0) { return Error.InvalidArgument; } - _ = try self.list.set(@intFromFloat(index.number), val); + _ = try self.list.ptr().set(@intFromFloat(index.number), val); } }; } diff --git a/zlox/src/obj/native.zig b/zlox/src/obj/native.zig @@ -3,6 +3,7 @@ const std = @import("std"); const utils = @import("../comptime_utils.zig"); const GC = @import("../gc.zig").GC; const Value = @import("../value.zig").Value; +const pack = @import("../packed.zig"); pub fn Native(fields: anytype) type { const Super = @import("../obj.zig").Obj(fields); @@ -19,20 +20,27 @@ pub fn Native(fields: anytype) type { pub const Arg = struct { fun: Fn, arity_min: u8 = ArityMin, arity_max: u8 = ArityMax, name: []const u8 = "" }; obj: Super, - fun: Fn, + fun: pack.Packed(Fn), arity_min: u8, arity_max: u8, - name: [*]const u8, + name: pack.Packed([*]const u8), name_len: usize, pub fn init(arg: Arg, allocator: std.mem.Allocator) Error!*Self { const self: *Self = try allocator.create(Self); - self.* = Self{ .obj = Super.make(Self), .fun = arg.fun, .arity_min = arg.arity_min, .arity_max = arg.arity_max, .name = arg.name.ptr, .name_len = arg.name.len }; + self.* = Self{ + .obj = Super.make(Self), + .fun = pack.Packed(Fn).init(arg.fun), + .arity_min = arg.arity_min, + .arity_max = arg.arity_max, + .name = pack.Packed([*]const u8).init(arg.name.ptr), + .name_len = arg.name.len + }; return self; } pub fn call(self: *const Self, gc: *GC, argCount: u8, args: [*]Value) Error!Value { - const callable = self.fun; // Compiler bug: https://github.com/ziglang/zig/issues/20539 + const callable = self.fun.ptr(); return callable(gc, args[0..argCount]); } @@ -42,7 +50,7 @@ pub fn Native(fields: anytype) type { pub fn format(self: *const Self, writer: *std.Io.Writer) !void { _ = try writer.write("<N: "); - _ = try writer.write(self.name[0..self.name_len]); + _ = try writer.write(self.name.ptr()[0..self.name_len]); _ = try writer.writeAll(">"); } diff --git a/zlox/src/obj/table.zig b/zlox/src/obj/table.zig @@ -3,6 +3,7 @@ const table = @import("../table.zig"); const hash = @import("../hash.zig"); const Value = @import("../value.zig").Value; const utils = @import("../comptime_utils.zig"); +const pack = @import("../packed.zig"); pub fn Table(fields: anytype) type { const Super = @import("../obj.zig").Obj(fields); @@ -14,17 +15,17 @@ pub fn Table(fields: anytype) type { pub const Error = error { OutOfMemory } || Self.Table.Error; obj: Super, - table: *Self.Table, + table: pack.Packed(*Self.Table), len: usize, pub fn init(_: Arg, allocator: std.mem.Allocator) Error!*Self { const self: *Self = try allocator.create(Self); self.* = Self{ .obj = Super.make(Self), - .table = try allocator.create(Self.Table), + .table = try pack.Packed(*Self.Table).new(allocator), .len = 0, }; - self.table.* = Self.Table.init(allocator); + self.table.ptr().* = Self.Table.init(allocator); return self; } @@ -34,15 +35,15 @@ pub fn Table(fields: anytype) type { pub fn set(self: *Self, key: Value, val: Value) Error!bool { self.len += 1; - return self.table.set(key, val); + return self.table.ptr().set(key, val); } pub fn get(self: *Self, key: Value) Error!Value { - return self.table.get(key); + return self.table.ptr().get(key); } pub fn delete(self: *Self, key: Value) void { - if (self.table.delete(key)) self.len -= 1; + if (self.table.ptr().delete(key)) self.len -= 1; } pub fn format(self: *const Self, writer: *std.Io.Writer) !void { @@ -63,8 +64,8 @@ pub fn Table(fields: anytype) type { var printer = Printer{.writer = writer, .count = self.len}; _ = try writer.write("["); - if (self.table.count > 0) { - try self.table.for_each_try(&printer, Printer.print); + if (self.table.ptr().count > 0) { + try self.table.ptr().for_each_try(&printer, Printer.print); } else { _ = try writer.write(":"); } @@ -72,12 +73,12 @@ pub fn Table(fields: anytype) type { } pub fn eql(self: *const Self, other: *const Self) bool { - return self.table.eql(other.table, Value.eql); + return self.table.ptr().eql(other.table.ptr(), Value.eql); } pub fn free(self: *const Self, allocator: std.mem.Allocator) void { - self.table.deinit(); - allocator.destroy(self.table); + self.table.ptr().deinit(); + self.table.free(allocator); allocator.destroy(self); } }; diff --git a/zlox/src/obj/upvalue.zig b/zlox/src/obj/upvalue.zig @@ -2,6 +2,7 @@ const std = @import("std"); const utils = @import("../comptime_utils.zig"); const Value = @import("../value.zig").Value; +const pack = @import("../packed.zig"); pub fn Upvalue(fields: anytype) type { const Super = @import("../obj.zig").Obj(fields); @@ -13,7 +14,7 @@ pub fn Upvalue(fields: anytype) type { pub const Error = error { OutOfMemory }; obj: Super, - location: *Value, + location: pack.Packed(*Value), closed: bool, slot: u8, @@ -21,7 +22,7 @@ pub fn Upvalue(fields: anytype) type { const self: *Self = try allocator.create(Self); self.* = Self{ .obj = Super.make(Self), - .location = arg.val, + .location = pack.Packed(*Value).init(arg.val), .closed = false, .slot = arg.slot }; @@ -31,8 +32,8 @@ pub fn Upvalue(fields: anytype) type { pub fn close(self: *Self, allocator: std.mem.Allocator) Error!void { if (!self.closed) { const new = try allocator.create(Value); - new.* = self.location.*; - self.location = new; + new.* = self.location.ptr().*; + self.location = pack.Packed(*Value).init(new); self.closed = true; } } @@ -43,7 +44,7 @@ pub fn Upvalue(fields: anytype) type { } pub fn format(self: *const Self, writer: *std.Io.Writer) !void { - try writer.print("<Upvalue{{{f} at 0x{x}, {any}, {d}}}>", .{self.location.*, @intFromPtr(self.location), self.closed, self.slot}); + try writer.print("<Upvalue{{{f} at 0x{x}, {any}, {d}}}>", .{self.location.ptr().*, self.location._ptr, self.closed, self.slot}); } pub fn eql(_: *const Self, _: *const Self) bool { @@ -51,7 +52,7 @@ pub fn Upvalue(fields: anytype) type { } pub fn free(self: *const Self, allocator: std.mem.Allocator) void { - if (self.closed) allocator.destroy(self.location); + if (self.closed) allocator.destroy(self.location.ptr()); allocator.destroy(self); } }; diff --git a/zlox/src/packed.zig b/zlox/src/packed.zig @@ -0,0 +1,70 @@ +const std = @import("std"); + +fn is_type(T: type, comptime name: []const u8) bool { + return @as(std.meta.Tag(std.builtin.Type), @typeInfo(T)) == @field(std.meta.Tag(std.builtin.Type), name); +} + +pub fn Packed(T: type) type { + comptime var _Type = T; + comptime var _Ptr =T; + + const _optional = is_type(_Type, "optional"); + if (_optional) { + _Type = @typeInfo(_Type).optional.child; + } + + const _pointer = is_type(_Type, "pointer"); + if (_pointer) { + _Ptr = _Type; + _Type = @typeInfo(_Type).pointer.child; + } else { + @compileError("Expected pointer type, got " ++ @typeName(_Type)); + } + + return packed struct { + const pointer = _pointer; + const optional = _optional; + const Type = _Type; + const Ptr = _Ptr; + + const Self = @This(); + + _ptr: usize, + + pub fn new(allocator: std.mem.Allocator) !Self { + return Self.init(try allocator.create(Type)); + } + + pub fn init(arg: Ptr) Self { + return Self{ + ._ptr = @intFromPtr(arg), + }; + } + + pub fn nil() Self { + if (!optional) { + @compileError("Cannot create nil for non-optional type"); + } + + return Self{ + ._ptr = 0, + }; + } + + pub fn valid(self: Self) bool { + return !optional or self._ptr != 0; + } + + pub fn ptr(self: Self) Ptr { + if (self.valid()) { + return @ptrFromInt(self._ptr); + } else { + @panic("Attempt to access null pointer"); + } + } + + pub fn free(self: Self, allocator: std.mem.Allocator) void { + allocator.destroy(self.ptr()); + } + }; +} diff --git a/zlox/src/vm.zig b/zlox/src/vm.zig @@ -55,8 +55,8 @@ pub const VM = struct { pub fn init(comptime tp: Obj.Type, callee: *const tp.get(), slots: [*]Value) @This() { return switch (tp) { - .Function => @This(){ .callee = callee.cast(), .ip = callee.chunk.code.data.ptr, .chunk = callee.chunk, .slots = slots }, - .Closure => @This(){ .callee = callee.cast(), .ip = callee.function.chunk.code.data.ptr, .chunk = callee.function.chunk, .slots = slots }, + .Function => @This(){ .callee = callee.cast(), .ip = callee.chunk.ptr().code.data.ptr, .chunk = callee.chunk.ptr(), .slots = slots }, + .Closure => @This(){ .callee = callee.cast(), .ip = callee.function.ptr().chunk.ptr().code.data.ptr, .chunk = callee.function.ptr().chunk.ptr(), .slots = slots }, else => @compileError("Invalid type"), }; } @@ -68,15 +68,15 @@ pub const VM = struct { _ = try self.globals.set(nameObj, Global.make_con(Value.init(funObj))); } - pub fn init(allocator: std.mem.Allocator) !@This() { - var self = @This(){ .globals = Globals.init(allocator), .objects = try GC.init(allocator), .allocator = allocator }; + pub fn init(allocator: std.mem.Allocator, io: std.Io) !@This() { + var self = @This(){ .globals = Globals.init(allocator), .objects = try GC.init(allocator, io), .allocator = allocator }; try self.defineNative("clock", 0, 0, vm_native.Clock.clock); try self.defineNative("put", 1, 1, vm_native.put); try self.defineNative("table", 0, Obj.Native.ArityMax, vm_native.table); try self.defineNative("list", 0, Obj.Native.ArityMax, vm_native.list); - try vm_native.Clock.set_start(); + vm_native.Clock.set_start(io); return self; } @@ -87,7 +87,7 @@ pub const VM = struct { const function = try compiler.Compiler(stack_size).compile(source, &self.objects); - if (dbg) try debug.disassembleChunk(function.chunk, "Main"); + if (dbg) try debug.disassembleChunk(function.chunk.ptr(), "Main"); try Interpreter(callstack_size, stack_size).run(self, function, dbg); } @@ -178,8 +178,8 @@ pub const VM = struct { } fn callClosure(self: *@This(), callee: *Obj.Closure, argCount: u8) !void { - if (argCount != callee.function.arity) { - self.runtimeError("Expected {d} arguments but got {d}", .{ callee.function.arity, argCount }); + if (argCount != callee.function.ptr().arity) { + self.runtimeError("Expected {d} arguments but got {d}", .{ callee.function.ptr().arity, argCount }); return InterpreterError.RuntimeError; } if (self.frameCount == callstack_size - 1) @@ -338,12 +338,12 @@ pub const VM = struct { @intFromEnum(OP.GET_UPVALUE) => { const closure = try self.frame().callee.cast(.Closure); const index = self.read_byte(); - self.push(closure.upvalues[index].?.location.*); + self.push(closure.upvalues.ptr()[index].?.location.ptr().*); }, @intFromEnum(OP.SET_UPVALUE) => { const closure = try self.frame().callee.cast(.Closure); const index = self.read_byte(); - closure.upvalues[index].?.location.* = self.peek(0); + closure.upvalues.ptr()[index].?.location.ptr().* = self.peek(0); }, @intFromEnum(OP.CLOSE_UPVALUE) => { try self.closeUpvalues(self.current_slot()); @@ -399,14 +399,14 @@ pub const VM = struct { @intFromEnum(OP.CLOSURE) => { const function = try self.read_constant().obj.cast(.Function); const closure = try self.vm.objects.emplace(.Closure, function); - for (closure.upvalues[0..closure.upvalues_len]) |*upvalue| { + for (closure.upvalues.ptr()[0..closure.upvalues_len]) |*upvalue| { const isLocal = self.read_byte(); const slot = self.read_byte(); if (isLocal == 1) { upvalue.* = try self.captureUpvalue(slot); } else { const callee = try self.frame().callee.cast(.Closure); - upvalue.* = callee.upvalues[slot]; + upvalue.* = callee.upvalues.ptr()[slot]; } } self.push(Value.init(closure.cast())); diff --git a/zlox/src/vm/native.zig b/zlox/src/vm/native.zig @@ -5,16 +5,14 @@ const Value = @import("../value.zig").Value; pub const Error = GC.Obj.Native.Error; pub const Clock = struct { - var start: std.time.Instant = undefined; + var start: std.Io.Timestamp = undefined; - pub fn set_start() !void { - start = try std.time.Instant.now(); + pub fn set_start(io: std.Io) void { + start = std.Io.Timestamp.now(io, std.Io.Clock.awake); } - pub fn clock(_: *GC, _: []const Value) Error!Value { - const now = std.time.Instant.now() catch return Error.Native; - const elapsed: f64 = @floatFromInt(now.since(start)); - return Value.init(elapsed / std.time.ns_per_s); + pub fn clock(gc: *GC, _: []const Value) Error!Value { + return Value.init(@as(f64, @floatFromInt(std.Io.Timestamp.untilNow(start, gc.io, std.Io.Clock.awake).toSeconds()))); } }; @@ -36,7 +34,7 @@ pub fn table(gc: *GC, args: []const Value) Error!Value { pub fn list(gc: *GC, args: []const Value) Error!Value { var lis = gc.emplace(.List, {}) catch return Error.Native; for (args) |arg| { - lis.list.push(arg) catch return Error.Native; + lis.list.ptr().push(arg) catch return Error.Native; } return Value.init(lis.cast()); }