commit 21af2b44699d3f682c70983534e263ce8ebb4c83
parent d4f440b41b027c3333067b328ce19a5c3bab6aa1
Author: Szymon Mikulicz <szymon.mikulicz@posteo.net>
Date: Fri, 6 Dec 2024 19:35:39 +0100
Bugfixes
Diffstat:
5 files changed, 79 insertions(+), 112 deletions(-)
diff --git a/zlox/src/compiler.zig b/zlox/src/compiler.zig
@@ -262,11 +262,11 @@ pub fn Compiler(size: comptime_int) type {
const argCount = self.argumentList();
self.emit(OP.CALL, argCount);
}
-
+
fn argumentList(self: *Self) u8 {
var argCount: u8 = 0;
if (!self.check(Token.RIGHT_PAREN)) {
- while(true) {
+ while (true) {
self.expression();
if (argCount == std.math.maxInt(u8)) {
self.errorAtPrevious("Too many arguments");
@@ -287,7 +287,7 @@ pub fn Compiler(size: comptime_int) type {
return err;
}));
}
-
+
fn emitObj(self: *Self, comptime tp: Obj.Type, arg: tp.get().Arg) !void {
self.emit(OP.CONSTANT, try self.makeObj(tp, arg));
}
@@ -298,9 +298,9 @@ pub fn Compiler(size: comptime_int) type {
var argCount: u8 = 0;
var isList = true;
- if (self.match(Token.RIGHT_BRACKET)) {
- } else if (self.match(Token.COLON)) {
+ if (self.match(Token.RIGHT_BRACKET)) {} else if (self.match(Token.COLON)) {
isList = false;
+ self.consume(Token.RIGHT_BRACKET, "Expect ']'");
} else {
self.expression();
argCount += 1;
@@ -309,12 +309,12 @@ pub fn Compiler(size: comptime_int) type {
self.expression();
argCount += 1;
}
- while(!self.match(Token.RIGHT_BRACKET)) {
+ while (!self.match(Token.RIGHT_BRACKET)) {
self.consume(Token.COMMA, "Expect ',' between expressions");
if (self.match(Token.RIGHT_BRACKET)) break;
self.expression();
argCount += 1;
- if(!isList) {
+ if (!isList) {
self.consume(Token.COLON, "Expect ':' between key and value");
self.expression();
argCount += 1;
@@ -322,9 +322,9 @@ pub fn Compiler(size: comptime_int) type {
}
}
if (isList) {
- self.currentChunk().code.set(offset, self.makeObj(.Native, Obj.Native.Arg{.name = "internal::list", .fun = vm_native.list}) catch return) catch return;
+ self.currentChunk().code.set(offset, self.makeObj(.Native, Obj.Native.Arg{ .name = "internal::list", .fun = vm_native.list }) catch return) catch return;
} else {
- self.currentChunk().code.set(offset, self.makeObj(.Native, Obj.Native.Arg{.name = "internal::table", .fun = vm_native.table}) catch return) catch return;
+ self.currentChunk().code.set(offset, self.makeObj(.Native, Obj.Native.Arg{ .name = "internal::table", .fun = vm_native.table }) catch return) catch return;
}
self.emit(OP.CALL, argCount);
}
@@ -345,15 +345,15 @@ pub fn Compiler(size: comptime_int) type {
}
fn namedVariable(self: *Self, tok: scanner.Token, canAssign: bool) void {
- const OPs: struct {get: OP, set: OP, arg: u8} = if (self.resolveLocal(tok)) |arg|
- .{.get = OP.GET_LOCAL, .set = OP.SET_LOCAL, .arg = arg}
+ const OPs: struct { get: OP, set: OP, arg: u8 } = if (self.resolveLocal(tok)) |arg|
+ .{ .get = OP.GET_LOCAL, .set = OP.SET_LOCAL, .arg = arg }
else if (self.resolveUpvalue(tok)) |arg|
- .{.get = OP.GET_UPVALUE, .set = OP.SET_UPVALUE, .arg = arg}
+ .{ .get = OP.GET_UPVALUE, .set = OP.SET_UPVALUE, .arg = arg }
else
- .{.get = OP.GET_GLOBAL, .set = OP.SET_GLOBAL, .arg = self.identifierConstant(tok) catch return};
+ .{ .get = OP.GET_GLOBAL, .set = OP.SET_GLOBAL, .arg = self.identifierConstant(tok) catch return };
if (canAssign and self.match(Token.EQUAL)) {
- if(OPs.get == OP.GET_LOCAL and self.locals[OPs.arg].con) {
+ if (OPs.get == OP.GET_LOCAL and self.locals[OPs.arg].con) {
self.errorAtPrevious("Cannot assign to a constant");
return;
}
@@ -372,10 +372,10 @@ pub fn Compiler(size: comptime_int) type {
} else if (enclosing.resolveUpvalue(name)) |upvalue| {
return self.addUpvalue(upvalue, false) catch null;
}
- }
+ }
return null;
}
-
+
fn addUpvalue(self: *Self, idx: u8, isLocal: bool) !u8 {
const count = self.currentFunction.upvalue_count;
@@ -391,7 +391,7 @@ pub fn Compiler(size: comptime_int) type {
return self.lastError;
}
- self.upvalues[count] = .{.index = idx, .isLocal = isLocal};
+ self.upvalues[count] = .{ .index = idx, .isLocal = isLocal };
self.currentFunction.upvalue_count += 1;
return count;
}
@@ -399,9 +399,9 @@ pub fn Compiler(size: comptime_int) type {
fn resolveLocal(self: *Self, name: scanner.Token) ?u8 {
var i = self.localCount;
while (i > 0) : (i -= 1) {
- if (identifiersEql(self.locals[i-1].name, name)) {
- if(self.locals[i-1].depth) |_| {
- return @intCast(i-1);
+ if (identifiersEql(self.locals[i - 1].name, name)) {
+ if (self.locals[i - 1].depth) |_| {
+ return @intCast(i - 1);
} else {
self.errorAt(name, "Can't read local variable in it's own initializer");
}
@@ -599,7 +599,7 @@ pub fn Compiler(size: comptime_int) type {
self.consume(Token.IDENTIFIER, errorMessage);
self.declareVariable(con);
- if(self.scopeDepth > 0) return 0;
+ if (self.scopeDepth > 0) return 0;
return self.identifierConstant(self.previous);
}
@@ -617,7 +617,7 @@ pub fn Compiler(size: comptime_int) type {
var i = self.localCount;
while (i > 0) : (i -= 1) {
- const local = self.locals[i-1];
+ const local = self.locals[i - 1];
if (local.depth) |depth| {
if (depth < self.scopeDepth) break;
}
@@ -639,17 +639,17 @@ pub fn Compiler(size: comptime_int) type {
self.errorAt(name, "Too many variables in function");
return;
}
- self.locals[self.localCount] = Local {.name = name, .con = con};
+ self.locals[self.localCount] = Local{ .name = name, .con = con };
self.localCount += 1;
}
fn markInitialized(self: *Self) void {
- if(self.scopeDepth == 0) return;
- self.locals[self.localCount-1].depth = self.scopeDepth;
+ if (self.scopeDepth == 0) return;
+ self.locals[self.localCount - 1].depth = self.scopeDepth;
}
fn defineVariable(self: *Self, global: u8, con: bool) void {
- if (self.scopeDepth > 0){
+ if (self.scopeDepth > 0) {
self.markInitialized();
return;
}
@@ -715,8 +715,8 @@ pub fn Compiler(size: comptime_int) type {
self.consume(Token.LEFT_PAREN, "Expect '(' after 'switch'.");
- self.emitObj(.Native, Obj.Native.Arg{.name = "switch", .fun = vm_native.table}) catch return;
-
+ self.emitObj(.Native, Obj.Native.Arg{ .name = "switch", .fun = vm_native.table }) catch return;
+
var jumpOver = self.emitJump(OP.JUMP);
const switchExpression = self.currentChunk().code.len;
self.expression();
@@ -733,7 +733,7 @@ pub fn Compiler(size: comptime_int) type {
self.consume(Token.LEFT_BRACE, "Expect '{' after switch()");
- while(!self.match(Token.RIGHT_BRACE)) {
+ while (!self.match(Token.RIGHT_BRACE)) {
if (self.match(Token.CASE)) {
self.expression();
argCount += 2;
@@ -888,11 +888,10 @@ pub fn Compiler(size: comptime_int) type {
self.currentChunk().code.set(offset + 1, @intCast(jump & 0xff)) catch {
self.errorAtPrevious("Invalid jump offset");
};
-
}
fn block(self: *Self) void {
- while(!self.check(Token.RIGHT_BRACE) and !self.check(Token.EOF)) {
+ while (!self.check(Token.RIGHT_BRACE) and !self.check(Token.EOF)) {
self.declaration();
}
@@ -906,13 +905,13 @@ pub fn Compiler(size: comptime_int) type {
fn endScope(self: *Self) void {
self.scopeDepth -= 1;
- while(self.localCount > 0) {
- if (self.locals[self.localCount-1].depth) |depth| {
+ while (self.localCount > 0) {
+ if (self.locals[self.localCount - 1].depth) |depth| {
if (depth <= self.scopeDepth) break;
} else {
- self.errorAt(self.locals[self.localCount-1].name, "Unitialized variable at scope end");
+ self.errorAt(self.locals[self.localCount - 1].name, "Unitialized variable at scope end");
}
- if (self.locals[self.localCount-1].captured) {
+ if (self.locals[self.localCount - 1].captured) {
self.emitOP(OP.CLOSE_UPVALUE);
} else {
self.emitOP(OP.POP);
@@ -957,14 +956,14 @@ pub fn Compiler(size: comptime_int) type {
.localCount = 1,
.scopeDepth = 0,
.enclosing = null,
- .upvalues = [_]Upvalue{Upvalue{.index = 0, .isLocal = false}} ** upvalues_size,
+ .upvalues = [_]Upvalue{Upvalue{ .index = 0, .isLocal = false }} ** upvalues_size,
};
self.locals[0].depth = 0;
return self;
}
fn init_enclosed(enclosing: *Self, fun: *Obj.Function) Self {
- var enclosed = Self.init(enclosing.scanner, enclosing.objects, fun);
+ var enclosed = Self.init(enclosing.scanner, enclosing.objects, fun);
enclosed.current = enclosing.current;
enclosed.enclosing = enclosing;
enclosed.beginScope();
diff --git a/zlox/src/gc.zig b/zlox/src/gc.zig
@@ -4,8 +4,7 @@ const list = @import("list.zig");
const Value = @import("value.zig").Value;
pub const GC = struct {
-
- pub const Obj = @import("obj.zig").Obj(.{.mark = false});
+ pub const Obj = @import("obj.zig").Obj(.{ .mark = false });
const Self = @This();
@@ -48,7 +47,7 @@ pub const GC = struct {
if (DBG_STRESS) {
self.collect();
}
- dbg_print("Allocating {} at 0x{x}: {s}\n", .{obj.obj.type, @intFromPtr(obj), obj});
+ dbg_print("Allocating {} at 0x{x}: {s}\n", .{ obj.obj.type, @intFromPtr(obj), obj });
try self.list.push(obj.cast());
}
return obj;
@@ -56,37 +55,36 @@ pub const GC = struct {
pub fn markTable(table: anytype) void {
const Table = @TypeOf(table);
- table.for_each({}, struct{
+ table.for_each({}, struct {
pub fn fun(key: Table.Key, val: Table.Value) void {
Self.mark(key);
Self.mark(val);
}
}.fun);
-
}
pub fn markArray(arr: anytype) void {
- for(arr) |el| {
+ for (arr) |el| {
Self.mark(el);
}
}
pub fn mark(arg: anytype) void {
const T = @TypeOf(arg);
- switch(T) {
- Value => switch(arg) {
+ switch (T) {
+ Value => switch (arg) {
.obj => |o| {
mark(o);
},
- else => {}
+ else => {},
},
*Obj => {
- dbg_print("Marking {} at 0x{x}: {s}\n", .{arg.type, @intFromPtr(arg), arg});
+ dbg_print("Marking {} at 0x{x}: {s}\n", .{ arg.type, @intFromPtr(arg), arg });
arg.fields.mark = true;
},
- else => if(Obj.isChild(T)) {
+ else => if (Obj.isChild(T)) {
mark(arg.cast());
- }
+ },
}
}
@@ -97,7 +95,7 @@ pub const GC = struct {
pub fn deinit(self: *Self) void {
while (true) {
const el = self.list.pop() catch break;
- dbg_print("Freeing {} at 0x{x}: {s}\n", .{el.type, @intFromPtr(el), el});
+ dbg_print("Freeing {} at 0x{x}: {s}\n", .{ el.type, @intFromPtr(el), el });
el.free(self.allocator);
}
self.list.free();
diff --git a/zlox/src/obj/native.zig b/zlox/src/obj/native.zig
@@ -9,19 +9,14 @@ pub fn Native(fields: anytype) type {
return packed struct {
const Self = @This();
- pub const Error = error { OutOfMemory, Native };
+ 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 = ""
- };
+ pub const Arg = struct { fun: Fn, arity_min: u8 = ArityMin, arity_max: u8 = ArityMax, name: []const u8 = "" };
obj: Super,
fun: Fn,
@@ -32,19 +27,13 @@ pub fn Native(fields: anytype) type {
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 = arg.fun,
- .arity_min = arg.arity_min,
- .arity_max = arg.arity_max,
- .name = arg.name.ptr,
- .name_len = arg.name.len
- };
+ self.* = Self{ .obj = Super.make(Self), .fun = arg.fun, .arity_min = arg.arity_min, .arity_max = arg.arity_max, .name = arg.name.ptr, .name_len = arg.name.len };
return self;
}
pub fn call(self: *const Self, gc: *GC, argCount: u8, args: [*]Value) Error!Value {
- return self.fun(gc, args[0..argCount]);
+ const callable = self.fun; // Compiler bug: https://github.com/ziglang/zig/issues/20539
+ return callable(gc, args[0..argCount]);
}
pub fn cast(self: anytype) utils.copy_const(@TypeOf(self), *Super) {
diff --git a/zlox/src/vm.zig b/zlox/src/vm.zig
@@ -31,14 +31,14 @@ pub const VM = struct {
}
pub fn make_var(v: Value) Self {
- return Self {
+ return Self{
.val = v,
.con = false,
};
}
pub fn make_con(v: Value) Self {
- return Self {
+ return Self{
.val = v,
.con = true,
};
@@ -54,27 +54,17 @@ pub const VM = struct {
chunk: *const Chunk,
pub fn init(comptime tp: Obj.Type, callee: *const tp.get(), slots: [*]Value) @This() {
- return switch(tp) {
- .Function => @This() {
- .callee = callee.cast(),
- .ip = callee.chunk.code.data.ptr,
- .chunk = callee.chunk,
- .slots = slots
- },
- .Closure => @This() {
- .callee = callee.cast(),
- .ip = callee.function.chunk.code.data.ptr,
- .chunk = callee.function.chunk,
- .slots = slots
- },
- else => @compileError("Invalid type")
+ return switch (tp) {
+ .Function => @This(){ .callee = callee.cast(), .ip = callee.chunk.code.data.ptr, .chunk = callee.chunk, .slots = slots },
+ .Closure => @This(){ .callee = callee.cast(), .ip = callee.function.chunk.code.data.ptr, .chunk = callee.function.chunk, .slots = slots },
+ else => @compileError("Invalid type"),
};
}
};
fn defineNative(self: *@This(), name: []const u8, arity_min: u8, arity_max: u8, fun: Obj.Native.Fn) !void {
const nameObj = try self.objects.emplace(.String, &.{name});
- const funObj = try self.objects.emplace_cast(.Native, Obj.Native.Arg{.fun = fun, .name = name, .arity_min = arity_min, .arity_max = arity_max});
+ const funObj = try self.objects.emplace_cast(.Native, Obj.Native.Arg{ .fun = fun, .name = name, .arity_min = arity_min, .arity_max = arity_max });
_ = try self.globals.set(nameObj, Global.make_con(Value.init(funObj)));
}
@@ -114,14 +104,7 @@ pub const VM = struct {
open_upvalues: List,
pub fn run(vm: *VM, function: *Obj.Function, dbg: bool) InterpreterError!void {
- var self = @This(){
- .frames = [_]CallFrame{undefined} ** callstack_size,
- .frameCount = 1,
- .stack = [_]Value{Value.init({})} ** stack_size,
- .stackTop = undefined,
- .vm = vm,
- .open_upvalues = List.init(vm.allocator)
- };
+ var self = @This(){ .frames = [_]CallFrame{undefined} ** callstack_size, .frameCount = 1, .stack = [_]Value{Value.init({})} ** stack_size, .stackTop = undefined, .vm = vm, .open_upvalues = List.init(vm.allocator) };
defer self.open_upvalues.free();
@@ -182,11 +165,11 @@ pub const VM = struct {
}
fn callValue(self: *@This(), callee: Value, argCount: u8) !void {
- if(callee.is(Obj.Type.Function)) {
+ if (callee.is(Obj.Type.Function)) {
try self.callFunction(callee.obj.cast(.Function) catch unreachable, argCount);
- } else if(callee.is(Obj.Type.Closure)) {
+ } else if (callee.is(Obj.Type.Closure)) {
try self.callClosure(callee.obj.cast(.Closure) catch unreachable, argCount);
- } else if(callee.is(Obj.Type.Native)) {
+ } else if (callee.is(Obj.Type.Native)) {
try self.callNative(callee.obj.cast(.Native) catch unreachable, argCount);
} else {
self.runtimeError("Can only call functions and classes", .{});
@@ -196,7 +179,7 @@ pub const VM = struct {
fn callClosure(self: *@This(), callee: *Obj.Closure, argCount: u8) !void {
if (argCount != callee.function.arity) {
- self.runtimeError("Expected {d} arguments but got {d}", .{callee.function.arity, argCount});
+ self.runtimeError("Expected {d} arguments but got {d}", .{ callee.function.arity, argCount });
return InterpreterError.RuntimeError;
}
if (self.frameCount == callstack_size - 1)
@@ -205,10 +188,9 @@ pub const VM = struct {
self.frames[self.frameCount - 1] = CallFrame.init(.Closure, callee, self.stackTop - argCount - 1);
}
-
fn callFunction(self: *@This(), callee: *Obj.Function, argCount: u8) !void {
if (argCount != callee.arity) {
- self.runtimeError("Expected {d} arguments but got {d}", .{callee.arity, argCount});
+ self.runtimeError("Expected {d} arguments but got {d}", .{ callee.arity, argCount });
return InterpreterError.RuntimeError;
}
if (self.frameCount == callstack_size - 1)
@@ -219,7 +201,7 @@ pub const VM = struct {
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});
+ self.runtimeError("Expected from {d} to {d} arguments but got {d}", .{ native.arity_min, native.arity_max, argCount });
return InterpreterError.RuntimeError;
}
const result = try native.call(&self.vm.objects, argCount, self.stackTop - argCount);
@@ -230,20 +212,20 @@ pub const VM = struct {
fn captureUpvalue(self: *@This(), slot: u8) !*Obj.Upvalue {
var upvalue = self.open_upvalues.tip;
- while(upvalue) |el| : (upvalue = el.next) {
+ while (upvalue) |el| : (upvalue = el.next) {
const val = el.val.?;
if (val.slot == slot)
return val;
if (val.slot > slot)
break;
}
- const new = try self.vm.objects.emplace(.Upvalue, .{.val = &self.frame().slots[slot], .slot = slot});
+ const new = try self.vm.objects.emplace(.Upvalue, .{ .val = &self.frame().slots[slot], .slot = slot });
try self.open_upvalues.insert_after(upvalue, new);
return new;
}
fn closeUpvalues(self: *@This(), slot: u8) !void {
- while(self.open_upvalues.tip) |el| {
+ while (self.open_upvalues.tip) |el| {
if (el.val.?.slot < slot) break;
const upval = self.open_upvalues.pop() catch unreachable;
@@ -372,7 +354,7 @@ pub const VM = struct {
const obj = self.pop();
var pushed = false;
if (obj.is(Value.obj)) {
- switch(obj.obj.type) {
+ switch (obj.obj.type) {
.Function, .Native, .Closure, .Upvalue => {},
inline else => |tp| {
self.push((obj.obj.cast(tp) catch unreachable).get(key) catch Value.init({}));
@@ -391,7 +373,7 @@ pub const VM = struct {
const obj = self.pop();
var pushed = false;
if (obj.is(Value.obj)) {
- switch(obj.obj.type) {
+ switch (obj.obj.type) {
.Function, .Native, .Closure, .Upvalue, .String => {},
inline else => |tp| {
var m = obj.obj.cast(tp) catch unreachable;
@@ -401,7 +383,7 @@ pub const VM = struct {
_ = try m.set(key, val);
}
pushed = true;
- }
+ },
}
}
if (!pushed) {
@@ -417,10 +399,10 @@ pub const VM = struct {
@intFromEnum(OP.CLOSURE) => {
const function = try self.read_constant().obj.cast(.Function);
const closure = try self.vm.objects.emplace(.Closure, function);
- for(closure.upvalues[0..closure.upvalues_len]) |*upvalue| {
+ for (closure.upvalues[0..closure.upvalues_len]) |*upvalue| {
const isLocal = self.read_byte();
const slot = self.read_byte();
- if(isLocal == 1) {
+ if (isLocal == 1) {
upvalue.* = try self.captureUpvalue(slot);
} else {
const callee = try self.frame().callee.cast(.Closure);
@@ -451,7 +433,7 @@ pub const VM = struct {
while (true) : (i -= 1) {
const fram = self.frames[i];
const idx = @intFromPtr(fram.ip) - @intFromPtr(fram.chunk.code.data.ptr);
- std.debug.print("[line {d}] in {s}\n", .{fram.chunk.lines.get(idx) catch 1, fram.callee});
+ std.debug.print("[line {d}] in {s}\n", .{ fram.chunk.lines.get(idx) catch 1, fram.callee });
if (i == 0) break;
}
std.debug.print(fmt ++ "\n", args);
diff --git a/zlox/src/vm/native.zig b/zlox/src/vm/native.zig
@@ -11,14 +11,13 @@ pub const Clock = struct {
start = try std.time.Instant.now();
}
- pub fn clock(_: *GC, _: [] const Value) Error!Value {
+ pub fn clock(_: *GC, _: []const Value) Error!Value {
const now = std.time.Instant.now() catch return Error.Native;
const elapsed: f64 = @floatFromInt(now.since(start));
return Value.init(elapsed / std.time.ns_per_s);
}
};
-
pub fn put(_: *GC, args: []const Value) Error!Value {
std.debug.print("{s}", .{args[0]});
return Value.init({});
@@ -28,15 +27,15 @@ 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;
+ 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| {
+ for (args) |arg| {
lis.list.push(arg) catch return Error.Native;
}
return Value.init(lis.cast());