Created
May 31, 2015 11:55
-
-
Save liranz/d1a42b47f8d744db2c69 to your computer and use it in GitHub Desktop.
KW arguments implemented as a library "function"
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import std.traits; | |
import std.typetuple; | |
import std.typecons; | |
import std.string; | |
import std.stdio; | |
import std.conv; | |
auto KWArg(string name, T)(T arguments) | |
{ | |
static struct Args | |
{ | |
T argValue; | |
enum argName = name; | |
alias argType = T; | |
alias argValue this; | |
} | |
return Args(cast(Unqual!T)arguments); | |
} | |
private enum isKWArgument(T) = hasMember!(T, "argName") && hasMember!(T, "argValue"); | |
template KWFunc(alias fun) { | |
struct KWFunc { | |
static int getNumOfPositionalArguments(int curr,ARGS...)() { | |
alias types = ParameterTypeTuple!fun; | |
static if (ARGS.length == 0) { | |
return curr; // case that all are positional | |
} | |
alias first = ARGS[0]; | |
static if (!isKWArgument!first) { | |
static assert(is(first : types[curr]), | |
format("positional argument of wrong type. Expected %s found %s", | |
types[curr].stringof, ARGS[0].stringof)); | |
return getNumOfPositionalArguments!(curr +1, ARGS[1..$])(); | |
} else { // Finished all positional, lets make sure rest are KWArgs | |
foreach(k, A; ARGS) { | |
static assert(isKWArgument!A); | |
} | |
return curr; | |
} | |
} | |
static int getPositionByArgName(int positionalArguments, string name, ARGS...)() { | |
int ret; | |
foreach(j, A; ARGS[positionalArguments .. $]) { | |
static if (name == A.argName) { | |
return j + positionalArguments; | |
} | |
} | |
return -1; | |
} | |
static string generateCallerString(ARGS...)() { | |
alias names = ParameterIdentifierTuple!fun; | |
alias types = ParameterTypeTuple!fun; | |
alias defaults = ParameterDefaultValueTuple!fun; | |
string ret = "fun("; | |
enum positionalArguments = getNumOfPositionalArguments!(0, ARGS)(); | |
foreach (i, n; names) { | |
static if (i != 0) { | |
ret ~= ", "; | |
} | |
static if (i < positionalArguments) { | |
ret ~= format("args[%s]", i); | |
} else { | |
enum argumentPosition = getPositionByArgName!(positionalArguments, n, ARGS); | |
static if (-1 != argumentPosition) { | |
alias current = ARGS[argumentPosition]; | |
static assert(n == current.argName, | |
format("KW Argument name ended up wrong. Expected '%s' found '%s'", | |
n, current.argName)); | |
static assert(is(current.argType == types[i]), | |
format("KW argument with name %s and type '%s' conflicts ofiginal type '%s'", | |
n, current.argType.stringof, types[i].stringof)); | |
ret ~= format("args[%d]", argumentPosition); | |
} else { | |
static if (!is(defaults[i] : void)) { | |
ret ~= to!string(defaults[i]); | |
} else { | |
// We were not able to place any argument. Announce failure | |
static assert(false, format("Could not place anything for argument #%s : %s %s", | |
i, types[i].stringof, n)); | |
} | |
} | |
} | |
} | |
ret ~= " );"; | |
return ret; | |
} | |
static auto opCall(ARGS...)(ARGS args) { | |
enum ret = generateCallerString!ARGS(); | |
static if(is(ReturnType!func == void)) { | |
mixin(ret); | |
} else { | |
mixin("return " ~ ret); | |
} | |
} | |
} | |
} | |
string normalFunc(string pos0, int pos1, string arg1, int arg2, long arg3 = 50, long arg4 = 100) { | |
return format("pos0 is '%s', pos1 is '%s', arg1 is '%s' arg2 is '%s' arg3 is '%s' arg4 is '%s'", pos0, pos1, arg1, arg2, arg3, arg4); | |
} | |
unittest | |
{ | |
alias arg2 = KWArg!("arg2", int); | |
// test 2 positional argument, out of order KW arguments and default value | |
auto ret = KWFunc!normalFunc("positional", 144, KWArg!"arg1"("full fledged"), KWArg!"arg4"(22L), arg2(2)); | |
assert(ret == "pos0 is 'positional', pos1 is '144', arg1 is 'full fledged' arg2 is '2' arg3 is '50' arg4 is '22'"); | |
//TODO: Add more test cases :) | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment