how could I implement this?
const Operand = union(enum) {
bool: bool,
int: i32,
float: f32,
string: []const u8,
@"struct",
fn initContextValue(key: []const u8, ctx: anytype) !Operand {
switch (@typeInfo(@TypeOf(ctx))) {
.Struct => |@"struct"| {
inline for (@"struct".fields) |field| if (mem.eql(u8, field.name, key)) {
switch (@typeInfo(field.type)) {
.Struct => return .@"struct",
else => {
log.err("`ctx.{s}`: unsupported type {s}", .{ key, @typeName(field.type) });
return error.Context;
},
}
};
log.err("`ctx` does not have field '{s}'", .{key});
return error.Context;
},
else => unreachable,
}
}
};
};
elsewhere, passing in this value as ctx: .{ .foo = .{ .bar = "Hello" } }.
fn evalIdentifierNode(self: *Interpreter, node: Ast.Node, stack_top: usize, ctx: anytype) anyerror!Operand {
const value = self.ast.tokenValue(node.token);
var lhs = try Operand.initContextValue(value, ctx);
// first we init an Operand.struct with `foo` value
while (stack.popOrNull()) |rhs| {
.field_access => switch (lhs) {
.@"struct" => {
// TODO this attempts to search for `ctx.bar`, but needs to search for `ctx.foo.bar`. can infinitely recurse
return try Operand.initContextValue(self.ast.tokenValue(rhs.data.rhs), ctx)
},
else => {
log.err("Unexpected {s} node", .{@tagName(rhs.type)});
return error.UnexpectedNode;
},
},
}
}