summaryrefslogtreecommitdiff
path: root/clap/streaming.zig
diff options
context:
space:
mode:
authorGravatar Komari Spaghetti2021-05-26 20:46:23 +0200
committerGravatar Komari Spaghetti2021-05-26 20:46:23 +0200
commitbc32ab045926fb07e4c02c2dbab5aeaddd1f6a02 (patch)
treea545acd4583d4d344d1e235c445b9b9b5060514b /clap/streaming.zig
parentMerge branch 'master' into zig-master (diff)
parentModernize codebase (diff)
downloadzig-clap-bc32ab045926fb07e4c02c2dbab5aeaddd1f6a02.tar.gz
zig-clap-bc32ab045926fb07e4c02c2dbab5aeaddd1f6a02.tar.xz
zig-clap-bc32ab045926fb07e4c02c2dbab5aeaddd1f6a02.zip
Merge branch 'master' into zig-master
Diffstat (limited to 'clap/streaming.zig')
-rw-r--r--clap/streaming.zig224
1 files changed, 98 insertions, 126 deletions
diff --git a/clap/streaming.zig b/clap/streaming.zig
index 0fe5aae..a2a0ca8 100644
--- a/clap/streaming.zig
+++ b/clap/streaming.zig
@@ -40,12 +40,13 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type {
40 iter: *ArgIterator, 40 iter: *ArgIterator,
41 state: State = .normal, 41 state: State = .normal,
42 positional: ?*const clap.Param(Id) = null, 42 positional: ?*const clap.Param(Id) = null,
43 diagnostic: ?*clap.Diagnostic = null,
43 44
44 /// Get the next Arg that matches a Param. 45 /// Get the next Arg that matches a Param.
45 pub fn next(parser: *@This(), diag: ?*clap.Diagnostic) !?Arg(Id) { 46 pub fn next(parser: *@This()) !?Arg(Id) {
46 switch (parser.state) { 47 switch (parser.state) {
47 .normal => return try parser.normal(diag), 48 .normal => return try parser.normal(),
48 .chaining => |state| return try parser.chainging(state, diag), 49 .chaining => |state| return try parser.chainging(state),
49 .rest_are_positional => { 50 .rest_are_positional => {
50 const param = parser.positionalParam() orelse unreachable; 51 const param = parser.positionalParam() orelse unreachable;
51 const value = (try parser.iter.next()) orelse return null; 52 const value = (try parser.iter.next()) orelse return null;
@@ -54,7 +55,7 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type {
54 } 55 }
55 } 56 }
56 57
57 fn normal(parser: *@This(), diag: ?*clap.Diagnostic) !?Arg(Id) { 58 fn normal(parser: *@This()) !?Arg(Id) {
58 const arg_info = (try parser.parseNextArg()) orelse return null; 59 const arg_info = (try parser.parseNextArg()) orelse return null;
59 const arg = arg_info.arg; 60 const arg = arg_info.arg;
60 switch (arg_info.kind) { 61 switch (arg_info.kind) {
@@ -68,9 +69,9 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type {
68 69
69 if (!mem.eql(u8, name, match)) 70 if (!mem.eql(u8, name, match))
70 continue; 71 continue;
71 if (param.takes_value == .None) { 72 if (param.takes_value == .none) {
72 if (maybe_value != null) 73 if (maybe_value != null)
73 return err(diag, arg, .{ .long = name }, error.DoesntTakeValue); 74 return parser.err(arg, .{ .long = name }, error.DoesntTakeValue);
74 75
75 return Arg(Id){ .param = param }; 76 return Arg(Id){ .param = param };
76 } 77 }
@@ -80,18 +81,18 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type {
80 break :blk v; 81 break :blk v;
81 82
82 break :blk (try parser.iter.next()) orelse 83 break :blk (try parser.iter.next()) orelse
83 return err(diag, arg, .{ .long = name }, error.MissingValue); 84 return parser.err(arg, .{ .long = name }, error.MissingValue);
84 }; 85 };
85 86
86 return Arg(Id){ .param = param, .value = value }; 87 return Arg(Id){ .param = param, .value = value };
87 } 88 }
88 89
89 return err(diag, arg, .{ .long = name }, error.InvalidArgument); 90 return parser.err(arg, .{ .long = name }, error.InvalidArgument);
90 }, 91 },
91 .short => return try parser.chainging(.{ 92 .short => return try parser.chainging(.{
92 .arg = arg, 93 .arg = arg,
93 .index = 0, 94 .index = 0,
94 }, diag), 95 }),
95 .positional => if (parser.positionalParam()) |param| { 96 .positional => if (parser.positionalParam()) |param| {
96 // If we find a positional with the value `--` then we 97 // If we find a positional with the value `--` then we
97 // interpret the rest of the arguments as positional 98 // interpret the rest of the arguments as positional
@@ -104,12 +105,12 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type {
104 105
105 return Arg(Id){ .param = param, .value = arg }; 106 return Arg(Id){ .param = param, .value = arg };
106 } else { 107 } else {
107 return err(diag, arg, .{}, error.InvalidArgument); 108 return parser.err(arg, .{}, error.InvalidArgument);
108 }, 109 },
109 } 110 }
110 } 111 }
111 112
112 fn chainging(parser: *@This(), state: State.Chaining, diag: ?*clap.Diagnostic) !?Arg(Id) { 113 fn chainging(parser: *@This(), state: State.Chaining) !?Arg(Id) {
113 const arg = state.arg; 114 const arg = state.arg;
114 const index = state.index; 115 const index = state.index;
115 const next_index = index + 1; 116 const next_index = index + 1;
@@ -121,7 +122,7 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type {
121 122
122 // Before we return, we have to set the new state of the clap 123 // Before we return, we have to set the new state of the clap
123 defer { 124 defer {
124 if (arg.len <= next_index or param.takes_value != .None) { 125 if (arg.len <= next_index or param.takes_value != .none) {
125 parser.state = .normal; 126 parser.state = .normal;
126 } else { 127 } else {
127 parser.state = .{ 128 parser.state = .{
@@ -134,15 +135,15 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type {
134 } 135 }
135 136
136 const next_is_eql = if (next_index < arg.len) arg[next_index] == '=' else false; 137 const next_is_eql = if (next_index < arg.len) arg[next_index] == '=' else false;
137 if (param.takes_value == .None) { 138 if (param.takes_value == .none) {
138 if (next_is_eql) 139 if (next_is_eql)
139 return err(diag, arg, .{ .short = short }, error.DoesntTakeValue); 140 return parser.err(arg, .{ .short = short }, error.DoesntTakeValue);
140 return Arg(Id){ .param = param }; 141 return Arg(Id){ .param = param };
141 } 142 }
142 143
143 if (arg.len <= next_index) { 144 if (arg.len <= next_index) {
144 const value = (try parser.iter.next()) orelse 145 const value = (try parser.iter.next()) orelse
145 return err(diag, arg, .{ .short = short }, error.MissingValue); 146 return parser.err(arg, .{ .short = short }, error.MissingValue);
146 147
147 return Arg(Id){ .param = param, .value = value }; 148 return Arg(Id){ .param = param, .value = value };
148 } 149 }
@@ -153,7 +154,7 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type {
153 return Arg(Id){ .param = param, .value = arg[next_index..] }; 154 return Arg(Id){ .param = param, .value = arg[next_index..] };
154 } 155 }
155 156
156 return err(diag, arg, .{ .short = arg[index] }, error.InvalidArgument); 157 return parser.err(arg, .{ .short = arg[index] }, error.InvalidArgument);
157 } 158 }
158 159
159 fn positionalParam(parser: *@This()) ?*const clap.Param(Id) { 160 fn positionalParam(parser: *@This()) ?*const clap.Param(Id) {
@@ -194,8 +195,8 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type {
194 return ArgInfo{ .arg = full_arg, .kind = .positional }; 195 return ArgInfo{ .arg = full_arg, .kind = .positional };
195 } 196 }
196 197
197 fn err(diag: ?*clap.Diagnostic, arg: []const u8, names: clap.Names, _err: anytype) @TypeOf(_err) { 198 fn err(parser: @This(), arg: []const u8, names: clap.Names, _err: anytype) @TypeOf(_err) {
198 if (diag) |d| 199 if (parser.diagnostic) |d|
199 d.* = .{ .arg = arg, .name = names }; 200 d.* = .{ .arg = arg, .name = names };
200 return _err; 201 return _err;
201 } 202 }
@@ -210,7 +211,7 @@ fn testNoErr(params: []const clap.Param(u8), args_strings: []const []const u8, r
210 }; 211 };
211 212
212 for (results) |res| { 213 for (results) |res| {
213 const arg = (c.next(null) catch unreachable) orelse unreachable; 214 const arg = (c.next() catch unreachable) orelse unreachable;
214 testing.expectEqual(res.param, arg.param); 215 testing.expectEqual(res.param, arg.param);
215 const expected_value = res.value orelse { 216 const expected_value = res.value orelse {
216 testing.expectEqual(@as(@TypeOf(arg.value), null), arg.value); 217 testing.expectEqual(@as(@TypeOf(arg.value), null), arg.value);
@@ -220,22 +221,23 @@ fn testNoErr(params: []const clap.Param(u8), args_strings: []const []const u8, r
220 testing.expectEqualSlices(u8, expected_value, actual_value); 221 testing.expectEqualSlices(u8, expected_value, actual_value);
221 } 222 }
222 223
223 if (c.next(null) catch unreachable) |_| 224 if (c.next() catch unreachable) |_|
224 unreachable; 225 unreachable;
225} 226}
226 227
227fn testErr(params: []const clap.Param(u8), args_strings: []const []const u8, expected: []const u8) void { 228fn testErr(params: []const clap.Param(u8), args_strings: []const []const u8, expected: []const u8) void {
228 var diag: clap.Diagnostic = undefined; 229 var diag = clap.Diagnostic{};
229 var iter = args.SliceIterator{ .args = args_strings }; 230 var iter = args.SliceIterator{ .args = args_strings };
230 var c = StreamingClap(u8, args.SliceIterator){ 231 var c = StreamingClap(u8, args.SliceIterator){
231 .params = params, 232 .params = params,
232 .iter = &iter, 233 .iter = &iter,
234 .diagnostic = &diag,
233 }; 235 };
234 while (c.next(&diag) catch |err| { 236 while (c.next() catch |err| {
235 var buf: [1024]u8 = undefined; 237 var buf: [1024]u8 = undefined;
236 var slice_stream = io.fixedBufferStream(&buf); 238 var fbs = io.fixedBufferStream(&buf);
237 diag.report(slice_stream.writer(), err) catch unreachable; 239 diag.report(fbs.writer(), err) catch unreachable;
238 testing.expectEqualStrings(expected, slice_stream.getWritten()); 240 testing.expectEqualStrings(expected, fbs.getWritten());
239 return; 241 return;
240 }) |_| {} 242 }) |_| {}
241 243
@@ -244,23 +246,17 @@ fn testErr(params: []const clap.Param(u8), args_strings: []const []const u8, exp
244 246
245test "short params" { 247test "short params" {
246 const params = [_]clap.Param(u8){ 248 const params = [_]clap.Param(u8){
247 clap.Param(u8){ 249 .{ .id = 0, .names = .{ .short = 'a' } },
248 .id = 0, 250 .{ .id = 1, .names = .{ .short = 'b' } },
249 .names = clap.Names{ .short = 'a' }, 251 .{
250 },
251 clap.Param(u8){
252 .id = 1,
253 .names = clap.Names{ .short = 'b' },
254 },
255 clap.Param(u8){
256 .id = 2, 252 .id = 2,
257 .names = clap.Names{ .short = 'c' }, 253 .names = .{ .short = 'c' },
258 .takes_value = .One, 254 .takes_value = .one,
259 }, 255 },
260 clap.Param(u8){ 256 .{
261 .id = 3, 257 .id = 3,
262 .names = clap.Names{ .short = 'd' }, 258 .names = .{ .short = 'd' },
263 .takes_value = .Many, 259 .takes_value = .many,
264 }, 260 },
265 }; 261 };
266 262
@@ -277,42 +273,36 @@ test "short params" {
277 "0", "-ac=0", "-d=0", 273 "0", "-ac=0", "-d=0",
278 }, 274 },
279 &[_]Arg(u8){ 275 &[_]Arg(u8){
280 Arg(u8){ .param = a }, 276 .{ .param = a },
281 Arg(u8){ .param = b }, 277 .{ .param = b },
282 Arg(u8){ .param = a }, 278 .{ .param = a },
283 Arg(u8){ .param = b }, 279 .{ .param = b },
284 Arg(u8){ .param = b }, 280 .{ .param = b },
285 Arg(u8){ .param = a }, 281 .{ .param = a },
286 Arg(u8){ .param = c, .value = "0" }, 282 .{ .param = c, .value = "0" },
287 Arg(u8){ .param = c, .value = "0" }, 283 .{ .param = c, .value = "0" },
288 Arg(u8){ .param = a }, 284 .{ .param = a },
289 Arg(u8){ .param = c, .value = "0" }, 285 .{ .param = c, .value = "0" },
290 Arg(u8){ .param = a }, 286 .{ .param = a },
291 Arg(u8){ .param = c, .value = "0" }, 287 .{ .param = c, .value = "0" },
292 Arg(u8){ .param = d, .value = "0" }, 288 .{ .param = d, .value = "0" },
293 }, 289 },
294 ); 290 );
295} 291}
296 292
297test "long params" { 293test "long params" {
298 const params = [_]clap.Param(u8){ 294 const params = [_]clap.Param(u8){
299 clap.Param(u8){ 295 .{ .id = 0, .names = .{ .long = "aa" } },
300 .id = 0, 296 .{ .id = 1, .names = .{ .long = "bb" } },
301 .names = clap.Names{ .long = "aa" }, 297 .{
302 },
303 clap.Param(u8){
304 .id = 1,
305 .names = clap.Names{ .long = "bb" },
306 },
307 clap.Param(u8){
308 .id = 2, 298 .id = 2,
309 .names = clap.Names{ .long = "cc" }, 299 .names = .{ .long = "cc" },
310 .takes_value = .One, 300 .takes_value = .one,
311 }, 301 },
312 clap.Param(u8){ 302 .{
313 .id = 3, 303 .id = 3,
314 .names = clap.Names{ .long = "dd" }, 304 .names = .{ .long = "dd" },
315 .takes_value = .Many, 305 .takes_value = .many,
316 }, 306 },
317 }; 307 };
318 308
@@ -329,59 +319,47 @@ test "long params" {
329 "--cc=0", "--dd=0", 319 "--cc=0", "--dd=0",
330 }, 320 },
331 &[_]Arg(u8){ 321 &[_]Arg(u8){
332 Arg(u8){ .param = aa }, 322 .{ .param = aa },
333 Arg(u8){ .param = bb }, 323 .{ .param = bb },
334 Arg(u8){ .param = cc, .value = "0" }, 324 .{ .param = cc, .value = "0" },
335 Arg(u8){ .param = cc, .value = "0" }, 325 .{ .param = cc, .value = "0" },
336 Arg(u8){ .param = dd, .value = "0" }, 326 .{ .param = dd, .value = "0" },
337 }, 327 },
338 ); 328 );
339} 329}
340 330
341test "positional params" { 331test "positional params" {
342 const params = [_]clap.Param(u8){clap.Param(u8){ 332 const params = [_]clap.Param(u8){.{
343 .id = 0, 333 .id = 0,
344 .takes_value = .One, 334 .takes_value = .one,
345 }}; 335 }};
346 336
347 testNoErr( 337 testNoErr(
348 &params, 338 &params,
349 &[_][]const u8{ "aa", "bb" }, 339 &[_][]const u8{ "aa", "bb" },
350 &[_]Arg(u8){ 340 &[_]Arg(u8){
351 Arg(u8){ .param = &params[0], .value = "aa" }, 341 .{ .param = &params[0], .value = "aa" },
352 Arg(u8){ .param = &params[0], .value = "bb" }, 342 .{ .param = &params[0], .value = "bb" },
353 }, 343 },
354 ); 344 );
355} 345}
356 346
357test "all params" { 347test "all params" {
358 const params = [_]clap.Param(u8){ 348 const params = [_]clap.Param(u8){
359 clap.Param(u8){ 349 .{
360 .id = 0, 350 .id = 0,
361 .names = clap.Names{ 351 .names = .{ .short = 'a', .long = "aa" },
362 .short = 'a',
363 .long = "aa",
364 },
365 }, 352 },
366 clap.Param(u8){ 353 .{
367 .id = 1, 354 .id = 1,
368 .names = clap.Names{ 355 .names = .{ .short = 'b', .long = "bb" },
369 .short = 'b',
370 .long = "bb",
371 },
372 }, 356 },
373 clap.Param(u8){ 357 .{
374 .id = 2, 358 .id = 2,
375 .names = clap.Names{ 359 .names = .{ .short = 'c', .long = "cc" },
376 .short = 'c', 360 .takes_value = .one,
377 .long = "cc",
378 },
379 .takes_value = .One,
380 },
381 clap.Param(u8){
382 .id = 3,
383 .takes_value = .One,
384 }, 361 },
362 .{ .id = 3, .takes_value = .one },
385 }; 363 };
386 364
387 const aa = &params[0]; 365 const aa = &params[0];
@@ -399,46 +377,40 @@ test "all params" {
399 "-", "--", "--cc=0", "-a", 377 "-", "--", "--cc=0", "-a",
400 }, 378 },
401 &[_]Arg(u8){ 379 &[_]Arg(u8){
402 Arg(u8){ .param = aa }, 380 .{ .param = aa },
403 Arg(u8){ .param = bb }, 381 .{ .param = bb },
404 Arg(u8){ .param = aa }, 382 .{ .param = aa },
405 Arg(u8){ .param = bb }, 383 .{ .param = bb },
406 Arg(u8){ .param = bb }, 384 .{ .param = bb },
407 Arg(u8){ .param = aa }, 385 .{ .param = aa },
408 Arg(u8){ .param = cc, .value = "0" }, 386 .{ .param = cc, .value = "0" },
409 Arg(u8){ .param = cc, .value = "0" }, 387 .{ .param = cc, .value = "0" },
410 Arg(u8){ .param = aa }, 388 .{ .param = aa },
411 Arg(u8){ .param = cc, .value = "0" }, 389 .{ .param = cc, .value = "0" },
412 Arg(u8){ .param = aa }, 390 .{ .param = aa },
413 Arg(u8){ .param = cc, .value = "0" }, 391 .{ .param = cc, .value = "0" },
414 Arg(u8){ .param = aa }, 392 .{ .param = aa },
415 Arg(u8){ .param = bb }, 393 .{ .param = bb },
416 Arg(u8){ .param = cc, .value = "0" }, 394 .{ .param = cc, .value = "0" },
417 Arg(u8){ .param = cc, .value = "0" }, 395 .{ .param = cc, .value = "0" },
418 Arg(u8){ .param = positional, .value = "something" }, 396 .{ .param = positional, .value = "something" },
419 Arg(u8){ .param = positional, .value = "-" }, 397 .{ .param = positional, .value = "-" },
420 Arg(u8){ .param = positional, .value = "--cc=0" }, 398 .{ .param = positional, .value = "--cc=0" },
421 Arg(u8){ .param = positional, .value = "-a" }, 399 .{ .param = positional, .value = "-a" },
422 }, 400 },
423 ); 401 );
424} 402}
425 403
426test "errors" { 404test "errors" {
427 const params = [_]clap.Param(u8){ 405 const params = [_]clap.Param(u8){
428 clap.Param(u8){ 406 .{
429 .id = 0, 407 .id = 0,
430 .names = clap.Names{ 408 .names = .{ .short = 'a', .long = "aa" },
431 .short = 'a',
432 .long = "aa",
433 },
434 }, 409 },
435 clap.Param(u8){ 410 .{
436 .id = 1, 411 .id = 1,
437 .names = clap.Names{ 412 .names = .{ .short = 'c', .long = "cc" },
438 .short = 'c', 413 .takes_value = .one,
439 .long = "cc",
440 },
441 .takes_value = .One,
442 }, 414 },
443 }; 415 };
444 testErr(&params, &[_][]const u8{"q"}, "Invalid argument 'q'\n"); 416 testErr(&params, &[_][]const u8{"q"}, "Invalid argument 'q'\n");