1
0
Files
otyaSMILEBASIC/SMILEBASIC/builtinfunctions.d
2015-08-23 12:03:34 +09:00

978 lines
29 KiB
D

module otya.smilebasic.builtinfunctions;
import std.conv;
import std.typecons;
import std.typetuple;
import std.traits;
import std.stdio;
import std.ascii;
import std.range;
import otya.smilebasic.error;
import otya.smilebasic.type;
import otya.smilebasic.petitcomputer;
import otya.smilebasic.sprite;
import otya.smilebasic.vm;
//プチコンの引数省略は特殊なので
//LOCATE ,,0のように省略できる
struct DefaultValue(T, bool skippable = true)
{
T value;
bool isDefault;
this(T v, bool f)
{
value = v;
isDefault = f;
}
this(T v)
{
value = v;
isDefault = false;
}
this(bool f)
{
isDefault = f;
}
void setDefaultValue(T v)
{
if(isDefault)
value = v;
}
mixin Proxy!value;
}
alias ValueType = otya.smilebasic.type.ValueType;
struct BuiltinFunctionArgument
{
ValueType argType;
bool optionalArg;
bool skipArg;
}
class BuiltinFunction
{
BuiltinFunctionArgument[] argments;
ValueType result;
void function(PetitComputer, Value[], Value[]) func;
int startskip;
bool variadic;
string name;
this(BuiltinFunctionArgument[] argments, ValueType result, void function(PetitComputer, Value[], Value[]) func, int startskip,
bool variadic, string name)
{
this.argments = argments;
this.result = result;
this.func = func;
this.startskip = startskip;
this.variadic = variadic;
this.name = name;
}
bool hasSkipArgument()
{
return this.startskip != this.argments.length;
}
import std.math;
/*
static pure double ABS(double a)
{
return a < 0 ? -a : a;
}*/
static double function(double) ABS = &abs!double;
static double function(double) SGN = &sgn!double;
static double SIN(double arg1)
{
return sin(arg1);
}
static double SINH(double arg1)
{
return sinh(arg1);
}
static double COS(double arg1)
{
return cos(arg1);
}
static double COSH(double arg1)
{
return cosh(arg1);
}
static double TAN(double arg1)
{
return tan(arg1);
}
static double TANH(double arg1)
{
return tanh(arg1);
}
static double RAD(double arg1)
{
return arg1 * std.math.PI / 180;
}
static double DEG(double arg1)
{
return arg1 * 180 / std.math.PI;
}
static double PI()
{
return std.math.PI;
}
//static ABS = function double(double x) => abs(this.result == ValueType.Double ? 1 : 0);
static void LOCATE(PetitComputer p, DefaultValue!int x, DefaultValue!int y, DefaultValue!(int, false) z)
{
x.setDefaultValue(p.CSRX);
y.setDefaultValue(p.CSRY);
z.setDefaultValue(p.CSRZ);
p.CSRX = cast(int)x;
p.CSRY = cast(int)y;
p.CSRZ = cast(int)z;
}
static void COLOR(PetitComputer p, DefaultValue!int fore, DefaultValue!(int, false) back)
{
fore.setDefaultValue(p.consoleForeColor);
back.setDefaultValue(p.consoleBackColor);
p.consoleForeColor = cast(int)fore;
p.consoleBackColor = cast(int)back;
}
static void VSYNC(PetitComputer p, DefaultValue!int time)
{
time.setDefaultValue(1);
p.vsync(cast(int)time);
}
static void WAIT(PetitComputer p, DefaultValue!int time)
{
time.setDefaultValue(1);
p.vsync(cast(int)time);
}
//TODO:プチコンのCLSには引数の個数制限がない
static void CLS(PetitComputer p/*vaarg*/)
{
p.cls;
}
static void ASSERT__(PetitComputer p, int cond, wstring message)
{
if(!cond)
{
p.printConsole("Assertion failed: ", message, "\n");
}
assert(cond, message.to!string);
}
static int BUTTON(PetitComputer p, DefaultValue!(int, false) mode)
{
return p.button;
}
static void VISIBLE(PetitComputer p, DefaultValue!(int) console, DefaultValue!(int) graphic, DefaultValue!(int) BG, DefaultValue!(int) sprite)
{
}
static void XSCREEN(PetitComputer p, int mode, DefaultValue!(int, false) a, DefaultValue!(int, false) b)
{
a.setDefaultValue(512);
b.setDefaultValue(512);
p.xscreen(mode, cast(int)a, cast(int)b);
}
static void DISPLAY(PetitComputer p, int display)
{
p.display(display);
}
static void GCLS(PetitComputer p, DefaultValue!(int, false) color)
{
color.setDefaultValue(0);
p.gfill(p.useGRP, 0, 0, 511, 511, cast(int)color);
}
static void GPSET(PetitComputer p, int x, int y, DefaultValue!(int, false) color)
{
color.setDefaultValue(p.gcolor);
p.gpset(p.useGRP, x, y, cast(int)color);
}
static void GLINE(PetitComputer p, int x, int y, int x2, int y2, DefaultValue!(int, false) color)
{
color.setDefaultValue(p.gcolor);
p.gline(p.useGRP, x, y, x2, y2, cast(int)color);
}
static void GBOX(PetitComputer p, int x, int y, int x2, int y2, DefaultValue!(int, false) color)
{
color.setDefaultValue(p.gcolor);
p.gbox(p.useGRP, x, y, x2, y2, cast(int)color);
}
static void GFILL(PetitComputer p, int x, int y, int x2, int y2, DefaultValue!(int, false) color)
{
color.setDefaultValue(p.gcolor);
p.gfill(p.useGRP, x, y, x2, y2, cast(int)color);
}
static void GCOLOR(PetitComputer p, int color)
{
p.gcolor = color;
}
static void GPRIO(PetitComputer p, int z)
{
}
static void GPAGE(PetitComputer p, int showPage, int usePage)
{
p.showGRP = showPage;
p.useGRP = usePage;
}
static void BGMPLAY(PetitComputer p, int music)
{
}
static void BEEP(PetitComputer p, DefaultValue!(int, false) beep, DefaultValue!(int, false) pitch, DefaultValue!(int, false) volume, DefaultValue!(int, false) pan)
{
}
static void STICK(PetitComputer p, DefaultValue!(int, false) mp, out int x, out int y)
{
//JOYSTICK?
x = 0;
y = 0;
}
static int RGB(int R, int G, int B, DefaultValue!(int, false) _)
{
if(!_.isDefault)
{
//やや強引なオーバーロード
return PetitComputer.RGB(cast(ubyte)R, cast(ubyte)G, cast(ubyte)B, cast(ubyte)_);
}
return PetitComputer.RGB(cast(ubyte)R, cast(ubyte)G, cast(ubyte)B);
}
static int RND(int max)
{
import std.random;
return uniform(0, max - 1 + 1);
}
static void DTREAD(DefaultValue!(wstring, false) date, out int Y, out int M, out int D/*W*/)
{
import std.datetime;
auto currentTime = Clock.currTime();
if(date.isDefault)
{
Y = currentTime.year;
M = currentTime.month;
D = currentTime.day;
}
else
{
import std.format;
auto v = date.value;
formattedRead(v, "%d/%d/%d", &Y, &M, &D);
}
}
//hairetuha?
static int LEN(wstring str)
{
return str.length;
}
static double VAL(wstring str)
{
try
{
if(str.length > 2 && str[0..2] == "&H")
{
return str[2..$].to!int(16);
}
if(str.length > 2 && str[0..2] == "&B")
{
return str[2..$].to!int(2);
}
double val = str.to!double;
return val;
}
catch(Exception e)
{
return 0;//toriaezu
}
}
static double FLOOR(double val)
{
return val.floor;
}
static double ROUND(double val)
{
return val.round;
}
static double CEIL(double val)
{
return val.ceil;
}
static wstring MID(wstring str, int i, int len)
{
if(i + len > str.length)
{
return "";//範囲外で空文字
}
//挙動未定
return str[i..i + len];
}
//INSTRSUSBTLEFT
static wstring LEFT(wstring str, int len)
{
return str[0..len];
}
static wstring SUBST(wstring str, int i, Value alen, DefaultValue!(Value,false) areplace)
{
int len = 1;
wstring replace = "";
if(alen.isNumber)
{
len = alen.castInteger;
replace = areplace.castString;
}
else
{
replace = alen.castString;
//省略されたらi以降の全文字を置換
return str[0..i] ~ replace;
}
if(str.length <= i + len)
{
return str[0..i] ~ replace;
}
str.replaceInPlace(i, i + len, replace);
return str;
}
static int INSTR(Value vstart, Value vstr1, DefaultValue!(wstring, false) vstr2)
{
import std.string;
int start = 0;
wstring str1, str2;
if(!vstr2.isDefault)
{
start = vstart.castInteger;
str1 = vstr1.castString;
str2 = cast(wstring)vstr2;
}
else
{
str1 = vstart.castString;
str2 = vstr1.castString;
}
int aaa = str1[start..$].indexOf(str2, CaseSensitive.no);
return str1[start..$].indexOf(str2, CaseSensitive.no);
}
static int ASC(wstring str)
{
return cast(int)str[0];
}
static wstring STR(int val)
{
return val.to!wstring;
}
static wstring HEX(int val)
{
//ひどい
return val.to!string(16).to!wstring;
}
static void SPSET(PetitComputer p, int id, int defno)
{
p.sprite.spset(id, defno);
}
static void SPHIDE(PetitComputer p, int id)
{
p.sprite.sphide(id);
}
static void SPSHOW(PetitComputer p, int id)
{
p.sprite.spshow(id);
}
static void SPOFS(PetitComputer p, int id, int x, int y, DefaultValue!(int, false) z)
{
p.sprite.spofs(id, x, y);
}
static void SPANIM(PetitComputer p, Value[] va_args)
{
//TODO:配列
auto args = retro(va_args);
int no = args[0].castInteger;
double[] animdata = new double[args.length - 2];
int i;
foreach(a; args[2..$])
{
animdata[i++] = a.castDouble;
}
if(args[1].isString)
p.sprite.spanim(no, args[1].castString, animdata);
if(args[1].isNumber)
p.sprite.spanim(no, cast(SpriteAnimTarget)(args[1].castInteger), animdata);
}
static void SPDEF(PetitComputer p, Value[] va_args)
{
switch(va_args.length)
{
case 1://array
{
if(va_args[0].isNumberArray)
{
writeln("NOTIMPL:SPDEF ARRAY");
//return;
}
if(va_args[0].isString)
{
VM vm = p.vm;
vm.pushDataIndex();
vm.restoreData(va_args[0].castString);
auto count = vm.readData().castInteger;//読み込むスプライト数
int defno = 0;//?
for(int i = 0; i < count; i++)
{
int U = vm.readData().castInteger;
int V = vm.readData().castInteger;
int W = vm.readData().castInteger;
int H = vm.readData().castInteger;
int HX = vm.readData().castInteger;
int HY = vm.readData().castInteger;
int ATTR = vm.readData().castInteger;
p.sprite.SPDEFTable[defno] = SpriteDef(U, V, W, H, HX, HY, cast(SpriteAttr)ATTR);
defno++;
}
vm.popDataIndex();
return;
}
throw new IllegalFunctionCall("SPDEF");
return;
}
default:
}
{
int defno = va_args[0].castInteger;
int U = va_args[1].castInteger;
int V = va_args[2].castInteger;
int W = 16, H = 16, HX = 0, HY = 0, ATTR = 1;
if(va_args.length > 3)
{
W = va_args[3].castInteger;
}
if(va_args.length > 4)
{
H = va_args[4].castInteger;
}
if(va_args.length > 5)
{
HX = va_args[5].castInteger;
}
if(va_args.length > 6)
{
HY = va_args[6].castInteger;
}
if(va_args.length > 7)
{
ATTR = va_args[7].castInteger;
}
p.sprite.SPDEFTable[defno] = SpriteDef(U, V, W, H, HX, HY, cast(SpriteAttr)ATTR);
}
}
static void SPCLR(PetitComputer p, DefaultValue!(int, false) i)
{
if(i.isDefault)
p.sprite.spclr();
else
p.sprite.spclr(cast(int)i);
}
static void SPHOME(PetitComputer p, int i, int hx, int hy)
{
p.sprite.sphome(i, hx, hy);
}
static void SPSCALE(PetitComputer p, int i, int x, int y)
{
p.sprite.spscale(i, x, y);
}
static void BGMSTOP(PetitComputer p)
{
writeln("NOTIMPL:BGMSTOP");
}
static int BGMCHK(PetitComputer p)
{
writeln("NOTIMPL:BGMCHK");
return false;
}
static int CHKCHR(PetitComputer p, int x, int y)
{
return cast(int)(p.console[y][x].character);
}
static wstring FORMAT(PetitComputer p, Value[] va_args)
{
alias retro!(Value[]) VaArgs;
auto args = retro(va_args);
auto format = args[0].castString;
import std.array : appender;
import std.format;
import std.string;
auto w = appender!wstring();
int j = 1;
for(int i = 0; i < format.length; i++)
{
auto f = format[i];
if(f == '%')
{
int d = indexOf(format, 'D', CaseSensitive.yes);
if(d != -1)
{
auto spec = singleSpec(format[i .. d + 1]);
spec.spec = 'd';
formatValue(w, args[j].castInteger, spec);
j++;
i = d;
continue;
}
d = indexOf(format, 'X', CaseSensitive.yes);
if(d != -1)
{
auto spec = singleSpec(format[i .. d + 1]);
spec.spec = 'x';
formatValue(w, args[j].castDouble, spec);
j++;
i = d;
continue;
}
d = indexOf(format, 'S', CaseSensitive.yes);
if(d != -1)
{
auto spec = singleSpec(format[i .. d + 1]);
spec.spec = 's';
formatValue(w, args[j].castString, spec);
j++;
i = d;
continue;
}
d = indexOf(format, 'F', CaseSensitive.yes);
if(d != -1)
{
auto spec = singleSpec(format[i .. d + 1]);
spec.spec = 'f';
formatValue(w, args[j].castDouble, spec);
j++;
i = d;
continue;
}
}
w ~= f;
}
//プチコン互換FOMA
return cast(immutable)w.data();
}
static wstring CHR(int code)
{
return (cast(wchar)code).to!wstring;
}
static double POW(double a1, double a2)
{
return a1 ^^ a2;
}
static double SQR(double a1)
{
return sqrt(a1);
}
//GalateaTalk利用面倒くさい...
static void TALK(wstring a1)
{
}
//alias void function(PetitComputer, Value[], Value[]) BuiltinFunc;
static BuiltinFunction[wstring] builtinFunctions;
static this()
{
foreach(name; __traits(derivedMembers, BuiltinFunction))
{
writeln(name);
static if(/*__traits(isStaticFunction, __traits(getMember, BuiltinFunction, name)) && */name[0].isUpper)
{
pragma(msg, AddFunc!(BuiltinFunction, name));
wstring suffix = "";
if(is(ReturnType!(__traits(getMember, BuiltinFunction, name)) == wstring))
{
suffix = "$";
}
builtinFunctions[name ~ suffix] = new BuiltinFunction(
GetFunctionParamType!(BuiltinFunction, name),
GetFunctionReturnType!(BuiltinFunction, name),
mixin(AddFunc!(BuiltinFunction, name)),
GetStartSkip!(BuiltinFunction, name),
IsVariadic!(BuiltinFunction, name),
name,
);
writeln(AddFunc!(BuiltinFunction, name));
}
}
}
}
template GetStartSkip(T, string N)
{
private template SkipSkip(int I, P...)
{
static if(P.length <= I)
{
enum SkipSkip = I - is(P[0] == PetitComputer);
}
else static if(is(P[I] == DefaultValue!(int, false)))
{
enum SkipSkip = I - is(P[0] : PetitComputer);
}
else static if(is(P[I] == DefaultValue!(wstring, false)))
{
enum SkipSkip = I - is(P[0] : PetitComputer);
}
else static if(is(P[I] == DefaultValue!(Value, false)))
{
enum SkipSkip = I - is(P[0] : PetitComputer);
}
else
{
enum SkipSkip = SkipSkip!(I + 1, P);
}
}
enum GetStartSkip = SkipSkip!(0, ParameterTypeTuple!(__traits(getMember, T, N)));
}
template GetFunctionReturnType(T, string N)
{
static if(is(ReturnType!(__traits(getMember, T, N)) == double))
{
enum GetFunctionReturnType = ValueType.Double;
}
else static if(is(ReturnType!(__traits(getMember, T, N)) == int))
{
enum GetFunctionReturnType = ValueType.Integer;
}
else static if(is(ReturnType!(__traits(getMember, T, N)) == void))
{
enum GetFunctionReturnType = ValueType.Void;
}
else static if(is(ReturnType!(__traits(getMember, T, N)) == wstring))
{
enum GetFunctionReturnType = ValueType.String;
}
else
{
enum GetFunctionReturnType = ValueType.Void;
static assert(false, "Invalid type");
}
}
template AddFunc(T, string N)
{
static if(is(ReturnType!(__traits(getMember, T, N)) == double) || is(ReturnType!(__traits(getMember, T, N)) == int))
{
const string AddFunc = "function void(PetitComputer p, Value[] arg, Value[] ret){if(ret.length != 1){throw new IllegalFunctionCall(\"" ~ N ~ "\");}ret[0] = Value(" ~ N ~ "(" ~
AddFuncArg!(/*ParameterTypeTuple!(__traits(getMember, T, N)).length*/GetArgumentCount!(T,N) - 1, 0, 0, 0, T, N
, ParameterTypeTuple!(__traits(getMember, T, N))) ~ "));}";
}
else static if(is(ReturnType!(__traits(getMember, T, N)) == void))
{
pragma(msg, GetArgumentCount!(T,N));
const string AddFunc = "function void(PetitComputer p, Value[] arg, Value[] ret){/*if(ret.length != 0){throw new IllegalFunctionCall(\"" ~ N ~ "\");}*/" ~ OutArgsInit!(T,N) ~ N ~ "(" ~
AddFuncArg!(/*ParameterTypeTuple!(__traits(getMember, T, N)).length*/GetArgumentCount!(T,N) - 1, 0, 0, 0, T, N,
ParameterTypeTuple!(__traits(getMember, T, N))) ~ ");}";
}
else static if(is(ReturnType!(__traits(getMember, T, N)) == wstring))
{
const string AddFunc = "function void(PetitComputer p, Value[] arg, Value[] ret){if(ret.length != 1){throw new IllegalFunctionCall(\"" ~ N ~ "\");}ret[0] = Value(" ~ N ~ "(" ~
AddFuncArg!(/*ParameterTypeTuple!(__traits(getMember, T, N)).length*/GetArgumentCount!(T,N) - 1, 0, 0, 0, T, N
, ParameterTypeTuple!(__traits(getMember, T, N))) ~ "));}";
}
else
{
const string AddFunc = "";
static assert(false, "Invalid type");
}
}
DefaultValue!int fromIntToDefault(Value v)
{
if(v.isNumber)
return DefaultValue!int(v.castInteger());
else
return DefaultValue!int(true);
}
DefaultValue!(int, false) fromIntToSkip(Value v)
{
if(v.isNumber)
return DefaultValue!(int, false)(v.castInteger());
else
return DefaultValue!(int, false)(true);
}
DefaultValue!wstring fromStringToDefault(Value v)
{
if(v.type == ValueType.String)
return DefaultValue!wstring(v.castString());
else
return DefaultValue!wstring(true);
}
DefaultValue!(wstring, false) fromStringToSkip(Value v)
{
if(v.type == ValueType.String)
return DefaultValue!(wstring, false)(v.castString());
else
return DefaultValue!(wstring, false)(true);
}
DefaultValue!Value fromValueToDefault(Value v)
{
if(v.type != ValueType.Void)
return DefaultValue!Value(v);
else
return DefaultValue!Value(true);
}
DefaultValue!(Value, false) fromValueToSkip(Value v)
{
if(v.type != ValueType.Void)
return DefaultValue!(Value, false)(v);
else
return DefaultValue!(Value, false)(true);
}
template GetFunctionParamType(T, string N)
{
enum GetFunctionParamType = mixin("[" ~ Array!(ParameterTypeTuple!(__traits(getMember, T, N))) ~ "]");
private template Array(P...)
{
static if(P.length == 0)
{
const string arg = "";
enum Array = "";
}
else
{
static if(is(P[0] == double))
{
const string arg = "ValueType.Double, false";
}
else static if(is(P[0] == int))
{
const string arg = "ValueType.Integer, false";
}
else static if(is(P[0] == wstring))
{
const string arg = "ValueType.String, false";
}
else static if(is(P[0] == DefaultValue!int))
{
const string arg = "ValueType.Integer, true";
}
else static if(is(P[0] == DefaultValue!(int, false)))
{
const string arg = "ValueType.Integer, true";
}
else static if(is(P[0] == DefaultValue!(wstring)))
{
const string arg = "ValueType.String, false";
}
else static if(is(P[0] == DefaultValue!(wstring, false)))
{
const string arg = "ValueType.String, true";
}
else static if(is(P[0] == Value[]))
{
const string arg = "";
}
else static if(is(P[0] == DefaultValue!(Value)) || is(P[0] == Value))
{
const string arg = "ValueType.Void, false";
}
else static if(is(P[0] == DefaultValue!(Value, false)))
{
const string arg = "ValueType.Void, true";
}
else static if(is(P[0] == PetitComputer))
{
static if(P.length != 0)
{
enum Array = Array!(P[1..$]);
}
else
{
enum Array = "";
}
}
static if(1 == P.length && !is(P[0] == PetitComputer))
{
enum Array = "BuiltinFunctionArgument(" ~ arg ~ ")";
}
else static if(!is(P[0] == PetitComputer))
{
enum Array = "BuiltinFunctionArgument(" ~ arg ~ ")," ~ Array!(P[1..$]);
}
}
}
}
template AddFuncArg(int L, int N, int M, int O, T, string NAME, P...)
{
enum I = L - N;
static if(ParameterStorageClassTuple!(__traits(getMember, T, NAME)).length <= M)
{
const string AddFuncArg = "";
}
else
{
enum storage = ParameterStorageClassTuple!(__traits(getMember, T, NAME))[M];
static if(is(P[0] == double))
{
enum add = 1;
enum outadd = 0;
const string arg = "arg[" ~ I.to!string ~ "].castDouble";
}
else static if(is(P[0] == PetitComputer))
{
enum add = 0;
enum outadd = 0;
const string arg = "p";
}
else static if(is(P[0] == int))
{
static if(storage & ParameterStorageClass.out_)
{
enum add = 0;
enum outadd = 1;
const string arg = "ret[" ~ O.to!string ~ "].integerValue";
}
else
{
enum add = 1;
enum outadd = 0;
const string arg = "arg[" ~ I.to!string ~ "].castInteger";
}
}
else static if(is(P[0] == wstring))
{
enum add = 1;
enum outadd = 0;
const string arg = "arg[" ~ I.to!string ~ "].castString";
}
else static if(is(P[0] == DefaultValue!int))
{
enum add = 1;
enum outadd = 0;
const string arg = "fromIntToDefault(arg[" ~ I.to!string ~ "])";
}
else static if(is(P[0] == DefaultValue!(int, false)))
{
enum add = 1;
enum outadd = 0;
const string arg = "fromIntToSkip(arg[" ~ I.to!string ~ "])";
}
else static if(is(P[0] == DefaultValue!wstring))
{
enum add = 1;
enum outadd = 0;
const string arg = "fromStringToDefault(arg[" ~ I.to!string ~ "])";
}
else static if(is(P[0] == DefaultValue!(wstring, false)))
{
enum add = 1;
enum outadd = 0;
const string arg = "fromStringToSkip(arg[" ~ I.to!string ~ "])";
}
else static if(is(P[0] == Value[]))
{
const string arg = "arg";
}
else static if(is(P[0] == Value))
{
enum add = 1;
enum outadd = 0;
const string arg = "arg[" ~ I.to!string ~ "]";
}
else static if(is(P[0] == DefaultValue!Value))
{
enum add = 1;
enum outadd = 0;
const string arg = "fromValueToDefault(arg[" ~ I.to!string ~ "])";
}
else static if(is(P[0] == DefaultValue!(Value, false)))
{
enum add = 1;
enum outadd = 0;
const string arg = "fromValueToSkip(arg[" ~ I.to!string ~ "])";
}
else
{
enum add = 1;
enum outadd = 0;
pragma(msg, P[0]);
static assert(false, "Invalid type");
const string arg = "";
}
static if(1 == P.length)
{
const string AddFuncArg = arg;
}
else
{
const string AddFuncArg = arg ~ ", " ~ AddFuncArg!(L - !add, N + add, M + 1, O + outadd, T, NAME, P[1..$]);
}
}
}
template OutArgsInit(T, string N, int I = 0, int J = 0)
{
enum tuple = ParameterStorageClassTuple!(__traits(getMember, T, N))[I];
alias param = ParameterTypeTuple!(__traits(getMember, T, N));
static if(!param.length)
{
enum OutArgsInit = "";
}
else
{
static if(tuple & ParameterStorageClass.out_)
{
enum add = 1;
enum ret1 = "ret[" ~ J.to!string ~ "].type = ";
static if(is(param[I] == int))
{
enum ret2 = "ValueType.Integer;";
}
enum result = ret1 ~ ret2;
}
else
{
enum add = 0;
enum result = "";
}
static if(param.length > I + 1)
{
enum OutArgsInit = result ~ OutArgsInit!(T, N, I + 1, J + add);
}
else
{
enum OutArgsInit = result;
}
}
}
template GetArgumentCount(T, string N, int I = 0)
{
alias param = ParameterTypeTuple!(__traits(getMember, T, N));
static if(param.length <= I)
{
enum GetArgumentCount = 0;
}
else
{
enum tuple = ParameterStorageClassTuple!(__traits(getMember, T, N))[I];
static if(is(param[I] == PetitComputer))
{
enum add = 0 + 1;
}
else
{
static if(tuple & ParameterStorageClass.out_)
{
enum add = 0;
}
else
{
enum add = 1;
}
}
static if(param.length > I + 1)
{
enum GetArgumentCount = add + GetArgumentCount!(T, N, I + 1);
}
else
{
enum GetArgumentCount = add;
}
}
}
template IsVariadic(T, string N, int I = 0)
{
alias param = ParameterTypeTuple!(__traits(getMember, T, N));
static if(param.length == 0 || param.length <= I)
{
enum IsVariadic = false;
}
else static if(is(param[I] == Value[]))
{
enum IsVariadic = true;
}
else
{
enum IsVariadic = IsVariadic!(T, N, I + 1);
}
}