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, allow_comments: bool = false,
/// Not to error on trailing comma, default is `false` for obvious reasons /// Not to error on trailing comma, default is `false` for obvious reasons
allow_trailing_comma: bool = false, 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 { pub const Options = struct {
comptime indent_len: usize = 4, comptime indent_len: usize = 4,
comptime max_depth: usize = 256, comptime max_depth: usize = 256,
comptime flags: Flags = .{}, flags: Flags = .{},
}; };
index: std.MultiArrayList(JsonValue) = .{}, index: std.MultiArrayList(JsonValue) = .{},

View File

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