commit 6a04bf164625fc290aad19d49c88f28c9d44a408
parent bb0372fa9cd599acb5a2a6ed771ff4f994fae1fe
Author: Szymon Mikulicz <szymon.mikulicz@posteo.net>
Date: Tue, 1 Sep 2026 17:19:37 +0200
Fix upvalue bug
Diffstat:
11 files changed, 107 insertions(+), 55 deletions(-)
diff --git a/zlox/fib.lox b/zlox/fib.lox
@@ -1,29 +0,0 @@
-con fib = fun(n) {
- if (n < 2) return n;
- return fib(n - 2) + fib(n - 1);
-};
-
-con printf = fun(fmt, args) {
- var args_i = 0;
- for(var i = 0; fmt[i]; i = i + 1) {
- if(fmt[i] == '{' and fmt[i+1] == '}') {
- put(args[args_i]);
- args_i = args_i + 1;
- i = i + 1;
- } else {
- put(fmt[i]);
- }
- }
- print "";
-};
-
-con main = fun() {
- con num = 28;
- con start = clock();
- con result = fib(num);
- con end = clock() - start;
-
- printf("fib({}) == {}, time: {} ms", [num, result, end]);
-};
-
-main();
diff --git a/zlox/src/lib::list.zig b/zlox/src/lib::list.zig
@@ -41,16 +41,18 @@ pub fn List(T: type) type {
return ret;
}
- pub fn add_prev(self: *Element, gpa: std.mem.Allocator, val: Value) !void {
+ pub fn add_prev(self: *Element, gpa: std.mem.Allocator, val: Value) !*Element {
self.prev.next = try Element.init(gpa, self.prev, self, val);
self.prev = self.prev.next;
if (self.next == self) self.next = self.prev;
+ return self.prev;
}
- pub fn add_next(self: *Element, gpa: std.mem.Allocator, val: Value) !void {
+ pub fn add_next(self: *Element, gpa: std.mem.Allocator, val: Value) !*Element {
self.next.prev = try Element.init(gpa, self, self.next, val);
self.next = self.next.prev;
if (self.prev == self) self.prev = self.next;
+ return self.next;
}
pub fn new(gpa: std.mem.Allocator, val: Value) !*Element {
@@ -96,9 +98,9 @@ pub fn List(T: type) type {
if (@"const") @compileError("Cannot call push() on a const Iterator");
if (self.this) |el| {
- try self.super.insert(false, el, val);
+ self.super.retip(el, try self.super.insert(.prev, el, val));
} else if (self.super.tip) |el| {
- try self.super.insert(true, el.prev, val);
+ _ = try self.super.insert(.prev, el, val);
} else {
try self.super.begin(val);
}
@@ -156,10 +158,10 @@ pub fn List(T: type) type {
}
fn at(self: *Self, idx: isize) Error!*Element {
- return if (@abs(idx) >= self._len and idx < -self._len)
- Error.IndexOutOfBounds
+ return if (-self._len <= idx and idx < self._len)
+ try self._at(idx)
else
- try self._at(idx);
+ Error.IndexOutOfBounds;
}
pub fn set(self: *Self, idx: isize, val: Value) Error!void {
@@ -196,25 +198,34 @@ pub fn List(T: type) type {
self._len = 1;
}
- fn insert(self: *Self, after: bool, anchor: *Element, val: Value) !void {
- if (after) {
- try anchor.add_next(self.gpa, val);
- } else {
+ fn insert(self: *Self, dir: enum { next, prev }, anchor: *Element, val: Value) !*Element {
+ const new = if (dir == .next)
+ 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;
+
+ return new;
+ }
+
+ fn retip(self: *Self, old: ?*Element, new: *Element) void {
+ if (self.tip == old) self.tip = new;
}
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 len1 = self._len + 1;
+
+ if (-len1 <= idx and idx < len1) {
const el = self._at(idx) catch return self.begin(val);
- try self.insert(idx < 0, el, val);
+ const new = try self.insert(if (idx < 0) .next else .prev, el, val);
+
+ if (idx == -len1 or idx == 0) {
+ self.tip = new;
+ }
+ } else {
+ return Error.IndexOutOfBounds;
}
}
};
diff --git a/zlox/src/obj::closure.zig b/zlox/src/obj::closure.zig
@@ -34,8 +34,7 @@ pub fn Closure(fields: anytype) type {
}
pub fn format(_: *const Self, writer: *std.Io.Writer) !void {
- _ = try writer.write("<C: ");
- _ = try writer.writeAll(">");
+ _ = try writer.write("<Closure>");
}
pub fn eql(_: *const Self, _: *const Self) bool {
diff --git a/zlox/src/obj::function.zig b/zlox/src/obj::function.zig
@@ -42,10 +42,9 @@ pub fn Function(fields: anytype) type {
pub fn format(self: *const Self, writer: *std.Io.Writer) !void {
switch (self.type) {
- .Function => _ = try writer.write("<F: "),
- .Script => _ = try writer.write("<S: "),
+ .Function => _ = try writer.write("<Function>"),
+ .Script => _ = try writer.write("<Script>"),
}
- _ = try writer.writeAll(">");
}
pub fn eql(_: *const Self, _: *const Self) bool {
diff --git a/zlox/src/obj::native.zig b/zlox/src/obj::native.zig
@@ -57,10 +57,9 @@ pub fn Native(fields: anytype) type {
pub fn format(self: *const Self, writer: *std.Io.Writer) !void {
switch (self.type) {
- .Builtin => _ = try writer.write("<B: "),
- .Literal => _ = try writer.write("<L: "),
+ .Builtin => _ = try writer.write("<Builtin>"),
+ .Literal => _ = try writer.write("<Literal> "),
}
- _ = try writer.writeAll(">");
}
pub fn eql(_: *const Self, _: *const Self) bool {
diff --git a/zlox/src/obj::upvalue.zig b/zlox/src/obj::upvalue.zig
@@ -49,6 +49,8 @@ pub fn Upvalue(fields: anytype) type {
}
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/vm.zig b/zlox/src/vm.zig
@@ -102,6 +102,7 @@ pub const VM = struct {
try self.defineNative("table", 0, Obj.Native.ArityMax, native.table);
try self.defineNative("list", 0, Obj.Native.ArityMax, native.list);
try self.defineNative("rungc", 0, 0, native.rungc);
+ try self.defineNative("len", 1, 1, native.len);
native.Clock.set_start(io);
diff --git a/zlox/src/vm::native.zig b/zlox/src/vm::native.zig
@@ -48,3 +48,16 @@ pub fn rungc(gc: *GC, _: []const Value) Error!Value {
gc.collect();
return Value.init({});
}
+
+pub fn len(_: *GC, val: []const Value) Error!Value {
+ if (val[0].cast_if(Value.obj)) |obj| {
+ const ret = switch (obj.type) {
+ .String => (obj.cast(.String) catch unreachable).len,
+ .Table => (obj.cast(.Table) catch unreachable).table.ptr().count,
+ .List => (obj.cast(.List) catch unreachable).list.ptr().len(),
+ else => return Error.Native,
+ };
+ return Value.init(@as(f64, @floatFromInt(ret)));
+ }
+ return Error.Native;
+}
diff --git a/zlox/test/closure.lox b/zlox/test/closure.lox
@@ -0,0 +1,20 @@
+fun mk() {
+ var i = 0;
+ var l = [];
+ return fun() {
+ l[len(l)] = i = i + 1;
+ print l;
+ };
+}
+
+con f = mk();
+
+f();
+f();
+f();
+
+con f2 = mk();
+
+f2();
+f2();
+f2();
diff --git a/zlox/test/fib.lox b/zlox/test/fib.lox
@@ -0,0 +1,29 @@
+fun fib(n) {
+ if (n < 2) return n;
+ return fib(n - 2) + fib(n - 1);
+}
+
+fun printf(fmt, args) {
+ var args_i = 0;
+ for(var i = 0; fmt[i]; i = i + 1) {
+ if(fmt[i] == '{' and fmt[i+1] == '}') {
+ put(args[args_i]);
+ args_i = args_i + 1;
+ i = i + 1;
+ } else {
+ put(fmt[i]);
+ }
+ }
+ print "";
+}
+
+fun main() {
+ con num = 28;
+ con start = clock();
+ con result = fib(num);
+ con end = clock() - start;
+
+ printf("fib({}) == {}, time: {} ms", [num, result, end]);
+}
+
+main();
diff --git a/zlox/test/list.lox b/zlox/test/list.lox
@@ -0,0 +1,8 @@
+con a = [];
+
+a[0] = 1;
+print a;
+a[1] = 2;
+print a;
+a[-3] = 0;
+print a;