DzLox

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

commit 68378e629d0ced133499efba76b570bd7a5e4068
parent c28ffd6c01e94fde49e78fc710a307922efbaf0a
Author: Szymon Mikulicz <szymon.mikulicz@posteo.net>
Date:   Thu, 27 Aug 2026 17:29:58 +0200

Anonymous functions

Diffstat:
Mzlox/fib.lox | 12++++++------
Mzlox/src/compiler.zig | 27+++++----------------------
Mzlox/src/debug.zig | 26++++++++------------------
Mzlox/src/gc.zig | 2--
Mzlox/src/lib::array.zig | 12++++++++++++
Mzlox/src/lib::packed.zig | 2+-
Mzlox/src/obj::closure.zig | 7+------
Mzlox/src/obj::function.zig | 17+++--------------
Mzlox/src/obj::native.zig | 4----
Mzlox/src/value.zig | 7+++++++
Mzlox/src/vm.zig | 4++--
11 files changed, 45 insertions(+), 75 deletions(-)

diff --git a/zlox/fib.lox b/zlox/fib.lox @@ -1,9 +1,9 @@ -fun fib(n) { +con fib = fun(n) { if (n < 2) return n; return fib(n - 2) + fib(n - 1); -} +}; -fun printf(fmt, args) { +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] == '}') { @@ -15,15 +15,15 @@ fun printf(fmt, args) { } } print ""; -} +}; -fun main() { +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/compiler.zig b/zlox/src/compiler.zig @@ -115,6 +115,7 @@ pub fn Compiler(size: comptime_int) type { T.NIL => R(S.literal, null, P.NONE ), T.OR => R(null, S._or, P.OR ), T.TRUE => R(S.literal, null, P.NONE ), + T.FUN => R(S.function, null, P.NONE ), else => R(null, null, P.NONE ), // zig fmt: on }; @@ -328,13 +329,11 @@ pub fn Compiler(size: comptime_int) type { } if (isList) { self.currentChunk().code.set(offset, self.makeObj(.Native, Obj.Native.Arg{ - .name = "list", .fun = vm_native.list, .type = .Literal, }) catch return) catch return; } else { self.currentChunk().code.set(offset, self.makeObj(.Native, Obj.Native.Arg{ - .name = "table", .fun = vm_native.table, .type = .Literal, }) catch return) catch return; @@ -515,9 +514,7 @@ pub fn Compiler(size: comptime_int) type { } fn declaration(self: *Self) void { - if (self.match(Token.FUN)) { - self.funDeclaration(); - } else if (self.match(Token.VAR)) { + if (self.match(Token.VAR)) { self.varDeclaration(); } else if (self.match(Token.CON)) { self.conDeclaration(); @@ -528,15 +525,8 @@ pub fn Compiler(size: comptime_int) type { if (self.panicMode) self.synchronize(); } - fn funDeclaration(self: *Self) void { - const global = self.parseVariable("Expect function name.", true) catch return; - self.markInitialized(); - self.function(self.previous.lexeme, Obj.Function.Type.Function); - self.defineVariable(global, true); - } - - fn function(self: *Self, name: []const u8, tp: Obj.Function.Type) void { - var fun = self.objects.emplace(Obj.Type.Function, tp) catch |err| { + fn function(self: *Self, _: bool) void { + var fun = self.objects.emplace(Obj.Type.Function, .Function) catch |err| { self.errorAtPrevious("Couldn't allocate function"); self.lastError = err; return; @@ -548,12 +538,6 @@ pub fn Compiler(size: comptime_int) type { return; }; - fun.set_name(self.objects.emplace(Obj.Type.String, &.{name}) catch |err| { - self.errorAtPrevious("Couldn't allocate function name"); - self.lastError = err; - return; - }); - compiler.consume(Token.LEFT_PAREN, "Expect '(' after function name"); if (!compiler.check(Token.RIGHT_PAREN)) { while (true) { @@ -734,7 +718,6 @@ 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, .type = .Literal, }) catch return; @@ -1005,7 +988,7 @@ pub fn Compiler(size: comptime_int) type { pub fn compile(source: []const u8, objects: *GC) CompilerError!*Obj.Function { var scan = try scanner.Scanner.init(source); - const fun = try objects.emplace(Obj.Type.Function, Obj.Function.Type.Script); + const fun = try objects.emplace(Obj.Type.Function, .Script); var self = Self.init(&scan, objects, fun); try objects.push_callback(&gc_callback, &self); diff --git a/zlox/src/debug.zig b/zlox/src/debug.zig @@ -7,15 +7,15 @@ 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}); +pub fn disassembleChunk(ch: *const chunk.Chunk) Error!void { + print("/=======\\\n", .{}); var offset: usize = 0; while (offset < ch.code.len) { offset = try _disassembleInstruction(ch, offset, true); } - print("\\= {s} =/\n", .{name}); + print("\\=======/\n", .{}); } pub fn print_offset(ch: *const chunk.Chunk, offset: usize) !void { @@ -88,14 +88,9 @@ fn constantInstruction(name: []const u8, ch: *const chunk.Chunk, offset: usize, const constant = try ch.code.get(offset + 1); const constval = try ch.constants.get(constant); print("{s:<32} {d:4} '{f}'\n", .{ name, constant, constval }); - if (print_fn and constval.is(Obj.Type.Function)) { - const function = constval.obj.cast(.Function) catch unreachable; - if (function.name.get()) |fn_name| { - try disassembleChunk(function.chunk.ptr(), fn_name.slice()); - } else { - try disassembleChunk(function.chunk.ptr(), "<anon>"); - } - } + if (print_fn) if (constval.cast_if(Obj.Type.Function)) |function| { + try disassembleChunk(function.chunk.ptr()); + }; return offset + 2; } @@ -126,13 +121,8 @@ fn closureInstruction(name: []const u8, ch: *const chunk.Chunk, offset: usize, p print("{s:<38}|-> {s} {d}\n", .{ "", if (isLocal == 1) "local" else "upvalue", idx }); off += 2; } - if (print_fn) { - if (function.name.get()) |fn_name| { - try disassembleChunk(function.chunk.ptr(), fn_name.slice()); - } else { - try disassembleChunk(function.chunk.ptr(), "<anon>"); - } - } + if (print_fn) + try disassembleChunk(function.chunk.ptr()); return off + 1; } diff --git a/zlox/src/gc.zig b/zlox/src/gc.zig @@ -99,8 +99,6 @@ pub const GC = struct { }.fun); }, *Obj.Function => { - if (obj.name.ptr()) |name| - self.mark("f", name); for (obj.chunk.ptr().constants.slice()) |constant| self.mark("f", constant); }, diff --git a/zlox/src/lib::array.zig b/zlox/src/lib::array.zig @@ -28,6 +28,12 @@ pub fn Array(comptime T: type, comptime S: type, comptime size: S) type { return self.data[idx]; } + pub fn if_get(self: *const @This(), idx: S) ?T { + if (idx >= self.len) + return null; + return self.data[idx]; + } + pub fn set(self: *const @This(), idx: S, val: T) !void { if (idx >= self.len) return error.IndexOutOfBounds; @@ -40,6 +46,12 @@ pub fn Array(comptime T: type, comptime S: type, comptime size: S) type { return self.data[self.len - 1]; } + pub fn if_last(self: *const @This()) ?T { + if (self.len == 0) + return null; + return self.data[self.len - 1]; + } + pub fn deinit(self: *@This()) void { self.allocator.free(self.data); } diff --git a/zlox/src/lib::packed.zig b/zlox/src/lib::packed.zig @@ -118,7 +118,7 @@ pub fn Packed(Type: type) type { } } - pub fn set(self: Self, val: if (many or slice) Ptr else Child) void { + pub fn set(self: Self, val: if (many or slice) utils.mod_ptr_t(Ptr, "const", true) else Child) void { if (many or slice) @memcpy(self.ptr(), val) else diff --git a/zlox/src/obj::closure.zig b/zlox/src/obj::closure.zig @@ -33,13 +33,8 @@ pub fn Closure(fields: anytype) type { return @ptrCast(self); } - pub fn format(self: *const Self, writer: *std.Io.Writer) !void { + pub fn format(_: *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(">"); } diff --git a/zlox/src/obj::function.zig b/zlox/src/obj::function.zig @@ -8,10 +8,10 @@ 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}; @@ -20,28 +20,22 @@ pub fn Function(fields: anytype) type { 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 { + pub fn init(tpe: 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, + .type = tpe, .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); } @@ -51,11 +45,6 @@ pub fn Function(fields: anytype) 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(">"); } diff --git a/zlox/src/obj::native.zig b/zlox/src/obj::native.zig @@ -25,7 +25,6 @@ pub fn Native(fields: anytype) type { fun: Fn, arity_min: u8 = ArityMin, arity_max: u8 = ArityMax, - name: []const u8 = "", type: Type = .Builtin, }; @@ -33,7 +32,6 @@ pub fn Native(fields: anytype) type { fun: Packed(Fn), arity_min: u8, arity_max: u8, - name: Packed([]const u8), type: Type, pub fn init(arg: Arg, allocator: std.mem.Allocator) Error!*Self { @@ -43,7 +41,6 @@ pub fn Native(fields: anytype) type { .fun = Packed(Fn).init(arg.fun), .arity_min = arg.arity_min, .arity_max = arg.arity_max, - .name = Packed([]const u8).init(arg.name), .type = arg.type, }; return self; @@ -63,7 +60,6 @@ pub fn Native(fields: anytype) type { .Builtin => _ = try writer.write("<B: "), .Literal => _ = try writer.write("<L: "), } - _ = try writer.write(self.name.ptr()); _ = try writer.writeAll(">"); } diff --git a/zlox/src/value.zig b/zlox/src/value.zig @@ -56,6 +56,13 @@ pub const Value = union(enum) { }; } + pub fn cast_if(self: Self, comptime tag: anytype) if (@TypeOf(tag) == Tag) ?utils.typeFromTag(Self, tag) else ?*Obj.Type.get(tag) { + return switch (self) { + toTag(tag) => if (@TypeOf(tag) == Tag) self.get(tag) else self.obj.cast_if(tag), + else => null, + }; + } + pub fn get(self: Self, comptime tag: anytype) tagType(tag) { return @field(self, @tagName(toTag(tag))); } diff --git a/zlox/src/vm.zig b/zlox/src/vm.zig @@ -68,9 +68,9 @@ pub const VM = struct { 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}); GC.exclude(nameObj.cast()); + const funObj = try self.objects.emplace_cast(.Native, Obj.Native.Arg{ .fun = fun, - .name = nameObj.slice(), .arity_min = arity_min, .arity_max = arity_max, }); @@ -117,7 +117,7 @@ pub const VM = struct { const function = try compiler.Compiler(stack_size).compile(source, &self.objects); - if (dbg) try debug.disassembleChunk(function.chunk.ptr(), "Main"); + if (dbg) try debug.disassembleChunk(function.chunk.ptr()); try Interpreter(callstack_size, stack_size).run(self, function, dbg); }