related:
I think easiest would be to use a unique prefix for every callsite and then use the index from the for loop:
const std = @import("std");
pub fn gensym(comptime name: []const u8, count: comptime_int, comptime src: ?std.builtin.SourceLocation) []const u8 {
return if (src) |loc|
std.fmt.comptimePrint("{s}{d}@{s}:{s}:{d}:{d}", .{ name, count, loc.file, loc.fn_name, loc.line, loc.column })
else
std.fmt.comptimePrint("{s}{d}", .{ name, count });
}
pub fn main() void {
inline for (0..3) |i| {
const name = gensym("foo", i, null);
std.debug.print("value: {s}\n", .{name});
}
inline for (0..5) |i| {
const name = gensym("bar", i, @src());
std.debug.print("value: {s}\n", .{name});
}
}
value: foo0
value: foo1
value: foo2
value: bar0@gensym.zig:main:17:39
value: bar1@gensym.zig:main:17:39
value: bar2@gensym.zig:main:17:39
value: bar3@gensym.zig:main:17:39
value: bar4@gensym.zig:main:17:39
If you have multiple layers of calls you could pass in the start index as a comptime parameter and return the end index, then thread the value through or you could have a locally scoped comptime var counter = 0
that gets increased for every nested call.
Or you even could use 1 “parent” gensym that is used as name to generate new ones. For example if you add a delimiter between the name and the count you could generate names like: foo_1, foo_2 and then use that to generate names foo_1_1, foo_1_2, foo_1_3, foo_2_1, etc.
Or if you use @src
even names that contain multiple source locations and indizies. In the best case the name would describe in which nested inline for loop it was created to make debugging easier.