converters: doodle error reporting mechanism
This needs a bit more thought. To support outside-in error writing, converters need access to an allocator so they can create new buffer writers. This can be done by passing in a pointer to an ArrayList object directly, rather than an already bound writer.
This commit is contained in:
parent
0d5dd9b36c
commit
b01c10409d
@ -7,8 +7,14 @@ const parameters = @import("./parameters.zig");
|
|||||||
const ValueCount = parameters.ValueCount;
|
const ValueCount = parameters.ValueCount;
|
||||||
const ParameterGenerics = parameters.ParameterGenerics;
|
const ParameterGenerics = parameters.ParameterGenerics;
|
||||||
|
|
||||||
|
const ErrorWriter = std.ArrayList(u8).Writer;
|
||||||
|
|
||||||
pub fn ConverterSignature(comptime gen: ParameterGenerics) type {
|
pub fn ConverterSignature(comptime gen: ParameterGenerics) type {
|
||||||
return *const fn (*gen.UserContext, gen.IntermediateType()) ConversionError!gen.ConvertedType();
|
return *const fn (
|
||||||
|
context: *gen.UserContext,
|
||||||
|
input: gen.IntermediateType(),
|
||||||
|
failure: ErrorWriter,
|
||||||
|
) ConversionError!gen.ConvertedType();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_converter(comptime gen: ParameterGenerics) ?ConverterSignature(gen) {
|
pub fn default_converter(comptime gen: ParameterGenerics) ?ConverterSignature(gen) {
|
||||||
@ -40,12 +46,12 @@ fn multi_converter(comptime gen: ParameterGenerics) ?ConverterSignature(gen) {
|
|||||||
const Intermediate = gen.IntermediateType();
|
const Intermediate = gen.IntermediateType();
|
||||||
|
|
||||||
return struct {
|
return struct {
|
||||||
pub fn handler(context: *gen.UserContext, input: Intermediate) ConversionError!std.ArrayList(gen.OutputType) {
|
pub fn handler(context: *gen.UserContext, input: Intermediate, failure: ErrorWriter) ConversionError!std.ArrayList(gen.OutputType) {
|
||||||
var output = std.ArrayList(gen.OutputType).initCapacity(input.allocator, input.items.len) catch
|
var output = std.ArrayList(gen.OutputType).initCapacity(input.allocator, input.items.len) catch
|
||||||
return ConversionError.ConversionFailed;
|
return ConversionError.ConversionFailed;
|
||||||
|
|
||||||
for (input.items) |item| {
|
for (input.items) |item| {
|
||||||
output.appendAssumeCapacity(try converter(context, item));
|
output.appendAssumeCapacity(try converter(context, item, failure));
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
@ -55,7 +61,7 @@ fn multi_converter(comptime gen: ParameterGenerics) ?ConverterSignature(gen) {
|
|||||||
|
|
||||||
fn flag_converter(comptime gen: ParameterGenerics) ConverterSignature(gen) {
|
fn flag_converter(comptime gen: ParameterGenerics) ConverterSignature(gen) {
|
||||||
return struct {
|
return struct {
|
||||||
pub fn handler(_: *gen.UserContext, input: []const u8) ConversionError!bool {
|
pub fn handler(_: *gen.UserContext, input: []const u8, _: ErrorWriter) ConversionError!bool {
|
||||||
// treat an empty string as falsy
|
// treat an empty string as falsy
|
||||||
if (input.len == 0) return false;
|
if (input.len == 0) return false;
|
||||||
|
|
||||||
@ -75,8 +81,8 @@ fn flag_converter(comptime gen: ParameterGenerics) ConverterSignature(gen) {
|
|||||||
|
|
||||||
fn string_converter(comptime gen: ParameterGenerics) ConverterSignature(gen) {
|
fn string_converter(comptime gen: ParameterGenerics) ConverterSignature(gen) {
|
||||||
return struct {
|
return struct {
|
||||||
pub fn handler(_: *gen.UserContext, value: []const u8) ConversionError![]const u8 {
|
pub fn handler(_: *gen.UserContext, input: []const u8, _: ErrorWriter) ConversionError![]const u8 {
|
||||||
return value;
|
return input;
|
||||||
}
|
}
|
||||||
}.handler;
|
}.handler;
|
||||||
}
|
}
|
||||||
@ -85,8 +91,12 @@ fn int_converter(comptime gen: ParameterGenerics) ConverterSignature(gen) {
|
|||||||
const IntType = gen.OutputType;
|
const IntType = gen.OutputType;
|
||||||
|
|
||||||
return struct {
|
return struct {
|
||||||
pub fn handler(_: *gen.UserContext, value: []const u8) ConversionError!IntType {
|
pub fn handler(_: *gen.UserContext, input: []const u8, failure: ErrorWriter) ConversionError!IntType {
|
||||||
return std.fmt.parseInt(IntType, value, 0) catch return ConversionError.ConversionFailed;
|
return std.fmt.parseInt(IntType, input, 0) catch {
|
||||||
|
// ignore the error
|
||||||
|
try failure.print("cannot interpret \"{s}\" as an integer", .{input});
|
||||||
|
return ConversionError.ConversionFailed;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}.handler;
|
}.handler;
|
||||||
}
|
}
|
||||||
@ -97,8 +107,14 @@ fn struct_converter(comptime gen: ParameterGenerics) ConverterSignature(gen) {
|
|||||||
const Intermediate = gen.IntermediateType();
|
const Intermediate = gen.IntermediateType();
|
||||||
|
|
||||||
return struct {
|
return struct {
|
||||||
pub fn handler(context: *gen.UserContext, value: Intermediate) ConversionError!StructType {
|
pub fn handler(context: *gen.UserContext, input: Intermediate, failure: ErrorWriter) ConversionError!StructType {
|
||||||
if (value.items.len != type_info.fields.len) return ConversionError.ConversionFailed;
|
if (input.items.len != type_info.fields.len) {
|
||||||
|
try failure.print(
|
||||||
|
"Wrong number of fields provided. Got {d}, needed {d}",
|
||||||
|
.{ input.items.len, type_info.fields.len },
|
||||||
|
);
|
||||||
|
return ConversionError.ConversionFailed;
|
||||||
|
}
|
||||||
|
|
||||||
var result: StructType = undefined;
|
var result: StructType = undefined;
|
||||||
inline for (comptime type_info.fields, 0..) |field, idx| {
|
inline for (comptime type_info.fields, 0..) |field, idx| {
|
||||||
@ -110,7 +126,7 @@ fn struct_converter(comptime gen: ParameterGenerics) ConverterSignature(gen) {
|
|||||||
) orelse
|
) orelse
|
||||||
@compileError("cannot get converter for field" ++ field.name);
|
@compileError("cannot get converter for field" ++ field.name);
|
||||||
|
|
||||||
@field(result, field.name) = try converter(context, value.items[idx]);
|
@field(result, field.name) = try converter(context, input.items[idx], failure);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -122,8 +138,11 @@ fn choice_converter(comptime gen: ParameterGenerics) ConverterSignature(gen) {
|
|||||||
const EnumType = gen.OutputType;
|
const EnumType = gen.OutputType;
|
||||||
|
|
||||||
return struct {
|
return struct {
|
||||||
pub fn handler(_: *gen.UserContext, value: []const u8) ConversionError!EnumType {
|
pub fn handler(_: *gen.UserContext, input: []const u8, failure: ErrorWriter) ConversionError!EnumType {
|
||||||
return std.meta.stringToEnum(gen.ConvertedType(), value) orelse ConversionError.ConversionFailed;
|
return std.meta.stringToEnum(gen.ConvertedType(), input) orelse {
|
||||||
|
try failure.print("\"{s}\" is not a valid choice", .{input});
|
||||||
|
return ConversionError.ConversionFailed;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}.handler;
|
}.handler;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
pub const ConversionError = error{
|
pub const ConversionError = error{
|
||||||
|
OutOfMemory,
|
||||||
ConversionFailed,
|
ConversionFailed,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -423,7 +423,9 @@ pub fn Parser(comptime command: anytype, comptime callback: anytype) type {
|
|||||||
|
|
||||||
fn convert_param(self: *@This(), comptime param: anytype, context: *UserContext) NoclipError!void {
|
fn convert_param(self: *@This(), comptime param: anytype, context: *UserContext) NoclipError!void {
|
||||||
if (@field(self.intermediate, param.name)) |intermediate| {
|
if (@field(self.intermediate, param.name)) |intermediate| {
|
||||||
@field(self.output, param.name) = try param.converter(context, intermediate);
|
var buffer = std.ArrayList(u8).init(self.allocator);
|
||||||
|
const writer = buffer.writer();
|
||||||
|
@field(self.output, param.name) = try param.converter(context, intermediate, writer);
|
||||||
} else {
|
} else {
|
||||||
if (comptime param.required) {
|
if (comptime param.required) {
|
||||||
return ParseError.RequiredParameterMissing;
|
return ParseError.RequiredParameterMissing;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user