The arg iterator is now responsible for allocation instead of core.Clap

This commit is contained in:
Jimmi HC 2018-06-01 09:07:47 +02:00
parent 8ff2b3ff83
commit 5ebe2be10b
4 changed files with 62 additions and 60 deletions

View File

@ -7,8 +7,10 @@ const mem = std.mem;
const Names = clap.Names;
const Param = clap.Param;
const ArgError = clap.OsArgIterator.Error;
// TODO: More specific error in this func type.
const Command = fn(&mem.Allocator, &clap.ArgIterator) error!void;
const Command = fn(&mem.Allocator, &clap.ArgIterator(ArgError)) error!void;
const params = []Param(Command){
Param(Command).init(help, false, Names.prefix("help")),
@ -52,11 +54,12 @@ pub fn main() !void {
const allocator = &arena.allocator;
var args = clap.OsArgIterator.init();
var parser = clap.Clap(Command).init(params, &args.iter, allocator);
defer parser.deinit();
var args = clap.OsArgIterator.init(allocator);
defer args.deinit();
const exe = try args.iter.next();
var parser = clap.Clap(Command, ArgError).init(params, &args.iter);
const exe = try parser.nextNoParse();
const maybe_arg = parser.next() catch |err| b: {
debug.warn("{}.\n", @errorName(err));
// debug.warn(usage); TODO: error: evaluation exceeded 1000 backwards branches
@ -71,7 +74,7 @@ pub fn main() !void {
try arg.param.id(allocator, parser.iter);
}
pub fn help(allocator: &mem.Allocator, args: &clap.ArgIterator) (error{}!void) {
pub fn help(allocator: &mem.Allocator, args: &clap.ArgIterator(ArgError)) (error{}!void) {
// debug.warn(usage); TODO: error: evaluation exceeded 1000 backwards branches
}
@ -144,7 +147,7 @@ const missing_build_file =
\\
;
fn cmdBuild(allocator: &mem.Allocator, args: &clap.ArgIterator) !void {
fn cmdBuild(allocator: &mem.Allocator, args: &clap.ArgIterator(ArgError)) !void {
var init = false;
var build_file: []const u8 = "build.zig";
var cache_dir: []const u8 = "zig-cache";
@ -157,8 +160,7 @@ fn cmdBuild(allocator: &mem.Allocator, args: &clap.ArgIterator) !void {
var verbose_llvm_ir = false;
var verbose_cimport = false;
var parser = clap.Clap(Build).init(build_params, args, allocator);
defer parser.deinit();
var parser = clap.Clap(Build, ArgError).init(build_params, args);
while (parser.next() catch |err| {
debug.warn("{}.\n", @errorName(err));
@ -321,17 +323,17 @@ const build_generic_usage =
;
fn cmdBuildExe(allocator: &mem.Allocator, args: &clap.ArgIterator) (error{}!void) {
fn cmdBuildExe(allocator: &mem.Allocator, args: &clap.ArgIterator(ArgError)) (error{}!void) {
}
// cmd:build-lib ///////////////////////////////////////////////////////////////////////////////////
fn cmdBuildLib(allocator: &mem.Allocator, args: &clap.ArgIterator) (error{}!void) {
fn cmdBuildLib(allocator: &mem.Allocator, args: &clap.ArgIterator(ArgError)) (error{}!void) {
}
// cmd:build-obj ///////////////////////////////////////////////////////////////////////////////////
fn cmdBuildObj(allocator: &mem.Allocator, args: &clap.ArgIterator) (error{}!void) {
fn cmdBuildObj(allocator: &mem.Allocator, args: &clap.ArgIterator(ArgError)) (error{}!void) {
}
// cmd:fmt /////////////////////////////////////////////////////////////////////////////////////////
@ -348,17 +350,17 @@ const usage_fmt =
\\
;
fn cmdFmt(allocator: &mem.Allocator, args: &clap.ArgIterator) (error{}!void) {
fn cmdFmt(allocator: &mem.Allocator, args: &clap.ArgIterator(ArgError)) (error{}!void) {
}
// cmd:targets /////////////////////////////////////////////////////////////////////////////////////
fn cmdTargets(allocator: &mem.Allocator, args: &clap.ArgIterator) (error{}!void) {
fn cmdTargets(allocator: &mem.Allocator, args: &clap.ArgIterator(ArgError)) (error{}!void) {
}
// cmd:version /////////////////////////////////////////////////////////////////////////////////////
fn cmdVersion(allocator: &mem.Allocator, args: &clap.ArgIterator) (error{}!void) {
fn cmdVersion(allocator: &mem.Allocator, args: &clap.ArgIterator(ArgError)) (error{}!void) {
}
// cmd:test ////////////////////////////////////////////////////////////////////////////////////////
@ -372,7 +374,7 @@ const usage_test =
\\
;
fn cmdTest(allocator: &mem.Allocator, args: &clap.ArgIterator) (error{}!void) {
fn cmdTest(allocator: &mem.Allocator, args: &clap.ArgIterator(ArgError)) (error{}!void) {
}
// cmd:run /////////////////////////////////////////////////////////////////////////////////////////
@ -388,7 +390,7 @@ const usage_run =
\\
;
fn cmdRun(allocator: &mem.Allocator, args: &clap.ArgIterator) (error{}!void) {
fn cmdRun(allocator: &mem.Allocator, args: &clap.ArgIterator(ArgError)) (error{}!void) {
}
// cmd:translate-c /////////////////////////////////////////////////////////////////////////////////
@ -404,7 +406,7 @@ const usage_translate_c =
\\
;
fn cmdTranslateC(allocator: &mem.Allocator, args: &clap.ArgIterator) (error{}!void) {
fn cmdTranslateC(allocator: &mem.Allocator, args: &clap.ArgIterator(ArgError)) (error{}!void) {
}
// cmd:zen /////////////////////////////////////////////////////////////////////////////////////////
@ -426,7 +428,7 @@ const info_zen =
\\
;
fn cmdZen(allocator: &mem.Allocator, args: &clap.ArgIterator) (error{}!void) {
fn cmdZen(allocator: &mem.Allocator, args: &clap.ArgIterator(ArgError)) (error{}!void) {
}
// cmd:internal ////////////////////////////////////////////////////////////////////////////////////
@ -440,5 +442,5 @@ const usage_internal =
\\
;
fn cmdInternal(allocator: &mem.Allocator, args: &clap.ArgIterator) (error{}!void) {
fn cmdInternal(allocator: &mem.Allocator, args: &clap.ArgIterator(ArgError)) (error{}!void) {
}

View File

@ -136,34 +136,39 @@ pub fn Arg(comptime Id: type) type {
}
/// A interface for iterating over command line arguments
pub const ArgIterator = struct {
const Error = error{OutOfMemory};
pub fn ArgIterator(comptime E: type) type {
return struct {
const Self = this;
const Error = E;
nextFn: fn(iter: &ArgIterator, allocator: &mem.Allocator) Error!?[]const u8,
nextFn: fn(iter: &Self) Error!?[]const u8,
pub fn next(iter: &ArgIterator, allocator: &mem.Allocator) Error!?[]const u8 {
return iter.nextFn(iter, allocator);
}
};
pub fn next(iter: &Self) Error!?[]const u8 {
return iter.nextFn(iter);
}
};
}
/// An ::ArgIterator, which iterates over a slice of arguments.
/// This implementation does not allocate.
pub const ArgSliceIterator = struct {
const Error = error{};
args: []const []const u8,
index: usize,
iter: ArgIterator,
iter: ArgIterator(Error),
pub fn init(args: []const []const u8) ArgSliceIterator {
return ArgSliceIterator {
.args = args,
.index = 0,
.iter = ArgIterator {
.iter = ArgIterator(Error) {
.nextFn = nextFn,
},
};
}
fn nextFn(iter: &ArgIterator, allocator: &mem.Allocator) ArgIterator.Error!?[]const u8 {
fn nextFn(iter: &ArgIterator(Error)) Error!?[]const u8 {
const self = @fieldParentPtr(ArgSliceIterator, "iter", iter);
if (self.args.len <= self.index)
return null;
@ -176,22 +181,30 @@ pub const ArgSliceIterator = struct {
/// An ::ArgIterator, which wraps the ArgIterator in ::std.
/// On windows, this iterator allocates.
pub const OsArgIterator = struct {
args: os.ArgIterator,
iter: ArgIterator,
const Error = os.ArgIterator.NextError;
pub fn init() OsArgIterator {
arena: heap.ArenaAllocator,
args: os.ArgIterator,
iter: ArgIterator(Error),
pub fn init(allocator: &mem.Allocator) OsArgIterator {
return OsArgIterator {
.arena = heap.ArenaAllocator.init(allocator),
.args = os.args(),
.iter = ArgIterator {
.iter = ArgIterator(Error) {
.nextFn = nextFn,
},
};
}
fn nextFn(iter: &ArgIterator, allocator: &mem.Allocator) ArgIterator.Error!?[]const u8 {
pub fn deinit(iter: &OsArgIterator) void {
iter.arena.deinit();
}
fn nextFn(iter: &ArgIterator(Error)) Error!?[]const u8 {
const self = @fieldParentPtr(OsArgIterator, "iter", iter);
if (builtin.os == builtin.Os.windows) {
return try self.args.next(allocator) ?? return null;
return try self.args.next(self.allocator) ?? return null;
} else {
return self.args.nextPosix();
}
@ -201,7 +214,7 @@ pub const OsArgIterator = struct {
/// A command line argument parser which, given an ::ArgIterator, will parse arguments according
/// to the ::params. ::Clap parses in an iterating manner, so you have to use a loop together with
/// ::Clap.next to parse all the arguments of your program.
pub fn Clap(comptime Id: type) type {
pub fn Clap(comptime Id: type, comptime ArgError: type) type {
return struct {
const Self = this;
@ -215,14 +228,12 @@ pub fn Clap(comptime Id: type) type {
};
};
arena: heap.ArenaAllocator,
params: []const Param(Id),
iter: &ArgIterator,
iter: &ArgIterator(ArgError),
state: State,
pub fn init(params: []const Param(Id), iter: &ArgIterator, allocator: &mem.Allocator) Self {
pub fn init(params: []const Param(Id), iter: &ArgIterator(ArgError)) Self {
var res = Self {
.arena = heap.ArenaAllocator.init(allocator),
.params = params,
.iter = iter,
.state = State.Normal,
@ -231,10 +242,6 @@ pub fn Clap(comptime Id: type) type {
return res;
}
pub fn deinit(clap: &Self) void {
clap.arena.deinit();
}
/// Get the next ::Arg that matches a ::Param.
pub fn next(clap: &Self) !?Arg(Id) {
const ArgInfo = struct {
@ -246,7 +253,7 @@ pub fn Clap(comptime Id: type) type {
switch (clap.state) {
State.Normal => {
const full_arg = (try clap.nextNoParse()) ?? return null;
const full_arg = (try clap.iter.next()) ?? return null;
const arg_info = blk: {
var arg = full_arg;
var kind = ArgInfo.Kind.Bare;
@ -294,7 +301,7 @@ pub fn Clap(comptime Id: type) type {
if (maybe_value) |v|
break :blk v;
break :blk (try clap.nextNoParse()) ?? return error.MissingValue;
break :blk (try clap.iter.next()) ?? return error.MissingValue;
};
return Arg(Id).init(param, value);
@ -351,7 +358,7 @@ pub fn Clap(comptime Id: type) type {
return Arg(Id).init(param, null);
if (arg.len <= next_index) {
const value = (try clap.nextNoParse()) ?? return error.MissingValue;
const value = (try clap.iter.next()) ?? return error.MissingValue;
return Arg(Id).init(param, value);
}
@ -364,11 +371,5 @@ pub fn Clap(comptime Id: type) type {
return error.InvalidArgument;
}
// Returns the next arg in the underlying arg iterator
pub fn nextNoParse(clap: &Self) !?[]const u8 {
clap.state = State.Normal;
return try clap.iter.next(&clap.arena.allocator);
}
};
}

View File

@ -103,13 +103,13 @@ pub const Command = struct {
return res;
}
pub fn parse(comptime command: &const Command, allocator: &mem.Allocator, arg_iter: &core.ArgIterator) !command.Result {
pub fn parse(comptime command: &const Command, allocator: &mem.Allocator, arg_iter: var) !command.Result {
const Parent = struct {};
var parent = Parent{};
return command.parseHelper(&parent, allocator, arg_iter);
}
fn parseHelper(comptime command: &const Command, parent: var, allocator: &mem.Allocator, arg_iter: &core.ArgIterator) !command.Result {
fn parseHelper(comptime command: &const Command, parent: var, allocator: &mem.Allocator, arg_iter: var) !command.Result {
const Result = struct {
parent: @typeOf(parent),
result: command.Result,
@ -159,11 +159,10 @@ pub const Command = struct {
};
var pos: usize = 0;
var iter = core.Clap(usize).init(core_params, arg_iter, allocator);
defer iter.deinit();
var clap = core.Clap(usize, @typeOf(arg_iter.*).Error).init(core_params, arg_iter);
arg_loop:
while (try iter.next()) |arg| : (pos += 1) {
while (try clap.next()) |arg| : (pos += 1) {
inline for(command.params) |param, i| {
comptime const field = "result." ++ param.field;

View File

@ -14,7 +14,7 @@ const Clap = core.Clap;
fn testNoErr(params: []const Param(u8), args: []const []const u8, ids: []const u8, values: []const ?[]const u8) void {
var arg_iter = ArgSliceIterator.init(args);
var iter = Clap(u8).init(params, &arg_iter.iter, debug.global_allocator);
var iter = Clap(u8, ArgSliceIterator.Error).init(params, &arg_iter.iter);
var i: usize = 0;
while (iter.next() catch unreachable) |arg| : (i += 1) {