Skip to content

Commit

Permalink
Use RawParam in parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
andrey-zherikov committed Nov 1, 2024
1 parent 235ffd0 commit adb60c2
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 73 deletions.
69 changes: 39 additions & 30 deletions source/argparse/internal/arguments.d
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module argparse.internal.arguments;
import argparse.internal.lazystring;

import argparse.config;
import argparse.param;
import argparse.result;

import std.typecons: Nullable;
Expand Down Expand Up @@ -36,23 +37,23 @@ package(argparse) struct ArgumentInfo
Nullable!size_t minValuesCount;
Nullable!size_t maxValuesCount;

auto checkValuesCount(const Config config, string argName, size_t count) const
auto checkValuesCount(const ref RawParam param) const
{
immutable min = minValuesCount.get;
immutable max = maxValuesCount.get;

// override for boolean flags
if(isBooleanFlag && count == 1)
if(isBooleanFlag && param.value.length == 1)
return Result.Success;

if(min == max && count != min)
return Result.Error("Argument '",config.styling.argumentName(argName),"': expected ",min,min == 1 ? " value" : " values");
if(min == max && param.value.length != min)
return Result.Error("Argument '",param.config.styling.argumentName(param.name),"': expected ",min,min == 1 ? " value" : " values");

if(count < min)
return Result.Error("Argument '",config.styling.argumentName(argName),"': expected at least ",min,min == 1 ? " value" : " values");
if(param.value.length < min)
return Result.Error("Argument '",param.config.styling.argumentName(param.name),"': expected at least ",min,min == 1 ? " value" : " values");

if(count > max)
return Result.Error("Argument '",config.styling.argumentName(argName),"': expected at most ",max,max == 1 ? " value" : " values");
if(param.value.length > max)
return Result.Error("Argument '",param.config.styling.argumentName(param.name),"': expected at most ",max,max == 1 ? " value" : " values");

return Result.Success;
}
Expand All @@ -70,28 +71,36 @@ unittest
return info;
}

assert(info(2,4).checkValuesCount(Config.init, "", 1).isError("expected at least 2 values"));
assert(info(2,4).checkValuesCount(Config.init, "", 2));
assert(info(2,4).checkValuesCount(Config.init, "", 3));
assert(info(2,4).checkValuesCount(Config.init, "", 4));
assert(info(2,4).checkValuesCount(Config.init, "", 5).isError("expected at most 4 values"));

assert(info(2,2).checkValuesCount(Config.init, "", 1).isError("expected 2 values"));
assert(info(2,2).checkValuesCount(Config.init, "", 2));
assert(info(2,2).checkValuesCount(Config.init, "", 3).isError("expected 2 values"));

assert(info(1,1).checkValuesCount(Config.init, "", 0).isError("expected 1 value"));
assert(info(1,1).checkValuesCount(Config.init, "", 1));
assert(info(1,1).checkValuesCount(Config.init, "", 2).isError("expected 1 value"));

assert(info(0,1).checkValuesCount(Config.init, "", 0));
assert(info(0,1).checkValuesCount(Config.init, "", 1));
assert(info(0,1).checkValuesCount(Config.init, "", 2).isError("expected at most 1 value"));

assert(info(1,2).checkValuesCount(Config.init, "", 0).isError("expected at least 1 value"));
assert(info(1,2).checkValuesCount(Config.init, "", 1));
assert(info(1,2).checkValuesCount(Config.init, "", 2));
assert(info(1,2).checkValuesCount(Config.init, "", 3).isError("expected at most 2 values"));
Config config;
auto p0 = RawParam(&config, "", []);
auto p1 = RawParam(&config, "", ["",]);
auto p2 = RawParam(&config, "", ["","",]);
auto p3 = RawParam(&config, "", ["","","",]);
auto p4 = RawParam(&config, "", ["","","","",]);
auto p5 = RawParam(&config, "", ["","","","","",]);

assert(info(2,4).checkValuesCount(p1).isError("expected at least 2 values"));
assert(info(2,4).checkValuesCount(p2));
assert(info(2,4).checkValuesCount(p3));
assert(info(2,4).checkValuesCount(p4));
assert(info(2,4).checkValuesCount(p5).isError("expected at most 4 values"));

assert(info(2,2).checkValuesCount(p1).isError("expected 2 values"));
assert(info(2,2).checkValuesCount(p2));
assert(info(2,2).checkValuesCount(p3).isError("expected 2 values"));

assert(info(1,1).checkValuesCount(p0).isError("expected 1 value"));
assert(info(1,1).checkValuesCount(p1));
assert(info(1,1).checkValuesCount(p2).isError("expected 1 value"));

assert(info(0,1).checkValuesCount(p0));
assert(info(0,1).checkValuesCount(p1));
assert(info(0,1).checkValuesCount(p2).isError("expected at most 1 value"));

assert(info(1,2).checkValuesCount(p0).isError("expected at least 1 value"));
assert(info(1,2).checkValuesCount(p1));
assert(info(1,2).checkValuesCount(p2));
assert(info(1,2).checkValuesCount(p3).isError("expected at most 2 values"));
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down
8 changes: 4 additions & 4 deletions source/argparse/internal/argumentuda.d
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,19 @@ package(argparse) struct ArgumentUDA(ValueParser)

package(argparse) ValueParser valueParser;

package Result parse(COMMAND_STACK, RECEIVER)(const Config config, const COMMAND_STACK cmdStack, ref RECEIVER receiver, string argName, string[] rawValues)
package Result parse(COMMAND_STACK, RECEIVER)(const COMMAND_STACK cmdStack, ref RECEIVER receiver, RawParam param)
{
try
{
auto res = info.checkValuesCount(config, argName, rawValues.length);
auto res = info.checkValuesCount(param);
if(!res)
return res;

return valueParser.parseParameter(receiver, RawParam(&config, argName, rawValues));
return valueParser.parseParameter(receiver, param);
}
catch(Exception e)
{
return Result.Error("Argument '", config.styling.argumentName(argName), ": ", e.msg);
return Result.Error("Argument '", param.config.styling.argumentName(param.name), ": ", e.msg);
}
}

Expand Down
37 changes: 20 additions & 17 deletions source/argparse/internal/command.d
Original file line number Diff line number Diff line change
Expand Up @@ -41,23 +41,24 @@ package struct SubCommands

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

private Result ArgumentParsingFunction(Config config, alias uda, RECEIVER)(const Command[] cmdStack,
ref RECEIVER receiver,
string argName,
string[] rawValues)
private Result ArgumentParsingFunction(alias uda, RECEIVER)(const Command[] cmdStack,
ref RECEIVER receiver,
ref RawParam param)
{
static if(uda.info.memberSymbol)
auto target = &__traits(getMember, receiver, uda.info.memberSymbol);
else
auto target = null;

return uda.parse(config, cmdStack, target, argName, rawValues);
return uda.parse(cmdStack, target, param);
}

private Result ArgumentCompleteFunction(Config config, alias uda, RECEIVER)(const Command[] cmdStack,
ref RECEIVER receiver,
string argName,
string[] rawValues)
private alias getArgumentParsingFunction1(alias uda) =
(const Command[] cmdStack, ref RawParam param) => ArgumentParsingFunction!uda(cmdStack, receiver, param);

private Result ArgumentCompleteFunction(alias uda, RECEIVER)(const Command[] cmdStack,
ref RECEIVER receiver,
ref RawParam param)
{
return Result.Success;
}
Expand All @@ -70,10 +71,12 @@ unittest
auto test(string[] values)
{
T t;
Config cfg;
auto param = RawParam(&cfg, "a", values);

enum uda = getMemberArgumentUDA!(T, "a")(Config.init);

return ArgumentParsingFunction!(Config.init, uda)([], t, "a", values);
return ArgumentParsingFunction!uda([], t, param);
}

assert(test(["raw-value"]));
Expand All @@ -88,19 +91,21 @@ unittest
}

T t;
Config cfg;
auto param = RawParam(&cfg, "func", []);

enum uda = getMemberArgumentUDA!(T, "func")(Config.init);

auto res = ArgumentParsingFunction!(Config.init, uda)([], t, "func", []);
auto res = ArgumentParsingFunction!uda([], t, param);

assert(res.isError(Config.init.styling.argumentName("func")~": My Message."));
assert(res.isError("func",": My Message."));
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package struct Command
{
alias Parse = Result delegate(const Command[] cmdStack, string argName, string[] argValue);
alias Parse = Result delegate(const Command[] cmdStack,ref RawParam param);

struct Argument
{
Expand Down Expand Up @@ -351,14 +356,12 @@ package(argparse) Command createCommand(Config config, COMMAND_TYPE)(ref COMMAND
res.restrictions.add!(COMMAND_TYPE, [typeTraits.argumentInfos])(config);

enum getArgumentParsingFunction(alias uda) =
(const Command[] cmdStack, string argName, string[] argValue)
=> ArgumentParsingFunction!(config, uda)(cmdStack, receiver, argName, argValue);
(const Command[] cmdStack, ref RawParam param) => ArgumentParsingFunction!uda(cmdStack, receiver, param);

res.parseFuncs = [staticMap!(getArgumentParsingFunction, typeTraits.argumentUDAs)];

enum getArgumentCompleteFunction(alias uda) =
(const Command[] cmdStack, string argName, string[] argValue)
=> ArgumentCompleteFunction!(config, uda)(cmdStack, receiver, argName, argValue);
(const Command[] cmdStack, ref RawParam param) => ArgumentCompleteFunction!uda(cmdStack, receiver, param);

res.completeFuncs = [staticMap!(getArgumentCompleteFunction, typeTraits.argumentUDAs)];

Expand Down
5 changes: 3 additions & 2 deletions source/argparse/internal/help.d
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module argparse.internal.help;

import argparse.ansi;
import argparse.config;
import argparse.param;
import argparse.result;
import argparse.api.ansi: ansiStylingArgument;
import argparse.internal.lazystring;
Expand Down Expand Up @@ -154,7 +155,7 @@ package struct HelpArgumentUDA
return info;
}();

Result parse(COMMAND_STACK, RECEIVER)(const Config config, const COMMAND_STACK cmdStack, ref RECEIVER, string argName, string[] rawValues)
Result parse(COMMAND_STACK, RECEIVER)(const COMMAND_STACK cmdStack, ref RECEIVER receiver, RawParam param)
{
import std.stdio: stdout;
import std.algorithm: map;
Expand All @@ -165,7 +166,7 @@ package struct HelpArgumentUDA
auto args = cmdStack.map!((ref _) => &_.arguments).array;

auto output = stdout.lockingTextWriter();
printHelp(_ => output.put(_), config, cmdStack[$-1], args, progName);
printHelp(_ => output.put(_), *param.config, cmdStack[$-1], args, progName);

return Result.Error(0, ""); // hack to force-exit (to be removed)
}
Expand Down
Loading

0 comments on commit adb60c2

Please sign in to comment.