This commit is contained in:
yuzu 2025-05-30 01:58:02 -05:00
parent 6c68c4cb33
commit e87e08e964
2 changed files with 45 additions and 21 deletions

View File

@ -103,20 +103,12 @@ pub const Flags = packed struct {
allow_comments: bool = false,
/// Not to error on trailing comma, default is `false` for obvious reasons
allow_trailing_comma: bool = false,
/// Allows parsing `packed struct` as an `int`, size is the backing int
bitfields: bool = false,
/// Allows parsing `enum` as an `int`, size is the backing int
real_enums: bool = false,
/// Allows parsing unions, default behaviour is yet to be concluded
unions: bool = false,
/// To cast numbers always as f64, as the name says
numbersf64: bool = false,
};
pub const Options = struct {
comptime indent_len: usize = 4,
comptime max_depth: usize = 256,
comptime flags: Flags = .{},
flags: Flags = .{},
};
index: std.MultiArrayList(JsonValue) = .{},

View File

@ -33,35 +33,59 @@ pub fn deinit(self: *Self, allocator: mem.Allocator) void {
allocator.destroy(self.tokenizer);
}
/// always returns 0 (root)
/// needs an index
/// const idx: usize = try self.language.parse(allocator, self.tokenizer);
/// needs an index but useful otherwise
/// root starting from idx
pub fn reflectT(self: *Self, comptime T: type, allocator: mem.Allocator, idx: usize) !T {
const Schema = @typeInfo(T);
const flags = self.language.options.flags;
switch (self.language.index.get(idx)) {
.null => {
if (Schema == .null) return null;
return error.TypeError;
},
.bool => |b| {
if (Schema == .bool) return b;
return error.TypeError;
.bool => |b| switch (Schema) {
.bool => return b,
.@"union" => |unionInfo| inline for (unionInfo.fields) |field| {
var r: T = undefined;
r = @unionInit(T, field.name, b);
return r;
},
else => return error.TypeError,
},
.number => |number| switch (Schema) {
.int, .comptime_int => return @intFromFloat(number),
.float, .comptime_float => return @floatCast(number),
.@"enum" => |enumInfo| {
const int: enumInfo.tag_type = @intFromFloat(number);
return @enumFromInt(int);
},
.@"struct" => |structInfo| switch (structInfo.layout) {
.@"packed" => {
const my_int: structInfo.backing_integer.? =
@intFromFloat(number);
return @bitCast(my_int);
const int: structInfo.backing_integer.? = @intFromFloat(number);
return @bitCast(int);
},
else => return error.TypeError,
},
.@"union" => |unionInfo| {
inline for (unionInfo.fields) |field| switch (@typeInfo(field.type)) {
.int, .comptime_int => return @unionInit(T, field.name, @intFromFloat(number)),
.float, .comptime_float => return @unionInit(T, field.name, @floatCast(number)),
else => {},
};
return error.TypeError;
},
else => unreachable,
},
.string => |string| switch (Schema) {
.@"union" => |unionInfo| inline for (unionInfo.fields) |field| {
if (field.type == []const u8) {
var r: T = undefined;
const strslice = string.slice(&self.language.strings);
r = @unionInit(T, field.name, strslice);
return r;
}
},
.array => |arrayInfo| {
assert(arrayInfo.child == u8);
const strslice = string.slice(&self.language.strings);
@ -141,7 +165,11 @@ pub fn reflectT(self: *Self, comptime T: type, allocator: mem.Allocator, idx: us
if (map.get(field.name)) |next_i| {
@field(r, field.name) = try self.reflectT(field.type, allocator, next_i);
} else switch (@typeInfo(field.type)) {
.optional => @field(r, field.name) = null,
.optional => {
if (flags.bitfields)
@field(r, field.name) = null;
@panic("Unknown property: " ++ field.name);
},
else => @panic("Unknown property: " ++ field.name),
}
}
@ -163,7 +191,9 @@ test reflectT {
\\ "age": 15,
\\ "name": "Yuzu",
\\ "admin": true,
\\ "flags": 0
\\ "flags": 0,
\\ "union": ":D",
\\ "enum": 1
\\}
;
var self = try allocator.create(Self);
@ -184,9 +214,11 @@ test reflectT {
name: []const u8,
admin: bool,
flags: UserFlags,
@"union": union { hi: bool, bye: f64, n128: []const u8 },
@"enum": enum { hello, world },
};
const root = try self.reflectT(UserSchema, allocator, idx);
std.debug.print("is cool? {} is friendly? {}\n", .{ root.flags.is_cool, root.flags.is_friendly });
std.debug.print("friend? {s}\n", .{root.@"union".n128});
}