diff options
| author | 2018-03-14 21:36:50 +0100 | |
|---|---|---|
| committer | 2018-03-14 21:36:50 +0100 | |
| commit | 79f0c9cee9e5cd4413a65ae96a32872330e308ad (patch) | |
| tree | 5b9e8f835ce7b4d9e3189db63777aa8e2ffe2c83 | |
| parent | Fixed code crashing Zig (diff) | |
| download | zig-clap-79f0c9cee9e5cd4413a65ae96a32872330e308ad.tar.gz zig-clap-79f0c9cee9e5cd4413a65ae96a32872330e308ad.tar.xz zig-clap-79f0c9cee9e5cd4413a65ae96a32872330e308ad.zip | |
Refactored clap to use inline loops where possible.
Time to study the differences in the assemply
| -rw-r--r-- | .gitattributes | 1 | ||||
| -rw-r--r-- | clap.zig | 110 |
2 files changed, 64 insertions, 47 deletions
diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..ef01f61 --- /dev/null +++ b/.gitattributes | |||
| @@ -0,0 +1 @@ | |||
| *.zig text eol=lf | |||
| @@ -22,16 +22,16 @@ pub fn Option(comptime Result: type, comptime ParseError: type) type { | |||
| 22 | IgnoresRequired | 22 | IgnoresRequired |
| 23 | }; | 23 | }; |
| 24 | 24 | ||
| 25 | parser: fn(&Result, []const u8) ParseError!void, | 25 | parse: fn(&Result, []const u8) ParseError!void, |
| 26 | help: []const u8, | 26 | help: []const u8, |
| 27 | kind: Kind, | 27 | kind: Kind, |
| 28 | takes_value: bool, | 28 | takes_value: bool, |
| 29 | short: ?u8, | 29 | short: ?u8, |
| 30 | long: ?[]const u8, | 30 | long: ?[]const u8, |
| 31 | 31 | ||
| 32 | pub fn init(parser: fn(&Result, []const u8) ParseError!void) Self { | 32 | pub fn init(parse_fn: fn(&Result, []const u8) ParseError!void) Self { |
| 33 | return Self { | 33 | return Self { |
| 34 | .parser = parser, | 34 | .parse = parse_fn, |
| 35 | .help = "", | 35 | .help = "", |
| 36 | .kind = Kind.Optional, | 36 | .kind = Kind.Optional, |
| 37 | .takes_value = false, | 37 | .takes_value = false, |
| @@ -82,10 +82,12 @@ pub fn Parser(comptime Result: type, comptime ParseError: type, comptime default | |||
| 82 | // This limits the user to 128 required arguments, which is more than | 82 | // This limits the user to 128 required arguments, which is more than |
| 83 | // enough. | 83 | // enough. |
| 84 | const required_mask = comptime blk: { | 84 | const required_mask = comptime blk: { |
| 85 | var required_index : u128 = 0; | ||
| 85 | var required_res : u128 = 0; | 86 | var required_res : u128 = 0; |
| 86 | for (options) |option, i| { | 87 | for (options) |option, i| { |
| 87 | if (option.kind == OptionT.Kind.Required) { | 88 | if (option.kind == OptionT.Kind.Required) { |
| 88 | required_res = (required_res << 1) | 0x1; | 89 | required_res |= 0x1 << required_index; |
| 90 | required_index += 1; | ||
| 89 | } | 91 | } |
| 90 | } | 92 | } |
| 91 | 93 | ||
| @@ -93,7 +95,17 @@ pub fn Parser(comptime Result: type, comptime ParseError: type, comptime default | |||
| 93 | }; | 95 | }; |
| 94 | 96 | ||
| 95 | return struct { | 97 | return struct { |
| 96 | fn parse(args: []const []const u8) !Result { | 98 | fn newRequired(option: &const OptionT, old_required: u128, index: usize) u128 { |
| 99 | switch (option.kind) { | ||
| 100 | OptionT.Kind.Required => { | ||
| 101 | return bits.set(u128, old_required, u7(index), false); | ||
| 102 | }, | ||
| 103 | OptionT.Kind.IgnoresRequired => return 0, | ||
| 104 | else => return old_required, | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | pub fn parse(args: []const []const u8) !Result { | ||
| 97 | var result = *defaults; | 109 | var result = *defaults; |
| 98 | var required = required_mask; | 110 | var required = required_mask; |
| 99 | 111 | ||
| @@ -111,57 +123,61 @@ pub fn Parser(comptime Result: type, comptime ParseError: type, comptime default | |||
| 111 | const arg = pair.arg; | 123 | const arg = pair.arg; |
| 112 | const kind = pair.kind; | 124 | const kind = pair.kind; |
| 113 | 125 | ||
| 114 | var required_index : usize = 0; | 126 | success: { |
| 115 | for (options) |option, op_i| { | 127 | var required_index = usize(0); |
| 128 | |||
| 116 | switch (kind) { | 129 | switch (kind) { |
| 117 | Arg.Kind.None => { | 130 | Arg.Kind.None => { |
| 118 | if (option.short != null) continue; | 131 | inline for (options) |option| { |
| 119 | if (option.long != null) continue; | 132 | defer if (option.kind == OptionT.Kind.Required) required_index += 1; |
| 120 | 133 | if (option.short != null) continue; | |
| 121 | try option.parser(&result, arg); | 134 | if (option.long != null) continue; |
| 122 | 135 | ||
| 123 | switch (option.kind) { | 136 | try option.parse(&result, arg); |
| 124 | OptionT.Kind.Required => { | 137 | required = newRequired(option, required, required_index); |
| 125 | required = bits.set(u128, required, u7(required_index), false); | 138 | break :success; |
| 126 | required_index += 1; | ||
| 127 | }, | ||
| 128 | OptionT.Kind.IgnoresRequired => { | ||
| 129 | required = 0; | ||
| 130 | required_index += 1; | ||
| 131 | }, | ||
| 132 | else => {} | ||
| 133 | } | 139 | } |
| 134 | |||
| 135 | break; | ||
| 136 | }, | 140 | }, |
| 137 | Arg.Kind.Short => { | 141 | Arg.Kind.Short => { |
| 138 | const short = option.short ?? continue; | 142 | inline for (options) |option| { |
| 139 | if (arg.len != 1 or arg[0] != short) continue; | 143 | defer if (option.kind == OptionT.Kind.Required) required_index += 1; |
| 144 | const short = option.short ?? continue; | ||
| 145 | if (arg.len == 1 and arg[0] == short) { | ||
| 146 | if (option.takes_value) { | ||
| 147 | arg_i += 1; | ||
| 148 | if (args.len <= arg_i) return error.OptionMissingValue; | ||
| 149 | |||
| 150 | try option.parse(&result, args[arg_i]); | ||
| 151 | } else { | ||
| 152 | try option.parse(&result, []u8{}); | ||
| 153 | } | ||
| 154 | |||
| 155 | required = newRequired(option, required, required_index); | ||
| 156 | break :success; | ||
| 157 | } | ||
| 158 | } | ||
| 140 | }, | 159 | }, |
| 141 | Arg.Kind.Long => { | 160 | Arg.Kind.Long => { |
| 142 | const long = option.long ?? continue; | 161 | inline for (options) |option| { |
| 143 | if (!mem.eql(u8, long, arg)) continue; | 162 | defer if (option.kind == OptionT.Kind.Required) required_index += 1; |
| 163 | const long = option.long ?? continue; | ||
| 164 | if (mem.eql(u8, arg, long)) { | ||
| 165 | if (option.takes_value) { | ||
| 166 | arg_i += 1; | ||
| 167 | if (args.len <= arg_i) return error.OptionMissingValue; | ||
| 168 | |||
| 169 | try option.parse(&result, args[arg_i]); | ||
| 170 | } else { | ||
| 171 | try option.parse(&result, []u8{}); | ||
| 172 | } | ||
| 173 | |||
| 174 | required = newRequired(option, required, required_index); | ||
| 175 | break :success; | ||
| 176 | } | ||
| 177 | } | ||
| 144 | } | 178 | } |
| 145 | } | 179 | } |
| 146 | 180 | ||
| 147 | if (option.takes_value) arg_i += 1; | ||
| 148 | if (args.len <= arg_i) return error.MissingValueToArgument; | ||
| 149 | try option.parser(&result, args[arg_i]); | ||
| 150 | |||
| 151 | switch (option.kind) { | ||
| 152 | OptionT.Kind.Required => { | ||
| 153 | required = bits.set(u128, required, u7(required_index), false); | ||
| 154 | required_index += 1; | ||
| 155 | }, | ||
| 156 | OptionT.Kind.IgnoresRequired => { | ||
| 157 | required = 0; | ||
| 158 | required_index += 1; | ||
| 159 | }, | ||
| 160 | else => {} | ||
| 161 | } | ||
| 162 | |||
| 163 | break; | ||
| 164 | } else { | ||
| 165 | return error.InvalidArgument; | 181 | return error.InvalidArgument; |
| 166 | } | 182 | } |
| 167 | } | 183 | } |
| @@ -294,7 +310,7 @@ test "clap.parse.Example" { | |||
| 294 | Case { | 310 | Case { |
| 295 | .args = [][]const u8 { "-g" }, | 311 | .args = [][]const u8 { "-g" }, |
| 296 | .res = Color { .r = 0, .g = 0, .b = 0 }, | 312 | .res = Color { .r = 0, .g = 0, .b = 0 }, |
| 297 | .err = error.MissingValueToArgument, | 313 | .err = error.OptionMissingValue, |
| 298 | }, | 314 | }, |
| 299 | }; | 315 | }; |
| 300 | 316 | ||