From aa334d8c1df252f48960e0253eb25544678a6023 Mon Sep 17 00:00:00 2001 From: Komari Spaghetti Date: Mon, 26 Apr 2021 16:23:15 +0200 Subject: Refactor Diagnostic (and others) into a ParseOption struct This allows for default arguments, which we can also extend without breaking peoples code in the future. This is a breaking change right now though. --- clap/comptime.zig | 19 ++++++++----------- clap/streaming.zig | 40 +++++++++++++++++++++------------------- 2 files changed, 29 insertions(+), 30 deletions(-) (limited to 'clap') diff --git a/clap/comptime.zig b/clap/comptime.zig index 8ab61cb..9bec38e 100644 --- a/clap/comptime.zig +++ b/clap/comptime.zig @@ -1,10 +1,10 @@ const clap = @import("../clap.zig"); const std = @import("std"); -const testing = std.testing; +const debug = std.debug; const heap = std.heap; const mem = std.mem; -const debug = std.debug; +const testing = std.testing; /// Deprecated: Use `parseEx` instead pub fn ComptimeClap( @@ -42,7 +42,8 @@ pub fn ComptimeClap( pos: []const []const u8, allocator: *mem.Allocator, - pub fn parse(allocator: *mem.Allocator, iter: anytype, diag: ?*clap.Diagnostic) !@This() { + pub fn parse(iter: anytype, opt: clap.ParseOptions) !@This() { + const allocator = opt.allocator; var multis = [_]std.ArrayList([]const u8){undefined} ** multi_options; for (multis) |*multi| { multi.* = std.ArrayList([]const u8).init(allocator); @@ -62,7 +63,7 @@ pub fn ComptimeClap( .params = converted_params, .iter = iter, }; - while (try stream.next(diag)) |arg| { + while (try stream.next()) |arg| { const param = arg.param; if (param.names.long == null and param.names.short == null) { try pos.append(arg.value.?); @@ -81,19 +82,17 @@ pub fn ComptimeClap( } } - for (multis) |*multi, i| { + for (multis) |*multi, i| res.multi_options[i] = multi.toOwnedSlice(); - } res.pos = pos.toOwnedSlice(); return res; } - pub fn deinit(parser: *@This()) void { + pub fn deinit(parser: @This()) void { for (parser.multi_options) |o| parser.allocator.free(o); parser.allocator.free(parser.pos); - parser.* = undefined; } pub fn flag(parser: @This(), comptime name: []const u8) bool { @@ -155,14 +154,12 @@ test "" { clap.parseParam("

") catch unreachable, }); - var buf: [1024]u8 = undefined; - var fb_allocator = heap.FixedBufferAllocator.init(buf[0..]); var iter = clap.args.SliceIterator{ .args = &[_][]const u8{ "-a", "-c", "0", "something", "-d", "a", "--dd", "b", }, }; - var args = try Clap.parse(&fb_allocator.allocator, &iter, null); + var args = try Clap.parse(&iter, .{ .allocator = testing.allocator }); defer args.deinit(); testing.expect(args.flag("-a")); diff --git a/clap/streaming.zig b/clap/streaming.zig index 11145f0..8030a67 100644 --- a/clap/streaming.zig +++ b/clap/streaming.zig @@ -40,12 +40,13 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { iter: *ArgIterator, state: State = .normal, positional: ?*const clap.Param(Id) = null, + diagnostic: ?*clap.Diagnostic = null, /// Get the next Arg that matches a Param. - pub fn next(parser: *@This(), diag: ?*clap.Diagnostic) !?Arg(Id) { + pub fn next(parser: *@This()) !?Arg(Id) { switch (parser.state) { - .normal => return try parser.normal(diag), - .chaining => |state| return try parser.chainging(state, diag), + .normal => return try parser.normal(), + .chaining => |state| return try parser.chainging(state), .rest_are_positional => { const param = parser.positionalParam() orelse unreachable; const value = (try parser.iter.next()) orelse return null; @@ -54,7 +55,7 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { } } - fn normal(parser: *@This(), diag: ?*clap.Diagnostic) !?Arg(Id) { + fn normal(parser: *@This()) !?Arg(Id) { const arg_info = (try parser.parseNextArg()) orelse return null; const arg = arg_info.arg; switch (arg_info.kind) { @@ -70,7 +71,7 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { continue; if (param.takes_value == .None) { if (maybe_value != null) - return err(diag, arg, .{ .long = name }, error.DoesntTakeValue); + return parser.err(arg, .{ .long = name }, error.DoesntTakeValue); return Arg(Id){ .param = param }; } @@ -80,18 +81,18 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { break :blk v; break :blk (try parser.iter.next()) orelse - return err(diag, arg, .{ .long = name }, error.MissingValue); + return parser.err(arg, .{ .long = name }, error.MissingValue); }; return Arg(Id){ .param = param, .value = value }; } - return err(diag, arg, .{ .long = name }, error.InvalidArgument); + return parser.err(arg, .{ .long = name }, error.InvalidArgument); }, .short => return try parser.chainging(.{ .arg = arg, .index = 0, - }, diag), + }), .positional => if (parser.positionalParam()) |param| { // If we find a positional with the value `--` then we // interpret the rest of the arguments as positional @@ -104,12 +105,12 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { return Arg(Id){ .param = param, .value = arg }; } else { - return err(diag, arg, .{}, error.InvalidArgument); + return parser.err(arg, .{}, error.InvalidArgument); }, } } - fn chainging(parser: *@This(), state: State.Chaining, diag: ?*clap.Diagnostic) !?Arg(Id) { + fn chainging(parser: *@This(), state: State.Chaining) !?Arg(Id) { const arg = state.arg; const index = state.index; const next_index = index + 1; @@ -136,13 +137,13 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { const next_is_eql = if (next_index < arg.len) arg[next_index] == '=' else false; if (param.takes_value == .None) { if (next_is_eql) - return err(diag, arg, .{ .short = short }, error.DoesntTakeValue); + return parser.err(arg, .{ .short = short }, error.DoesntTakeValue); return Arg(Id){ .param = param }; } if (arg.len <= next_index) { const value = (try parser.iter.next()) orelse - return err(diag, arg, .{ .short = short }, error.MissingValue); + return parser.err(arg, .{ .short = short }, error.MissingValue); return Arg(Id){ .param = param, .value = value }; } @@ -153,7 +154,7 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { return Arg(Id){ .param = param, .value = arg[next_index..] }; } - return err(diag, arg, .{ .short = arg[index] }, error.InvalidArgument); + return parser.err(arg, .{ .short = arg[index] }, error.InvalidArgument); } fn positionalParam(parser: *@This()) ?*const clap.Param(Id) { @@ -194,8 +195,8 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { return ArgInfo{ .arg = full_arg, .kind = .positional }; } - fn err(diag: ?*clap.Diagnostic, arg: []const u8, names: clap.Names, _err: anytype) @TypeOf(_err) { - if (diag) |d| + fn err(parser: @This(), arg: []const u8, names: clap.Names, _err: anytype) @TypeOf(_err) { + if (parser.diagnostic) |d| d.* = .{ .arg = arg, .name = names }; return _err; } @@ -210,7 +211,7 @@ fn testNoErr(params: []const clap.Param(u8), args_strings: []const []const u8, r }; for (results) |res| { - const arg = (c.next(null) catch unreachable) orelse unreachable; + const arg = (c.next() catch unreachable) orelse unreachable; testing.expectEqual(res.param, arg.param); const expected_value = res.value orelse { testing.expectEqual(@as(@TypeOf(arg.value), null), arg.value); @@ -220,18 +221,19 @@ fn testNoErr(params: []const clap.Param(u8), args_strings: []const []const u8, r testing.expectEqualSlices(u8, expected_value, actual_value); } - if (c.next(null) catch unreachable) |_| + if (c.next() catch unreachable) |_| unreachable; } fn testErr(params: []const clap.Param(u8), args_strings: []const []const u8, expected: []const u8) void { - var diag: clap.Diagnostic = undefined; + var diag = clap.Diagnostic{}; var iter = args.SliceIterator{ .args = args_strings }; var c = StreamingClap(u8, args.SliceIterator){ .params = params, .iter = &iter, + .diagnostic = &diag, }; - while (c.next(&diag) catch |err| { + while (c.next() catch |err| { var buf: [1024]u8 = undefined; var slice_stream = io.fixedBufferStream(&buf); diag.report(slice_stream.outStream(), err) catch unreachable; -- cgit v1.2.3 From 4c14bfd5188bb61d7076bc33fccbcc6a5e9dac01 Mon Sep 17 00:00:00 2001 From: Komari Spaghetti Date: Sat, 8 May 2021 18:08:52 +0200 Subject: Modernize codebase * Better naming for variables * Follow naming style of enums * Use `writer()` instead of `outStream()` * Change many initializers to be a one liner * Don't explicitly initialize fields to their default value --- clap/comptime.zig | 20 +++--- clap/streaming.zig | 184 ++++++++++++++++++++++------------------------------- 2 files changed, 87 insertions(+), 117 deletions(-) (limited to 'clap') diff --git a/clap/comptime.zig b/clap/comptime.zig index 9bec38e..122ff16 100644 --- a/clap/comptime.zig +++ b/clap/comptime.zig @@ -19,9 +19,9 @@ pub fn ComptimeClap( var index: usize = 0; if (param.names.long != null or param.names.short != null) { const ptr = switch (param.takes_value) { - .None => &flags, - .One => &single_options, - .Many => &multi_options, + .none => &flags, + .one => &single_options, + .many => &multi_options, }; index = ptr.*; ptr.* += 1; @@ -67,11 +67,11 @@ pub fn ComptimeClap( const param = arg.param; if (param.names.long == null and param.names.short == null) { try pos.append(arg.value.?); - } else if (param.takes_value == .One) { + } else if (param.takes_value == .one) { debug.assert(res.single_options.len != 0); if (res.single_options.len != 0) res.single_options[param.id] = arg.value.?; - } else if (param.takes_value == .Many) { + } else if (param.takes_value == .many) { debug.assert(multis.len != 0); if (multis.len != 0) try multis[param.id].append(arg.value.?); @@ -97,7 +97,7 @@ pub fn ComptimeClap( pub fn flag(parser: @This(), comptime name: []const u8) bool { const param = comptime findParam(name); - if (param.takes_value != .None) + if (param.takes_value != .none) @compileError(name ++ " is an option and not a flag."); return parser.flags[param.id]; @@ -105,18 +105,18 @@ pub fn ComptimeClap( pub fn option(parser: @This(), comptime name: []const u8) ?[]const u8 { const param = comptime findParam(name); - if (param.takes_value == .None) + if (param.takes_value == .none) @compileError(name ++ " is a flag and not an option."); - if (param.takes_value == .Many) + if (param.takes_value == .many) @compileError(name ++ " takes many options, not one."); return parser.single_options[param.id]; } pub fn options(parser: @This(), comptime name: []const u8) []const []const u8 { const param = comptime findParam(name); - if (param.takes_value == .None) + if (param.takes_value == .none) @compileError(name ++ " is a flag and not an option."); - if (param.takes_value == .One) + if (param.takes_value == .one) @compileError(name ++ " takes one option, not multiple."); return parser.multi_options[param.id]; diff --git a/clap/streaming.zig b/clap/streaming.zig index 8030a67..a2a0ca8 100644 --- a/clap/streaming.zig +++ b/clap/streaming.zig @@ -69,7 +69,7 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { if (!mem.eql(u8, name, match)) continue; - if (param.takes_value == .None) { + if (param.takes_value == .none) { if (maybe_value != null) return parser.err(arg, .{ .long = name }, error.DoesntTakeValue); @@ -122,7 +122,7 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { // Before we return, we have to set the new state of the clap defer { - if (arg.len <= next_index or param.takes_value != .None) { + if (arg.len <= next_index or param.takes_value != .none) { parser.state = .normal; } else { parser.state = .{ @@ -135,7 +135,7 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { } const next_is_eql = if (next_index < arg.len) arg[next_index] == '=' else false; - if (param.takes_value == .None) { + if (param.takes_value == .none) { if (next_is_eql) return parser.err(arg, .{ .short = short }, error.DoesntTakeValue); return Arg(Id){ .param = param }; @@ -235,9 +235,9 @@ fn testErr(params: []const clap.Param(u8), args_strings: []const []const u8, exp }; while (c.next() catch |err| { var buf: [1024]u8 = undefined; - var slice_stream = io.fixedBufferStream(&buf); - diag.report(slice_stream.outStream(), err) catch unreachable; - testing.expectEqualStrings(expected, slice_stream.getWritten()); + var fbs = io.fixedBufferStream(&buf); + diag.report(fbs.writer(), err) catch unreachable; + testing.expectEqualStrings(expected, fbs.getWritten()); return; }) |_| {} @@ -246,23 +246,17 @@ fn testErr(params: []const clap.Param(u8), args_strings: []const []const u8, exp test "short params" { const params = [_]clap.Param(u8){ - clap.Param(u8){ - .id = 0, - .names = clap.Names{ .short = 'a' }, - }, - clap.Param(u8){ - .id = 1, - .names = clap.Names{ .short = 'b' }, - }, - clap.Param(u8){ + .{ .id = 0, .names = .{ .short = 'a' } }, + .{ .id = 1, .names = .{ .short = 'b' } }, + .{ .id = 2, - .names = clap.Names{ .short = 'c' }, - .takes_value = .One, + .names = .{ .short = 'c' }, + .takes_value = .one, }, - clap.Param(u8){ + .{ .id = 3, - .names = clap.Names{ .short = 'd' }, - .takes_value = .Many, + .names = .{ .short = 'd' }, + .takes_value = .many, }, }; @@ -279,42 +273,36 @@ test "short params" { "0", "-ac=0", "-d=0", }, &[_]Arg(u8){ - Arg(u8){ .param = a }, - Arg(u8){ .param = b }, - Arg(u8){ .param = a }, - Arg(u8){ .param = b }, - Arg(u8){ .param = b }, - Arg(u8){ .param = a }, - Arg(u8){ .param = c, .value = "0" }, - Arg(u8){ .param = c, .value = "0" }, - Arg(u8){ .param = a }, - Arg(u8){ .param = c, .value = "0" }, - Arg(u8){ .param = a }, - Arg(u8){ .param = c, .value = "0" }, - Arg(u8){ .param = d, .value = "0" }, + .{ .param = a }, + .{ .param = b }, + .{ .param = a }, + .{ .param = b }, + .{ .param = b }, + .{ .param = a }, + .{ .param = c, .value = "0" }, + .{ .param = c, .value = "0" }, + .{ .param = a }, + .{ .param = c, .value = "0" }, + .{ .param = a }, + .{ .param = c, .value = "0" }, + .{ .param = d, .value = "0" }, }, ); } test "long params" { const params = [_]clap.Param(u8){ - clap.Param(u8){ - .id = 0, - .names = clap.Names{ .long = "aa" }, - }, - clap.Param(u8){ - .id = 1, - .names = clap.Names{ .long = "bb" }, - }, - clap.Param(u8){ + .{ .id = 0, .names = .{ .long = "aa" } }, + .{ .id = 1, .names = .{ .long = "bb" } }, + .{ .id = 2, - .names = clap.Names{ .long = "cc" }, - .takes_value = .One, + .names = .{ .long = "cc" }, + .takes_value = .one, }, - clap.Param(u8){ + .{ .id = 3, - .names = clap.Names{ .long = "dd" }, - .takes_value = .Many, + .names = .{ .long = "dd" }, + .takes_value = .many, }, }; @@ -331,59 +319,47 @@ test "long params" { "--cc=0", "--dd=0", }, &[_]Arg(u8){ - Arg(u8){ .param = aa }, - Arg(u8){ .param = bb }, - Arg(u8){ .param = cc, .value = "0" }, - Arg(u8){ .param = cc, .value = "0" }, - Arg(u8){ .param = dd, .value = "0" }, + .{ .param = aa }, + .{ .param = bb }, + .{ .param = cc, .value = "0" }, + .{ .param = cc, .value = "0" }, + .{ .param = dd, .value = "0" }, }, ); } test "positional params" { - const params = [_]clap.Param(u8){clap.Param(u8){ + const params = [_]clap.Param(u8){.{ .id = 0, - .takes_value = .One, + .takes_value = .one, }}; testNoErr( ¶ms, &[_][]const u8{ "aa", "bb" }, &[_]Arg(u8){ - Arg(u8){ .param = ¶ms[0], .value = "aa" }, - Arg(u8){ .param = ¶ms[0], .value = "bb" }, + .{ .param = ¶ms[0], .value = "aa" }, + .{ .param = ¶ms[0], .value = "bb" }, }, ); } test "all params" { const params = [_]clap.Param(u8){ - clap.Param(u8){ + .{ .id = 0, - .names = clap.Names{ - .short = 'a', - .long = "aa", - }, + .names = .{ .short = 'a', .long = "aa" }, }, - clap.Param(u8){ + .{ .id = 1, - .names = clap.Names{ - .short = 'b', - .long = "bb", - }, + .names = .{ .short = 'b', .long = "bb" }, }, - clap.Param(u8){ + .{ .id = 2, - .names = clap.Names{ - .short = 'c', - .long = "cc", - }, - .takes_value = .One, - }, - clap.Param(u8){ - .id = 3, - .takes_value = .One, + .names = .{ .short = 'c', .long = "cc" }, + .takes_value = .one, }, + .{ .id = 3, .takes_value = .one }, }; const aa = ¶ms[0]; @@ -401,46 +377,40 @@ test "all params" { "-", "--", "--cc=0", "-a", }, &[_]Arg(u8){ - Arg(u8){ .param = aa }, - Arg(u8){ .param = bb }, - Arg(u8){ .param = aa }, - Arg(u8){ .param = bb }, - Arg(u8){ .param = bb }, - Arg(u8){ .param = aa }, - Arg(u8){ .param = cc, .value = "0" }, - Arg(u8){ .param = cc, .value = "0" }, - Arg(u8){ .param = aa }, - Arg(u8){ .param = cc, .value = "0" }, - Arg(u8){ .param = aa }, - Arg(u8){ .param = cc, .value = "0" }, - Arg(u8){ .param = aa }, - Arg(u8){ .param = bb }, - Arg(u8){ .param = cc, .value = "0" }, - Arg(u8){ .param = cc, .value = "0" }, - Arg(u8){ .param = positional, .value = "something" }, - Arg(u8){ .param = positional, .value = "-" }, - Arg(u8){ .param = positional, .value = "--cc=0" }, - Arg(u8){ .param = positional, .value = "-a" }, + .{ .param = aa }, + .{ .param = bb }, + .{ .param = aa }, + .{ .param = bb }, + .{ .param = bb }, + .{ .param = aa }, + .{ .param = cc, .value = "0" }, + .{ .param = cc, .value = "0" }, + .{ .param = aa }, + .{ .param = cc, .value = "0" }, + .{ .param = aa }, + .{ .param = cc, .value = "0" }, + .{ .param = aa }, + .{ .param = bb }, + .{ .param = cc, .value = "0" }, + .{ .param = cc, .value = "0" }, + .{ .param = positional, .value = "something" }, + .{ .param = positional, .value = "-" }, + .{ .param = positional, .value = "--cc=0" }, + .{ .param = positional, .value = "-a" }, }, ); } test "errors" { const params = [_]clap.Param(u8){ - clap.Param(u8){ + .{ .id = 0, - .names = clap.Names{ - .short = 'a', - .long = "aa", - }, + .names = .{ .short = 'a', .long = "aa" }, }, - clap.Param(u8){ + .{ .id = 1, - .names = clap.Names{ - .short = 'c', - .long = "cc", - }, - .takes_value = .One, + .names = .{ .short = 'c', .long = "cc" }, + .takes_value = .one, }, }; testErr(¶ms, &[_][]const u8{"q"}, "Invalid argument 'q'\n"); -- cgit v1.2.3