DzLox

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

commit 80a74f80476e5f8fee826829d9fc44d688794cf3
parent 3a280a553cf0189bda3c0546b94716be5b07e506
Author: Szymon Mikulicz <szymon.mikulicz@aptiv.com>
Date:   Sun, 18 Aug 2024 17:59:47 +0200

Lists finished

Diffstat:
Mzlox/src/obj/list.zig | 92++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Mzlox/src/obj/table.zig | 14+++++++++++---
Mzlox/src/vm.zig | 25++++++++++++++++++-------
3 files changed, 109 insertions(+), 22 deletions(-)

diff --git a/zlox/src/obj/list.zig b/zlox/src/obj/list.zig @@ -13,6 +13,7 @@ pub const List = packed struct { const Element = struct { val: Value, next: ?*@This(), + prev: ?*@This(), }; pub const Arg = void; @@ -20,6 +21,7 @@ pub const List = packed struct { obj: Super, len: usize = 0, tip: ?*Element, + end: ?*Element, pub fn init(_: Arg, allocator: std.mem.Allocator) Error!*Self { const self: *Self = try allocator.create(Self); @@ -28,6 +30,7 @@ pub const List = packed struct { .type = Super.Type.List, }, .tip = null, + .end = null, }; return self; } @@ -38,10 +41,10 @@ pub const List = packed struct { pub fn format(self: *const Self, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) utils.fn_error(@TypeOf(writer).write)!void { _ = try writer.write("["); - var tip = self.tip; - while (tip) |el| : (tip = el.next) { + var end = self.end; + while (end) |el| : (end = el.prev) { try el.val.format(fmt, options, writer); - _ = try writer.write(","); + if (el.prev) |_| _ = try writer.write(", "); } _ = try writer.writeAll("]"); } @@ -68,17 +71,64 @@ pub const List = packed struct { if (!index.is(Value.number) or index.number >= @as(Value.tagType(Value.number), @floatFromInt(self.len)) or index.number < 0) { return error.KeyError; } - var idx = self.len - @as(usize, @intFromFloat(index.number)); - var tip = self.tip; - while(idx > 1) : (idx -= 1) { - tip = tip.?.next; + var idx_rev: usize = @intFromFloat(index.number); + var idx = self.len - idx_rev; + idx_rev += 1; + + if (idx < idx_rev) { + var tip = self.tip; + while(idx > 1) : (idx -= 1) { + tip = tip.?.next; + } + return tip.?.val; + } else { + var end = self.end; + while(idx_rev > 1) : (idx_rev -= 1) { + end = end.?.prev; + } + return end.?.val; + } + } + + pub fn set(self: *Self, index: Value, val: Value, allocator: std.mem.Allocator) !void { + if (!index.is(Value.number) or index.number < 0) { + return error.KeyError; + } + + var idx_rev: isize = @intFromFloat(index.number); + var idx: isize = @as(isize, @intCast(self.len)) - idx_rev; + idx_rev += 1; + + if (idx <= 0) { + while(idx < 0) : (idx += 1) { + try self.push(Value.init({}), allocator); + } + try self.push(val, allocator); + } else if (idx < idx_rev) { + var tip = self.tip; + while(idx > 1) : (idx -= 1) { + tip = tip.?.next; + } + tip.?.val = val; + } else { + var end = self.end; + while(idx_rev > 1) : (idx_rev -= 1) { + end = end.?.prev; + } + end.?.val = val; } - return tip.?.val; + } pub fn pop(self: *Self, allocator: std.mem.Allocator) ?Value { if (self.tip) |tip| { - self.tip = tip.next; + if (tip.next) |next| { + next.prev = null; + self.tip = next; + } else { + self.tip = null; + self.end = null; + } self.len -= 1; const val = tip.val; allocator.destroy(tip); @@ -88,10 +138,28 @@ pub const List = packed struct { } pub fn push(self: *Self, val: Value, allocator: std.mem.Allocator) Error!void { - var new_tip = try allocator.create(Element); - new_tip.next = self.tip; - new_tip.val = val; + const new_tip = try allocator.create(Element); + if (self.end == null) { + self.end = new_tip; + } + if (self.tip) |old_tip| { + old_tip.prev = new_tip; + } + new_tip.* = Element{.val = val, .next = self.tip, .prev = null}; self.tip = new_tip; self.len += 1; } + + pub fn push_end(self: *Self, val: Value, allocator: std.mem.Allocator) Error!void { + const new_end = try allocator.create(Element); + if (self.tip == null) { + self.tip = new_end; + } + if (self.end) |old_end| { + old_end.next = new_end; + } + new_end.* = Element{.val = val, .next = null, .prev = self.end}; + self.end = new_end; + self.len += 1; + } }; diff --git a/zlox/src/obj/table.zig b/zlox/src/obj/table.zig @@ -50,18 +50,26 @@ pub const Table = packed struct { const Printer = struct { options: std.fmt.FormatOptions, writer: @TypeOf(writer), + count: usize, + + pub fn print(this: *@This(), key: value.Value, val: value.Value) utils.fn_error(@TypeOf(writer).write)!void { + this.count -= 1; - pub fn print(this: @This(), key: value.Value, val: value.Value) utils.fn_error(@TypeOf(writer).write)!void { try key.format(fmt, this.options, this.writer); _ = try this.writer.write(":"); try val.format(fmt, this.options, this.writer); - _ = try this.writer.write(","); + if (this.count > 0) _ = try this.writer.write(", "); } }; + var printer = Printer{.options = options, .writer = writer, .count = self.table.count}; _ = try writer.write("["); - try self.table.for_each_try(Printer{.options = options, .writer = writer}, Printer.print); + if (self.table.count > 0) { + try self.table.for_each_try(&printer, Printer.print); + } else { + _ = try writer.write(":"); + } _ = try writer.writeAll("]"); } pub fn eql(self: *const Self, other: *const Self) bool { diff --git a/zlox/src/vm.zig b/zlox/src/vm.zig @@ -309,16 +309,27 @@ pub const VM = struct { const val = self.pop(); const key = self.pop(); const obj = self.pop(); - if (!obj.is(Obj.Type.Table)) { + if (obj.is(Obj.Type.Table)) { + var m = obj.obj.cast(.Table) catch unreachable; + if (val.is(Value.nil)) { + m.delete(key); + } else { + _ = try m.set(key, val); + } + } else if (obj.is(Obj.Type.List)) { + var m = obj.obj.cast(.List) catch unreachable; + if (val.is(Value.nil) and key.eql(Value.init(@as(f64, @floatFromInt(m.len - 1))))) { + _ = m.pop(self.vm.allocator); + } else { + m.set(key, val, self.vm.allocator) catch { + self.runtimeError("Invalid index for a list, has to be a number greater than 0", .{}); + return InterpreterError.RuntimeError; + }; + } + } else { self.runtimeError("Cannot index a non-table value", .{}); return InterpreterError.RuntimeError; } - var m = obj.obj.cast(.Table) catch unreachable; - if (val.is(Value.nil)) { - m.delete(key); - } else { - _ = try m.set(key, val); - } self.push(val); }, @intFromEnum(OP.CALL) => {