import std.stdio;
import std.traits;
import std.typetuple;
import std.metastrings;

alias ParameterStorageClassTuple PSCT;
alias ParameterStorageClass PSC;
alias ParameterTypeTuple PTT;

string ToStorageName(alias T)()
{
    static if(T == PSC.REF) return "ref";
    else static if (T == PSC.OUT) return "out";
    else static if (T == PSC.LAZY) return "lazy";
    else static if (T == PSC.SCOPE) return "scope";
    else static if (T == PSC.NONE) return "in";
    else static assert(false, "other");
}

string PrintStorageTuple(int index, alias F, STs...)()
{
    alias PTT!F Ts;

    string ret = "";

    static if (STs.length > 0)
    {
        ret ~= ToStorageName!(STs[0])() ~ " "  ~ Ts[0].stringof;
        ret ~= " arg" ~ toStringNow!(index);
    }

    static if (STs.length > 1)
    {
        void func(Ts[1..$] a)
        {
        }
        const a = index + 1;
        ret ~= ", " ~ PrintStorageTuple!(a, func, STs[1..$])();
    }

    return ret;
}



string PrintStorage(alias F)(string name)
{
    alias PSCT!F STs;
    string ret = "auto " ~ name ~ "(" ~ PrintStorageTuple!(0, F, STs)() ~ ")";
    return ret;
}


// **** tests
int Multiply(int a, int b, out int c)
{
    return c = a * b;
}

mixin(PrintStorage!Multiply("DebugMultiply") ~ q{ 
{
    writeln("DEBUG: ", arg0, " ", arg1, " ", arg2);
    return Multiply(arg0, arg1, arg2);
}
  });


void main()
{
    int a= 10, b = -3, c;
    writeln(Multiply(a, b, c));
    writeln(c);
    a = 3;
    b = -4;
    writeln(DebugMultiply(a, b, c));
    writeln(c);
}
