diff options
| author | 2022-08-25 18:07:44 +0200 | |
|---|---|---|
| committer | 2022-08-25 18:07:44 +0200 | |
| commit | ee6cb6a17bd8748c3af45467c5dabbe1d56be832 (patch) | |
| tree | 7686bd4de2dac502ea7eb7e134a46dce7c9a413c /clap.zig | |
| parent | Have all tests have a name (diff) | |
| download | zig-clap-ee6cb6a17bd8748c3af45467c5dabbe1d56be832.tar.gz zig-clap-ee6cb6a17bd8748c3af45467c5dabbe1d56be832.tar.xz zig-clap-ee6cb6a17bd8748c3af45467c5dabbe1d56be832.zip | |
Fix zig-clap for new default compiler
Also enable test suit for both stage 1 and stage 2, to ensure we don't
break things for people who haven't switched yet.
Diffstat (limited to 'clap.zig')
| -rw-r--r-- | clap.zig | 87 |
1 files changed, 50 insertions, 37 deletions
| @@ -6,6 +6,7 @@ const heap = std.heap; | |||
| 6 | const io = std.io; | 6 | const io = std.io; |
| 7 | const math = std.math; | 7 | const math = std.math; |
| 8 | const mem = std.mem; | 8 | const mem = std.mem; |
| 9 | const meta = std.meta; | ||
| 9 | const process = std.process; | 10 | const process = std.process; |
| 10 | const testing = std.testing; | 11 | const testing = std.testing; |
| 11 | 12 | ||
| @@ -25,6 +26,7 @@ pub const Names = struct { | |||
| 25 | /// '--' prefix | 26 | /// '--' prefix |
| 26 | long: ?[]const u8 = null, | 27 | long: ?[]const u8 = null, |
| 27 | 28 | ||
| 29 | /// The longest of the possible names this `Names` struct can represent. | ||
| 28 | pub fn longest(names: *const Names) Longest { | 30 | pub fn longest(names: *const Names) Longest { |
| 29 | if (names.long) |long| | 31 | if (names.long) |long| |
| 30 | return .{ .kind = .long, .name = long }; | 32 | return .{ .kind = .long, .name = long }; |
| @@ -73,7 +75,7 @@ pub const Values = enum { | |||
| 73 | /// * Positional parameters must take a value. | 75 | /// * Positional parameters must take a value. |
| 74 | pub fn Param(comptime Id: type) type { | 76 | pub fn Param(comptime Id: type) type { |
| 75 | return struct { | 77 | return struct { |
| 76 | id: Id = Id{}, | 78 | id: Id, |
| 77 | names: Names = Names{}, | 79 | names: Names = Names{}, |
| 78 | takes_value: Values = .none, | 80 | takes_value: Values = .none, |
| 79 | }; | 81 | }; |
| @@ -199,7 +201,7 @@ pub fn parseParamEx(str: []const u8, end: *usize) !Param(Help) { | |||
| 199 | // * Someone points out how this is a really bad idea. | 201 | // * Someone points out how this is a really bad idea. |
| 200 | @setEvalBranchQuota(std.math.maxInt(u32)); | 202 | @setEvalBranchQuota(std.math.maxInt(u32)); |
| 201 | 203 | ||
| 202 | var res = Param(Help){}; | 204 | var res = Param(Help){ .id = .{} }; |
| 203 | var start: usize = 0; | 205 | var start: usize = 0; |
| 204 | var state: enum { | 206 | var state: enum { |
| 205 | start, | 207 | start, |
| @@ -449,11 +451,11 @@ test "parseParams" { | |||
| 449 | \\--bb This should be a new param | 451 | \\--bb This should be a new param |
| 450 | \\ | 452 | \\ |
| 451 | , &.{ | 453 | , &.{ |
| 452 | .{ .names = .{ .short = 's' } }, | 454 | .{ .id = .{}, .names = .{ .short = 's' } }, |
| 453 | .{ .names = .{ .long = "str" } }, | 455 | .{ .id = .{}, .names = .{ .long = "str" } }, |
| 454 | .{ .names = .{ .long = "str-str" } }, | 456 | .{ .id = .{}, .names = .{ .long = "str-str" } }, |
| 455 | .{ .names = .{ .long = "str_str" } }, | 457 | .{ .id = .{}, .names = .{ .long = "str_str" } }, |
| 456 | .{ .names = .{ .short = 's', .long = "str" } }, | 458 | .{ .id = .{}, .names = .{ .short = 's', .long = "str" } }, |
| 457 | .{ | 459 | .{ |
| 458 | .id = .{ .val = "str" }, | 460 | .id = .{ .val = "str" }, |
| 459 | .names = .{ .long = "str" }, | 461 | .names = .{ .long = "str" }, |
| @@ -671,6 +673,7 @@ pub fn parse( | |||
| 671 | }; | 673 | }; |
| 672 | } | 674 | } |
| 673 | 675 | ||
| 676 | /// The result of `parse`. Is owned by the caller and should be freed with `deinit`. | ||
| 674 | pub fn Result( | 677 | pub fn Result( |
| 675 | comptime Id: type, | 678 | comptime Id: type, |
| 676 | comptime params: []const Param(Id), | 679 | comptime params: []const Param(Id), |
| @@ -721,14 +724,13 @@ pub fn parseEx( | |||
| 721 | opt: ParseOptions, | 724 | opt: ParseOptions, |
| 722 | ) !ResultEx(Id, params, value_parsers) { | 725 | ) !ResultEx(Id, params, value_parsers) { |
| 723 | const allocator = opt.allocator; | 726 | const allocator = opt.allocator; |
| 724 | var positionals = std.ArrayList( | 727 | const Positional = FindPositionalType(Id, params, value_parsers); |
| 725 | FindPositionalType(Id, params, value_parsers), | ||
| 726 | ).init(allocator); | ||
| 727 | 728 | ||
| 729 | var positionals = std.ArrayList(Positional).init(allocator); | ||
| 728 | var arguments = Arguments(Id, params, value_parsers, .list){}; | 730 | var arguments = Arguments(Id, params, value_parsers, .list){}; |
| 729 | errdefer deinitArgs(Id, params, value_parsers, .list, allocator, &arguments); | 731 | errdefer deinitArgs(Id, params, allocator, &arguments); |
| 730 | 732 | ||
| 731 | var stream = streaming.Clap(Id, @typeInfo(@TypeOf(iter)).Pointer.child){ | 733 | var stream = streaming.Clap(Id, meta.Child(@TypeOf(iter))){ |
| 732 | .params = params, | 734 | .params = params, |
| 733 | .iter = iter, | 735 | .iter = iter, |
| 734 | .diagnostic = opt.diagnostic, | 736 | .diagnostic = opt.diagnostic, |
| @@ -756,8 +758,10 @@ pub fn parseEx( | |||
| 756 | try res; | 758 | try res; |
| 757 | } | 759 | } |
| 758 | 760 | ||
| 761 | // We are done parsing, but our arguments are stored in lists, and not slices. Map the list | ||
| 762 | // fields to slices and return that. | ||
| 759 | var result_args = Arguments(Id, params, value_parsers, .slice){}; | 763 | var result_args = Arguments(Id, params, value_parsers, .slice){}; |
| 760 | inline for (@typeInfo(@TypeOf(arguments)).Struct.fields) |field| { | 764 | inline for (meta.fields(@TypeOf(arguments))) |field| { |
| 761 | if (@typeInfo(field.field_type) == .Struct and | 765 | if (@typeInfo(field.field_type) == .Struct and |
| 762 | @hasDecl(field.field_type, "toOwnedSlice")) | 766 | @hasDecl(field.field_type, "toOwnedSlice")) |
| 763 | { | 767 | { |
| @@ -803,6 +807,7 @@ fn parseArg( | |||
| 803 | } | 807 | } |
| 804 | } | 808 | } |
| 805 | 809 | ||
| 810 | /// The result of `parseEx`. Is owned by the caller and should be freed with `deinit`. | ||
| 806 | pub fn ResultEx( | 811 | pub fn ResultEx( |
| 807 | comptime Id: type, | 812 | comptime Id: type, |
| 808 | comptime params: []const Param(Id), | 813 | comptime params: []const Param(Id), |
| @@ -814,7 +819,7 @@ pub fn ResultEx( | |||
| 814 | allocator: mem.Allocator, | 819 | allocator: mem.Allocator, |
| 815 | 820 | ||
| 816 | pub fn deinit(result: *@This()) void { | 821 | pub fn deinit(result: *@This()) void { |
| 817 | deinitArgs(Id, params, value_parsers, .slice, result.allocator, &result.args); | 822 | deinitArgs(Id, params, result.allocator, &result.args); |
| 818 | result.allocator.free(result.positionals); | 823 | result.allocator.free(result.positionals); |
| 819 | } | 824 | } |
| 820 | }; | 825 | }; |
| @@ -825,15 +830,22 @@ fn FindPositionalType( | |||
| 825 | comptime params: []const Param(Id), | 830 | comptime params: []const Param(Id), |
| 826 | comptime value_parsers: anytype, | 831 | comptime value_parsers: anytype, |
| 827 | ) type { | 832 | ) type { |
| 833 | const pos = findPositional(Id, params) orelse return []const u8; | ||
| 834 | return ParamType(Id, pos, value_parsers); | ||
| 835 | } | ||
| 836 | |||
| 837 | fn findPositional(comptime Id: type, params: []const Param(Id)) ?Param(Id) { | ||
| 828 | for (params) |param| { | 838 | for (params) |param| { |
| 829 | const longest = param.names.longest(); | 839 | const longest = param.names.longest(); |
| 830 | if (longest.kind == .positinal) | 840 | if (longest.kind == .positinal) |
| 831 | return ParamType(Id, param, value_parsers); | 841 | return param; |
| 832 | } | 842 | } |
| 833 | 843 | ||
| 834 | return []const u8; | 844 | return null; |
| 835 | } | 845 | } |
| 836 | 846 | ||
| 847 | /// Given a parameter figure out which type that parameter is parsed into when using the correct | ||
| 848 | /// parser from `value_parsers`. | ||
| 837 | fn ParamType( | 849 | fn ParamType( |
| 838 | comptime Id: type, | 850 | comptime Id: type, |
| 839 | comptime param: Param(Id), | 851 | comptime param: Param(Id), |
| @@ -846,13 +858,13 @@ fn ParamType( | |||
| 846 | return parsers.Result(@TypeOf(parser)); | 858 | return parsers.Result(@TypeOf(parser)); |
| 847 | } | 859 | } |
| 848 | 860 | ||
| 861 | /// Deinitializes a struct of type `Argument`. Since the `Argument` type is generated, and we | ||
| 862 | /// cannot add the deinit declaration to it, we declare it here instead. | ||
| 849 | fn deinitArgs( | 863 | fn deinitArgs( |
| 850 | comptime Id: type, | 864 | comptime Id: type, |
| 851 | comptime params: []const Param(Id), | 865 | comptime params: []const Param(Id), |
| 852 | comptime value_parsers: anytype, | ||
| 853 | comptime multi_arg_kind: MultiArgKind, | ||
| 854 | allocator: mem.Allocator, | 866 | allocator: mem.Allocator, |
| 855 | arguments: *Arguments(Id, params, value_parsers, multi_arg_kind), | 867 | arguments: anytype, |
| 856 | ) void { | 868 | ) void { |
| 857 | inline for (params) |param| { | 869 | inline for (params) |param| { |
| 858 | const longest = comptime param.names.longest(); | 870 | const longest = comptime param.names.longest(); |
| @@ -861,15 +873,22 @@ fn deinitArgs( | |||
| 861 | if (param.takes_value != .many) | 873 | if (param.takes_value != .many) |
| 862 | continue; | 874 | continue; |
| 863 | 875 | ||
| 864 | switch (multi_arg_kind) { | 876 | const field = @field(arguments, longest.name); |
| 865 | .slice => allocator.free(@field(arguments, longest.name)), | 877 | |
| 866 | .list => @field(arguments, longest.name).deinit(allocator), | 878 | // If the multi value field is a struct, we know it is a list and should be deinited. |
| 879 | // Otherwise, it is a slice that should be freed. | ||
| 880 | switch (@typeInfo(@TypeOf(field))) { | ||
| 881 | .Struct => @field(arguments, longest.name).deinit(allocator), | ||
| 882 | else => allocator.free(@field(arguments, longest.name)), | ||
| 867 | } | 883 | } |
| 868 | } | 884 | } |
| 869 | } | 885 | } |
| 870 | 886 | ||
| 871 | const MultiArgKind = enum { slice, list }; | 887 | const MultiArgKind = enum { slice, list }; |
| 872 | 888 | ||
| 889 | /// Turn a list of parameters into a struct with one field for each none positional parameter. | ||
| 890 | /// The type of each parameter field is determined by `ParamType`. Positional arguments will not | ||
| 891 | /// havea field in this struct. | ||
| 873 | fn Arguments( | 892 | fn Arguments( |
| 874 | comptime Id: type, | 893 | comptime Id: type, |
| 875 | comptime params: []const Param(Id), | 894 | comptime params: []const Param(Id), |
| @@ -885,27 +904,21 @@ fn Arguments( | |||
| 885 | continue; | 904 | continue; |
| 886 | 905 | ||
| 887 | const T = ParamType(Id, param, value_parsers); | 906 | const T = ParamType(Id, param, value_parsers); |
| 888 | const FieldType = switch (param.takes_value) { | 907 | const default_value = switch (param.takes_value) { |
| 889 | .none => bool, | 908 | .none => false, |
| 890 | .one => ?T, | 909 | .one => @as(?T, null), |
| 891 | .many => switch (multi_arg_kind) { | 910 | .many => switch (multi_arg_kind) { |
| 892 | .slice => []const T, | 911 | .slice => @as([]const T, &[_]T{}), |
| 893 | .list => std.ArrayListUnmanaged(T), | 912 | .list => std.ArrayListUnmanaged(T){}, |
| 894 | }, | 913 | }, |
| 895 | }; | 914 | }; |
| 915 | |||
| 896 | fields[i] = .{ | 916 | fields[i] = .{ |
| 897 | .name = longest.name, | 917 | .name = longest.name, |
| 898 | .field_type = FieldType, | 918 | .field_type = @TypeOf(default_value), |
| 899 | .default_value = switch (param.takes_value) { | 919 | .default_value = @ptrCast(*const anyopaque, &default_value), |
| 900 | .none => &false, | ||
| 901 | .one => &@as(?T, null), | ||
| 902 | .many => switch (multi_arg_kind) { | ||
| 903 | .slice => &@as([]const T, &[_]T{}), | ||
| 904 | .list => &std.ArrayListUnmanaged(T){}, | ||
| 905 | }, | ||
| 906 | }, | ||
| 907 | .is_comptime = false, | 920 | .is_comptime = false, |
| 908 | .alignment = @alignOf(FieldType), | 921 | .alignment = @alignOf(@TypeOf(default_value)), |
| 909 | }; | 922 | }; |
| 910 | i += 1; | 923 | i += 1; |
| 911 | } | 924 | } |