summaryrefslogtreecommitdiff
path: root/clap/comptime.zig
diff options
context:
space:
mode:
authorGravatar Jimmi Holst Christensen2019-10-06 17:20:56 +0200
committerGravatar Jimmi Holst Christensen2019-10-06 17:20:56 +0200
commitf3eb797336c1bbdae391657ef6ac54e4015b5fde (patch)
tree0f99b8a43adddcadca24a2ec0b47b779ef923904 /clap/comptime.zig
parentDelete download-zig.sh (diff)
downloadzig-clap-f3eb797336c1bbdae391657ef6ac54e4015b5fde.tar.gz
zig-clap-f3eb797336c1bbdae391657ef6ac54e4015b5fde.tar.xz
zig-clap-f3eb797336c1bbdae391657ef6ac54e4015b5fde.zip
fmt, mv src/ clap/ and run fmt on build
Diffstat (limited to 'clap/comptime.zig')
-rw-r--r--clap/comptime.zig143
1 files changed, 143 insertions, 0 deletions
diff --git a/clap/comptime.zig b/clap/comptime.zig
new file mode 100644
index 0000000..f5c2762
--- /dev/null
+++ b/clap/comptime.zig
@@ -0,0 +1,143 @@
1const clap = @import("../clap.zig");
2const std = @import("std");
3
4const testing = std.testing;
5const heap = std.heap;
6const mem = std.mem;
7const debug = std.debug;
8
9pub fn ComptimeClap(comptime Id: type, comptime params: []const clap.Param(Id)) type {
10 var flags: usize = 0;
11 var options: usize = 0;
12 var converted_params: []const clap.Param(usize) = [_]clap.Param(usize){};
13 for (params) |param| {
14 var index: usize = 0;
15 if (param.names.long != null or param.names.short != null) {
16 const ptr = if (param.takes_value) &options else &flags;
17 index = ptr.*;
18 ptr.* += 1;
19 }
20
21 const converted = clap.Param(usize){
22 .id = index,
23 .names = param.names,
24 .takes_value = param.takes_value,
25 };
26 converted_params = converted_params ++ [_]clap.Param(usize){converted};
27 }
28
29 return struct {
30 options: [options]?[]const u8,
31 flags: [flags]bool,
32 pos: []const []const u8,
33 allocator: *mem.Allocator,
34
35 pub fn parse(allocator: *mem.Allocator, comptime ArgIter: type, iter: *ArgIter) !@This() {
36 var pos = std.ArrayList([]const u8).init(allocator);
37 var res = @This(){
38 .options = [_]?[]const u8{null} ** options,
39 .flags = [_]bool{false} ** flags,
40 .pos = undefined,
41 .allocator = allocator,
42 };
43
44 var stream = clap.StreamingClap(usize, ArgIter){
45 .params = converted_params,
46 .iter = iter,
47 };
48 while (try stream.next()) |arg| {
49 const param = arg.param;
50 if (param.names.long == null and param.names.short == null) {
51 try pos.append(arg.value.?);
52 } else if (param.takes_value) {
53 // If we don't have any optional parameters, then this code should
54 // never be reached.
55 debug.assert(res.options.len != 0);
56
57 // Hack: Utilize Zigs lazy analyzis to avoid a compiler error
58 if (res.options.len != 0)
59 res.options[param.id] = arg.value.?;
60 } else {
61 debug.assert(res.flags.len != 0);
62 if (res.flags.len != 0)
63 res.flags[param.id] = true;
64 }
65 }
66
67 res.pos = pos.toOwnedSlice();
68 return res;
69 }
70
71 pub fn deinit(parser: *@This()) void {
72 parser.allocator.free(parser.pos);
73 parser.* = undefined;
74 }
75
76 pub fn flag(parser: @This(), comptime name: []const u8) bool {
77 const param = comptime findParam(name);
78 if (param.takes_value)
79 @compileError(name ++ " is an option and not a flag.");
80
81 return parser.flags[param.id];
82 }
83
84 pub fn option(parser: @This(), comptime name: []const u8) ?[]const u8 {
85 const param = comptime findParam(name);
86 if (!param.takes_value)
87 @compileError(name ++ " is a flag and not an option.");
88
89 return parser.options[param.id];
90 }
91
92 pub fn positionals(parser: @This()) []const []const u8 {
93 return parser.pos;
94 }
95
96 fn findParam(comptime name: []const u8) clap.Param(usize) {
97 comptime {
98 for (converted_params) |param| {
99 if (param.names.short) |s| {
100 if (mem.eql(u8, name, "-" ++ [_]u8{s}))
101 return param;
102 }
103 if (param.names.long) |l| {
104 if (mem.eql(u8, name, "--" ++ l))
105 return param;
106 }
107 }
108
109 @compileError(name ++ " is not a parameter.");
110 }
111 }
112 };
113}
114
115test "clap.comptime.ComptimeClap" {
116 const Clap = ComptimeClap(clap.Help, comptime [_]clap.Param(clap.Help){
117 clap.parseParam("-a, --aa ") catch unreachable,
118 clap.parseParam("-b, --bb ") catch unreachable,
119 clap.parseParam("-c, --cc <V>") catch unreachable,
120 clap.Param(clap.Help){
121 .takes_value = true,
122 },
123 });
124
125 var buf: [1024]u8 = undefined;
126 var fb_allocator = heap.FixedBufferAllocator.init(buf[0..]);
127 var iter = clap.args.SliceIterator{
128 .args = [_][]const u8{
129 "-a", "-c", "0", "something",
130 },
131 };
132 var args = try Clap.parse(&fb_allocator.allocator, clap.args.SliceIterator, &iter);
133 defer args.deinit();
134
135 testing.expect(args.flag("-a"));
136 testing.expect(args.flag("--aa"));
137 testing.expect(!args.flag("-b"));
138 testing.expect(!args.flag("--bb"));
139 testing.expectEqualSlices(u8, "0", args.option("-c").?);
140 testing.expectEqualSlices(u8, "0", args.option("--cc").?);
141 testing.expectEqual(usize(1), args.positionals().len);
142 testing.expectEqualSlices(u8, "something", args.positionals()[0]);
143}