From 5ebe2be10b96410a6182a2aa66ff0d2bd43eed3f Mon Sep 17 00:00:00 2001 From: Jimmi HC Date: Fri, 1 Jun 2018 09:07:47 +0200 Subject: The arg iterator is now responsible for allocation instead of core.Clap --- examples/core.zig | 42 +++++++++++++++++----------------- src/core.zig | 67 ++++++++++++++++++++++++++++--------------------------- src/extended.zig | 9 ++++---- tests/core.zig | 2 +- 4 files changed, 61 insertions(+), 59 deletions(-) diff --git a/examples/core.zig b/examples/core.zig index 8bcc928..eb512ef 100644 --- a/examples/core.zig +++ b/examples/core.zig @@ -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) { } diff --git a/src/core.zig b/src/core.zig index 8570220..5e47714 100644 --- a/src/core.zig +++ b/src/core.zig @@ -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 { + const Error = os.ArgIterator.NextError; + + arena: heap.ArenaAllocator, args: os.ArgIterator, - iter: ArgIterator, + iter: ArgIterator(Error), - pub fn init() OsArgIterator { + 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); - } }; } diff --git a/src/extended.zig b/src/extended.zig index b94f6f5..31e6455 100644 --- a/src/extended.zig +++ b/src/extended.zig @@ -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; diff --git a/tests/core.zig b/tests/core.zig index d4304a1..91b62fe 100644 --- a/tests/core.zig +++ b/tests/core.zig @@ -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) { -- cgit v1.2.3