commit ec78fb1986020c2c2b9d2b11fcad0fb6b49f17d1
parent f691de138bef1a690406ee83f179a8cee6469eaf
Author: Szymon Mikulicz <szymon.mikulicz@posteo.net>
Date: Fri, 21 Aug 2026 19:27:15 +0200
Flat file hierarchy for easier imports
Diffstat:
37 files changed, 1332 insertions(+), 1292 deletions(-)
diff --git a/zlox/src/chunk.zig b/zlox/src/chunk.zig
@@ -1,6 +1,8 @@
const std = @import("std");
+
+const array = @import("lib::array.zig");
+
const Value = @import("value.zig").Value;
-const array = @import("array.zig");
pub const OP = enum(u8) {
CONSTANT,
@@ -35,7 +37,7 @@ pub const OP = enum(u8) {
GET_INDEX,
CALL,
CLOSURE,
- CLOSE_UPVALUE
+ CLOSE_UPVALUE,
};
pub const Chunk = struct {
diff --git a/zlox/src/compiler.zig b/zlox/src/compiler.zig
@@ -1,15 +1,19 @@
const std = @import("std");
+
+const vm_native = @import("vm::native.zig");
+const utils = @import("lib::utils.zig");
const scanner = @import("scanner.zig");
-const Chunk = @import("chunk.zig").Chunk;
-const OP = @import("chunk.zig").OP;
-const Value = @import("value.zig").Value;
-const ValueArray = @import("value.zig").ValueArray;
-const GC = @import("gc.zig").GC;
-const Obj = GC.Obj;
const debug = @import("debug.zig");
+const chunk = @import("chunk.zig");
+const value = @import("value.zig");
+
const Token = scanner.TokenType;
-const vm_native = @import("vm/native.zig");
-const utils = @import("comptime_utils.zig");
+const Chunk = chunk.Chunk;
+const OP = chunk.OP;
+const Value = value.Value;
+const ValueArray = value.ValueArray;
+const GC = @import("gc.zig").GC;
+const Obj = GC.Obj;
pub const CompilerError = Obj.Error || scanner.ScannerError || Chunk.Error || Value.ParseNumberError || error{ UnexpectedToken, NotAnExpression };
diff --git a/zlox/src/debug.zig b/zlox/src/debug.zig
@@ -1,10 +1,11 @@
const std = @import("std");
+
const chunk = @import("chunk.zig");
const value = @import("value.zig");
-const Obj = @import("gc.zig").GC.Obj;
-const print = std.debug.print;
+const Obj = @import("gc.zig").GC.Obj;
const Error = Obj.Error;
+const print = std.debug.print;
pub fn disassembleChunk(ch: *const chunk.Chunk, name: []const u8) Error!void {
print("/= {s} =\\\n", .{name});
diff --git a/zlox/src/gc.zig b/zlox/src/gc.zig
@@ -1,8 +1,9 @@
const std = @import("std");
-const list = @import("list.zig");
+const list = @import("lib::list.zig");
+const utils = @import("lib::utils.zig");
+
const Value = @import("value.zig").Value;
-const utils = @import("comptime_utils.zig");
const VM = @import("vm.zig").VM;
pub const GC = struct {
diff --git a/zlox/src/array.zig b/zlox/src/lib::array.zig
diff --git a/zlox/src/lib::list.zig b/zlox/src/lib::list.zig
@@ -0,0 +1,225 @@
+const std = @import("std");
+
+const utils = @import("lib::utils.zig");
+
+fn sign(v: anytype) @TypeOf(v) {
+ return if (v >= 0) 1 else -1;
+}
+
+pub fn List(T: type) type {
+ return struct {
+ const Self = @This();
+
+ pub const Error = error{ OutOfMemory, IndexOutOfBounds, Empty };
+ pub const Value = T;
+
+ const Element = struct {
+ val: Value,
+ next: *@This(),
+ prev: *@This(),
+
+ fn jmp(self: *Element, idx: isize) *Element {
+ var ret = self;
+
+ for (0..@abs(idx)) |_| {
+ ret = if (idx > 0) ret.next else ret.prev;
+ }
+
+ return ret;
+ }
+
+ pub fn del(self: *Element, gpa: std.mem.Allocator) void {
+ self.next.prev = self.prev;
+ self.prev.next = self.next;
+
+ gpa.destroy(self);
+ }
+
+ fn init(gpa: std.mem.Allocator, prv: ?*Element, nxt: ?*Element, val: Value) !*Element {
+ const ret = try gpa.create(Element);
+ ret.* = Element{
+ .prev = prv orelse ret,
+ .next = nxt orelse ret,
+ .val = val,
+ };
+ return ret;
+ }
+
+ pub fn add_prev(self: *Element, gpa: std.mem.Allocator, val: Value) !void {
+ self.prev.next = try Element.init(gpa, self.prev, self, val);
+ self.prev = self.prev.next;
+ if (self.next == self) self.next = self.prev;
+ }
+
+ pub fn add_next(self: *Element, gpa: std.mem.Allocator, val: Value) !void {
+ self.next.prev = try Element.init(gpa, self, self.next, val);
+ self.next = self.next.prev;
+ if (self.prev == self) self.prev = self.next;
+ }
+
+ pub fn new(gpa: std.mem.Allocator, val: Value) !*Element {
+ return try Element.init(gpa, null, null, val);
+ }
+ };
+
+ pub fn Iterator(@"const": bool) type {
+ return struct {
+ const Super = utils.mod_ptr_t(*Self, "const", @"const");
+ const This = utils.mod_ptr_t(*Element, "const", @"const");
+
+ super: Super,
+ this: ?This,
+
+ pub fn new(sup: Super) @This() {
+ return .{
+ .super = sup,
+ .this = sup.tip,
+ };
+ }
+
+ pub fn next(self: *@This()) ?Value {
+ if (self.this) |el| {
+ self.this = if (el.next == self.super.tip) null else el.next;
+ return el.val;
+ } else {
+ return null;
+ }
+ }
+
+ pub fn pop(self: *@This()) void {
+ if (@"const") @compileError("Cannot call pop() on a const Iterator");
+
+ const el = if (self.this) |el| el.prev else self.super.tip orelse return;
+
+ if (self.this == el) self.this = null;
+
+ self.super.del(el);
+ }
+
+ pub fn push(self: *@This(), val: Value) !void {
+ if (@"const") @compileError("Cannot call push() on a const Iterator");
+
+ if (self.this) |el| {
+ try self.super.insert(false, el, val);
+ } else if (self.super.tip) |el| {
+ try self.super.insert(true, el.prev, val);
+ } else {
+ try self.super.begin(val);
+ }
+ }
+ };
+ }
+
+ _len: isize,
+ tip: ?*Element,
+
+ gpa: std.mem.Allocator,
+
+ pub fn iter(self: anytype) Iterator(utils.is_const(@TypeOf(self))) {
+ return Iterator(utils.is_const(@TypeOf(self))).new(self);
+ }
+
+ pub fn init(gpa: std.mem.Allocator) Self {
+ return Self{
+ ._len = 0,
+ .tip = null,
+ .gpa = gpa,
+ };
+ }
+
+ pub fn len(self: *const Self) usize {
+ return @intCast(self._len);
+ }
+
+ pub fn eql(self: *const Self, other: *const Self, eql_fn: fn (Value, Value) bool) bool {
+ if (self._len != other._len) return false;
+
+ var iter1 = self.iter();
+ var iter2 = other.iter();
+
+ while (iter1.next()) |val1| {
+ if (!eql_fn(val1, iter2.next().?)) return false;
+ }
+
+ return true;
+ }
+
+ pub fn free(self: *Self) void {
+ while (true) {
+ _ = self.pop(-1) catch break;
+ }
+ }
+
+ fn _at(self: *Self, idx: isize) Error!*Element {
+ if (self.tip) |tip| {
+ const haf: isize = sign(idx) * @divTrunc(self._len, 2);
+ return tip.jmp(@rem(idx + haf, self._len) - haf);
+ } else {
+ return Error.Empty;
+ }
+ }
+
+ fn at(self: *Self, idx: isize) Error!*Element {
+ return if (@abs(idx) >= self._len and idx < -self._len)
+ Error.IndexOutOfBounds
+ else
+ try self._at(idx);
+ }
+
+ pub fn set(self: *Self, idx: isize, val: Value) Error!void {
+ (try self.at(idx)).val = val;
+ }
+
+ pub fn get(self: *Self, idx: isize) Error!Value {
+ return (try self.at(idx)).val;
+ }
+
+ fn del(self: *Self, el: *Element) void {
+ self._len -= 1;
+
+ if (self.tip == el) {
+ self.tip = if (el.next == el) null else el.next;
+ }
+
+ el.del(self.gpa);
+ }
+
+ pub fn pop(self: *Self, idx: isize) Error!Value {
+ const el = try self.at(idx);
+ const ret = el.val;
+
+ self.del(el);
+
+ return ret;
+ }
+
+ fn begin(self: *Self, val: Value) !void {
+ if (self.tip) |_| @panic("This function can only be called on an empty list");
+
+ self.tip = try Element.new(self.gpa, val);
+ self._len = 1;
+ }
+
+ fn insert(self: *Self, after: bool, anchor: *Element, val: Value) !void {
+ if (after) {
+ try anchor.add_next(self.gpa, val);
+ } else {
+ try anchor.add_prev(self.gpa, val);
+
+ if (self.tip == anchor) self.tip = anchor.prev;
+ }
+
+ self._len += 1;
+ }
+
+ pub fn push(self: *Self, idx: isize, val: Value) Error!void {
+ if (@abs(idx) > self._len and idx < -self._len - 1) {
+ return Error.IndexOutOfBounds;
+ } else {
+ const el = self._at(idx) catch return self.begin(val);
+
+ try self.insert(idx < 0, el, val);
+ }
+ }
+ };
+}
diff --git a/zlox/src/lib::packed.zig b/zlox/src/lib::packed.zig
@@ -0,0 +1,135 @@
+const std = @import("std");
+
+const utils = @import("lib::utils.zig");
+
+pub fn Packed(Type: type) type {
+ return packed struct {
+ const optional = utils.is_type(Type, "optional");
+
+ const Ptr = if (optional) @typeInfo(Type).optional.child else Type;
+
+ const Child = if (utils.is_type(Ptr, "pointer"))
+ @typeInfo(Ptr).pointer.child
+ else
+ @compileError("Expected pointer type, got " ++ @typeName(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 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: Type) Self {
+ return Self{
+ ._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 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);
+ }
+
+ 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 len(self: Self) usize {
+ return if (slice)
+ self._len
+ else
+ @compileError("Cannot call len() on a non-slice pointer");
+ }
+
+ 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 {
+ if (count != 1)
+ @panic("Count has to be equal 1 for a single-item pointer");
+
+ allocator.destroy(pointer);
+ }
+ }
+
+ 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/lib::table.zig b/zlox/src/lib::table.zig
@@ -0,0 +1,215 @@
+const std = @import("std");
+
+const utils = @import("lib::utils.zig");
+
+pub fn Table(K: type, V: type, hash_fn: fn (K) u32, cmp_fn: fn (K, K) bool) type {
+ return struct {
+ const Self = @This();
+ const MaxLoad: f32 = 0.75;
+
+ pub const Error = error{ OutOfMemory, KeyError };
+
+ pub const Key = K;
+ pub const Value = V;
+
+ pub const Entry = union(enum) {
+ const Some = struct {
+ key: K,
+ value: V,
+ };
+ some: Some,
+ none,
+ tomb,
+ };
+
+ count: usize,
+ entries: []Entry,
+ allocator: std.mem.Allocator,
+
+ pub fn init(allocator: std.mem.Allocator) Self {
+ return Self{ .count = 0, .entries = &.{}, .allocator = allocator };
+ }
+
+ fn growCapacity(self: *const Self) usize {
+ return if (self.entries.len > 0)
+ self.entries.len * 2
+ else
+ 10;
+ }
+
+ fn adjustCapacity(self: *Self, newsize: usize) Error!void {
+ const entries = try self.allocator.alloc(Entry, newsize);
+ for (entries) |*entry| {
+ entry.* = .none;
+ }
+ self.count = 0;
+ for (self.entries) |entry| {
+ switch (entry) {
+ .some => |some| {
+ find(entries, some.key).* = entry;
+ self.count += 1;
+ },
+ else => {},
+ }
+ }
+ self.allocator.free(self.entries);
+ self.entries = entries;
+ }
+ pub fn find_check(key: K) struct {
+ k: K,
+ pub fn check(self: *const @This(), k2: K) bool {
+ return cmp_fn(self.k, k2);
+ }
+ } {
+ return @TypeOf(find_check(key)){ .k = key };
+ }
+
+ pub fn find(entries: []Entry, key: K) *Entry {
+ return find_(entries, hash_fn(key), find_check(key));
+ }
+
+ pub fn find_(entries: []Entry, hash: u32, check: anytype) *Entry {
+ var idx = hash % entries.len;
+ var tomb: ?*Entry = null;
+
+ while (true) {
+ const entry = &entries[idx];
+ switch (entry.*) {
+ .some => |some| if (check.check(some.key)) return entry,
+ .tomb => tomb = if (tomb) |t| t else entry,
+ .none => return if (tomb) |t| t else entry,
+ }
+ idx = (idx + 1) % entries.len;
+ }
+ }
+
+ pub fn addAll(self: *Self, other: *const Self) Error!void {
+ for (other.entries) |entry| {
+ switch (entry) {
+ .some => |some| self.set(some.key, some.value),
+ else => {},
+ }
+ }
+ }
+
+ pub fn for_each(self: *const Self, arg: anytype, fun: if (@TypeOf(arg) == void) fn (K, V) void else fn (@TypeOf(arg), K, V) void) void {
+ for (self.entries) |entry| {
+ switch (entry) {
+ .some => |some| if (@TypeOf(arg) == void)
+ fun(some.key, some.value)
+ else
+ fun(arg, some.key, some.value),
+ else => {},
+ }
+ }
+ }
+
+ pub fn for_each_try(self: *const Self, arg: anytype, fun: anytype) utils.fn_error(fun).?!void {
+ for (self.entries) |entry| {
+ switch (entry) {
+ .some => |some| if (@TypeOf(arg) == void)
+ try fun(some.key, some.value)
+ else
+ try fun(arg, some.key, some.value),
+ else => {},
+ }
+ }
+ }
+
+ pub fn set_(self: *Self, entry: *Entry, key: K, val: V) bool {
+ const isNewKey = switch (entry.*) {
+ .none => blk: {
+ self.count += 1;
+ break :blk true;
+ },
+ .tomb => true,
+ .some => false,
+ };
+
+ entry.* = Entry{ .some = Entry.Some{ .key = key, .value = val } };
+ return isNewKey;
+ }
+
+ pub fn eql(self: *const Self, other: *const Self, cmpval_fn: fn (V, V) bool) bool {
+ for (self.entries) |entry| {
+ switch (entry) {
+ .some => |some| {
+ switch (find(other.entries, some.key).*) {
+ .some => |some2| if (!cmpval_fn(some.value, some2.value)) {
+ return false;
+ },
+ else => return false,
+ }
+ },
+ else => {},
+ }
+ }
+ return true;
+ }
+
+ pub fn checkCapacity(self: *Self) Error!void {
+ const len: f32 = @floatFromInt(self.entries.len);
+ const count: f32 = @floatFromInt(self.count);
+ if (count + 1.0 > len * MaxLoad) {
+ try self.adjustCapacity(self.growCapacity());
+ }
+ }
+
+ pub fn set(self: *Self, key: K, val: V) Error!bool {
+ try self.checkCapacity();
+ return self.set_(find(self.entries, key), key, val);
+ }
+
+ pub fn replace(self: *Self, key: K, val: V) Error!void {
+ if (self.entries.len == 0)
+ return Error.KeyError;
+
+ const entry = find(self.entries, key);
+ switch (entry.*) {
+ .some => _ = self.set_(entry, key, val),
+ else => return Error.KeyError,
+ }
+ }
+
+ pub fn replace_if(self: *Self, key: K, val: V, fun: fn (V) bool) Error!bool {
+ if (self.entries.len == 0)
+ return Error.KeyError;
+
+ const entry = find(self.entries, key);
+ switch (entry.*) {
+ .some => |some| return fun(some.value) and !self.set_(entry, key, val),
+ else => return Error.KeyError,
+ }
+ }
+
+ pub fn get(self: *const Self, key: K) Error!V {
+ if (self.entries.len == 0)
+ return Error.KeyError;
+
+ return switch (find(self.entries, key).*) {
+ .some => |some| some.value,
+ else => Error.KeyError,
+ };
+ }
+
+ pub fn delete(self: *Self, key: K) bool {
+ if (self.entries.len == 0) return false;
+
+ const entry = find(self.entries, key);
+ switch (entry.*) {
+ .some => entry.* = .tomb,
+ else => return false,
+ }
+
+ return true;
+ }
+
+ pub fn deinit(self: *@This()) void {
+ if (self.entries.len > 0) {
+ self.allocator.free(self.entries);
+ self.entries = &.{};
+ self.count = 0;
+ }
+ }
+ };
+}
diff --git a/zlox/src/comptime_utils.zig b/zlox/src/lib::utils.zig
diff --git a/zlox/src/list.zig b/zlox/src/list.zig
@@ -1,224 +0,0 @@
-const std = @import("std");
-const utils = @import("comptime_utils.zig");
-
-fn sign(v: anytype) @TypeOf(v) {
- return if (v >= 0) 1 else -1;
-}
-
-pub fn List(T: type) type {
- return struct {
- const Self = @This();
-
- pub const Error = error{ OutOfMemory, IndexOutOfBounds, Empty };
- pub const Value = T;
-
- const Element = struct {
- val: Value,
- next: *@This(),
- prev: *@This(),
-
- fn jmp(self: *Element, idx: isize) *Element {
- var ret = self;
-
- for (0..@abs(idx)) |_| {
- ret = if (idx > 0) ret.next else ret.prev;
- }
-
- return ret;
- }
-
- pub fn del(self: *Element, gpa: std.mem.Allocator) void {
- self.next.prev = self.prev;
- self.prev.next = self.next;
-
- gpa.destroy(self);
- }
-
- fn init(gpa: std.mem.Allocator, prv: ?*Element, nxt: ?*Element, val: Value) !*Element {
- const ret = try gpa.create(Element);
- ret.* = Element{
- .prev = prv orelse ret,
- .next = nxt orelse ret,
- .val = val,
- };
- return ret;
- }
-
- pub fn add_prev(self: *Element, gpa: std.mem.Allocator, val: Value) !void {
- self.prev.next = try Element.init(gpa, self.prev, self, val);
- self.prev = self.prev.next;
- if (self.next == self) self.next = self.prev;
- }
-
- pub fn add_next(self: *Element, gpa: std.mem.Allocator, val: Value) !void {
- self.next.prev = try Element.init(gpa, self, self.next, val);
- self.next = self.next.prev;
- if (self.prev == self) self.prev = self.next;
- }
-
- pub fn new(gpa: std.mem.Allocator, val: Value) !*Element {
- return try Element.init(gpa, null, null, val);
- }
- };
-
- pub fn Iterator(@"const": bool) type {
- return struct {
- const Super = utils.mod_ptr_t(*Self, "const", @"const");
- const This = utils.mod_ptr_t(*Element, "const", @"const");
-
- super: Super,
- this: ?This,
-
- pub fn new(sup: Super) @This() {
- return .{
- .super = sup,
- .this = sup.tip,
- };
- }
-
- pub fn next(self: *@This()) ?Value {
- if (self.this) |el| {
- self.this = if (el.next == self.super.tip) null else el.next;
- return el.val;
- } else {
- return null;
- }
- }
-
- pub fn pop(self: *@This()) void {
- if (@"const") @compileError("Cannot call pop() on a const Iterator");
-
- const el = if (self.this) |el| el.prev else self.super.tip orelse return;
-
- if (self.this == el) self.this = null;
-
- self.super.del(el);
- }
-
- pub fn push(self: *@This(), val: Value) !void {
- if (@"const") @compileError("Cannot call push() on a const Iterator");
-
- if (self.this) |el| {
- try self.super.insert(false, el, val);
- } else if (self.super.tip) |el| {
- try self.super.insert(true, el.prev, val);
- } else {
- try self.super.begin(val);
- }
- }
- };
- }
-
- _len: isize,
- tip: ?*Element,
-
- gpa: std.mem.Allocator,
-
- pub fn iter(self: anytype) Iterator(utils.is_const(@TypeOf(self))) {
- return Iterator(utils.is_const(@TypeOf(self))).new(self);
- }
-
- pub fn init(gpa: std.mem.Allocator) Self {
- return Self{
- ._len = 0,
- .tip = null,
- .gpa = gpa,
- };
- }
-
- pub fn len(self: *const Self) usize {
- return @intCast(self._len);
- }
-
- pub fn eql(self: *const Self, other: *const Self, eql_fn: fn (Value, Value) bool) bool {
- if (self._len != other._len) return false;
-
- var iter1 = self.iter();
- var iter2 = other.iter();
-
- while (iter1.next()) |val1| {
- if (!eql_fn(val1, iter2.next().?)) return false;
- }
-
- return true;
- }
-
- pub fn free(self: *Self) void {
- while (true) {
- _ = self.pop(-1) catch break;
- }
- }
-
- fn _at(self: *Self, idx: isize) Error!*Element {
- if (self.tip) |tip| {
- const haf: isize = sign(idx) * @divTrunc(self._len, 2);
- return tip.jmp(@rem(idx + haf, self._len) - haf);
- } else {
- return Error.Empty;
- }
- }
-
- fn at(self: *Self, idx: isize) Error!*Element {
- return if (@abs(idx) >= self._len and idx < -self._len)
- Error.IndexOutOfBounds
- else
- try self._at(idx);
- }
-
- pub fn set(self: *Self, idx: isize, val: Value) Error!void {
- (try self.at(idx)).val = val;
- }
-
- pub fn get(self: *Self, idx: isize) Error!Value {
- return (try self.at(idx)).val;
- }
-
- fn del(self: *Self, el: *Element) void {
- self._len -= 1;
-
- if (self.tip == el) {
- self.tip = if (el.next == el) null else el.next;
- }
-
- el.del(self.gpa);
- }
-
- pub fn pop(self: *Self, idx: isize) Error!Value {
- const el = try self.at(idx);
- const ret = el.val;
-
- self.del(el);
-
- return ret;
- }
-
- fn begin(self: *Self, val: Value) !void {
- if (self.tip) |_| @panic("This function can only be called on an empty list");
-
- self.tip = try Element.new(self.gpa, val);
- self._len = 1;
- }
-
- fn insert(self: *Self, after: bool, anchor: *Element, val: Value) !void {
- if (after) {
- try anchor.add_next(self.gpa, val);
- } else {
- try anchor.add_prev(self.gpa, val);
-
- if (self.tip == anchor) self.tip = anchor.prev;
- }
-
- self._len += 1;
- }
-
- pub fn push(self: *Self, idx: isize, val: Value) Error!void {
- if (@abs(idx) > self._len and idx < -self._len - 1) {
- return Error.IndexOutOfBounds;
- } else {
- const el = self._at(idx) catch return self.begin(val);
-
- try self.insert(idx < 0, el, val);
- }
- }
- };
-}
diff --git a/zlox/src/main.zig b/zlox/src/main.zig
@@ -1,6 +1,7 @@
const std = @import("std");
+const linenoise = @import("linenoise");
+
const vm = @import("vm.zig");
-const Linenoise = @import("linenoise");
pub fn main(init: std.process.Init) anyerror!u8 {
const allocator = init.gpa;
@@ -37,13 +38,13 @@ 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);
+ _ = linenoise.linenoiseHistorySetMaxLen(100);
- while (Linenoise.linenoise("lox> ")) |line| {
- defer Linenoise.linenoiseFree(line);
+ while (linenoise.linenoise("lox> ")) |line| {
+ defer linenoise.linenoiseFree(line);
VM.interpret(std.mem.span(line), dbg) catch |err| {
std.debug.print("\nError: {any}\n", .{err});
};
- _ = Linenoise.linenoiseHistoryAdd(line);
+ _ = linenoise.linenoiseHistoryAdd(line);
}
}
diff --git a/zlox/src/obj.zig b/zlox/src/obj.zig
@@ -1,5 +1,6 @@
const std = @import("std");
-const utils = @import("comptime_utils.zig");
+
+const utils = @import("lib::utils.zig");
fn nameOf(fqn: []const u8) []const u8 {
var lastDot = 0;
@@ -17,13 +18,13 @@ pub fn Obj(fields: anytype) type {
type: Type,
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);
- pub const Table = @import("obj/table.zig").Table(fields);
- pub const Function = @import("obj/function.zig").Function(fields);
- pub const Native = @import("obj/native.zig").Native(fields);
- pub const Closure = @import("obj/closure.zig").Closure(fields);
- pub const Upvalue = @import("obj/upvalue.zig").Upvalue(fields);
+ pub const List = @import("obj::list.zig").List(fields);
+ pub const String = @import("obj::string.zig").String(fields);
+ pub const Table = @import("obj::table.zig").Table(fields);
+ pub const Function = @import("obj::function.zig").Function(fields);
+ pub const Native = @import("obj::native.zig").Native(fields);
+ 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;
diff --git a/zlox/src/obj/closure.zig b/zlox/src/obj/closure.zig
@@ -1,52 +0,0 @@
-const std = @import("std");
-const utils = @import("../comptime_utils.zig");
-const Packed = @import("../packed.zig").Packed;
-
-pub fn Closure(fields: anytype) type {
- const Super = @import("../obj.zig").Obj(fields);
-
- return packed struct {
- const Self = @This();
-
- pub const Arg = *Super.Function;
- pub const Error = error{OutOfMemory};
-
- obj: Super,
- function: Packed(*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{
- .obj = Super.make(Self),
- .upvalues = try Packed([]?*Super.Upvalue).alloc(allocator, arg.upvalue_count),
- .function = Packed(*Super.Function).init(arg),
- };
- for (self.upvalues.ptr()) |*upvalue| upvalue.* = null;
- return self;
- }
-
- 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.write("<C: ");
- if (self.function.ptr().name.get()) |fn_name| {
- _ = try writer.write(fn_name.slice());
- } else {
- _ = try writer.write("-");
- }
- _ = try writer.writeAll(">");
- }
-
- pub fn eql(_: *const Self, _: *const Self) bool {
- return false;
- }
-
- pub fn free(self: *const Self, allocator: std.mem.Allocator) void {
- self.upvalues.destroy(allocator);
- allocator.destroy(self);
- }
- };
-}
diff --git a/zlox/src/obj/function.zig b/zlox/src/obj/function.zig
@@ -1,69 +0,0 @@
-const std = @import("std");
-const chunk = @import("../chunk.zig");
-const utils = @import("../comptime_utils.zig");
-const Packed = @import("../packed.zig").Packed;
-
-pub fn Function(fields: anytype) type {
- const Super = @import("../obj.zig").Obj(fields);
- const String = Super.String;
-
- return packed struct {
- const Self = @This();
- pub const Arg = Type;
- pub const Error = error{OutOfMemory};
-
- pub const Type = enum(u8) { Function, Script };
-
- obj: Super,
- arity: u8,
- chunk: Packed(*chunk.Chunk),
- name: Packed(?*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{
- .obj = Super.make(Self),
- .chunk = try Packed(*chunk.Chunk).create(allocator),
- .arity = 0,
- .name = Packed(?*String).init(null),
- .type = tp,
- .upvalue_count = 0,
- };
- self.chunk.set(try chunk.Chunk.init(allocator));
- return self;
- }
-
- pub fn set_name(self: *Self, name: *String) void {
- self.name = Packed(?*String).init(name);
- }
-
- 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 {
- switch (self.type) {
- .Function => _ = try writer.write("<F: "),
- .Script => _ = try writer.write("<S: "),
- }
- if (self.name.ptr()) |name| {
- _ = try writer.write(name.slice());
- } else {
- _ = try writer.write("-");
- }
- _ = try writer.writeAll(">");
- }
-
- pub fn eql(_: *const Self, _: *const Self) bool {
- return false;
- }
-
- pub fn free(self: *const Self, allocator: std.mem.Allocator) void {
- self.chunk.ptr().deinit();
- self.chunk.destroy(allocator);
- allocator.destroy(self);
- }
- };
-}
diff --git a/zlox/src/obj/list.zig b/zlox/src/obj/list.zig
@@ -1,82 +0,0 @@
-const std = @import("std");
-
-const Value = @import("../value.zig").Value;
-const utils = @import("../comptime_utils.zig");
-const list_zig = @import("../list.zig");
-const Packed = @import("../packed.zig").Packed;
-
-pub fn List(fields: anytype) type {
- const Super = @import("../obj.zig").Obj(fields);
-
- return packed struct {
- const Self = @This();
-
- pub const List = list_zig.List(Value);
- pub const Arg = void;
- pub const Error = error{ OutOfMemory, InvalidArgument } || Self.List.Error;
-
- obj: Super,
- list: 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 Packed(*Self.List).create(allocator),
- };
- self.list.set(Self.List.init(allocator));
- return self;
- }
-
- pub fn cast(self: anytype) utils.copy_const(@TypeOf(self), *Super) {
- return @ptrCast(self);
- }
-
- pub fn format(self: *const Self, writer: *std.Io.Writer) std.Io.Writer.Error!void {
- var iter = self.list.ptr().iter();
- var count = self.list.ptr().len();
-
- _ = try writer.write("[");
- while (iter.next()) |val| {
- count -= 1;
- try val.format(writer);
- if (count > 0) _ = try writer.write(", ");
- }
- _ = try writer.writeAll("]");
- }
-
- pub fn eql(self: *const Self, other: *const Self) bool {
- return self.list.ptr().eql(other.list.ptr(), Value.eql);
- }
-
- pub fn free(self: *Self, allocator: std.mem.Allocator) void {
- self.list.ptr().free();
- self.list.destroy(allocator);
- allocator.destroy(self);
- }
-
- pub fn delete(self: *Self, index: Value) void {
- var list = self.list.ptr();
- if (!index.is(Value.number) or index.number >= @as(Value.tagType(Value.number), @floatFromInt(list.len()))) {
- return;
- }
- _ = list.pop(@intFromFloat(index.number)) catch return;
- }
-
- pub fn get(self: *const Self, index: Value) Error!Value {
- var list = self.list.ptr();
- if (!index.is(Value.number) or index.number >= @as(Value.tagType(Value.number), @floatFromInt(list.len()))) {
- return Error.InvalidArgument;
- }
- return list.get(@intFromFloat(index.number));
- }
-
- pub fn set(self: *Self, index: Value, val: Value) Error!void {
- if (!index.is(Value.number)) {
- return Error.InvalidArgument;
- }
- _ = self.list.ptr().set(@intFromFloat(index.number), val) catch
- try self.list.ptr().push(@intFromFloat(index.number), val);
- }
- };
-}
diff --git a/zlox/src/obj/native.zig b/zlox/src/obj/native.zig
@@ -1,63 +0,0 @@
-const std = @import("std");
-
-const utils = @import("../comptime_utils.zig");
-const GC = @import("../gc.zig").GC;
-const Value = @import("../value.zig").Value;
-const Packed = @import("../packed.zig").Packed;
-
-pub fn Native(fields: anytype) type {
- const Super = @import("../obj.zig").Obj(fields);
-
- return packed struct {
- const Self = @This();
- pub const Error = error{ OutOfMemory, Native };
-
- pub const Fn = *const fn (*GC, []const Value) Error!Value;
-
- pub const ArityMin = 0;
- pub const ArityMax = std.math.maxInt(u8);
-
- pub const Arg = struct { fun: Fn, arity_min: u8 = ArityMin, arity_max: u8 = ArityMax, name: []const u8 = "" };
-
- obj: Super,
- fun: Packed(Fn),
- arity_min: u8,
- arity_max: u8,
- 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 = Packed(Fn).init(arg.fun),
- .arity_min = arg.arity_min,
- .arity_max = arg.arity_max,
- .name = Packed([]const u8).init(arg.name),
- };
- return self;
- }
-
- pub fn call(self: *const Self, gc: *GC, argCount: u8, args: [*]Value) Error!Value {
- const callable = self.fun.ptr();
- return callable(gc, args[0..argCount]);
- }
-
- 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.write("<N: ");
- _ = try writer.write(self.name.ptr());
- _ = try writer.writeAll(">");
- }
-
- pub fn eql(_: *const Self, _: *const Self) bool {
- return false;
- }
-
- pub fn free(self: *const Self, allocator: std.mem.Allocator) void {
- allocator.destroy(self);
- }
- };
-}
diff --git a/zlox/src/obj/string.zig b/zlox/src/obj/string.zig
@@ -1,111 +0,0 @@
-const std = @import("std");
-const table = @import("../table.zig");
-const hash = @import("../hash.zig");
-const utils = @import("../comptime_utils.zig");
-const value = @import("../value.zig");
-
-pub fn String(fields: anytype) type {
- const Super = @import("../obj.zig").Obj(fields);
-
- return packed struct {
- const Self = @This();
- pub const Table = table.Table(*Self, void, hash.hash_t(*const Self), Self.eql);
- pub const Arg = []const []const u8;
- pub const Error = error{ OutOfMemory, IndexOutOfBounds } || Table.Error;
-
- obj: Super,
- len: usize = 0,
- hash: u32,
-
- fn data(self: anytype) utils.copy_const(@TypeOf(self), [*]u8) {
- const p: utils.copy_const(@TypeOf(self), [*]u8) = @ptrCast(self);
- return p + @sizeOf(Self);
- }
-
- fn new(arg: Arg, params: ArgParams, allocator: std.mem.Allocator) Error!*Self {
- const ret: *Self = @ptrCast(try allocator.alignedAlloc(u8, std.mem.Alignment.of(Self), @sizeOf(Self) + params.len));
- ret.* = Self{
- .obj = Super.make(Self),
- .hash = params.hash,
- };
- for (arg) |el| {
- @memcpy(ret.data() + ret.len, el);
- ret.len += el.len;
- }
- return ret;
- }
-
- pub fn slice(self: *const Self) []const u8 {
- return self.data()[0..self.len];
- }
-
- 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.writeAll(self.slice());
- }
- pub fn eql(self: *const Self, other: *const Self) bool {
- return @intFromPtr(self) == @intFromPtr(other);
- }
- pub fn get(self: *const Self, index: value.Value) Error!value.Value {
- if (!index.is(value.Value.number) or index.number >= @as(value.Value.tagType(value.Value.number), @floatFromInt(self.len)) or index.number < 0) {
- return Error.IndexOutOfBounds;
- }
- return value.Value.init(self.data()[@intFromFloat(index.number)]);
- }
-
- const ArgParams = struct { len: usize, hash: u32 };
-
- fn table_check(m_arg: Arg, m_params: ArgParams) struct {
- arg: Arg,
- params: ArgParams,
- pub fn check(self: *const @This(), k2: *const Self) bool {
- if (k2.hash == self.params.hash and k2.len == self.params.len) {
- var idx: usize = 0;
- for (self.arg) |el| {
- if (!std.mem.eql(u8, k2.data()[idx .. idx + el.len], el))
- return false;
- idx += el.len;
- }
- return true;
- }
- return false;
- }
- } {
- return @TypeOf(table_check(m_arg, m_params)){ .arg = m_arg, .params = m_params };
- }
-
- fn arg_params(arg: Arg) ArgParams {
- var ret = ArgParams{ .len = 0, .hash = hash.hash_t([]const u8)(&.{}) };
-
- for (arg) |el| {
- ret.len += el.len;
- ret.hash = hash.hash_append(ret.hash, el);
- }
- return ret;
- }
-
- pub fn intern(arg: Arg, tabl: *Self.Table, isNewKey: *bool, allocator: std.mem.Allocator) Error!*Self {
- const params = arg_params(arg);
-
- try tabl.checkCapacity();
- const entry = Self.Table.find_(tabl.entries, params.hash, table_check(arg, params));
- isNewKey.* = entry.* != Self.Table.Entry.some;
- if (isNewKey.*) {
- _ = tabl.set_(entry, try new(arg, params, allocator), {});
- }
- return entry.some.key;
- }
-
- pub fn init(_: Arg, _: std.mem.Allocator) Error!*Self {
- @compileError("The String Obj has to be interned");
- }
-
- pub fn free(self: *const Self, allocator: std.mem.Allocator) void {
- const p: [*]align(@alignOf(Self)) const u8 = @ptrCast(self);
- allocator.free(p[0 .. @sizeOf(Self) + self.len]);
- }
- };
-}
diff --git a/zlox/src/obj/table.zig b/zlox/src/obj/table.zig
@@ -1,84 +0,0 @@
-const std = @import("std");
-const table = @import("../table.zig");
-const hash = @import("../hash.zig");
-const Value = @import("../value.zig").Value;
-const utils = @import("../comptime_utils.zig");
-const Packed = @import("../packed.zig").Packed;
-
-pub fn Table(fields: anytype) type {
- const Super = @import("../obj.zig").Obj(fields);
-
- return packed struct {
- const Self = @This();
- pub const Arg = void;
- pub const Table = table.Table(Value, Value, hash.hash_t(Value), Value.eql);
- pub const Error = error{OutOfMemory} || Self.Table.Error;
-
- obj: Super,
- 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{
- .obj = Super.make(Self),
- .table = try Packed(*Self.Table).create(allocator),
- .len = 0,
- };
- self.table.set(Self.Table.init(allocator));
- return self;
- }
-
- pub fn cast(self: anytype) utils.copy_const(@TypeOf(self), *Super) {
- return @ptrCast(self);
- }
-
- pub fn set(self: *Self, key: Value, val: Value) Error!bool {
- self.len += 1;
- return self.table.ptr().set(key, val);
- }
-
- pub fn get(self: *Self, key: Value) Error!Value {
- return self.table.ptr().get(key);
- }
-
- pub fn delete(self: *Self, key: Value) void {
- if (self.table.ptr().delete(key)) self.len -= 1;
- }
-
- pub fn format(self: *const Self, writer: *std.Io.Writer) !void {
- const Printer = struct {
- writer: @TypeOf(writer),
- count: usize,
-
- pub fn print(this: *@This(), key: Value, val: Value) std.Io.Writer.Error!void {
- this.count -= 1;
-
- try key.format(this.writer);
- _ = try this.writer.write(":");
- try val.format(this.writer);
- if (this.count > 0) _ = try this.writer.write(", ");
- }
- };
-
- 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);
- } else {
- _ = try writer.write(":");
- }
- _ = try writer.writeAll("]");
- }
-
- pub fn eql(self: *const Self, other: *const Self) bool {
- return self.table.ptr().eql(other.table.ptr(), Value.eql);
- }
-
- pub fn free(self: *const Self, allocator: std.mem.Allocator) void {
- self.table.ptr().deinit();
- self.table.destroy(allocator);
- allocator.destroy(self);
- }
- };
-}
diff --git a/zlox/src/obj/template.zig b/zlox/src/obj/template.zig
@@ -1,41 +0,0 @@
-const std = @import("std");
-
-const utils = @import("../comptime_utils.zig");
-
-pub fn Template(fields: anytype) type {
- const Super = @import("../obj.zig").Obj(fields);
-
- return packed struct {
- const Self = @This();
-
- pub const Arg = void;
- pub const Error = error { OutOfMemory };
-
- obj: Super,
- pub fn init(arg: Arg, allocator: std.mem.Allocator) Error!*Self {
- _ = arg;
- _ = allocator;
- return Error.OutOfMemory;
- }
-
- 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 {
- _ = self;
- _ = writer;
- }
-
- pub fn eql(self: *const Self, other: *const Self) bool {
- _ = self;
- _ = other;
- return false;
- }
-
- pub fn free(self: *const Self, allocator: std.mem.Allocator) void {
- _ = self;
- _ = allocator;
- }
- };
-}
diff --git a/zlox/src/obj/upvalue.zig b/zlox/src/obj/upvalue.zig
@@ -1,54 +0,0 @@
-const std = @import("std");
-
-const utils = @import("../comptime_utils.zig");
-const Value = @import("../value.zig").Value;
-const Packed = @import("../packed.zig").Packed;
-
-pub fn Upvalue(fields: anytype) type {
- const Super = @import("../obj.zig").Obj(fields);
-
- return packed struct {
- const Self = @This();
-
- pub const Arg = struct { val: *Value, slot: u8 };
- pub const Error = error{OutOfMemory};
-
- obj: Super,
- 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 = 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 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.get(), self.location._ptr, self.closed, self.slot });
- }
-
- pub fn eql(_: *const Self, _: *const Self) bool {
- return false;
- }
-
- pub fn free(self: *const Self, allocator: std.mem.Allocator) void {
- if (self.closed) self.location.destroy(allocator);
- allocator.destroy(self);
- }
- };
-}
diff --git a/zlox/src/obj::closure.zig b/zlox/src/obj::closure.zig
@@ -0,0 +1,55 @@
+const std = @import("std");
+
+const utils = @import("lib::utils.zig");
+
+const Packed = @import("lib::packed.zig").Packed;
+const Obj = @import("obj.zig").Obj;
+
+pub fn Closure(fields: anytype) type {
+ const Super = Obj(fields);
+
+ return packed struct {
+ const Self = @This();
+
+ pub const Arg = *Super.Function;
+ pub const Error = error{OutOfMemory};
+
+ obj: Super,
+ function: Packed(*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{
+ .obj = Super.make(Self),
+ .upvalues = try Packed([]?*Super.Upvalue).alloc(allocator, arg.upvalue_count),
+ .function = Packed(*Super.Function).init(arg),
+ };
+ for (self.upvalues.ptr()) |*upvalue| upvalue.* = null;
+ return self;
+ }
+
+ 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.write("<C: ");
+ if (self.function.ptr().name.get()) |fn_name| {
+ _ = try writer.write(fn_name.slice());
+ } else {
+ _ = try writer.write("-");
+ }
+ _ = try writer.writeAll(">");
+ }
+
+ pub fn eql(_: *const Self, _: *const Self) bool {
+ return false;
+ }
+
+ pub fn free(self: *const Self, allocator: std.mem.Allocator) void {
+ self.upvalues.destroy(allocator);
+ allocator.destroy(self);
+ }
+ };
+}
diff --git a/zlox/src/obj::function.zig b/zlox/src/obj::function.zig
@@ -0,0 +1,72 @@
+const std = @import("std");
+
+const utils = @import("lib::utils.zig");
+const chunk = @import("chunk.zig");
+
+const Packed = @import("lib::packed.zig").Packed;
+const Obj = @import("obj.zig").Obj;
+
+pub fn Function(fields: anytype) type {
+ const Super = Obj(fields);
+ const String = Super.String;
+
+ return packed struct {
+ const Self = @This();
+ pub const Arg = Type;
+ pub const Error = error{OutOfMemory};
+
+ pub const Type = enum(u8) { Function, Script };
+
+ obj: Super,
+ arity: u8,
+ chunk: Packed(*chunk.Chunk),
+ name: Packed(?*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{
+ .obj = Super.make(Self),
+ .chunk = try Packed(*chunk.Chunk).create(allocator),
+ .arity = 0,
+ .name = Packed(?*String).init(null),
+ .type = tp,
+ .upvalue_count = 0,
+ };
+ self.chunk.set(try chunk.Chunk.init(allocator));
+ return self;
+ }
+
+ pub fn set_name(self: *Self, name: *String) void {
+ self.name = Packed(?*String).init(name);
+ }
+
+ 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 {
+ switch (self.type) {
+ .Function => _ = try writer.write("<F: "),
+ .Script => _ = try writer.write("<S: "),
+ }
+ if (self.name.ptr()) |name| {
+ _ = try writer.write(name.slice());
+ } else {
+ _ = try writer.write("-");
+ }
+ _ = try writer.writeAll(">");
+ }
+
+ pub fn eql(_: *const Self, _: *const Self) bool {
+ return false;
+ }
+
+ pub fn free(self: *const Self, allocator: std.mem.Allocator) void {
+ self.chunk.ptr().deinit();
+ self.chunk.destroy(allocator);
+ allocator.destroy(self);
+ }
+ };
+}
diff --git a/zlox/src/obj::list.zig b/zlox/src/obj::list.zig
@@ -0,0 +1,86 @@
+const std = @import("std");
+
+const utils = @import("lib::utils.zig");
+const list = @import("lib::list.zig");
+
+const Packed = @import("lib::packed.zig").Packed;
+const Value = @import("value.zig").Value;
+const Obj = @import("obj.zig").Obj;
+
+pub fn List(fields: anytype) type {
+ const Super = Obj(fields);
+
+ return packed struct {
+ const Self = @This();
+
+ pub const List = list.List(Value);
+ pub const Arg = void;
+ pub const Error = error{ OutOfMemory, InvalidArgument } || Self.List.Error;
+
+ obj: Super,
+ list: 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 Packed(*Self.List).create(allocator),
+ };
+ self.list.set(Self.List.init(allocator));
+ return self;
+ }
+
+ pub fn cast(self: anytype) utils.copy_const(@TypeOf(self), *Super) {
+ return @ptrCast(self);
+ }
+
+ pub fn format(self: *const Self, writer: *std.Io.Writer) std.Io.Writer.Error!void {
+ var lis = self.list.ptr();
+ var iter = lis.iter();
+ var count = lis.len();
+
+ _ = try writer.write("[");
+ while (iter.next()) |val| {
+ count -= 1;
+ try val.format(writer);
+ if (count > 0) _ = try writer.write(", ");
+ }
+ _ = try writer.writeAll("]");
+ }
+
+ pub fn eql(self: *const Self, other: *const Self) bool {
+ return self.list.ptr().eql(other.list.ptr(), Value.eql);
+ }
+
+ pub fn free(self: *Self, allocator: std.mem.Allocator) void {
+ self.list.ptr().free();
+ self.list.destroy(allocator);
+ allocator.destroy(self);
+ }
+
+ pub fn delete(self: *Self, index: Value) void {
+ var lis = self.list.ptr();
+ if (!index.is(Value.number) or index.number >= @as(Value.tagType(Value.number), @floatFromInt(lis.len()))) {
+ return;
+ }
+ _ = lis.pop(@intFromFloat(index.number)) catch return;
+ }
+
+ pub fn get(self: *const Self, index: Value) Error!Value {
+ var lis = self.list.ptr();
+ if (!index.is(Value.number) or index.number >= @as(Value.tagType(Value.number), @floatFromInt(lis.len()))) {
+ return Error.InvalidArgument;
+ }
+ return lis.get(@intFromFloat(index.number));
+ }
+
+ pub fn set(self: *Self, index: Value, val: Value) Error!void {
+ var lis = self.list.ptr();
+ if (!index.is(Value.number)) {
+ return Error.InvalidArgument;
+ }
+ _ = lis.set(@intFromFloat(index.number), val) catch
+ try lis.push(@intFromFloat(index.number), val);
+ }
+ };
+}
diff --git a/zlox/src/obj::native.zig b/zlox/src/obj::native.zig
@@ -0,0 +1,65 @@
+const std = @import("std");
+
+const utils = @import("lib::utils.zig");
+
+const Packed = @import("lib::packed.zig").Packed;
+const GC = @import("gc.zig").GC;
+const Value = @import("value.zig").Value;
+const Obj = @import("obj.zig").Obj;
+
+pub fn Native(fields: anytype) type {
+ const Super = Obj(fields);
+
+ return packed struct {
+ const Self = @This();
+ pub const Error = error{ OutOfMemory, Native };
+
+ pub const Fn = *const fn (*GC, []const Value) Error!Value;
+
+ pub const ArityMin = 0;
+ pub const ArityMax = std.math.maxInt(u8);
+
+ pub const Arg = struct { fun: Fn, arity_min: u8 = ArityMin, arity_max: u8 = ArityMax, name: []const u8 = "" };
+
+ obj: Super,
+ fun: Packed(Fn),
+ arity_min: u8,
+ arity_max: u8,
+ 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 = Packed(Fn).init(arg.fun),
+ .arity_min = arg.arity_min,
+ .arity_max = arg.arity_max,
+ .name = Packed([]const u8).init(arg.name),
+ };
+ return self;
+ }
+
+ pub fn call(self: *const Self, gc: *GC, argCount: u8, args: [*]Value) Error!Value {
+ const callable = self.fun.ptr();
+ return callable(gc, args[0..argCount]);
+ }
+
+ 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.write("<N: ");
+ _ = try writer.write(self.name.ptr());
+ _ = try writer.writeAll(">");
+ }
+
+ pub fn eql(_: *const Self, _: *const Self) bool {
+ return false;
+ }
+
+ pub fn free(self: *const Self, allocator: std.mem.Allocator) void {
+ allocator.destroy(self);
+ }
+ };
+}
diff --git a/zlox/src/obj::string.zig b/zlox/src/obj::string.zig
@@ -0,0 +1,114 @@
+const std = @import("std");
+
+const table = @import("lib::table.zig");
+const utils = @import("lib::utils.zig");
+const hash = @import("hash.zig");
+const value = @import("value.zig");
+
+const Obj = @import("obj.zig").Obj;
+
+pub fn String(fields: anytype) type {
+ const Super = Obj(fields);
+
+ return packed struct {
+ const Self = @This();
+ pub const Table = table.Table(*Self, void, hash.hash_t(*const Self), Self.eql);
+ pub const Arg = []const []const u8;
+ pub const Error = error{ OutOfMemory, IndexOutOfBounds } || Table.Error;
+
+ obj: Super,
+ len: usize = 0,
+ hash: u32,
+
+ fn data(self: anytype) utils.copy_const(@TypeOf(self), [*]u8) {
+ const p: utils.copy_const(@TypeOf(self), [*]u8) = @ptrCast(self);
+ return p + @sizeOf(Self);
+ }
+
+ fn new(arg: Arg, params: ArgParams, allocator: std.mem.Allocator) Error!*Self {
+ const ret: *Self = @ptrCast(try allocator.alignedAlloc(u8, std.mem.Alignment.of(Self), @sizeOf(Self) + params.len));
+ ret.* = Self{
+ .obj = Super.make(Self),
+ .hash = params.hash,
+ };
+ for (arg) |el| {
+ @memcpy(ret.data() + ret.len, el);
+ ret.len += el.len;
+ }
+ return ret;
+ }
+
+ pub fn slice(self: *const Self) []const u8 {
+ return self.data()[0..self.len];
+ }
+
+ 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.writeAll(self.slice());
+ }
+ pub fn eql(self: *const Self, other: *const Self) bool {
+ return @intFromPtr(self) == @intFromPtr(other);
+ }
+ pub fn get(self: *const Self, index: value.Value) Error!value.Value {
+ if (!index.is(value.Value.number) or index.number >= @as(value.Value.tagType(value.Value.number), @floatFromInt(self.len)) or index.number < 0) {
+ return Error.IndexOutOfBounds;
+ }
+ return value.Value.init(self.data()[@intFromFloat(index.number)]);
+ }
+
+ const ArgParams = struct { len: usize, hash: u32 };
+
+ fn table_check(m_arg: Arg, m_params: ArgParams) struct {
+ arg: Arg,
+ params: ArgParams,
+ pub fn check(self: *const @This(), k2: *const Self) bool {
+ if (k2.hash == self.params.hash and k2.len == self.params.len) {
+ var idx: usize = 0;
+ for (self.arg) |el| {
+ if (!std.mem.eql(u8, k2.data()[idx .. idx + el.len], el))
+ return false;
+ idx += el.len;
+ }
+ return true;
+ }
+ return false;
+ }
+ } {
+ return @TypeOf(table_check(m_arg, m_params)){ .arg = m_arg, .params = m_params };
+ }
+
+ fn arg_params(arg: Arg) ArgParams {
+ var ret = ArgParams{ .len = 0, .hash = hash.hash_t([]const u8)(&.{}) };
+
+ for (arg) |el| {
+ ret.len += el.len;
+ ret.hash = hash.hash_append(ret.hash, el);
+ }
+ return ret;
+ }
+
+ pub fn intern(arg: Arg, tabl: *Self.Table, isNewKey: *bool, allocator: std.mem.Allocator) Error!*Self {
+ const params = arg_params(arg);
+
+ try tabl.checkCapacity();
+ const entry = Self.Table.find_(tabl.entries, params.hash, table_check(arg, params));
+ isNewKey.* = entry.* != Self.Table.Entry.some;
+ if (isNewKey.*) {
+ _ = tabl.set_(entry, try new(arg, params, allocator), {});
+ }
+ return entry.some.key;
+ }
+
+ pub fn init(_: Arg, _: std.mem.Allocator) Error!*Self {
+ @compileError("The String Obj has to be interned");
+ }
+
+ pub fn free(self: *const Self, allocator: std.mem.Allocator) void {
+ const p: [*]align(@alignOf(Self)) const u8 = @ptrCast(self);
+ allocator.free(p[0 .. @sizeOf(Self) + self.len]);
+ }
+ };
+}
diff --git a/zlox/src/obj::table.zig b/zlox/src/obj::table.zig
@@ -0,0 +1,87 @@
+const std = @import("std");
+
+const table = @import("lib::table.zig");
+const utils = @import("lib::utils.zig");
+const hash = @import("hash.zig");
+
+const Packed = @import("lib::packed.zig").Packed;
+const Value = @import("value.zig").Value;
+const Obj = @import("obj.zig").Obj;
+
+pub fn Table(fields: anytype) type {
+ const Super = Obj(fields);
+
+ return packed struct {
+ const Self = @This();
+ pub const Arg = void;
+ pub const Table = table.Table(Value, Value, hash.hash_t(Value), Value.eql);
+ pub const Error = error{OutOfMemory} || Self.Table.Error;
+
+ obj: Super,
+ 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{
+ .obj = Super.make(Self),
+ .table = try Packed(*Self.Table).create(allocator),
+ .len = 0,
+ };
+ self.table.set(Self.Table.init(allocator));
+ return self;
+ }
+
+ pub fn cast(self: anytype) utils.copy_const(@TypeOf(self), *Super) {
+ return @ptrCast(self);
+ }
+
+ pub fn set(self: *Self, key: Value, val: Value) Error!bool {
+ self.len += 1;
+ return self.table.ptr().set(key, val);
+ }
+
+ pub fn get(self: *Self, key: Value) Error!Value {
+ return self.table.ptr().get(key);
+ }
+
+ pub fn delete(self: *Self, key: Value) void {
+ if (self.table.ptr().delete(key)) self.len -= 1;
+ }
+
+ pub fn format(self: *const Self, writer: *std.Io.Writer) !void {
+ const Printer = struct {
+ writer: @TypeOf(writer),
+ count: usize,
+
+ pub fn print(this: *@This(), key: Value, val: Value) std.Io.Writer.Error!void {
+ this.count -= 1;
+
+ try key.format(this.writer);
+ _ = try this.writer.write(":");
+ try val.format(this.writer);
+ if (this.count > 0) _ = try this.writer.write(", ");
+ }
+ };
+
+ 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);
+ } else {
+ _ = try writer.write(":");
+ }
+ _ = try writer.writeAll("]");
+ }
+
+ pub fn eql(self: *const Self, other: *const Self) bool {
+ return self.table.ptr().eql(other.table.ptr(), Value.eql);
+ }
+
+ pub fn free(self: *const Self, allocator: std.mem.Allocator) void {
+ self.table.ptr().deinit();
+ self.table.destroy(allocator);
+ allocator.destroy(self);
+ }
+ };
+}
diff --git a/zlox/src/obj::template.zig b/zlox/src/obj::template.zig
@@ -0,0 +1,43 @@
+const std = @import("std");
+
+const utils = @import("lib::utils.zig");
+
+const Obj = @import("obj.zig").Obj;
+
+pub fn Template(fields: anytype) type {
+ const Super = Obj(fields);
+
+ return packed struct {
+ const Self = @This();
+
+ pub const Arg = void;
+ pub const Error = error{OutOfMemory};
+
+ obj: Super,
+ pub fn init(arg: Arg, allocator: std.mem.Allocator) Error!*Self {
+ _ = arg;
+ _ = allocator;
+ return Error.OutOfMemory;
+ }
+
+ 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 {
+ _ = self;
+ _ = writer;
+ }
+
+ pub fn eql(self: *const Self, other: *const Self) bool {
+ _ = self;
+ _ = other;
+ return false;
+ }
+
+ pub fn free(self: *const Self, allocator: std.mem.Allocator) void {
+ _ = self;
+ _ = allocator;
+ }
+ };
+}
diff --git a/zlox/src/obj::upvalue.zig b/zlox/src/obj::upvalue.zig
@@ -0,0 +1,56 @@
+const std = @import("std");
+
+const utils = @import("lib::utils.zig");
+
+const Packed = @import("lib::packed.zig").Packed;
+const Value = @import("value.zig").Value;
+const Obj = @import("obj.zig").Obj;
+
+pub fn Upvalue(fields: anytype) type {
+ const Super = Obj(fields);
+
+ return packed struct {
+ const Self = @This();
+
+ pub const Arg = struct { val: *Value, slot: u8 };
+ pub const Error = error{OutOfMemory};
+
+ obj: Super,
+ 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 = 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 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.get(), self.location._ptr, self.closed, self.slot });
+ }
+
+ pub fn eql(_: *const Self, _: *const Self) bool {
+ return false;
+ }
+
+ pub fn free(self: *const Self, allocator: std.mem.Allocator) void {
+ if (self.closed) self.location.destroy(allocator);
+ allocator.destroy(self);
+ }
+ };
+}
diff --git a/zlox/src/packed.zig b/zlox/src/packed.zig
@@ -1,134 +0,0 @@
-const std = @import("std");
-const utils = @import("comptime_utils.zig");
-
-pub fn Packed(Type: type) type {
- return packed struct {
- const optional = utils.is_type(Type, "optional");
-
- const Ptr = if (optional) @typeInfo(Type).optional.child else Type;
-
- const Child = if (utils.is_type(Ptr, "pointer"))
- @typeInfo(Ptr).pointer.child
- else
- @compileError("Expected pointer type, got " ++ @typeName(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 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: Type) Self {
- return Self{
- ._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 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);
- }
-
- 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 len(self: Self) usize {
- return if (slice)
- self._len
- else
- @compileError("Cannot call len() on a non-slice pointer");
- }
-
- 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 {
- if (count != 1)
- @panic("Count has to be equal 1 for a single-item pointer");
-
- allocator.destroy(pointer);
- }
- }
-
- 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/scanner.zig b/zlox/src/scanner.zig
@@ -156,7 +156,7 @@ pub const Scanner = struct {
fn char(self: *@This()) Token {
if (self.isAtEnd()) return self.makeToken(ScannerError.UnterminatedChar);
- _ = self.advance();
+ _ = self.advance();
if (self.isAtEnd() or self.peek() != '\'') return self.makeToken(ScannerError.UnterminatedChar);
_ = self.advance();
diff --git a/zlox/src/table.zig b/zlox/src/table.zig
@@ -1,214 +0,0 @@
-const std = @import("std");
-const utils = @import("comptime_utils.zig");
-
-pub fn Table(K: type, V: type, hash_fn: fn (K) u32, cmp_fn: fn (K, K) bool) type {
- return struct {
- const Self = @This();
- const MaxLoad: f32 = 0.75;
-
- pub const Error = error{ OutOfMemory, KeyError };
-
- pub const Key = K;
- pub const Value = V;
-
- pub const Entry = union(enum) {
- const Some = struct {
- key: K,
- value: V,
- };
- some: Some,
- none,
- tomb,
- };
-
- count: usize,
- entries: []Entry,
- allocator: std.mem.Allocator,
-
- pub fn init(allocator: std.mem.Allocator) Self {
- return Self{ .count = 0, .entries = &.{}, .allocator = allocator };
- }
-
- fn growCapacity(self: *const Self) usize {
- return if (self.entries.len > 0)
- self.entries.len * 2
- else
- 10;
- }
-
- fn adjustCapacity(self: *Self, newsize: usize) Error!void {
- const entries = try self.allocator.alloc(Entry, newsize);
- for (entries) |*entry| {
- entry.* = .none;
- }
- self.count = 0;
- for (self.entries) |entry| {
- switch (entry) {
- .some => |some| {
- find(entries, some.key).* = entry;
- self.count += 1;
- },
- else => {},
- }
- }
- self.allocator.free(self.entries);
- self.entries = entries;
- }
- pub fn find_check(key: K) struct {
- k: K,
- pub fn check(self: *const @This(), k2: K) bool {
- return cmp_fn(self.k, k2);
- }
- } {
- return @TypeOf(find_check(key)){ .k = key };
- }
-
- pub fn find(entries: []Entry, key: K) *Entry {
- return find_(entries, hash_fn(key), find_check(key));
- }
-
- pub fn find_(entries: []Entry, hash: u32, check: anytype) *Entry {
- var idx = hash % entries.len;
- var tomb: ?*Entry = null;
-
- while (true) {
- const entry = &entries[idx];
- switch (entry.*) {
- .some => |some| if (check.check(some.key)) return entry,
- .tomb => tomb = if (tomb) |t| t else entry,
- .none => return if (tomb) |t| t else entry,
- }
- idx = (idx + 1) % entries.len;
- }
- }
-
- pub fn addAll(self: *Self, other: *const Self) Error!void {
- for (other.entries) |entry| {
- switch (entry) {
- .some => |some| self.set(some.key, some.value),
- else => {},
- }
- }
- }
-
- pub fn for_each(self: *const Self, arg: anytype, fun: if (@TypeOf(arg) == void) fn (K, V) void else fn (@TypeOf(arg), K, V) void) void {
- for (self.entries) |entry| {
- switch (entry) {
- .some => |some| if (@TypeOf(arg) == void)
- fun(some.key, some.value)
- else
- fun(arg, some.key, some.value),
- else => {},
- }
- }
- }
-
- pub fn for_each_try(self: *const Self, arg: anytype, fun: anytype) utils.fn_error(fun).?!void {
- for (self.entries) |entry| {
- switch (entry) {
- .some => |some| if (@TypeOf(arg) == void)
- try fun(some.key, some.value)
- else
- try fun(arg, some.key, some.value),
- else => {},
- }
- }
- }
-
- pub fn set_(self: *Self, entry: *Entry, key: K, val: V) bool {
- const isNewKey = switch (entry.*) {
- .none => blk: {
- self.count += 1;
- break :blk true;
- },
- .tomb => true,
- .some => false,
- };
-
- entry.* = Entry{ .some = Entry.Some{ .key = key, .value = val } };
- return isNewKey;
- }
-
- pub fn eql(self: *const Self, other: *const Self, cmpval_fn: fn (V, V) bool) bool {
- for (self.entries) |entry| {
- switch (entry) {
- .some => |some| {
- switch (find(other.entries, some.key).*) {
- .some => |some2| if (!cmpval_fn(some.value, some2.value)) {
- return false;
- },
- else => return false,
- }
- },
- else => {},
- }
- }
- return true;
- }
-
- pub fn checkCapacity(self: *Self) Error!void {
- const len: f32 = @floatFromInt(self.entries.len);
- const count: f32 = @floatFromInt(self.count);
- if (count + 1.0 > len * MaxLoad) {
- try self.adjustCapacity(self.growCapacity());
- }
- }
-
- pub fn set(self: *Self, key: K, val: V) Error!bool {
- try self.checkCapacity();
- return self.set_(find(self.entries, key), key, val);
- }
-
- pub fn replace(self: *Self, key: K, val: V) Error!void {
- if (self.entries.len == 0)
- return Error.KeyError;
-
- const entry = find(self.entries, key);
- switch (entry.*) {
- .some => _ = self.set_(entry, key, val),
- else => return Error.KeyError,
- }
- }
-
- pub fn replace_if(self: *Self, key: K, val: V, fun: fn (V) bool) Error!bool {
- if (self.entries.len == 0)
- return Error.KeyError;
-
- const entry = find(self.entries, key);
- switch (entry.*) {
- .some => |some| return fun(some.value) and !self.set_(entry, key, val),
- else => return Error.KeyError,
- }
- }
-
- pub fn get(self: *const Self, key: K) Error!V {
- if (self.entries.len == 0)
- return Error.KeyError;
-
- return switch (find(self.entries, key).*) {
- .some => |some| some.value,
- else => Error.KeyError,
- };
- }
-
- pub fn delete(self: *Self, key: K) bool {
- if (self.entries.len == 0) return false;
-
- const entry = find(self.entries, key);
- switch (entry.*) {
- .some => entry.* = .tomb,
- else => return false,
- }
-
- return true;
- }
-
- pub fn deinit(self: *@This()) void {
- if (self.entries.len > 0) {
- self.allocator.free(self.entries);
- self.entries = &.{};
- self.count = 0;
- }
- }
- };
-}
diff --git a/zlox/src/value.zig b/zlox/src/value.zig
@@ -1,7 +1,9 @@
const std = @import("std");
-const array = @import("array.zig");
+
+const array = @import("lib::array.zig");
+const utils = @import("lib::utils.zig");
+
const Obj = @import("gc.zig").GC.Obj;
-const utils = @import("comptime_utils.zig");
pub const Value = union(enum) {
number: f64,
@@ -40,7 +42,6 @@ pub const Value = union(enum) {
return @unionInit(Self, tagNameOf(@TypeOf(val)), val);
}
-
fn toTag(comptime from: anytype) Tag {
return if (@TypeOf(from) == Obj.Type)
.obj
diff --git a/zlox/src/vm.zig b/zlox/src/vm.zig
@@ -1,19 +1,22 @@
-const Chunk = @import("chunk.zig").Chunk;
-const OP = @import("chunk.zig").OP;
-const Value = @import("value.zig").Value;
const std = @import("std");
+
+const table = @import("lib::table.zig");
+const list = @import("lib::list.zig");
+const utils = @import("lib::utils.zig");
+const callbacks = @import("vm::callbacks.zig");
+const native = @import("vm::native.zig");
const debug = @import("debug.zig");
const compiler = @import("compiler.zig");
+const hash = @import("hash.zig");
+const chunk = @import("chunk.zig");
+
+const Chunk = chunk.Chunk;
+const OP = chunk.OP;
+const Value = @import("value.zig").Value;
const GC = @import("gc.zig").GC;
const Obj = GC.Obj;
-const Callback = @import("vm/callbacks.zig");
-const table = @import("table.zig");
-const list = @import("list.zig");
-const hash = @import("hash.zig");
-const utils = @import("comptime_utils.zig");
-const vm_native = @import("vm/native.zig");
-const InterpreterError = Obj.Error || compiler.CompilerError || Callback.Error || error{ CompileError, RuntimeError, StackOverflow, IndexOutOfBounds, Overflow, DivisionByZero };
+const InterpreterError = Obj.Error || compiler.CompilerError || callbacks.Error || error{ CompileError, RuntimeError, StackOverflow, IndexOutOfBounds, Overflow, DivisionByZero };
pub const VM = struct {
objects: GC,
@@ -91,12 +94,12 @@ pub const VM = struct {
.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 self.defineNative("clock", 0, 0, native.Clock.clock);
+ try self.defineNative("put", 1, 1, native.put);
+ try self.defineNative("table", 0, Obj.Native.ArityMax, native.table);
+ try self.defineNative("list", 0, Obj.Native.ArityMax, native.list);
- vm_native.Clock.set_start(io);
+ native.Clock.set_start(io);
return self;
}
@@ -252,12 +255,12 @@ pub const VM = struct {
self.frames[self.frameCount - 1] = CallFrame.init(.Function, callee, self.stackTop - argCount - 1);
}
- fn callNative(self: *@This(), native: *Obj.Native, argCount: u8) !void {
- if (argCount < native.arity_min or argCount > native.arity_max) {
- self.runtimeError("Expected from {d} to {d} arguments but got {d}", .{ native.arity_min, native.arity_max, argCount });
+ fn callNative(self: *@This(), obj: *Obj.Native, argCount: u8) !void {
+ if (argCount < obj.arity_min or argCount > obj.arity_max) {
+ self.runtimeError("Expected from {d} to {d} arguments but got {d}", .{ obj.arity_min, obj.arity_max, argCount });
return InterpreterError.RuntimeError;
}
- const result = try native.call(&self.vm.objects, argCount, self.stackTop - argCount);
+ const result = try obj.call(&self.vm.objects, argCount, self.stackTop - argCount);
self.stackTop -= argCount + 1;
self.push(result);
return;
@@ -290,7 +293,7 @@ pub const VM = struct {
}
}
- fn binary_op(self: *@This(), comptime in_tag: anytype, comptime out_tag: anytype, op: Callback.Type(in_tag, out_tag)) InterpreterError!void {
+ fn binary_op(self: *@This(), comptime in_tag: anytype, comptime out_tag: anytype, op: callbacks.Type(in_tag, out_tag)) InterpreterError!void {
const b = self.pop();
const a = self.pop();
if (a.is(in_tag) and b.is(in_tag)) {
@@ -347,9 +350,9 @@ pub const VM = struct {
},
@intFromEnum(OP.ADD) => {
if (self.peek(0).is(Obj.Type.String)) {
- try self.binary_op(Obj.Type.String, Obj.Type.String, Callback.concatenate(&self.vm.objects));
+ try self.binary_op(Obj.Type.String, Obj.Type.String, callbacks.concatenate(&self.vm.objects));
} else {
- try self.binary_op(Value.number, Value.number, Callback.add);
+ try self.binary_op(Value.number, Value.number, callbacks.add);
}
},
@intFromEnum(OP.JUMP_IF_FALSE) => {
@@ -470,14 +473,14 @@ pub const VM = struct {
},
@intFromEnum(OP.DEFINE_GLOBAL) => _ = try self.vm.globals.set(self.read_string(), Global.make_var(self.pop())),
@intFromEnum(OP.DEFINE_GLOBAL_CONSTANT) => _ = try self.vm.globals.set(self.read_string(), Global.make_con(self.pop())),
- @intFromEnum(OP.SUBTRACT) => try self.binary_op(Value.number, Value.number, Callback.sub),
- @intFromEnum(OP.MULTIPLY) => try self.binary_op(Value.number, Value.number, Callback.mul),
- @intFromEnum(OP.DIVIDE) => try self.binary_op(Value.number, Value.number, Callback.div),
+ @intFromEnum(OP.SUBTRACT) => try self.binary_op(Value.number, Value.number, callbacks.sub),
+ @intFromEnum(OP.MULTIPLY) => try self.binary_op(Value.number, Value.number, callbacks.mul),
+ @intFromEnum(OP.DIVIDE) => try self.binary_op(Value.number, Value.number, callbacks.div),
@intFromEnum(OP.TRUE) => self.push(Value.init(true)),
@intFromEnum(OP.FALSE) => self.push(Value.init(false)),
@intFromEnum(OP.EQUAL) => self.push(Value.init(self.pop().eql(self.pop()))),
- @intFromEnum(OP.LESS) => try self.binary_op(Value.number, Value.bool, Callback.less),
- @intFromEnum(OP.GREATER) => try self.binary_op(Value.number, Value.bool, Callback.more),
+ @intFromEnum(OP.LESS) => try self.binary_op(Value.number, Value.bool, callbacks.less),
+ @intFromEnum(OP.GREATER) => try self.binary_op(Value.number, Value.bool, callbacks.more),
@intFromEnum(OP.NIL) => self.push(Value.init({})),
@intFromEnum(OP.NOT) => self.push(Value.init(!self.pop().isTruthy())),
else => return InterpreterError.CompileError,
diff --git a/zlox/src/vm/callbacks.zig b/zlox/src/vm/callbacks.zig
@@ -1,66 +0,0 @@
-const std = @import("std");
-const GC = @import("../gc.zig").GC;
-const Obj = GC.Obj;
-const Value = @import("../value.zig").Value;
-
-const Number = Value.tagType(.number);
-const Bool = Value.tagType(.bool);
-
-pub const Error = Obj.Error;
-
-pub fn Type(comptime in_tag: anytype, comptime out_tag: anytype) type {
- if (@TypeOf(in_tag) == Obj.Type) {
- return struct {
- objects: *GC,
- _call: *const fn (self: *const @This(), Value.tagType(in_tag), Value.tagType(in_tag)) Error!Value.tagType(out_tag),
- pub fn call(self: *const @This(), a: Value.tagType(in_tag), b: Value.tagType(in_tag)) Error!Value.tagType(out_tag) {
- return self._call(self, a, b);
- }
- };
- } else {
- return struct {
- call: fn (Value.tagType(in_tag), Value.tagType(in_tag)) callconv(.@"inline") Error!Value.tagType(out_tag),
- };
- }
-}
-
-pub fn concatenate(objects: *GC) Type(Obj.Type.String, Obj.Type.String) {
- const Ret = Type(Obj.Type.String, Obj.Type.String);
- const ret = Ret{ .objects = objects, ._call = struct {
- pub fn concatenate(self: *const Ret, lhs: *Obj, rhs: *Obj) Error!*Obj {
- return try self.objects.emplace_cast(.String, &.{ (lhs.cast(.String) catch unreachable).slice(), (rhs.cast(.String) catch unreachable).slice() });
- }
- }.concatenate };
- return ret;
-}
-
-pub const add = Type(Value.number, Value.number){ .call = struct {
- pub inline fn add(a: Number, b: Number) Error!Number {
- return a + b;
- }
-}.add };
-pub const mul = Type(Value.number, Value.number){ .call = struct {
- pub inline fn mul(a: Number, b: Number) Error!Number {
- return a * b;
- }
-}.mul };
-pub const sub = Type(Value.number, Value.number){ .call = struct {
- pub inline fn sub(a: Number, b: Number) Error!Number {
- return a - b;
- }
-}.sub };
-pub const div = Type(Value.number, Value.number){ .call = struct {
- pub inline fn div(a: Number, b: Number) Error!Number {
- return a / b;
- }
-}.div };
-pub const less = Type(Value.number, Value.bool){ .call = struct {
- pub inline fn less(a: Number, b: Number) Error!Bool {
- return a < b;
- }
-}.less };
-pub const more = Type(Value.number, Value.bool){ .call = struct {
- pub inline fn more(a: Number, b: Number) Error!Bool {
- return a > b;
- }
-}.more };
diff --git a/zlox/src/vm/native.zig b/zlox/src/vm/native.zig
@@ -1,40 +0,0 @@
-const std = @import("std");
-const GC = @import("../gc.zig").GC;
-const Value = @import("../value.zig").Value;
-
-pub const Error = GC.Obj.Native.Error;
-
-pub const Clock = struct {
- var start: std.Io.Timestamp = undefined;
-
- pub fn set_start(io: std.Io) void {
- start = std.Io.Timestamp.now(io, std.Io.Clock.awake);
- }
-
- 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).toMilliseconds())));
- }
-};
-
-pub fn put(_: *GC, args: []const Value) Error!Value {
- std.debug.print("{f}", .{args[0]});
- return Value.init({});
-}
-
-pub fn table(gc: *GC, args: []const Value) Error!Value {
- var tbl = gc.emplace(.Table, {}) catch return Error.Native;
- if (args.len % 2 != 0) return Error.Native;
- var i: usize = 0;
- while (i < args.len) : (i += 2) {
- _ = tbl.set(args[i], args[i + 1]) catch return Error.Native;
- }
- return Value.init(tbl.cast());
-}
-
-pub fn list(gc: *GC, args: []const Value) Error!Value {
- var lis = gc.emplace(.List, {}) catch return Error.Native;
- for (args) |arg| {
- lis.list.ptr().push(-1, arg) catch return Error.Native;
- }
- return Value.init(lis.cast());
-}
diff --git a/zlox/src/vm::callbacks.zig b/zlox/src/vm::callbacks.zig
@@ -0,0 +1,66 @@
+const std = @import("std");
+
+const GC = @import("gc.zig").GC;
+const Obj = GC.Obj;
+const Value = @import("value.zig").Value;
+pub const Error = Obj.Error;
+
+const Number = Value.tagType(.number);
+const Bool = Value.tagType(.bool);
+
+pub fn Type(comptime in_tag: anytype, comptime out_tag: anytype) type {
+ if (@TypeOf(in_tag) == Obj.Type) {
+ return struct {
+ objects: *GC,
+ _call: *const fn (self: *const @This(), Value.tagType(in_tag), Value.tagType(in_tag)) Error!Value.tagType(out_tag),
+ pub fn call(self: *const @This(), a: Value.tagType(in_tag), b: Value.tagType(in_tag)) Error!Value.tagType(out_tag) {
+ return self._call(self, a, b);
+ }
+ };
+ } else {
+ return struct {
+ call: fn (Value.tagType(in_tag), Value.tagType(in_tag)) callconv(.@"inline") Error!Value.tagType(out_tag),
+ };
+ }
+}
+
+pub fn concatenate(objects: *GC) Type(Obj.Type.String, Obj.Type.String) {
+ const Ret = Type(Obj.Type.String, Obj.Type.String);
+ const ret = Ret{ .objects = objects, ._call = struct {
+ pub fn concatenate(self: *const Ret, lhs: *Obj, rhs: *Obj) Error!*Obj {
+ return try self.objects.emplace_cast(.String, &.{ (lhs.cast(.String) catch unreachable).slice(), (rhs.cast(.String) catch unreachable).slice() });
+ }
+ }.concatenate };
+ return ret;
+}
+
+pub const add = Type(Value.number, Value.number){ .call = struct {
+ pub inline fn add(a: Number, b: Number) Error!Number {
+ return a + b;
+ }
+}.add };
+pub const mul = Type(Value.number, Value.number){ .call = struct {
+ pub inline fn mul(a: Number, b: Number) Error!Number {
+ return a * b;
+ }
+}.mul };
+pub const sub = Type(Value.number, Value.number){ .call = struct {
+ pub inline fn sub(a: Number, b: Number) Error!Number {
+ return a - b;
+ }
+}.sub };
+pub const div = Type(Value.number, Value.number){ .call = struct {
+ pub inline fn div(a: Number, b: Number) Error!Number {
+ return a / b;
+ }
+}.div };
+pub const less = Type(Value.number, Value.bool){ .call = struct {
+ pub inline fn less(a: Number, b: Number) Error!Bool {
+ return a < b;
+ }
+}.less };
+pub const more = Type(Value.number, Value.bool){ .call = struct {
+ pub inline fn more(a: Number, b: Number) Error!Bool {
+ return a > b;
+ }
+}.more };
diff --git a/zlox/src/vm::native.zig b/zlox/src/vm::native.zig
@@ -0,0 +1,41 @@
+const std = @import("std");
+
+const GC = @import("gc.zig").GC;
+const Value = @import("value.zig").Value;
+
+pub const Error = GC.Obj.Native.Error;
+
+pub const Clock = struct {
+ var start: std.Io.Timestamp = undefined;
+
+ pub fn set_start(io: std.Io) void {
+ start = std.Io.Timestamp.now(io, std.Io.Clock.awake);
+ }
+
+ 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).toMilliseconds())));
+ }
+};
+
+pub fn put(_: *GC, args: []const Value) Error!Value {
+ std.debug.print("{f}", .{args[0]});
+ return Value.init({});
+}
+
+pub fn table(gc: *GC, args: []const Value) Error!Value {
+ var tbl = gc.emplace(.Table, {}) catch return Error.Native;
+ if (args.len % 2 != 0) return Error.Native;
+ var i: usize = 0;
+ while (i < args.len) : (i += 2) {
+ _ = tbl.set(args[i], args[i + 1]) catch return Error.Native;
+ }
+ return Value.init(tbl.cast());
+}
+
+pub fn list(gc: *GC, args: []const Value) Error!Value {
+ var lis = gc.emplace(.List, {}) catch return Error.Native;
+ for (args) |arg| {
+ lis.list.ptr().push(-1, arg) catch return Error.Native;
+ }
+ return Value.init(lis.cast());
+}