commit 80a74f80476e5f8fee826829d9fc44d688794cf3
parent 3a280a553cf0189bda3c0546b94716be5b07e506
Author: Szymon Mikulicz <szymon.mikulicz@aptiv.com>
Date: Sun, 18 Aug 2024 17:59:47 +0200
Lists finished
Diffstat:
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) => {