DzLox

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

commit cd43147544be4d6d48a6959ea0bdae6176d9c321
parent bb3007599d98231af265275281a7f824aa96a29c
Author: Szymon Mikulicz <szymon.mikulicz@aptiv.com>
Date:   Fri,  9 Aug 2024 17:43:26 +0200

Print via format()

Diffstat:
Mzlox/src/comptime_utils.zig | 4++++
Mzlox/src/debug.zig | 4+---
Mzlox/src/obj.zig | 5+++--
Mzlox/src/obj/function.zig | 25++++++++++++++++++-------
Mzlox/src/obj/string.zig | 6++++--
Mzlox/src/obj/table.zig | 26++++++++++++++++----------
Mzlox/src/obj/template.zig | 5++++-
Mzlox/src/table.zig | 14++++++++++++--
Mzlox/src/value.zig | 39++++++++++++++++++++-------------------
Mzlox/src/vm.zig | 7++-----
10 files changed, 84 insertions(+), 51 deletions(-)

diff --git a/zlox/src/comptime_utils.zig b/zlox/src/comptime_utils.zig @@ -19,3 +19,7 @@ pub fn tagFromType(T: type, U: type) std.meta.Tag(T) { } @compileError("No matching tag for type " ++ @typeName(U) ++ " in Union " ++ @typeName(T)); } + +pub fn fn_error(comptime fun: anytype) type { + return @typeInfo(@typeInfo(@TypeOf(fun)).Fn.return_type.?).ErrorUnion.error_set; +} diff --git a/zlox/src/debug.zig b/zlox/src/debug.zig @@ -68,9 +68,7 @@ fn simpleInstruction(name: []const u8, offset: usize) usize { fn constantInstruction(name: []const u8, ch: chunk.Chunk, offset: usize) !usize { const constant = try ch.code.get(offset + 1); - print("{s:<32} {d:4} '", .{ name, constant }); - (try ch.constants.get(constant)).print(); - print("'\n", .{}); + print("{s:<32} {d:4} '{s}'\n", .{ name, constant, try ch.constants.get(constant)}); return offset + 2; } diff --git a/zlox/src/obj.zig b/zlox/src/obj.zig @@ -26,9 +26,10 @@ pub const Obj = packed struct { pub fn init(comptime tp: Type, arg: tp.get().Arg, allocator: std.mem.Allocator) !*Super { return (try tp.get().init(arg, allocator)).cast(); } - pub fn print(self: *const Super) void { + + pub fn format(self: *const Super, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { switch (self.type) { - inline else => |tp| self._cast(tp).print(), + inline else => |tp| try self._cast(tp).format(fmt, options, writer), } } pub fn eql(self: *const Super, other: *const Super) bool { diff --git a/zlox/src/obj/function.zig b/zlox/src/obj/function.zig @@ -14,18 +14,28 @@ pub const Function = packed struct { chunk: *chunk.Chunk, name: *String, - pub fn init(arg: Arg, allocator: std.mem.Allocator) Error!*Self { - _ = arg; - _ = allocator; - return error.OutOfMemory; + pub fn init(_: Arg, allocator: std.mem.Allocator) Error!*Self { + const self: *Self = try allocator.create(Self); + self.* = Self{ + .obj = Super{ + .type = Super.Type.Function, + }, + .chunk = try allocator.create(chunk.Chunk), + .arity = 0, + }; + self.chunk.* = chunk.Chunk.init(allocator); + return self; } pub fn cast(self: *Self) *Super { return @ptrCast(self); } - pub fn print(self: *const Self) void { + pub fn format(self: *const Self, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { _ = self; + _ = fmt; + _ = options; + _ = writer; } pub fn eql(self: *const Self, other: *const Self) bool { @@ -35,8 +45,9 @@ pub const Function = packed struct { } pub fn free(self: *const Self, allocator: std.mem.Allocator) void { - _ = self; - _ = allocator; + self.chunk.deinit(); + allocator.destroy(self.chunk); + allocator.destroy(self); } }; diff --git a/zlox/src/obj/string.zig b/zlox/src/obj/string.zig @@ -41,8 +41,10 @@ pub const String = packed struct { pub fn cast(self: *Self) *Super { return @ptrCast(self); } - pub fn print(self: *const Self) void { - std.debug.print("\"{s}\"", .{self.slice()}); + pub fn format(self: *const Self, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void { + _ = try writer.write("\""); + _ = try writer.write(self.slice()); + _ = try writer.writeAll("\""); } pub fn eql(self: *const Self, other: *const Self) bool { return @intFromPtr(self) == @intFromPtr(other); diff --git a/zlox/src/obj/table.zig b/zlox/src/obj/table.zig @@ -2,6 +2,7 @@ const std = @import("std"); const table = @import("../table.zig"); const hash = @import("../hash.zig"); const value = @import("../value.zig"); +const utils = @import("../comptime_utils.zig"); const Super = @import("../obj.zig").Obj; const Error = Super.Error; @@ -45,18 +46,23 @@ pub const Table = packed struct { self.hash -%= hash.hash(key) -% hash.hash(val); _ = self.table.delete(key); } + pub fn format(self: *const Self, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { + const Printer = struct { + options: std.fmt.FormatOptions, + writer: @TypeOf(writer), - fn print_element(key: value.Value, val: value.Value) void { - key.print(); - std.debug.print(":", .{}); - val.print(); - std.debug.print(",", .{}); + 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(","); + } - } - pub fn print(self: *const Self) void { - std.debug.print("[", .{}); - self.table.for_each(Self.print_element); - std.debug.print("]", .{}); + }; + + _ = try writer.write("["); + try self.table.for_each_try(Printer{.options = options, .writer = writer}, Printer.print); + _ = try writer.writeAll("]"); } pub fn eql(self: *const Self, other: *const Self) bool { return self.table.eql(other.table, value.Value.eql); diff --git a/zlox/src/obj/template.zig b/zlox/src/obj/template.zig @@ -19,8 +19,11 @@ pub const Template = packed struct { return @ptrCast(self); } - pub fn print(self: *const Self) void { + pub fn format(self: *const Self, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { _ = self; + _ = fmt; + _ = options; + _ = writer; } pub fn eql(self: *const Self, other: *const Self) bool { diff --git a/zlox/src/table.zig b/zlox/src/table.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const utils = @import("comptime_utils.zig"); pub const TableError = error{ OutOfMemory, KeyError }; @@ -87,10 +88,19 @@ pub fn Table(K: type, V: type, hash_fn: fn (K) u32, cmp_fn: fn (K, K) bool) type } } - pub fn for_each(self: *const Self, fun: fn (K, V) void) void { + pub fn for_each(self: *const Self, arg: anytype, fun: fn (@TypeOf(arg), K, V) void) void { for (self.entries) |entry| { switch (entry) { - .some => |some| fun(some.key, some.value), + .some => |some| fun(arg, some.key, some.value), + else => {}, + } + } + } + + pub fn for_each_try(self: *const Self, arg: anytype, fun: anytype) utils.fn_error(fun)!void { + for (self.entries) |entry| { + switch (entry) { + .some => |some| try fun(arg, some.key, some.value), else => {}, } } diff --git a/zlox/src/value.zig b/zlox/src/value.zig @@ -10,31 +10,32 @@ pub const Value = union(enum) { nil: void, obj: *Obj, - pub const Tag = std.meta.Tag(@This()); + const Self = @This(); + pub const Tag = std.meta.Tag(Self); - pub fn print(self: @This()) void { + pub fn format(self: Self, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { switch (self) { - .number => |val| std.debug.print("{d}", .{val}), - .char => |val| std.debug.print("'{s}'", .{&[_]u8{val}}), - .bool => |val| std.debug.print("{s}", .{if (val) "true" else "false"}), - .nil => std.debug.print("nil", .{}), - .obj => |o| o.print(), + .number => |val| try writer.print("{d}", .{val}), + .char => |val| try writer.writeAll(&[_]u8{val}), + .bool => |val| try writer.writeAll(if (val) "true" else "false"), + .nil => try writer.writeAll("nil"), + .obj => |o| try o.format(fmt, options, writer), } } pub fn tagNameOf(T: type) []const u8 { - return @tagName(utils.tagFromType(@This(), T)); + return @tagName(utils.tagFromType(Self, T)); } - pub fn typeName(self: @This()) []const u8 { + pub fn typeName(self: Self) []const u8 { return switch (self) { .obj => |o| @tagName(o.type), inline else => |tp| tagNameOf(@TypeOf(tp)), }; } - pub fn init(val: anytype) @This() { - return @unionInit(@This(), tagNameOf(@TypeOf(val)), val); + pub fn init(val: anytype) Self { + return @unionInit(Self, tagNameOf(@TypeOf(val)), val); } @@ -45,32 +46,32 @@ pub const Value = union(enum) { from; } - pub fn is(self: @This(), comptime tag: anytype) bool { + pub fn is(self: Self, comptime tag: anytype) bool { return switch (self) { toTag(tag) => @TypeOf(tag) == Tag or self.obj.is(tag), else => false, }; } - pub fn get(self: @This(), comptime tag: anytype) tagType(tag) { + pub fn get(self: Self, comptime tag: anytype) tagType(tag) { return @field(self, @tagName(toTag(tag))); } - pub fn set(self: *@This(), comptime tag: anytype, value: tagType(tag)) void { + pub fn set(self: *Self, comptime tag: anytype, value: tagType(tag)) void { @field(self, @tagName(toTag(tag))) = value; } pub fn tagType(comptime tag: anytype) type { - return utils.typeFromTag(@This(), toTag(tag)); + return utils.typeFromTag(Self, toTag(tag)); } pub const ParseNumberError = std.fmt.ParseFloatError; - pub fn parseNumber(str: []const u8) ParseNumberError!@This() { - return @This(){ .number = try std.fmt.parseFloat(tagType(Value.number), str) }; + pub fn parseNumber(str: []const u8) ParseNumberError!Self { + return Self{ .number = try std.fmt.parseFloat(tagType(Value.number), str) }; } - pub fn isTruthy(self: @This()) bool { + pub fn isTruthy(self: Self) bool { return switch (self) { .nil => false, .bool => |val| val, @@ -78,7 +79,7 @@ pub const Value = union(enum) { }; } - pub fn eql(self: @This(), other: @This()) bool { + pub fn eql(self: Self, other: Self) bool { if (@intFromEnum(self) != @intFromEnum(other)) return false; return switch (self) { .number => |x| x == other.number, diff --git a/zlox/src/vm.zig b/zlox/src/vm.zig @@ -135,9 +135,7 @@ pub const VM = struct { std.debug.print(" ", .{}); var stackPtr: [*]Value = &self.stack; while (stackPtr != self.stackTop) : (stackPtr += 1) { - std.debug.print("[ ", .{}); - stackPtr[0].print(); - std.debug.print(" ]", .{}); + std.debug.print("[{s}]", .{stackPtr[0]}); } std.debug.print("\n", .{}); _ = try debug.disassembleInstruction(self.chunk.*, self.instruction_idx()); @@ -145,8 +143,7 @@ pub const VM = struct { const instruction: u8 = self.read_byte(); switch (instruction) { @intFromEnum(OP.PRINT) => { - self.pop().print(); - std.debug.print("\n", .{}); + std.debug.print("{s}\n", .{self.pop()}); }, @intFromEnum(OP.RETURN) => return, @intFromEnum(OP.POP) => _ = self.pop(),