SPLINK,SPOFS OUT実装,BuiltinFunctionクラスをオーバーロード対応にした
This commit is contained in:
@@ -113,6 +113,15 @@ class VM
|
||||
}
|
||||
value = stack[--stacki];
|
||||
}
|
||||
void decSP()
|
||||
{
|
||||
if(stacki <= bp)
|
||||
{
|
||||
writeln("Stack underflow");
|
||||
readln();
|
||||
}
|
||||
--stacki;
|
||||
}
|
||||
Value testGetGlobalVariable(wstring name)
|
||||
{
|
||||
return global[globalTable[name].index];
|
||||
@@ -1391,3 +1400,10 @@ class PopSystemVariable : Code
|
||||
return "popsysvar " ~ var.to!string;
|
||||
}
|
||||
}
|
||||
class DecSP : Code
|
||||
{
|
||||
override void execute(VM vm)
|
||||
{
|
||||
vm.decSP;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,10 @@ struct DefaultValue(T, bool skippable = true)
|
||||
}
|
||||
mixin Proxy!value;
|
||||
}
|
||||
struct StartOptional
|
||||
{
|
||||
const char[] name;
|
||||
}
|
||||
alias ValueType = otya.smilebasic.type.ValueType;
|
||||
struct BuiltinFunctionArgument
|
||||
{
|
||||
@@ -46,23 +50,66 @@ struct BuiltinFunctionArgument
|
||||
bool optionalArg;
|
||||
bool skipArg;
|
||||
}
|
||||
//オーバーロード用
|
||||
class BuiltinFunctions
|
||||
{
|
||||
private BuiltinFunction[] func;
|
||||
this(BuiltinFunction f)
|
||||
{
|
||||
func = new BuiltinFunction[1];
|
||||
func[0] = f;
|
||||
}
|
||||
void addFunction(BuiltinFunction func)
|
||||
{
|
||||
this.func ~= func;
|
||||
}
|
||||
BuiltinFunction overloadResolution(int argc, int outargc)
|
||||
{
|
||||
BuiltinFunction va;
|
||||
//とりあえず引数の数で解決させる,というよりコンパイル時に型を取得する方法がない
|
||||
foreach(f; func)
|
||||
{
|
||||
if(f.startskip <= argc && f.argments.length >= argc && f.outoptional <= outargc && f.results.length >= outargc)
|
||||
return f;
|
||||
if(f.variadic)
|
||||
va = f;
|
||||
}
|
||||
//一応可変長は最後
|
||||
if(va) return va;
|
||||
writeln("====function overloads===");
|
||||
foreach(f; func)
|
||||
{
|
||||
writefln("name=\"%s\", argments=%s, results = %s, variadic = %s, startoptional = %d, function pointer=%s", f.name, f.argments, f.results, f.variadic, f.startskip, f.func);
|
||||
}
|
||||
//引数数ちがうのは実行前にエラー
|
||||
throw new IllegalFunctionCall(func[0].name);
|
||||
}
|
||||
}
|
||||
alias DefaultValue!(int, false) optionalint;
|
||||
alias DefaultValue!(int, false) optionaldouble;
|
||||
alias DefaultValue!(int, false) optionalstring;
|
||||
/**
|
||||
ここに関数を定義すればコンパイル時にBuiltinFunctionに変換してくれる便利なクラス
|
||||
*/
|
||||
class BuiltinFunction
|
||||
{
|
||||
BuiltinFunctionArgument[] argments;
|
||||
ValueType result;
|
||||
BuiltinFunctionArgument[] results;
|
||||
void function(PetitComputer, Value[], Value[]) func;
|
||||
int startskip;
|
||||
int outoptional;
|
||||
bool variadic;
|
||||
string name;
|
||||
this(BuiltinFunctionArgument[] argments, ValueType result, void function(PetitComputer, Value[], Value[]) func, int startskip,
|
||||
bool variadic, string name)
|
||||
this(BuiltinFunctionArgument[] argments, BuiltinFunctionArgument[] results, void function(PetitComputer, Value[], Value[]) func, int startskip,
|
||||
bool variadic, string name, int outoptional)
|
||||
{
|
||||
this.argments = argments;
|
||||
this.result = result;
|
||||
this.results = results;
|
||||
this.func = func;
|
||||
this.startskip = startskip;
|
||||
this.variadic = variadic;
|
||||
this.name = name;
|
||||
this.outoptional = outoptional;
|
||||
}
|
||||
bool hasSkipArgument()
|
||||
{
|
||||
@@ -74,8 +121,16 @@ class BuiltinFunction
|
||||
{
|
||||
return a < 0 ? -a : a;
|
||||
}*/
|
||||
static double function(double) ABS = &abs!double;
|
||||
static double function(double) SGN = &sgn!double;
|
||||
//static double function(double) ABS = &abs!double;
|
||||
//static double function(double) SGN = &sgn!double;
|
||||
static double ABS(double arg1)
|
||||
{
|
||||
return abs(arg1);
|
||||
}
|
||||
static double SGN(double arg1)
|
||||
{
|
||||
return sgn(arg1);
|
||||
}
|
||||
static double SIN(double arg1)
|
||||
{
|
||||
return sin(arg1);
|
||||
@@ -168,8 +223,12 @@ class BuiltinFunction
|
||||
}
|
||||
assert(cond, message.to!string);
|
||||
}
|
||||
static int BUTTON(PetitComputer p, DefaultValue!(int, false) mode)
|
||||
static int BUTTON(PetitComputer p, DefaultValue!(int, false) mode, DefaultValue!(int, false) mp)
|
||||
{
|
||||
if(!mp.isDefault)
|
||||
{
|
||||
writeln("NOTIMPL:BUTTON(ID, MPID)");
|
||||
}
|
||||
return p.button;
|
||||
}
|
||||
static void VISIBLE(PetitComputer p, DefaultValue!(int) console, DefaultValue!(int) graphic, DefaultValue!(int) BG, DefaultValue!(int) sprite)
|
||||
@@ -317,7 +376,11 @@ class BuiltinFunction
|
||||
{
|
||||
if(i + len > str.length)
|
||||
{
|
||||
return "";//範囲外で空文字
|
||||
if(i >= str.length)
|
||||
{
|
||||
return "";//範囲外で空文字
|
||||
}
|
||||
return str[i..$];//iがまだ範囲内なら最後まで
|
||||
}
|
||||
//挙動未定
|
||||
return str[i..i + len];
|
||||
@@ -462,9 +525,21 @@ class BuiltinFunction
|
||||
{
|
||||
p.sprite.spshow(id);
|
||||
}
|
||||
static void SPOFS(PetitComputer p, int id, int x, int y, DefaultValue!(int, false) z)
|
||||
static void SPOFS(PetitComputer p, int id, double x, double y, DefaultValue!(int, false) z)
|
||||
{
|
||||
p.sprite.spofs(id, x, y, cast(int)z);
|
||||
if(z.isDefault)
|
||||
{
|
||||
p.sprite.spofs(id, x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
p.sprite.spofs(id, x, y, cast(int)z);
|
||||
}
|
||||
}
|
||||
@StartOptional("z")
|
||||
static void SPOFS(PetitComputer p, int id, out double x, out double y, out int z)
|
||||
{
|
||||
p.sprite.getspofs(id, x, y, z);
|
||||
}
|
||||
static void SPANIM(PetitComputer p, Value[] va_args)
|
||||
{
|
||||
@@ -573,6 +648,14 @@ class BuiltinFunction
|
||||
{
|
||||
p.sprite.spcolor(id, cast(uint)color);
|
||||
}
|
||||
static void SPLINK(PetitComputer p, int child, int parent)
|
||||
{
|
||||
p.sprite.splink(child, parent);
|
||||
}
|
||||
static void SPUNLINK(PetitComputer p, int id)
|
||||
{
|
||||
p.sprite.spunlink(id);
|
||||
}
|
||||
static void BGMSTOP(PetitComputer p)
|
||||
{
|
||||
writeln("NOTIMPL:BGMSTOP");
|
||||
@@ -756,7 +839,7 @@ class BuiltinFunction
|
||||
throw new IllegalFunctionCall("COPY (Not implemented error)");
|
||||
}
|
||||
//alias void function(PetitComputer, Value[], Value[]) BuiltinFunc;
|
||||
static BuiltinFunction[wstring] builtinFunctions;
|
||||
static BuiltinFunctions[wstring] builtinFunctions;
|
||||
static this()
|
||||
{
|
||||
foreach(name; __traits(derivedMembers, BuiltinFunction))
|
||||
@@ -764,27 +847,74 @@ class 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))
|
||||
foreach(i, F; __traits(getOverloads, BuiltinFunction, name))
|
||||
{
|
||||
suffix = "$";
|
||||
//pragma(msg, AddFunc!(BuiltinFunction, name));
|
||||
wstring suffix = "";
|
||||
if(is(ReturnType!(__traits(getMember, BuiltinFunction, name)) == wstring))
|
||||
{
|
||||
suffix = "$";
|
||||
}
|
||||
wstring name2 = name ~ suffix;
|
||||
auto func = builtinFunctions.get(name2, null);
|
||||
alias BFD = BuiltinFunctionData!(BuiltinFunction, name, i);
|
||||
pragma(msg, AddFunc!BFD);
|
||||
auto f = new BuiltinFunction(
|
||||
GetFunctionParamType!(BFD),
|
||||
GetFunctionReturnType!(BFD),
|
||||
mixin(AddFunc!(BFD)),
|
||||
GetStartSkip!(BFD),
|
||||
IsVariadic!(BFD),
|
||||
name,
|
||||
GetOutStartSkip!(BFD)
|
||||
);
|
||||
if(func)
|
||||
{
|
||||
builtinFunctions[name2].addFunction(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
builtinFunctions[name2] = new BuiltinFunctions(f);
|
||||
}
|
||||
//writeln(AddFunc!(BuiltinFunction, name));
|
||||
}
|
||||
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)
|
||||
template GetOutStartSkip(BFD)
|
||||
{
|
||||
static if(__traits(getAttributes, __traits(getOverloads, BFD.C_, BFD.N)[BFD.I_]).length == 1 &&
|
||||
is(typeof(__traits(getAttributes, __traits(getOverloads, BFD.C_, BFD.N)[BFD.I_])[0]) == StartOptional))
|
||||
{
|
||||
enum so = __traits(getAttributes, __traits(getOverloads, BFD.C_, BFD.N)[BFD.I_])[0];
|
||||
int GetOutStartSkip()
|
||||
{
|
||||
int k;
|
||||
foreach (j, i; ParameterIdentifierTuple!(__traits(getOverloads, BFD.C_, BFD.N)[BFD.I_]))
|
||||
{
|
||||
if(i == so.name)
|
||||
{
|
||||
return k;
|
||||
}
|
||||
else if(BFD.ParameterStorageClass[j] & ParameterStorageClass.out_)
|
||||
{
|
||||
k++;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int GetOutStartSkip()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
template GetStartSkip(BFD)
|
||||
{
|
||||
private template SkipSkip(int I, P...)
|
||||
{
|
||||
@@ -792,10 +922,18 @@ template GetStartSkip(T, string N)
|
||||
{
|
||||
enum SkipSkip = I - is(P[0] == PetitComputer);
|
||||
}
|
||||
else static if(BFD.ParameterStorageClass[I] & ParameterStorageClass.out_)
|
||||
{
|
||||
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!(double, false)))
|
||||
{
|
||||
enum SkipSkip = I - is(P[0] : PetitComputer);
|
||||
}
|
||||
else static if(is(P[I] == DefaultValue!(wstring, false)))
|
||||
{
|
||||
enum SkipSkip = I - is(P[0] : PetitComputer);
|
||||
@@ -809,52 +947,170 @@ template GetStartSkip(T, string N)
|
||||
enum SkipSkip = SkipSkip!(I + 1, P);
|
||||
}
|
||||
}
|
||||
enum GetStartSkip = SkipSkip!(0, ParameterTypeTuple!(__traits(getMember, T, N)));
|
||||
enum GetStartSkip = SkipSkip!(0, BFD.ParameterType);
|
||||
}
|
||||
template GetFunctionReturnType(T, string N)
|
||||
template GetBuiltinFunctionArgment(P...)
|
||||
{
|
||||
static if(is(ReturnType!(__traits(getMember, T, N)) == double))
|
||||
static if(is(P[0] == double))
|
||||
{
|
||||
enum GetFunctionReturnType = ValueType.Double;
|
||||
const string arg = "ValueType.Double, false";
|
||||
}
|
||||
else static if(is(ReturnType!(__traits(getMember, T, N)) == int))
|
||||
else static if(is(P[0] == int))
|
||||
{
|
||||
enum GetFunctionReturnType = ValueType.Integer;
|
||||
const string arg = "ValueType.Integer, false";
|
||||
}
|
||||
else static if(is(ReturnType!(__traits(getMember, T, N)) == void))
|
||||
else static if(is(P[0] == wstring))
|
||||
{
|
||||
enum GetFunctionReturnType = ValueType.Void;
|
||||
const string arg = "ValueType.String, false";
|
||||
}
|
||||
else static if(is(ReturnType!(__traits(getMember, T, N)) == wstring))
|
||||
else static if(is(P[0] == DefaultValue!int))
|
||||
{
|
||||
enum GetFunctionReturnType = ValueType.String;
|
||||
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] == OptionalOutValue!int))
|
||||
{
|
||||
const string arg = "ValueType.Integer, true";
|
||||
}
|
||||
else static if(is(P[0] == DefaultValue!double))
|
||||
{
|
||||
const string arg = "ValueType.Double, true";
|
||||
}
|
||||
else static if(is(P[0] == DefaultValue!(double, false)))
|
||||
{
|
||||
const string arg = "ValueType.Double, 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] == void))
|
||||
{
|
||||
const string arg = "";
|
||||
}
|
||||
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))
|
||||
static if(is(P[0] == void))
|
||||
{
|
||||
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))) ~ "));}";
|
||||
enum GetBuiltinFunctionArgment = "";
|
||||
}
|
||||
else static if(is(ReturnType!(__traits(getMember, T, N)) == void))
|
||||
else
|
||||
{
|
||||
enum GetBuiltinFunctionArgment = "BuiltinFunctionArgument(" ~ arg ~ ")";
|
||||
}
|
||||
}
|
||||
template BuiltinFunctionData(C, string NAME, int I)
|
||||
{
|
||||
//struct BuiltinFunctionData
|
||||
//{
|
||||
//enum P = ParameterStorageClassTuple!(__traits(getOverloads, C, N)[I]);
|
||||
struct BuiltinFunctionData
|
||||
{
|
||||
alias P = std.traits.ParameterStorageClassTuple!(__traits(getOverloads, C, NAME)[I]);
|
||||
alias T = std.traits.ParameterTypeTuple!(__traits(getOverloads, C, NAME)[I]);
|
||||
alias R = std.traits.ReturnType!(__traits(getOverloads, C, NAME)[I]);
|
||||
alias ParameterStorageClass = std.traits.ParameterStorageClassTuple!(__traits(getOverloads, C, NAME)[I]);
|
||||
alias ParameterType = std.traits.ParameterTypeTuple!(__traits(getOverloads, C, NAME)[I]);
|
||||
alias ReturnType = std.traits.ReturnType!(__traits(getOverloads, C, NAME)[I]);
|
||||
enum F = &__traits(getOverloads, C, NAME)[I];
|
||||
alias N = NAME;
|
||||
alias C_ = C;
|
||||
alias I_ = I;
|
||||
}
|
||||
}
|
||||
template GetOutArgment(C, string N)
|
||||
{
|
||||
alias T = ParameterTypeTuple!(__traits(getMember, C, N));
|
||||
string GetOutArgment2()
|
||||
{
|
||||
string arg = "";
|
||||
foreach(i, J; T)
|
||||
{
|
||||
enum P = ParameterStorageClassTuple!(__traits(getMember, C, N))[i];
|
||||
static if(P & ParameterStorageClass.out_)
|
||||
{
|
||||
arg ~= GetBuiltinFunctionArgment!(J) ~ ",";
|
||||
}
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
enum GetOutArgment = GetOutArgment2();
|
||||
}
|
||||
template GetOutArgment2(BFD)
|
||||
{
|
||||
alias T = BFD.T;
|
||||
string GetOutArgment22()
|
||||
{
|
||||
string arg = "";
|
||||
foreach(i, J; T)
|
||||
{
|
||||
//enum P = ParameterStorageClassTuple!(__traits(getMember, C, N))[i];
|
||||
static if(BFD.P[i] & ParameterStorageClass.out_)
|
||||
{
|
||||
arg ~= GetBuiltinFunctionArgment!(J) ~ ",";
|
||||
}
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
enum GetOutArgment2 = GetOutArgment22();
|
||||
}
|
||||
//template GetOutArgment2(T2)
|
||||
//{
|
||||
//}
|
||||
template GetFunctionReturnType(BFD)
|
||||
{
|
||||
static if(is(BFD.R == void))
|
||||
{
|
||||
enum GetFunctionReturnType =
|
||||
mixin("[" ~ GetOutArgment2!(BFD) ~ "]");
|
||||
}
|
||||
else
|
||||
{
|
||||
enum GetFunctionReturnType =
|
||||
mixin("[" ~ GetBuiltinFunctionArgment!(BFD.R) ~ "]");
|
||||
}
|
||||
}
|
||||
template AddFunc(BFD)
|
||||
{
|
||||
static if(is(BFD.ReturnType == double) || is(BFD.ReturnType == int))
|
||||
{
|
||||
const string AddFunc = "function void(PetitComputer p, Value[] arg, Value[] ret){if(ret.length != 1){throw new IllegalFunctionCall(\"" ~ BFD.N ~ "\");}ret[0] = Value(" ~ BFD.N ~ "(" ~
|
||||
AddFuncArg!(/*ParameterTypeTuple!(__traits(getMember, T, N)).length*/GetArgumentCount!(BFD) - 1, 0, 0, 0, BFD,
|
||||
BFD.ParameterType) ~ "));}";
|
||||
}
|
||||
else static if(is(BFD.ReturnType == 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))) ~ ");}";
|
||||
const string AddFunc = "function void(PetitComputer p, Value[] arg, Value[] ret){/*if(ret.length != 0){throw new IllegalFunctionCall(\"" ~ BFD.N ~ "\");}*/" ~ OutArgsInit!(BFD) ~ BFD.N ~ "(" ~
|
||||
AddFuncArg!(/*ParameterTypeTuple!(__traits(getMember, T, N)).length*/GetArgumentCount!(BFD) - 1, 0, 0, 0, BFD,
|
||||
BFD.ParameterType) ~ ");}";
|
||||
}
|
||||
else static if(is(ReturnType!(__traits(getMember, T, N)) == wstring))
|
||||
else static if(is(BFD.ReturnType == 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))) ~ "));}";
|
||||
const string AddFunc = "function void(PetitComputer p, Value[] arg, Value[] ret){if(ret.length != 1){throw new IllegalFunctionCall(\"" ~ BFD.N ~ "\");}ret[0] = Value(" ~ BFD.N ~ "(" ~
|
||||
AddFuncArg!(/*ParameterTypeTuple!(__traits(getMember, T, N)).length*/GetArgumentCount!(BFD) - 1, 0, 0, 0, BFD,
|
||||
BFD.ParameterType) ~ "));}";
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -918,16 +1174,27 @@ DefaultValue!(Value, false) fromValueToSkip(Value v)
|
||||
else
|
||||
return DefaultValue!(Value, false)(true);
|
||||
}
|
||||
template GetFunctionParamType(T, string N)
|
||||
template GetFunctionParamType(BFD)
|
||||
{
|
||||
enum GetFunctionParamType = mixin("[" ~ Array!(ParameterTypeTuple!(__traits(getMember, T, N))) ~ "]");
|
||||
private template Array(P...)
|
||||
enum GetFunctionParamType = mixin("[" ~ Array!(0, BFD.T) ~ "]");
|
||||
private template Array(int I, P...)
|
||||
{
|
||||
static if(P.length == 0)
|
||||
{
|
||||
const string arg = "";
|
||||
enum Array = "";
|
||||
}
|
||||
else static if(BFD.ParameterStorageClass[I] & ParameterStorageClass.out_)
|
||||
{
|
||||
static if(1 == P.length && !is(P[0] == PetitComputer))
|
||||
{
|
||||
enum Array = "";
|
||||
}
|
||||
else static if(!is(P[0] == PetitComputer))
|
||||
{
|
||||
enum Array = Array!(I + 1, P[1..$]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
static if(is(P[0] == double))
|
||||
@@ -982,7 +1249,7 @@ template GetFunctionParamType(T, string N)
|
||||
{
|
||||
static if(P.length != 0)
|
||||
{
|
||||
enum Array = Array!(P[1..$]);
|
||||
enum Array = Array!(I + 1, P[1..$]);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -995,26 +1262,35 @@ template GetFunctionParamType(T, string N)
|
||||
}
|
||||
else static if(!is(P[0] == PetitComputer))
|
||||
{
|
||||
enum Array = "BuiltinFunctionArgument(" ~ arg ~ ")," ~ Array!(P[1..$]);
|
||||
enum Array = "BuiltinFunctionArgument(" ~ arg ~ ")," ~ Array!(I + 1, P[1..$]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
template AddFuncArg(int L, int N, int M, int O, T, string NAME, P...)
|
||||
template AddFuncArg(int L, int N, int M, int O, BFD, P...)
|
||||
{
|
||||
enum I = L - N;
|
||||
static if(ParameterStorageClassTuple!(__traits(getMember, T, NAME)).length <= M)
|
||||
static if(BFD.ParameterStorageClass.length <= M)
|
||||
{
|
||||
const string AddFuncArg = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
enum storage = ParameterStorageClassTuple!(__traits(getMember, T, NAME))[M];
|
||||
enum storage = BFD.ParameterStorageClass[M];
|
||||
static if(is(P[0] == double))
|
||||
{
|
||||
enum add = 1;
|
||||
enum outadd = 0;
|
||||
const string arg = "arg[" ~ I.to!string ~ "].castDouble";
|
||||
static if(storage & ParameterStorageClass.out_)
|
||||
{
|
||||
enum add = 0;
|
||||
enum outadd = 1;
|
||||
const string arg = "ret[" ~ O.to!string ~ "].doubleValue";
|
||||
}
|
||||
else
|
||||
{
|
||||
enum add = 1;
|
||||
enum outadd = 0;
|
||||
const string arg = "arg[" ~ I.to!string ~ "].castDouble";
|
||||
}
|
||||
}
|
||||
else static if(is(P[0] == PetitComputer))
|
||||
{
|
||||
@@ -1045,9 +1321,18 @@ template AddFuncArg(int L, int N, int M, int O, T, string NAME, P...)
|
||||
}
|
||||
else static if(is(P[0] == DefaultValue!int))
|
||||
{
|
||||
enum add = 1;
|
||||
enum outadd = 0;
|
||||
const string arg = "fromIntToDefault(arg[" ~ I.to!string ~ "])";
|
||||
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 = "fromIntToDefault(arg[" ~ I.to!string ~ "])";
|
||||
}
|
||||
}
|
||||
else static if(is(P[0] == DefaultValue!(int, false)))
|
||||
{
|
||||
@@ -1059,7 +1344,7 @@ template AddFuncArg(int L, int N, int M, int O, T, string NAME, P...)
|
||||
{
|
||||
enum add = 1;
|
||||
enum outadd = 0;
|
||||
const string arg = "fromIntDoubleToDefault(arg[" ~ I.to!string ~ "])";
|
||||
const string arg = "fromDoubleToDefault(arg[" ~ I.to!string ~ "])";
|
||||
}
|
||||
else static if(is(P[0] == DefaultValue!(double, false)))
|
||||
{
|
||||
@@ -1115,20 +1400,20 @@ template AddFuncArg(int L, int N, int M, int O, T, string NAME, P...)
|
||||
}
|
||||
else
|
||||
{
|
||||
const string AddFuncArg = arg ~ ", " ~ AddFuncArg!(L - !add, N + add, M + 1, O + outadd, T, NAME, P[1..$]);
|
||||
const string AddFuncArg = arg ~ ", " ~ AddFuncArg!(L - !add, N + add, M + 1, O + outadd, BFD, P[1..$]);
|
||||
}
|
||||
}
|
||||
}
|
||||
template OutArgsInit(T, string N, int I = 0, int J = 0)
|
||||
template OutArgsInit(BFD, int I = 0, int J = 0)
|
||||
{
|
||||
alias param = ParameterTypeTuple!(__traits(getMember, T, N));
|
||||
alias param = BFD.ParameterType;
|
||||
static if(!param.length)
|
||||
{
|
||||
enum OutArgsInit = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
enum tuple = ParameterStorageClassTuple!(__traits(getMember, T, N))[I];
|
||||
enum tuple = BFD.ParameterStorageClass[I];
|
||||
static if(tuple & ParameterStorageClass.out_)
|
||||
{
|
||||
enum add = 1;
|
||||
@@ -1137,6 +1422,26 @@ template OutArgsInit(T, string N, int I = 0, int J = 0)
|
||||
{
|
||||
enum ret2 = "ValueType.Integer;";
|
||||
}
|
||||
else static if(is(param[I] == DefaultValue!int))
|
||||
{
|
||||
enum ret2 = "ValueType.Integer;";
|
||||
}
|
||||
//else static if(is(param[I] == OptionalOutValue!int))
|
||||
//{
|
||||
// enum ret2 = "ValueType.Integer;";
|
||||
//}
|
||||
else static if(is(param[I] == double))
|
||||
{
|
||||
enum ret2 = "ValueType.Double;";
|
||||
}
|
||||
else static if(is(param[I] == Value[]))
|
||||
{
|
||||
enum ret2 = "ValueType.Void;";
|
||||
}
|
||||
else
|
||||
{
|
||||
static assert(false, "invalid type " ~ param[I].stringof);
|
||||
}
|
||||
enum result = ret1 ~ ret2;
|
||||
}
|
||||
else
|
||||
@@ -1146,7 +1451,7 @@ template OutArgsInit(T, string N, int I = 0, int J = 0)
|
||||
}
|
||||
static if(param.length > I + 1)
|
||||
{
|
||||
enum OutArgsInit = result ~ OutArgsInit!(T, N, I + 1, J + add);
|
||||
enum OutArgsInit = result ~ OutArgsInit!(BFD, I + 1, J + add);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1154,16 +1459,16 @@ template OutArgsInit(T, string N, int I = 0, int J = 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
template GetArgumentCount(T, string N, int I = 0)
|
||||
template GetArgumentCount(BFD, int I = 0)
|
||||
{
|
||||
alias param = ParameterTypeTuple!(__traits(getMember, T, N));
|
||||
alias param = BFD.ParameterType;
|
||||
static if(param.length <= I)
|
||||
{
|
||||
enum GetArgumentCount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
enum tuple = ParameterStorageClassTuple!(__traits(getMember, T, N))[I];
|
||||
enum tuple = BFD.ParameterStorageClass[I];
|
||||
static if(is(param[I] == PetitComputer))
|
||||
{
|
||||
enum add = 0 + 1;
|
||||
@@ -1181,7 +1486,7 @@ template GetArgumentCount(T, string N, int I = 0)
|
||||
}
|
||||
static if(param.length > I + 1)
|
||||
{
|
||||
enum GetArgumentCount = add + GetArgumentCount!(T, N, I + 1);
|
||||
enum GetArgumentCount = add + GetArgumentCount!(BFD, I + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1189,9 +1494,9 @@ template GetArgumentCount(T, string N, int I = 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
template IsVariadic(T, string N, int I = 0)
|
||||
template IsVariadic(BFD, int I = 0)
|
||||
{
|
||||
alias param = ParameterTypeTuple!(__traits(getMember, T, N));
|
||||
alias param = BFD.ParameterType;
|
||||
static if(param.length == 0 || param.length <= I)
|
||||
{
|
||||
enum IsVariadic = false;
|
||||
@@ -1202,7 +1507,7 @@ template IsVariadic(T, string N, int I = 0)
|
||||
}
|
||||
else
|
||||
{
|
||||
enum IsVariadic = IsVariadic!(T, N, I + 1);
|
||||
enum IsVariadic = IsVariadic!(BFD, I + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -416,9 +416,11 @@ class Compiler
|
||||
case NodeType.CallFunction:
|
||||
{
|
||||
auto func = cast(CallFunction)exp;
|
||||
auto bfun = otya.smilebasic.builtinfunctions.BuiltinFunction.builtinFunctions.get(func.name, null);
|
||||
if(bfun)
|
||||
auto bfuns = otya.smilebasic.builtinfunctions.BuiltinFunction.builtinFunctions.get(func.name, null);
|
||||
otya.smilebasic.builtinfunctions.BuiltinFunction bfun;
|
||||
if(bfuns)
|
||||
{
|
||||
bfun = bfuns.overloadResolution(func.args.length, 1);
|
||||
if(bfun.argments.length >= func.args.length)
|
||||
{
|
||||
auto k = bfun.argments.length - func.args.length;
|
||||
@@ -808,9 +810,11 @@ class Compiler
|
||||
case NodeType.CallFunctionStatement:
|
||||
{
|
||||
auto func = cast(CallFunctionStatement)i;
|
||||
auto bfun = otya.smilebasic.builtinfunctions.BuiltinFunction.builtinFunctions.get(func.name, null);
|
||||
if(bfun)
|
||||
auto bfuns = otya.smilebasic.builtinfunctions.BuiltinFunction.builtinFunctions.get(func.name, null);
|
||||
otya.smilebasic.builtinfunctions.BuiltinFunction bfun;
|
||||
if(bfuns)
|
||||
{
|
||||
bfun = bfuns.overloadResolution(func.args.length, func.outVariable.length);
|
||||
int k = cast(int)bfun.argments.length - cast(int)func.args.length;
|
||||
foreach(l;0..k)
|
||||
{
|
||||
@@ -823,13 +827,21 @@ class Compiler
|
||||
}
|
||||
if(bfun)
|
||||
{
|
||||
genCode(new CallBuiltinFunction(bfun, cast(int)func.args.length, cast(int)func.outVariable.length));
|
||||
genCode(new CallBuiltinFunction(bfun, cast(int)func.args.length, cast(int)bfun.results.length));//func.outVariable.length));
|
||||
}
|
||||
else
|
||||
{
|
||||
writeln(func.name);
|
||||
genCode(new CallFunctionCode(func.name, cast(int)func.args.length, cast(int)func.outVariable.length));
|
||||
}
|
||||
if(bfun)
|
||||
{
|
||||
int k = cast(int)bfun.results.length - cast(int)func.outVariable.length;
|
||||
foreach(l;0..k)
|
||||
{
|
||||
genCode(new DecSP);
|
||||
}
|
||||
}
|
||||
//TODO:OUT
|
||||
foreach_reverse(wstring var; func.outVariable)
|
||||
{
|
||||
|
||||
@@ -644,6 +644,7 @@ class PetitComputer
|
||||
DrawType dt;
|
||||
auto start = SDL_GetTicks();
|
||||
int i = s;
|
||||
static const size = 255.5f;
|
||||
for(; i < len; i++)
|
||||
{
|
||||
DrawMessage dm = drawMessageQueue[i];
|
||||
@@ -657,7 +658,7 @@ class PetitComputer
|
||||
case DrawType.PSET:
|
||||
glBegin(GL_POINTS);
|
||||
glColor4ubv(cast(ubyte*)&dm.color);
|
||||
glVertex2f((dm.x) / 256f - 1, (dm.y) / 256f - 1);
|
||||
glVertex2f((dm.x) / size - 1, (dm.y) / size - 1);
|
||||
glEnd();
|
||||
//draw.gpset(dm.page, dm.x, dm.y ,dm.color);
|
||||
break;
|
||||
@@ -665,8 +666,8 @@ class PetitComputer
|
||||
{
|
||||
glBegin(GL_LINES);
|
||||
glColor4ubv(cast(ubyte*)&dm.color);
|
||||
glVertex2f((dm.x) / 256f - 1, (dm.y) / 256f - 1);
|
||||
glVertex2f((dm.x2) / 256f - 1, (dm.y2) / 256f - 1);
|
||||
glVertex2f((dm.x) / size - 1, (dm.y) / size - 1);
|
||||
glVertex2f((dm.x2) / size - 1, (dm.y2) / size - 1);
|
||||
//glFlush();
|
||||
glEnd();
|
||||
}
|
||||
@@ -676,10 +677,10 @@ class PetitComputer
|
||||
{
|
||||
glBegin(GL_QUADS);
|
||||
glColor4ubv(cast(ubyte*)&dm.color);
|
||||
glVertex2f((dm.x) / 256f - 1, (dm.y) / 256f - 1);
|
||||
glVertex2f((dm.x) / 256f - 1, (dm.y2 + 1) / 256f - 1);
|
||||
glVertex2f((dm.x2 + 1) / 256f - 1, (dm.y2 + 1) / 256f - 1);
|
||||
glVertex2f((dm.x2 + 1) / 256f - 1, (dm.y) / 256f - 1);
|
||||
glVertex2f((dm.x) / size - 1, (dm.y) / size - 1);
|
||||
glVertex2f((dm.x) / size - 1, (dm.y2 + 1) / size - 1);
|
||||
glVertex2f((dm.x2 + 1) / size - 1, (dm.y2 + 1) / size - 1);
|
||||
glVertex2f((dm.x2 + 1) / size - 1, (dm.y) / size - 1);
|
||||
glEnd();
|
||||
}
|
||||
//draw.gfill(dm.page, dm.x, dm.y ,dm.x2, dm.y2, dm.color);
|
||||
@@ -688,10 +689,10 @@ class PetitComputer
|
||||
{
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glColor4ubv(cast(ubyte*)&dm.color);
|
||||
glVertex2f((dm.x) / 256f - 1, (dm.y) / 256f - 1);
|
||||
glVertex2f((dm.x) / 256f - 1, (dm.y2) / 256f - 1);
|
||||
glVertex2f((dm.x2) / 256f - 1, (dm.y2) / 256f - 1);
|
||||
glVertex2f((dm.x2) / 256f - 1, (dm.y) / 256f - 1);
|
||||
glVertex2f((dm.x) / size - 1, (dm.y) / size - 1);
|
||||
glVertex2f((dm.x) / size - 1, (dm.y2) / size - 1);
|
||||
glVertex2f((dm.x2) / size - 1, (dm.y2) / size - 1);
|
||||
glVertex2f((dm.x2) / size - 1, (dm.y) / size - 1);
|
||||
glEnd();
|
||||
}
|
||||
//draw.gbox(dm.page, dm.x, dm.y ,dm.x2, dm.y2, dm.color);
|
||||
@@ -1041,6 +1042,8 @@ class PetitComputer
|
||||
while(!buttonTable){}
|
||||
auto startTicks = SDL_GetTicks();
|
||||
Parser parser;
|
||||
otya.smilebasic.vm.VM vm;
|
||||
bool running;
|
||||
//デバッグ用
|
||||
version(NDirectMode)
|
||||
{
|
||||
@@ -1093,6 +1096,24 @@ class PetitComputer
|
||||
CL=(CL+1) MOD 16 : VSYNC 1
|
||||
GOTO @LOOP`*/
|
||||
);
|
||||
try
|
||||
{
|
||||
vm = parser.compile();
|
||||
vm.init(this);
|
||||
running = true;
|
||||
}
|
||||
catch(SmileBasicError sbe)
|
||||
{
|
||||
printConsole(sbe.getErrorMessage, "\n");
|
||||
printConsole(sbe.getErrorMessage2, "\n");
|
||||
//printConsole(sbe.to!string);
|
||||
writeln(sbe.to!string);
|
||||
writeln(sbe.getErrorMessage2);
|
||||
}
|
||||
catch(Throwable t)
|
||||
{
|
||||
writeln(t);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1109,13 +1130,30 @@ class PetitComputer
|
||||
printConsole("can't open program \"", file, "\".\n");
|
||||
continue;
|
||||
}
|
||||
try
|
||||
{
|
||||
vm = parser.compile();
|
||||
vm.init(this);
|
||||
running = true;
|
||||
}
|
||||
catch(SmileBasicError sbe)
|
||||
{
|
||||
printConsole(sbe.getErrorMessage, "\n");
|
||||
printConsole(sbe.getErrorMessage2, "\n");
|
||||
//printConsole(sbe.to!string);
|
||||
writeln(sbe.to!string);
|
||||
writeln(sbe.getErrorMessage2);
|
||||
continue;
|
||||
}
|
||||
catch(Throwable t)
|
||||
{
|
||||
writeln(t);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
} while(!quit);
|
||||
}
|
||||
if(quit) return;
|
||||
auto vm = parser.compile();
|
||||
bool running = true;
|
||||
vm.init(this);
|
||||
//vm.dump;
|
||||
this.vm = vm;
|
||||
bg[0].put(0,0,1);
|
||||
|
||||
@@ -239,18 +239,11 @@ struct SpriteData
|
||||
this.homey = s.hy;
|
||||
this.attr = s.a;
|
||||
}
|
||||
double debugZ()
|
||||
{
|
||||
import std.stdio;
|
||||
// writefln("sprite=%d, z=%f", id, z);
|
||||
return z;
|
||||
}
|
||||
int opCmp(ref SpriteData spr)
|
||||
{
|
||||
import std.stdio;
|
||||
writeln("WHAT!????");
|
||||
return 0;
|
||||
}
|
||||
//SPLINK用
|
||||
SpriteData* parent;
|
||||
//SPLINKの親は子より小さい管理番号でしかなれないのでsprite->child->nextのX座標を加算すればなんとかなる
|
||||
//->挙動的に違う
|
||||
int linkx, linky;
|
||||
}
|
||||
class Sprite
|
||||
{
|
||||
@@ -520,8 +513,19 @@ class Sprite
|
||||
}
|
||||
if(sprite.attr & SpriteAttr.show)
|
||||
{
|
||||
int x = cast(int)sprite.x;// - cast(int)(sprite.homex * sprite.scalex);
|
||||
int y = cast(int)sprite.y;// - cast(int)(sprite.homey * sprite.scaley);
|
||||
int x, y;
|
||||
if(sprite.parent)
|
||||
{
|
||||
x += cast(int)(sprite.x + sprite.parent.linkx);
|
||||
y += cast(int)(sprite.y + sprite.parent.linky);
|
||||
}
|
||||
else
|
||||
{
|
||||
x = cast(int)sprite.x;// - cast(int)(sprite.homex * sprite.scalex);
|
||||
y = cast(int)sprite.y;// - cast(int)(sprite.homey * sprite.scaley);
|
||||
}
|
||||
sprite.linkx = x;
|
||||
sprite.linky = y;
|
||||
auto homex2 = ((sprite.w / 2 ) - sprite.homex) / disw;
|
||||
auto homey2 = ((sprite.h / 2 ) - sprite.homey) / dish;
|
||||
int w = sprite.w;
|
||||
@@ -652,13 +656,13 @@ class Sprite
|
||||
auto spdef = SpriteDef(u, v, w, h, 0, 0, attr);
|
||||
sprites[id] = SpriteData(id, spdef, 0/*要調査*/);
|
||||
}
|
||||
void spofs(int id, int x, int y)
|
||||
void spofs(int id, double x, double y)
|
||||
{
|
||||
id = spid(id);
|
||||
sprites[id].x = x;
|
||||
sprites[id].y = y;
|
||||
}
|
||||
void spofs(int id, int x, int y, int z)
|
||||
void spofs(int id, double x, double y, int z)
|
||||
{
|
||||
id = spid(id);
|
||||
sprites[id].x = x;
|
||||
@@ -666,6 +670,13 @@ class Sprite
|
||||
sprites[id].z = z;
|
||||
zChange = true;
|
||||
}
|
||||
void getspofs(int id, out double x, out double y, out int z)
|
||||
{
|
||||
id = spid(id);
|
||||
x = sprites[id].x;
|
||||
y = sprites[id].y;
|
||||
z = sprites[id].z;
|
||||
}
|
||||
void sphide(int id)
|
||||
{
|
||||
id = spid(id);
|
||||
@@ -762,4 +773,24 @@ class Sprite
|
||||
id = spid(id);
|
||||
sprites[id].color = petitcom.toGLColor(color);
|
||||
}
|
||||
void splink(int child, int parent)
|
||||
{
|
||||
if(parent >= child)
|
||||
{
|
||||
throw new IllegalFunctionCall("SPLINK");
|
||||
}
|
||||
parent = spid(parent);
|
||||
child = spid(child);
|
||||
//SPLINK 2,0
|
||||
//SPLINK 2,1した時の挙動謎
|
||||
//最後にSPSETした親が優先される->子が親を保持?
|
||||
sprites[child].parent = &sprites[parent];
|
||||
}
|
||||
//再帰的にUNLINKされるのか?
|
||||
void spunlink(int id)
|
||||
{
|
||||
id = spid(id);
|
||||
//parent==nullでもエラーでない
|
||||
sprites[id].parent = null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user