I’m trying to implement a simple pretty printer for trees of arbitrary types and stuck at the point where the code below:
const std = @import("std");
fn ext(comptime path: []const u8) []const u8 {
var start = path.len -| 1;
while (start != 0) : (start -|= 1)
if (path[start] == '.') break;
return path[start..];
}
pub fn prettyPrint(alloc: std.mem.Allocator, val: anytype) !void {
const String = std.ArrayList(u8);
const Printer = struct {
lvl: usize = 0,
alloc: std.mem.Allocator,
out: String,
const Self = @This();
const Error = error{ValueTypeNotSupported};
pub fn init(a: std.mem.Allocator) Self {
return Self{ .out = String.init(a), .alloc = a };
}
pub fn run(self: *Self, next: anytype, cont: bool, field_name: ?[]const u8) !void {
const val_T = @TypeOf(next);
const val_T_info = @typeInfo(val_T);
const val_T_tag = @tagName(val_T_info);
const val_T_name = @typeName(val_T);
var buf: [256]u8 = undefined;
var printed: []const u8 = undefined;
switch (val_T_info) {
.Pointer => {
try self.out.append('*');
try self.run(next.*, true, null);
return;
},
.Struct => {
if (!cont) try self.out.appendNTimes(' ', self.lvl * 2);
try self.out.appendSlice("." ++ val_T_tag ++ comptime ext(val_T_name));
if (field_name) |name| {
// try self.out.appendSlice("(");
try self.out.appendSlice(name);
try self.out.appendSlice(": ");
}
try self.out.append('\n');
self.lvl += 1;
inline for (std.meta.fields(val_T)) |field| {
try self.out.appendNTimes(' ', self.lvl * 2);
try self.out.appendSlice("" ++ field.name ++ ": ");
try self.run(@field(next, field.name), true, null);
}
},
.Int, .ComptimeInt => {
if (!cont) try self.out.appendNTimes(' ', self.lvl * 2);
if (field_name) |name| {
// try self.out.appendSlice("(");
try self.out.appendSlice(name);
try self.out.appendSlice(": ");
}
try self.out.appendSlice("." ++ val_T_tag ++ "." ++ comptime ext(val_T_name));
try self.out.append('\n');
try self.out.appendNTimes(' ', (self.lvl + 1) * 2);
printed = try std.fmt.bufPrint(&buf, "{any}", .{next});
try self.out.appendSlice(printed);
try self.out.append('\n');
},
else => {
self.out.clearAndFree();
try self.out.appendSlice("Error.ValueTypeNotSupported");
// return Error.ValueTypeNotSupported;
},
}
}
pub fn deinit(self: *Self) void {
self.out.deinit();
}
};
var p = Printer.init(alloc);
try p.run(val, false, null);
defer p.deinit();
std.debug.print("{s}\n", .{p.out.items});
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const alloc = gpa.allocator();
const Pet = struct { Age: u8, Name: u8, Next: *const @This() };
const puppy1 = Pet{ .Age = 1, .Name = 2, .Next = undefined };
// Start here
try prettyPrint(alloc, &puppy1);
}
Throws:
.notes/q_unableToResolveError.zig:52:37: error: unable to resolve inferred error set
try self.run(@field(next, field.name), true, null);
It feels like it is somehow related to recursion. It happened once before already but somehow I was able to get around it. After I added a new .Next
field to the Pet
, I started to get that error again. Complete MIA.