parser: ostensibly fix sentinel handling

I guess arrays don't need special handling because their memory is
explicitly accounted for, but it would probably be good to check that
a sentinel-terminated array initialized as `undefined` does get the
correct sentinel value.
This commit is contained in:
torque 2023-10-22 16:38:41 -07:00
parent f371f16e2f
commit ce65dee71f
Signed by: torque
SSH Key Fingerprint: SHA256:nCrXefBNo6EbjNSQhv0nXmEg/VuNq3sMF5b8zETw3Tk
2 changed files with 18 additions and 5 deletions

View File

@ -9,7 +9,7 @@ const Example = struct {
useful: bool, useful: bool,
number: i32, number: i32,
string: []const u8, string: []const u8,
longstring: []const u8, longstring: [:0]const u8,
tuple: struct { bool, i8 }, tuple: struct { bool, i8 },
enume: enum { first, second, third }, enume: enum { first, second, third },
taggart: union(enum) { first: []const u8, second: i32 }, taggart: union(enum) { first: []const u8, second: i32 },

View File

@ -118,16 +118,30 @@ pub const Value = union(enum) {
// type to use for this? the problem is that it becomes // type to use for this? the problem is that it becomes
// invasive into downstream code. Ultimately this should // invasive into downstream code. Ultimately this should
// probably be solved in the zig stdlib or similar. // probably be solved in the zig stdlib or similar.
// TODO: This also doesn't handle sentinels properly.
switch (self) { switch (self) {
.scalar, .string => |str| return if (ptr.child == u8) str else error.BadValue, .scalar, .string => |str| {
if (ptr.child == u8) {
if (ptr.sentinel) |sent| {
var copy = try allocator.allocSentinel(u8, str.len, @as(*const u8, @ptrCast(sent)).*);
@memcpy(copy, str);
return copy;
}
return str;
} else {
return error.BadValue;
}
},
.list, .inline_list => |lst| { .list, .inline_list => |lst| {
var result = try std.ArrayList(ptr.child).initCapacity(allocator, lst.items.len); var result = try std.ArrayList(ptr.child).initCapacity(allocator, lst.items.len);
errdefer result.deinit(); errdefer result.deinit();
for (lst.items) |item| { for (lst.items) |item| {
result.appendAssumeCapacity(try item.convertTo(ptr.child, allocator, options)); result.appendAssumeCapacity(try item.convertTo(ptr.child, allocator, options));
} }
return result.toOwnedSlice(); if (ptr.sentinel) |sent| {
return try result.toOwnedSliceSentinel(@as(*align(1) const ptr.child, @ptrCast(sent)).*);
} else {
return try result.toOwnedSlice();
}
}, },
else => return error.BadValue, else => return error.BadValue,
} }
@ -146,7 +160,6 @@ pub const Value = union(enum) {
// type to use for this? the problem is that it becomes // type to use for this? the problem is that it becomes
// invasive into downstream code. Ultimately this should // invasive into downstream code. Ultimately this should
// probably be solved in the zig stdlib or similar. // probably be solved in the zig stdlib or similar.
// TODO: This also doesn't handle sentinels properly.
switch (self) { switch (self) {
.scalar, .string => |str| { .scalar, .string => |str| {
if (arr.child == u8 and str.len == arr.len) { if (arr.child == u8 and str.len == arr.len) {