commit 310d12bb78444322e65394cdeed765c4b6b8657c
parent 887d23fcc9859fb6ab70003af88f7e4d25a96af1
Author: Szymon Mikulicz <szymon.mikulicz@posteo.net>
Date: Mon, 17 Aug 2026 14:18:21 +0200
Zig 0.16 is horribly broken, so back to master
Diffstat:
13 files changed, 249 insertions(+), 195 deletions(-)
diff --git a/zlox/build.zig b/zlox/build.zig
@@ -66,9 +66,7 @@ pub fn build(b: *std.Build) void {
// This allows the user to pass arguments to the application in the build
// command itself, like this: `zig build run -- arg1 arg2 etc`
- if (b.args) |args| {
- run_cmd.addArgs(args);
- }
+ run_cmd.addPassthruArgs();
// This creates a build step. It will be visible in the `zig build --help` menu,
// and can be selected like this: `zig build run`
diff --git a/zlox/src/compiler.zig b/zlox/src/compiler.zig
@@ -9,6 +9,7 @@ const Obj = GC.Obj;
const debug = @import("debug.zig");
const Token = scanner.TokenType;
const vm_native = @import("vm/native.zig");
+const utils = @import("comptime_utils.zig");
pub const CompilerError = Obj.Error || scanner.ScannerError || Chunk.Error || Value.ParseNumberError || error{ UnexpectedToken, NotAnExpression };
@@ -78,7 +79,7 @@ pub fn Compiler(size: comptime_int) type {
};
const rules = init: {
- var new: [@typeInfo(Token).@"enum".fields.len]ParseRule = undefined;
+ var new: [utils.enum_len(Token)]ParseRule = undefined;
for (&new, 0..) |*v, i| {
const T = Token;
const S = Self;
@@ -952,11 +953,11 @@ pub fn Compiler(size: comptime_int) type {
.lastError = scanner.ScannerError.EmptyToken,
.currentFunction = fun,
.objects = objects,
- .locals = [_]Local{Local{}} ** size,
+ .locals = @splat(Local{}),
.localCount = 1,
.scopeDepth = 0,
.enclosing = null,
- .upvalues = [_]Upvalue{Upvalue{ .index = 0, .isLocal = false }} ** upvalues_size,
+ .upvalues = @splat(Upvalue{ .index = 0, .isLocal = false }),
};
self.locals[0].depth = 0;
return self;
diff --git a/zlox/src/comptime_utils.zig b/zlox/src/comptime_utils.zig
@@ -1,30 +1,47 @@
const std = @import("std");
+pub fn with_size(T: type, comptime size: std.builtin.Type.Pointer.Size) type {
+ return mod_ptr_t(T, "size", size);
+}
+
pub fn copy_const(T: type, U: type) type {
- const info = @typeInfo(U).pointer;
+ return mod_ptr_t(U, "const", @typeInfo(T).pointer.attrs.@"const");
+}
+
+pub fn mod_ptr_t(T: type, comptime field: []const u8, comptime val: anytype) type {
+ comptime var new = @typeInfo(T).pointer;
+
+ if (@hasField(std.lang.Type.Pointer.Attributes, field)) {
+ @field(new.attrs, field) = val;
+ } else {
+ @field(new, field) = val;
+ }
+
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)
+ new.size,
+ new.attrs,
+ new.child,
+ std.lang.Type.Pointer.sentinel(new),
);
}
+pub fn enum_len(T: type) usize {
+ return @typeInfo(T).@"enum".field_names.len;
+}
+
+pub 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 typeFromTag(T: type, comptime tag: std.meta.Tag(T)) type {
return @TypeOf(@field(@unionInit(T, @tagName(tag), undefined), @tagName(tag)));
-
}
pub fn tagFromType(T: type, U: type) std.meta.Tag(T) {
- inline for (@typeInfo(T).@"union".fields) |field| {
- if (U == field.type) {
- return @field(T, field.name);
+ const info = @typeInfo(T).@"union";
+ inline for (info.field_types, info.field_names) |field_type, field_name| {
+ if (U == field_type) {
+ return @field(T, field_name);
}
}
@compileError("No matching tag for type " ++ @typeName(U) ++ " in Union " ++ @typeName(T));
@@ -48,41 +65,33 @@ pub fn if_not_null(comptime fun: anytype) fn (?param_type(fun, 0)) void {
}.function;
}
-pub fn make_packed_t(s: type) type {
+pub fn pack_t(s: type) type {
const info = @typeInfo(s).@"struct";
- const Attributes = std.builtin.Type.StructField.Attributes;
-
- 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;
- }
+ const Attributes = std.lang.Type.Struct.FieldAttributes;
return @Struct(
- std.builtin.Type.ContainerLayout.@"packed",
+ std.lang.Type.ContainerLayout.@"packed",
info.backing_integer,
- &names,
- &types,
- &attrs
+ info.field_names,
+ info.field_types,
+ &@as(
+ [info.field_attrs.len]Attributes,
+ @splat(Attributes{
+ .@"align" = null,
+ .@"comptime" = false,
+ }),
+ ),
);
}
-pub fn make_packed(s: anytype) make_packed_t(@TypeOf(s)) {
+pub fn pack(s: anytype) pack_t(@TypeOf(s)) {
const T = @TypeOf(s);
- const fields = @typeInfo(T).@"struct".fields;
- var packd: make_packed_t(T) = undefined;
+ const fields = @typeInfo(T).@"struct".field_names;
+ var packed_struct: pack_t(T) = undefined;
- for (fields) |field| {
- @field(packd, field.name) = @field(s, field.name);
+ inline for (fields) |field| {
+ @field(packed_struct, field) = @field(s, field);
}
- return packd;
+ return packed_struct;
}
diff --git a/zlox/src/debug.zig b/zlox/src/debug.zig
@@ -68,11 +68,11 @@ fn _disassembleInstruction(ch: *const chunk.Chunk, offset: usize, print_fn: bool
@intFromEnum(OP.LOOP) => try jumpInstruction(name, false, ch, offset),
@intFromEnum(OP.SET_INDEX) => simpleInstruction(name, offset),
@intFromEnum(OP.GET_INDEX) => simpleInstruction(name, offset),
- @intFromEnum(OP.CALL) => try byteInstruction(name, ch, offset),
+ @intFromEnum(OP.CALL) => try byteInstruction(name, ch, offset),
@intFromEnum(OP.CLOSURE) => try closureInstruction(name, ch, offset, print_fn),
@intFromEnum(OP.CLOSE_UPVALUE) => simpleInstruction(name, offset),
else => blk: {
- print("Unknown opcode {d} {s}\n", .{op, name});
+ print("Unknown opcode {d} {s}\n", .{ op, name });
break :blk offset + 1;
},
};
@@ -86,21 +86,20 @@ fn simpleInstruction(name: []const u8, offset: usize) usize {
fn constantInstruction(name: []const u8, ch: *const chunk.Chunk, offset: usize, print_fn: bool) Error!usize {
const constant = try ch.code.get(offset + 1);
const constval = try ch.constants.get(constant);
- print("{s:<32} {d:4} '{f}'\n", .{ name, constant, constval});
+ 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.valid()) {
- try disassembleChunk(function.chunk.ptr(), function.name.ptr().slice());
+ if (function.name.get()) |fn_name| {
+ try disassembleChunk(function.chunk.ptr(), fn_name.slice());
} else {
try disassembleChunk(function.chunk.ptr(), "<anon>");
}
-
}
return offset + 2;
}
-fn byteInstruction(name: []const u8, ch:*const chunk.Chunk, offset: usize) Error!usize {
- print("{s:<32} {d:4}\n", .{name, try ch.code.get(offset+1)});
+fn byteInstruction(name: []const u8, ch: *const chunk.Chunk, offset: usize) Error!usize {
+ print("{s:<32} {d:4}\n", .{ name, try ch.code.get(offset + 1) });
return offset + 2;
}
@@ -109,7 +108,7 @@ fn jumpInstruction(name: []const u8, sign: bool, ch: *const chunk.Chunk, offset:
const lsb: u16 = try ch.code.get(offset + 2);
const jump = (msb << 8) | lsb;
- print("{s:<32} {d:4} -> {d}\n", .{name, offset, if (sign) offset + 3 + jump else offset + 3 - jump});
+ print("{s:<32} {d:4} -> {d}\n", .{ name, offset, if (sign) offset + 3 + jump else offset + 3 - jump });
return offset + 3;
}
@@ -118,21 +117,21 @@ fn closureInstruction(name: []const u8, ch: *const chunk.Chunk, offset: usize, p
const constant = try ch.code.get(off);
const val = try ch.constants.get(constant);
const function = try val.obj.cast(.Function);
- print("{s:<32} {d:4} '{f}'\n", .{ name, constant, function});
+ print("{s:<32} {d:4} '{f}'\n", .{ name, constant, function });
for (0..function.upvalue_count) |_| {
const isLocal = try ch.code.get(off + 1);
const idx = try ch.code.get(off + 2);
try print_offset(ch, off + 1);
- print("{s:<38}|-> {s} {d}\n", .{ "", if (isLocal == 1) "local" else "upvalue", idx});
+ print("{s:<38}|-> {s} {d}\n", .{ "", if (isLocal == 1) "local" else "upvalue", idx });
off += 2;
}
if (print_fn) {
- if (function.name.valid()) {
- try disassembleChunk(function.chunk.ptr(), function.name.ptr().slice());
+ if (function.name.get()) |fn_name| {
+ try disassembleChunk(function.chunk.ptr(), fn_name.slice());
} else {
try disassembleChunk(function.chunk.ptr(), "<anon>");
}
}
-
+
return off + 1;
}
diff --git a/zlox/src/obj.zig b/zlox/src/obj.zig
@@ -3,7 +3,7 @@ const utils = @import("comptime_utils.zig");
fn nameOf(fqn: []const u8) []const u8 {
var lastDot = 0;
- for(fqn, 0..) |c, i| {
+ for (fqn, 0..) |c, i| {
if (c == '.') lastDot = i + 1;
if (c == '(') return fqn[lastDot..i];
}
@@ -15,7 +15,7 @@ pub fn Obj(fields: anytype) type {
const Self = @This();
type: Type,
- fields: utils.make_packed_t(@TypeOf(fields)) = utils.make_packed(fields),
+ fields: utils.pack_t(@TypeOf(fields)) = utils.pack(fields),
pub const List = @import("obj/list.zig").List(fields);
pub const String = @import("obj/string.zig").String(fields);
@@ -25,15 +25,7 @@ pub fn Obj(fields: anytype) type {
pub const Closure = @import("obj/closure.zig").Closure(fields);
pub const Upvalue = @import("obj/upvalue.zig").Upvalue(fields);
- pub const Error = error {IllegalCastError}
- || List.Error
- || String.Error
- || Table.Error
- || Function.Error
- || Native.Error
- || List.Error
- || Closure.Error
- || Upvalue.Error;
+ pub const Error = error{IllegalCastError} || List.Error || String.Error || Table.Error || Function.Error || Native.Error || List.Error || Closure.Error || Upvalue.Error;
pub const Type = enum(u8) {
String,
@@ -50,7 +42,7 @@ pub fn Obj(fields: anytype) type {
};
pub fn isChild(T: type) bool {
- inline for(@typeInfo(Type).@"enum".fields) |field| {
+ inline for (@typeInfo(Type).@"enum".fields) |field| {
const U = @field(Self, field.name);
if (T == U or T == *U or T == *const U) return true;
}
@@ -58,7 +50,7 @@ pub fn Obj(fields: anytype) type {
}
pub fn make(child: type) Self {
- return Self {
+ return Self{
.type = @field(Type, nameOf(@typeName(child))),
};
}
diff --git a/zlox/src/obj/closure.zig b/zlox/src/obj/closure.zig
@@ -1,6 +1,6 @@
const std = @import("std");
const utils = @import("../comptime_utils.zig");
-const pack = @import("../packed.zig");
+const Packed = @import("../packed.zig").Packed;
pub fn Closure(fields: anytype) type {
const Super = @import("../obj.zig").Obj(fields);
@@ -9,23 +9,20 @@ pub fn Closure(fields: anytype) type {
const Self = @This();
pub const Arg = *const Super.Function;
- pub const Error = error { OutOfMemory };
+ pub const Error = error{OutOfMemory};
obj: Super,
- function: pack.Packed(*const Super.Function),
- upvalues: pack.Packed([*]?*Super.Upvalue),
- upvalues_len: u8,
+ function: Packed(*const Super.Function),
+ upvalues: Packed([]?*Super.Upvalue),
pub fn init(arg: Arg, allocator: std.mem.Allocator) Error!*Self {
const self: *Self = try allocator.create(Self);
- self.* = Self{
+ self.* = Self{
.obj = Super.make(Self),
- .upvalues = pack.Packed([*]?*Super.Upvalue).init((try allocator.alloc(?*Super.Upvalue, arg.upvalue_count)).ptr),
- .upvalues_len = arg.upvalue_count,
- .function = pack.Packed(*const Super.Function).init(arg),
+ .upvalues = try Packed([]?*Super.Upvalue).alloc(allocator, arg.upvalue_count),
+ .function = Packed(*const Super.Function).init(arg),
};
- for(self.upvalues.ptr()[0..self.upvalues_len])
- |*upvalue| upvalue.* = null;
+ for (self.upvalues.ptr()) |*upvalue| upvalue.* = null;
return self;
}
@@ -35,8 +32,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.ptr().name.valid()) {
- _ = try writer.write(self.function.ptr().name.ptr().slice());
+ if (self.function.ptr().name.get()) |fn_name| {
+ _ = try writer.write(fn_name.slice());
} else {
_ = try writer.write("-");
}
@@ -48,7 +45,7 @@ pub fn Closure(fields: anytype) type {
}
pub fn free(self: *const Self, allocator: std.mem.Allocator) void {
- allocator.free(self.upvalues.ptr()[0..self.upvalues_len]);
+ self.upvalues.destroy(allocator);
allocator.destroy(self);
}
};
diff --git a/zlox/src/obj/function.zig b/zlox/src/obj/function.zig
@@ -1,7 +1,7 @@
const std = @import("std");
const chunk = @import("../chunk.zig");
const utils = @import("../comptime_utils.zig");
-const pack = @import("../packed.zig");
+const Packed = @import("../packed.zig").Packed;
pub fn Function(fields: anytype) type {
const Super = @import("../obj.zig").Obj(fields);
@@ -10,36 +10,33 @@ pub fn Function(fields: anytype) type {
return packed struct {
const Self = @This();
pub const Arg = Type;
- pub const Error = error { OutOfMemory };
+ pub const Error = error{OutOfMemory};
- pub const Type = enum(u8) {
- Function,
- Script
- };
+ pub const Type = enum(u8) { Function, Script };
obj: Super,
arity: u8,
- chunk: pack.Packed(*chunk.Chunk),
- name: pack.Packed(?*const String),
+ chunk: Packed(*chunk.Chunk),
+ name: Packed(?*const String),
type: Type,
upvalue_count: u8,
pub fn init(tp: Arg, allocator: std.mem.Allocator) Error!*Self {
const self: *Self = try allocator.create(Self);
- self.* = Self{
+ self.* = Self{
.obj = Super.make(Self),
- .chunk = try pack.Packed(*chunk.Chunk).new(allocator),
+ .chunk = try Packed(*chunk.Chunk).create(allocator),
.arity = 0,
- .name = pack.Packed(?*const String).nil(),
+ .name = Packed(?*const String).init(null),
.type = tp,
.upvalue_count = 0,
};
- self.chunk.ptr().* = try chunk.Chunk.init(allocator);
+ self.chunk.set(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);
+ self.name = Packed(?*const String).init(name);
}
pub fn cast(self: anytype) utils.copy_const(@TypeOf(self), *Super) {
@@ -47,12 +44,12 @@ pub fn Function(fields: anytype) type {
}
pub fn format(self: *const Self, writer: *std.Io.Writer) !void {
- switch(self.type) {
+ switch (self.type) {
.Function => _ = try writer.write("<F: "),
.Script => _ = try writer.write("<S: "),
}
- if (self.name.valid()) {
- _ = try writer.write(self.name.ptr().slice());
+ if (self.name.get()) |name| {
+ _ = try writer.write(name.slice());
} else {
_ = try writer.write("-");
}
@@ -65,9 +62,8 @@ pub fn Function(fields: anytype) type {
pub fn free(self: *const Self, allocator: std.mem.Allocator) void {
self.chunk.ptr().deinit();
- self.chunk.free(allocator);
+ self.chunk.destroy(allocator);
allocator.destroy(self);
}
-
};
}
diff --git a/zlox/src/obj/list.zig b/zlox/src/obj/list.zig
@@ -3,7 +3,7 @@ const std = @import("std");
const Value = @import("../value.zig").Value;
const utils = @import("../comptime_utils.zig");
const list_zig = @import("../list.zig");
-const pack = @import("../packed.zig");
+const Packed = @import("../packed.zig").Packed;
pub fn List(fields: anytype) type {
const Super = @import("../obj.zig").Obj(fields);
@@ -13,18 +13,18 @@ pub fn List(fields: anytype) type {
pub const List = list_zig.List(Value);
pub const Arg = void;
- pub const Error = error { OutOfMemory, InvalidArgument } || Self.List.Error;
+ pub const Error = error{ OutOfMemory, InvalidArgument } || Self.List.Error;
obj: Super,
- list: pack.Packed(*Self.List),
+ list: Packed(*Self.List),
pub fn init(_: Arg, allocator: std.mem.Allocator) Error!*Self {
const self: *Self = try allocator.create(Self);
- self.* = Self{
+ self.* = Self{
.obj = Super.make(Self),
- .list = try pack.Packed(*Self.List).new(allocator)
+ .list = try Packed(*Self.List).create(allocator),
};
- self.list.ptr().* = Self.List.init(allocator);
+ self.list.set(Self.List.init(allocator));
return self;
}
@@ -46,10 +46,9 @@ pub fn List(fields: anytype) type {
}
if (this.count > 0) _ = try this.writer.write(", ");
}
-
};
- var printer = Printer{.writer = writer, .count = self.list.ptr().len};
+ var printer = Printer{ .writer = writer, .count = self.list.ptr().len };
_ = try writer.write("[");
try self.list.ptr().for_each_try(&printer, Printer.print);
@@ -62,7 +61,7 @@ pub fn List(fields: anytype) type {
pub fn free(self: *Self, allocator: std.mem.Allocator) void {
self.list.ptr().free();
- self.list.free(allocator);
+ self.list.destroy(allocator);
allocator.destroy(self);
}
diff --git a/zlox/src/obj/native.zig b/zlox/src/obj/native.zig
@@ -3,7 +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");
+const Packed = @import("../packed.zig").Packed;
pub fn Native(fields: anytype) type {
const Super = @import("../obj.zig").Obj(fields);
@@ -20,21 +20,19 @@ 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: pack.Packed(Fn),
+ fun: Packed(Fn),
arity_min: u8,
arity_max: u8,
- name: pack.Packed([*]const u8),
- name_len: usize,
+ name: Packed([]const 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),
- .fun = pack.Packed(Fn).init(arg.fun),
+ .fun = 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
+ .name = Packed([]const u8).init(arg.name),
};
return self;
}
@@ -50,7 +48,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.ptr()[0..self.name_len]);
+ _ = try writer.write(self.name.ptr());
_ = try writer.writeAll(">");
}
diff --git a/zlox/src/obj/table.zig b/zlox/src/obj/table.zig
@@ -3,7 +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");
+const Packed = @import("../packed.zig").Packed;
pub fn Table(fields: anytype) type {
const Super = @import("../obj.zig").Obj(fields);
@@ -12,20 +12,20 @@ pub fn Table(fields: anytype) type {
const Self = @This();
pub const Arg = void;
const Table = table.Table(Value, Value, hash.hash_t(Value), Value.eql);
- pub const Error = error { OutOfMemory } || Self.Table.Error;
+ pub const Error = error{OutOfMemory} || Self.Table.Error;
obj: Super,
- table: pack.Packed(*Self.Table),
+ table: Packed(*Self.Table),
len: usize,
pub fn init(_: Arg, allocator: std.mem.Allocator) Error!*Self {
const self: *Self = try allocator.create(Self);
- self.* = Self{
+ self.* = Self{
.obj = Super.make(Self),
- .table = try pack.Packed(*Self.Table).new(allocator),
+ .table = try Packed(*Self.Table).create(allocator),
.len = 0,
};
- self.table.ptr().* = Self.Table.init(allocator);
+ self.table.set(Self.Table.init(allocator));
return self;
}
@@ -59,10 +59,9 @@ pub fn Table(fields: anytype) type {
try val.format(this.writer);
if (this.count > 0) _ = try this.writer.write(", ");
}
-
};
- var printer = Printer{.writer = writer, .count = self.len};
+ var printer = Printer{ .writer = writer, .count = self.len };
_ = try writer.write("[");
if (self.table.ptr().count > 0) {
try self.table.ptr().for_each_try(&printer, Printer.print);
@@ -78,7 +77,7 @@ pub fn Table(fields: anytype) type {
pub fn free(self: *const Self, allocator: std.mem.Allocator) void {
self.table.ptr().deinit();
- self.table.free(allocator);
+ self.table.destroy(allocator);
allocator.destroy(self);
}
};
diff --git a/zlox/src/obj/upvalue.zig b/zlox/src/obj/upvalue.zig
@@ -2,7 +2,7 @@ const std = @import("std");
const utils = @import("../comptime_utils.zig");
const Value = @import("../value.zig").Value;
-const pack = @import("../packed.zig");
+const Packed = @import("../packed.zig").Packed;
pub fn Upvalue(fields: anytype) type {
const Super = @import("../obj.zig").Obj(fields);
@@ -10,41 +10,36 @@ pub fn Upvalue(fields: anytype) type {
return packed struct {
const Self = @This();
- pub const Arg = struct {val: *Value, slot: u8};
- pub const Error = error { OutOfMemory };
+ pub const Arg = struct { val: *Value, slot: u8 };
+ pub const Error = error{OutOfMemory};
obj: Super,
- location: pack.Packed(*Value),
+ location: Packed(*Value),
closed: bool,
slot: 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),
- .location = pack.Packed(*Value).init(arg.val),
- .closed = false,
- .slot = arg.slot
- };
+ self.* = Self{ .obj = Super.make(Self), .location = Packed(*Value).init(arg.val), .closed = false, .slot = arg.slot };
return self;
}
pub fn close(self: *Self, allocator: std.mem.Allocator) Error!void {
if (!self.closed) {
- const new = try allocator.create(Value);
- new.* = self.location.ptr().*;
- self.location = pack.Packed(*Value).init(new);
+ const old = self.location.get();
+
+ self.location = try Packed(*Value).create(allocator);
+ self.location.set(old);
self.closed = true;
}
}
-
pub fn cast(self: anytype) utils.copy_const(@TypeOf(self), *Super) {
return @ptrCast(self);
}
pub fn format(self: *const Self, writer: *std.Io.Writer) !void {
- try writer.print("<Upvalue{{{f} at 0x{x}, {any}, {d}}}>", .{self.location.ptr().*, self.location._ptr, self.closed, self.slot});
+ try writer.print("<Upvalue{{{f} at 0x{x}, {any}, {d}}}>", .{ self.location.get(), self.location._ptr, self.closed, self.slot });
}
pub fn eql(_: *const Self, _: *const Self) bool {
@@ -52,7 +47,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.ptr());
+ if (self.closed) self.location.destroy(allocator);
allocator.destroy(self);
}
};
diff --git a/zlox/src/packed.zig b/zlox/src/packed.zig
@@ -1,70 +1,134 @@
const std = @import("std");
+const utils = @import("comptime_utils.zig");
-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(Type: type) type {
+ return packed struct {
+ const optional = utils.is_type(Type, "optional");
-pub fn Packed(T: type) type {
- comptime var _Type = T;
- comptime var _Ptr =T;
+ const Ptr = if (optional) @typeInfo(Type).optional.child else Type;
- const _optional = is_type(_Type, "optional");
- if (_optional) {
- _Type = @typeInfo(_Type).optional.child;
- }
+ const Child = if (utils.is_type(Ptr, "pointer"))
+ @typeInfo(Ptr).pointer.child
+ else
+ @compileError("Expected pointer type, got " ++ @typeName(Ptr));
- 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 slice = @typeInfo(Ptr).pointer.size == .slice;
+ const many = @typeInfo(Ptr).pointer.size == .many;
const Self = @This();
_ptr: usize,
+ _len: if (slice) usize else void,
+
+ pub fn create(allocator: std.mem.Allocator) !Self {
+ return if (slice or many)
+ @compileError("Cannot create() a slice or many pointer, use alloc() instead")
+ else
+ Self.init(try allocator.create(Child));
+ }
- pub fn new(allocator: std.mem.Allocator) !Self {
- return Self.init(try allocator.create(Type));
+ pub fn alloc(allocator: std.mem.Allocator, count: usize) !Self {
+ return if (slice)
+ Self.init(try allocator.alloc(Child, count))
+ else if (many)
+ Self.init((try allocator.alloc(Child, count)).ptr)
+ else if (count == 1)
+ Self.create(allocator)
+ else
+ @panic("Cannot alloc() a single-item pointer with a count of more than one");
}
- pub fn init(arg: Ptr) Self {
+ pub fn init(arg: Type) Self {
return Self{
- ._ptr = @intFromPtr(arg),
+ ._ptr = if (optional)
+ if (arg) |val|
+ @intFromPtr(if (slice) val.ptr else val)
+ else
+ 0
+ else
+ @intFromPtr(if (slice) arg.ptr else arg),
+
+ ._len = if (slice)
+ if (optional)
+ if (arg) |val|
+ val.len
+ else
+ 0
+ else
+ arg.len,
};
}
- pub fn nil() Self {
- if (!optional) {
- @compileError("Cannot create nil for non-optional type");
- }
+ pub fn ptr(self: Self) Type {
+ return if (optional and self._ptr == 0)
+ null
+ else if (slice)
+ @as(utils.with_size(Ptr, .many), @ptrFromInt(self._ptr))[0..self._len]
+ else
+ @ptrFromInt(self._ptr);
+ }
- return Self{
- ._ptr = 0,
- };
+ pub fn get(self: Self) if (optional) ?Child else Child {
+ return if (slice or many)
+ @compileError("Cannot call get() on a slice or many pointer")
+ else if (optional and self._ptr == 0)
+ null
+ else
+ @as(Ptr, @ptrFromInt(self._ptr)).*;
+ }
+
+ pub fn at(self: Self, idx: usize) if (optional) ?Child else Child {
+ return if (!slice and !many)
+ @compileError("Cannot call at() on a single-item pointer")
+ else if (optional and self._ptr == 0)
+ null
+ else
+ self.ptr()[idx];
}
- pub fn valid(self: Self) bool {
- return !optional or self._ptr != 0;
+ pub fn len(self: Self) usize {
+ return if (slice)
+ self._len
+ else
+ @compileError("Cannot call len() on a non-slice pointer");
}
- pub fn ptr(self: Self) Ptr {
- if (self.valid()) {
- return @ptrFromInt(self._ptr);
+ pub fn free(self: Self, allocator: std.mem.Allocator, count: usize) void {
+ const pointer = if (optional)
+ if (self.ptr()) |_ptr|
+ _ptr
+ else
+ return
+ else
+ self.ptr();
+
+ if (many) {
+ allocator.free(pointer[0..count]);
+ } else if (slice) {
+ if (count != self._len)
+ @panic("Count has to be equal to the length of the slice");
+
+ allocator.free(pointer);
} else {
- @panic("Attempt to access null pointer");
+ if (count != 1)
+ @panic("Count has to be equal 1 for a single-item pointer");
+
+ allocator.destroy(pointer);
}
}
- pub fn free(self: Self, allocator: std.mem.Allocator) void {
- allocator.destroy(self.ptr());
+ pub fn set(self: Self, val: if (many or slice) Ptr else Child) void {
+ if (many or slice)
+ @memcpy(self.ptr(), val)
+ else
+ self.ptr().* = val;
+ }
+
+ pub fn destroy(self: Self, allocator: std.mem.Allocator) void {
+ if (many)
+ @compileError("Cannot use destroy() on a many-pointer, call free() instead");
+
+ self.free(allocator, if (slice) self._len else 1);
}
};
}
diff --git a/zlox/src/vm.zig b/zlox/src/vm.zig
@@ -104,7 +104,14 @@ pub const VM = struct {
open_upvalues: List,
pub fn run(vm: *VM, function: *Obj.Function, dbg: bool) InterpreterError!void {
- var self = @This(){ .frames = [_]CallFrame{undefined} ** callstack_size, .frameCount = 1, .stack = [_]Value{Value.init({})} ** stack_size, .stackTop = undefined, .vm = vm, .open_upvalues = List.init(vm.allocator) };
+ var self = @This(){
+ .frames = @splat(undefined),
+ .frameCount = 1,
+ .stack = @splat(Value.init({})),
+ .stackTop = undefined,
+ .vm = vm,
+ .open_upvalues = List.init(vm.allocator),
+ };
defer self.open_upvalues.free();
@@ -338,12 +345,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.ptr()[index].?.location.ptr().*);
+ self.push(closure.upvalues.at(index).?.location.ptr().*);
},
@intFromEnum(OP.SET_UPVALUE) => {
const closure = try self.frame().callee.cast(.Closure);
const index = self.read_byte();
- closure.upvalues.ptr()[index].?.location.ptr().* = self.peek(0);
+ closure.upvalues.at(index).?.location.ptr().* = self.peek(0);
},
@intFromEnum(OP.CLOSE_UPVALUE) => {
try self.closeUpvalues(self.current_slot());
@@ -399,14 +406,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.ptr()[0..closure.upvalues_len]) |*upvalue| {
+ for (closure.upvalues.ptr()) |*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.ptr()[slot];
+ upvalue.* = callee.upvalues.at(slot);
}
}
self.push(Value.init(closure.cast()));