minor improvements

This commit is contained in:
Yuzucchii 2025-06-04 21:59:32 -05:00
parent 25aa6fa37d
commit 656bc667e6
Signed by: yuzucchii
SSH Key Fingerprint: SHA256:3hT0Nn/790kQI9VFVQ2Kfh3Ma3JZe2pST86n1T5G7ww
2 changed files with 73 additions and 32 deletions

View File

@ -1 +0,0 @@
.zig-cache/

View File

@ -37,7 +37,6 @@ pub fn deinit(self: *Self, allocator: mem.Allocator) void {
/// root starting from idx /// root starting from idx
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;
if (std.meta.hasFn(T, "toJson")) { if (std.meta.hasFn(T, "toJson")) {
return T.toJson(self, allocator, idx); return T.toJson(self, allocator, idx);
@ -45,8 +44,7 @@ pub fn reflectT(self: *Self, comptime T: type, allocator: mem.Allocator, idx: us
switch (self.language.index.get(idx)) { switch (self.language.index.get(idx)) {
.null => { .null => {
if (Schema == .null) return null; if (Schema == .null or Schema == .optional) return null;
return error.TypeError;
}, },
.bool => |b| switch (Schema) { .bool => |b| switch (Schema) {
.bool => return b, .bool => return b,
@ -55,7 +53,7 @@ pub fn reflectT(self: *Self, comptime T: type, allocator: mem.Allocator, idx: us
r = @unionInit(T, field.name, b); r = @unionInit(T, field.name, b);
return r; return r;
}, },
else => return error.TypeError, else => unreachable,
}, },
.number => |number| switch (Schema) { .number => |number| switch (Schema) {
.int, .comptime_int => return @intCast(number.int), .int, .comptime_int => return @intCast(number.int),
@ -72,7 +70,7 @@ pub fn reflectT(self: *Self, comptime T: type, allocator: mem.Allocator, idx: us
const int: structInfo.backing_integer.? = @intCast(number.int); const int: structInfo.backing_integer.? = @intCast(number.int);
return @bitCast(int); return @bitCast(int);
}, },
else => return error.TypeError, else => unreachable, // may only cast packed structs
}, },
.@"union" => |unionInfo| { .@"union" => |unionInfo| {
inline for (unionInfo.fields) |field| switch (@typeInfo(field.type)) { inline for (unionInfo.fields) |field| switch (@typeInfo(field.type)) {
@ -101,13 +99,13 @@ pub fn reflectT(self: *Self, comptime T: type, allocator: mem.Allocator, idx: us
}, },
.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);
assert(arrayInfo.len == strslice.len - 1); assert(arrayInfo.len == strslice.len - 1);
var r: T = undefined; var r: T = undefined;
for (strslice, 0..) |char, i| for (strslice, 0..) |char, i| r[i] = char;
r[i] = char;
return r; return r;
}, },
.pointer => |ptrInfo| switch (ptrInfo.size) { .pointer => |ptrInfo| switch (ptrInfo.size) {
@ -135,11 +133,44 @@ pub fn reflectT(self: *Self, comptime T: type, allocator: mem.Allocator, idx: us
} }
return try arraylist.toOwnedSlice(); return try arraylist.toOwnedSlice();
}, },
else => return error.TypeError, .many => {
assert(ptrInfo.child == u8);
const strslice = string.slice(&self.language.strings);
var arraylist: std.ArrayList(u8) = .init(allocator);
try arraylist.ensureUnusedCapacity(strslice.len);
for (strslice) |char|
arraylist.appendAssumeCapacity(char);
if (ptrInfo.sentinel_ptr) |some| {
return arraylist.toOwnedSliceSentinel(blk: {
const sentinel: *align(1) const ptrInfo.child = @ptrCast(some);
break :blk sentinel.*;
});
}
return arraylist.toOwnedSlice();
},
else => unreachable,
}, },
else => return error.TypeError, else => unreachable,
}, },
.array => |slice| switch (Schema) { .array => |slice| switch (Schema) {
.@"struct" => |structInfo| {
if (structInfo.is_tuple) {
assert(structInfo.fields.len == slice.len);
var r: T = undefined;
inline for (structInfo.fields, 0..slice.len) |field, i| {
if (field.is_comptime)
@panic(@typeName(T) ++ "." ++ field.name ++ " may not be a comptime field");
@field(r, field.name) = try self.reflectT(field.type, allocator, slice.tip + i);
}
return r;
}
unreachable; // may only reflect tuples
},
.array => |arrayInfo| { .array => |arrayInfo| {
assert(slice.len == arrayInfo.len); assert(slice.len == arrayInfo.len);
var r: T = undefined; var r: T = undefined;
@ -153,8 +184,10 @@ pub fn reflectT(self: *Self, comptime T: type, allocator: mem.Allocator, idx: us
var r: T = try allocator.alloc(ptrInfo.child, slice.len); var r: T = try allocator.alloc(ptrInfo.child, slice.len);
if (ptrInfo.sentinel_ptr) |some| { if (ptrInfo.sentinel_ptr) |some| {
const sentinel = @as(*align(1) const ptrInfo.child, @ptrCast(some)).*; r[slice.len - 1] = blk: {
r[slice.len - 1] = sentinel; const sentinel: *align(1) const ptrInfo.child = @ptrCast(some);
break :blk sentinel.*;
};
} }
for (0..slice.len) |i| { for (0..slice.len) |i| {
@ -164,9 +197,9 @@ pub fn reflectT(self: *Self, comptime T: type, allocator: mem.Allocator, idx: us
} }
return r; return r;
}, },
else => return error.TypeError, else => unreachable,
}, },
else => return error.TypeError, else => unreachable,
}, },
.object => |object| switch (Schema) { .object => |object| switch (Schema) {
.@"struct" => |structInfo| { .@"struct" => |structInfo| {
@ -192,18 +225,14 @@ 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 => { .optional => @field(r, field.name) = null,
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),
} }
} }
return r; return r;
}, },
else => return error.TypeError, else => unreachable,
}, },
} }
@ -221,7 +250,8 @@ test reflectT {
\\ "flags": 0, \\ "flags": 0,
\\ "union": ":D", \\ "union": ":D",
\\ "enum": "world", \\ "enum": "world",
\\ "many": [1,2,3] \\ "many": [1,2,3],
\\ "tuple": [1, 2]
\\} \\}
; ;
var self = try allocator.create(Self); var self = try allocator.create(Self);
@ -245,6 +275,7 @@ test reflectT {
@"union": union { hi: bool, bye: f64, n128: []const u8 }, @"union": union { hi: bool, bye: f64, n128: []const u8 },
@"enum": enum { hello, world }, @"enum": enum { hello, world },
many: []const u8, many: []const u8,
tuple: struct { u64, u64 },
}; };
const root = try self.reflectT(UserSchema, allocator, idx); const root = try self.reflectT(UserSchema, allocator, idx);
@ -252,6 +283,7 @@ test reflectT {
std.debug.print("hello? {s}\n", .{@tagName(root.@"enum")}); std.debug.print("hello? {s}\n", .{@tagName(root.@"enum")});
std.debug.print("friend? {s}\n", .{root.@"union".n128}); std.debug.print("friend? {s}\n", .{root.@"union".n128});
std.debug.print("many: {any}\n", .{root.many}); std.debug.print("many: {any}\n", .{root.many});
std.debug.print("tuple: {any}\n", .{root.tuple});
allocator.free(root.many); allocator.free(root.many);
} }
@ -268,19 +300,18 @@ pub const Ruleset = packed struct {
allow_data_cast: bool = false, allow_data_cast: bool = false,
/// ignore comments /// ignore comments
allow_comments: bool = false, allow_comments: bool = false,
/// whether to print '*T' as int
allow_derefptrs: bool = false,
/// prettify the output /// prettify the output
pretty: bool = false, pretty: bool = false,
pub const Pedantic = Ruleset{ pub const Pedantic = Ruleset{};
.allow_bitfields = false,
.allow_data_cast = false,
.allow_comments = false,
};
pub const Chill = Ruleset{ pub const Chill = Ruleset{
.allow_bitfields = true, .allow_bitfields = true,
.allow_data_cast = true, .allow_data_cast = true,
.allow_comments = true, .allow_comments = true,
.allow_derefptrs = true,
}; };
}; };
@ -321,18 +352,16 @@ pub fn stringify(raw: anytype, comptime options: Options) ![]const u8 {
if (options.ruleset.allow_data_cast) { if (options.ruleset.allow_data_cast) {
const i: enumInfo.tag_type = @intFromEnum(raw); const i: enumInfo.tag_type = @intFromEnum(raw);
return std.fmt.bufPrint(&buf, "{d}", .{i}); return std.fmt.bufPrint(&buf, "{d}", .{i});
} else {
return std.fmt.bufPrint(&buf, "{s}", .{@tagName(raw)});
} }
return std.fmt.bufPrint(&buf, "{s}", .{@tagName(raw)});
}, },
.@"struct" => |structInfo| switch (structInfo.layout) { .@"struct" => |structInfo| switch (structInfo.layout) {
.@"packed" => { .@"packed" => {
if (options.ruleset.allow_bitfields) { if (options.ruleset.allow_bitfields) {
const i: structInfo.backing_integer.? = @bitCast(raw); const i: structInfo.backing_integer.? = @bitCast(raw);
return std.fmt.bufPrint(&buf, "{d}", .{i}); return std.fmt.bufPrint(&buf, "{d}", .{i});
} else {
return error.TypeError;
} }
return error.TypeError;
}, },
.auto, .@"extern" => { .auto, .@"extern" => {
var string: std.ArrayListUnmanaged(u8) = .empty; var string: std.ArrayListUnmanaged(u8) = .empty;
@ -380,6 +409,16 @@ pub fn stringify(raw: anytype, comptime options: Options) ![]const u8 {
return string.toOwnedSlice(); return string.toOwnedSlice();
}, },
.pointer => |ptrInfo| switch (ptrInfo.size) { .pointer => |ptrInfo| switch (ptrInfo.size) {
.one => {
if (options.ruleset.allow_derefptrs) {
return stringify(blk: {
const ptr: *align(ptrInfo.alignment) const ptrInfo.child = @ptrCast(raw);
break :blk ptr.*;
}, options);
}
return std.fmt.bufPrint(&buf, "{d}", .{@intFromPtr(raw)});
},
.slice => { .slice => {
if (ptrInfo.child == u8) { if (ptrInfo.child == u8) {
if (ptrInfo.is_const) if (ptrInfo.is_const)
@ -422,9 +461,8 @@ pub fn stringify(raw: anytype, comptime options: Options) ![]const u8 {
return error.TypeError; return error.TypeError;
} }
unreachable; unreachable;
} else {
return error.TypeError;
} }
unreachable; // union has no tag
}, },
else => |t| @compileError("Error on " ++ @tagName(t)), else => |t| @compileError("Error on " ++ @tagName(t)),
} }
@ -451,7 +489,10 @@ test stringify {
}, },
@"enum": enum { hello, world }, @"enum": enum { hello, world },
many: []const u8, many: []const u8,
epicptr: *const u8,
}; };
const e: []const u8 = "epic pointer";
const user = UserSchema{ const user = UserSchema{
.age = 15.0, .age = 15.0,
.name = "Yuzu", .name = "Yuzu",
@ -460,6 +501,7 @@ test stringify {
.@"union" = .{ .hi = true }, .@"union" = .{ .hi = true },
.@"enum" = .world, .@"enum" = .world,
.many = "hello", .many = "hello",
.epicptr = @ptrCast(e[0..1]),
}; };
const options = Options{ const options = Options{