Implement CALL SPRITE
This commit is contained in:
182
SMILEBASIC/VM.d
182
SMILEBASIC/VM.d
@@ -85,6 +85,22 @@ struct Callback
|
||||
return !func.isDead;
|
||||
return false;
|
||||
}
|
||||
void opCall(VM vm)
|
||||
{
|
||||
if (!isCallable)
|
||||
return;
|
||||
if (type == CallbackType.label)
|
||||
{
|
||||
vm.pushBackTrace("");
|
||||
vm.pushpc;
|
||||
vm.setCurrentSlot(slot.index);
|
||||
vm.pc = label - 1;
|
||||
}
|
||||
if (type == CallbackType.function_)
|
||||
{
|
||||
vm.call(func, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class VM
|
||||
@@ -501,6 +517,42 @@ class VM
|
||||
result.label = label;
|
||||
return result;
|
||||
}
|
||||
void call(Function func, int argCount, int outArgCount)
|
||||
{
|
||||
alias vm = this;
|
||||
if(func.argCount != argCount)
|
||||
{
|
||||
throw new IllegalFunctionCall(func.name.to!string);
|
||||
}
|
||||
if(func.outArgCount != outArgCount)
|
||||
{
|
||||
throw new IllegalFunctionCall(func.name.to!string);
|
||||
}
|
||||
vm.pushBackTrace(func.name);
|
||||
//TODO:args
|
||||
auto bp = vm.stacki;
|
||||
vm.push(Value(vm.currentFunction));
|
||||
vm.currentFunction = func;
|
||||
vm.push(Value(vm.currentData));
|
||||
vm.currentData.index = 0;
|
||||
vm.currentData.table = func.scope_.data;
|
||||
vm.push(Value(vm.bp));
|
||||
vm.pushpc;//vm.push(Value(vm.pc));
|
||||
vm.bp = bp;
|
||||
vm.pc = func.address - 1;
|
||||
vm.stacki += func.variableIndex - 1;
|
||||
foreach(wstring k, VMVariable v ; func.variable)
|
||||
{
|
||||
if(v.index > 0)
|
||||
{
|
||||
vm.stack[bp + v.index] = Value(v.type);
|
||||
}
|
||||
}
|
||||
if (func.isCommon)
|
||||
{
|
||||
vm.setCurrentSlot(func.slot.index);
|
||||
}
|
||||
}
|
||||
}
|
||||
enum CodeType
|
||||
{
|
||||
@@ -1612,38 +1664,7 @@ class CallFunctionCode : Code
|
||||
{
|
||||
resolve(vm);
|
||||
}
|
||||
if(func.argCount != this.argCount)
|
||||
{
|
||||
throw new IllegalFunctionCall(name.to!string);
|
||||
}
|
||||
if(func.outArgCount != this.outArgCount)
|
||||
{
|
||||
throw new IllegalFunctionCall(name.to!string);
|
||||
}
|
||||
vm.pushBackTrace(name);
|
||||
//TODO:args
|
||||
auto bp = vm.stacki;
|
||||
vm.push(Value(vm.currentFunction));
|
||||
vm.currentFunction = func;
|
||||
vm.push(Value(vm.currentData));
|
||||
vm.currentData.index = 0;
|
||||
vm.currentData.table = func.scope_.data;
|
||||
vm.push(Value(vm.bp));
|
||||
vm.pushpc;//vm.push(Value(vm.pc));
|
||||
vm.bp = bp;
|
||||
vm.pc = func.address - 1;
|
||||
vm.stacki += func.variableIndex - 1;
|
||||
foreach(wstring k, VMVariable v ; func.variable)
|
||||
{
|
||||
if(v.index > 0)
|
||||
{
|
||||
vm.stack[bp + v.index] = Value(v.type);
|
||||
}
|
||||
}
|
||||
if (func.isCommon)
|
||||
{
|
||||
vm.setCurrentSlot(func.slot.index);
|
||||
}
|
||||
vm.call(func, this.argCount, this.outArgCount);
|
||||
}
|
||||
override string toString(VM vm)
|
||||
{
|
||||
@@ -1690,34 +1711,7 @@ class CallFunctionS : Code
|
||||
}
|
||||
void callFunc(Function func, VM vm)
|
||||
{
|
||||
if(func.argCount != this.argCount)
|
||||
{
|
||||
throw new IllegalFunctionCall(func.name.to!string);
|
||||
}
|
||||
if(func.outArgCount != this.outArgCount)
|
||||
{
|
||||
throw new IllegalFunctionCall(func.name.to!string);
|
||||
}
|
||||
//TODO:args
|
||||
auto bp = vm.stacki;
|
||||
vm.push(Value(vm.currentFunction));
|
||||
vm.currentFunction = func;
|
||||
vm.push(Value(vm.currentData));
|
||||
vm.currentData.index = 0;
|
||||
vm.currentData.table = func.scope_.data;
|
||||
vm.push(Value(vm.bp));
|
||||
vm.pushpc;
|
||||
vm.bp = bp;
|
||||
vm.pc = func.address - 1;
|
||||
vm.stacki += func.variableIndex - 1;
|
||||
foreach(wstring k, VMVariable v ; func.variable)
|
||||
{
|
||||
if(v.index > 0)
|
||||
{
|
||||
vm.stack[bp + v.index] = Value(v.type);
|
||||
}
|
||||
}
|
||||
vm.setCurrentSlot(func.slot.index);
|
||||
vm.call(func, argCount, outArgCount);
|
||||
}
|
||||
override void execute(VM vm)
|
||||
{
|
||||
@@ -1759,7 +1753,6 @@ class CallFunctionS : Code
|
||||
callBuintinFunc(bfunc, vm);
|
||||
return;
|
||||
}
|
||||
vm.pushBackTrace(name.name);
|
||||
callFunc(func, vm);
|
||||
}
|
||||
override string toString(VM vm)
|
||||
@@ -2683,3 +2676,70 @@ class ConvertBool : Code
|
||||
top.type = ValueType.Integer;
|
||||
}
|
||||
}
|
||||
|
||||
/+
|
||||
SPFUNC 0,@A
|
||||
FOR I=1TO 511
|
||||
SPFUNC I,@B
|
||||
NEXT
|
||||
CALL SPRITE
|
||||
END
|
||||
@A
|
||||
?"BEFORE CALL BG",CALLIDX
|
||||
CALL BG
|
||||
?"AFTER CALL BG",CALLIDX
|
||||
RETUERN
|
||||
@B
|
||||
?CALLIDX
|
||||
RETURN
|
||||
|
||||
RESULT
|
||||
BEFORE CALL BG 0
|
||||
AFTER CALL BG 4
|
||||
=>SPFUNC 1~511 is not called
|
||||
+/
|
||||
class InitCallback : Code
|
||||
{
|
||||
override void execute(VM vm)
|
||||
{
|
||||
vm.petitcomputer.callidx = -1;
|
||||
vm.petitcomputer.callback = true;
|
||||
}
|
||||
}
|
||||
|
||||
class CallSprite : Code
|
||||
{
|
||||
override void execute(VM vm)
|
||||
{
|
||||
vm.petitcomputer.callidx++;
|
||||
if (!vm.petitcomputer.callback)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!vm.petitcomputer.sprite.isValidSpriteId(vm.petitcomputer.callidx))
|
||||
{
|
||||
vm.petitcomputer.callback = false;
|
||||
return;
|
||||
}
|
||||
auto callback = vm.petitcomputer.sprite.getCallback(vm.petitcomputer.callidx);
|
||||
vm.pc--;
|
||||
if (!callback.isCallable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
callback(vm);
|
||||
}
|
||||
}
|
||||
|
||||
class CallBG : Code
|
||||
{
|
||||
override void execute(VM vm)
|
||||
{
|
||||
if (!vm.petitcomputer.callback)
|
||||
{
|
||||
vm.petitcomputer.callidx++;
|
||||
return;
|
||||
}
|
||||
vm.petitcomputer.callidx++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,6 +227,7 @@ class Compiler
|
||||
addSystemVariable("HARDWARE", new Hardware());
|
||||
addSystemVariable("MILLISEC", new MilliSecond());
|
||||
addSystemVariable("PRGSLOT", new ProgramSlot());
|
||||
addSystemVariable("CALLIDX", new CallIndex());
|
||||
}
|
||||
void addSystemVariable(wstring name, SystemVariable var)
|
||||
{
|
||||
@@ -970,6 +971,16 @@ class Compiler
|
||||
genCode(new otya.smilebasic.vm.Linput);
|
||||
compilePopVar(linput.expression, sc);
|
||||
}
|
||||
void compileCallSprite(otya.smilebasic.node.CallSprite call, Scope sc)
|
||||
{
|
||||
genCode(new InitCallback);
|
||||
genCode(new otya.smilebasic.vm.CallSprite);
|
||||
}
|
||||
void compileCallBG(otya.smilebasic.node.CallBG call, Scope sc)
|
||||
{
|
||||
genCode(new InitCallback);
|
||||
genCode(new otya.smilebasic.vm.CallBG);
|
||||
}
|
||||
void compileStatement(Statement i, Scope s)
|
||||
{
|
||||
switch(i.type)
|
||||
@@ -1247,6 +1258,12 @@ class Compiler
|
||||
case NodeType.Linput:
|
||||
compileLinput(cast(otya.smilebasic.node.Linput)i, s);
|
||||
break;
|
||||
case NodeType.CallSprite:
|
||||
compileCallSprite(cast(otya.smilebasic.node.CallSprite)i, s);
|
||||
break;
|
||||
case NodeType.CallBG:
|
||||
compileCallBG(cast(otya.smilebasic.node.CallBG)i, s);
|
||||
break;
|
||||
default:
|
||||
stderr.writeln("Compile:NotImpl ", i.type);
|
||||
}
|
||||
|
||||
@@ -51,6 +51,8 @@ enum NodeType
|
||||
Exec,
|
||||
Use,
|
||||
Linput,
|
||||
CallSprite,
|
||||
CallBG,
|
||||
}
|
||||
abstract class Node
|
||||
{
|
||||
@@ -697,3 +699,19 @@ class Linput : Statement
|
||||
this.expression = expr;
|
||||
}
|
||||
}
|
||||
class CallSprite : Statement
|
||||
{
|
||||
this(SourceLocation loc)
|
||||
{
|
||||
super.location = loc;
|
||||
this.type = NodeType.CallSprite;
|
||||
}
|
||||
}
|
||||
class CallBG : Statement
|
||||
{
|
||||
this(SourceLocation loc)
|
||||
{
|
||||
super.location = loc;
|
||||
this.type = NodeType.CallBG;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -939,6 +939,23 @@ class Parser
|
||||
}
|
||||
}
|
||||
lex.popFront();
|
||||
if (token.type == TokenType.Call)
|
||||
{
|
||||
if (lex.front.type == TokenType.Iden)
|
||||
{
|
||||
auto arg = std.uni.toUpper(lex.front.value.castString);
|
||||
if (arg == "SPRITE")
|
||||
{
|
||||
node = new CallSprite(lex.location);
|
||||
break;
|
||||
}
|
||||
if (arg == "BG")
|
||||
{
|
||||
node = new CallBG(lex.location);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//命令呼び出し
|
||||
auto func = new CallFunctionStatement(name, lex.location);
|
||||
node = func;
|
||||
|
||||
@@ -1695,6 +1695,9 @@ class PetitComputer
|
||||
SDL_SetClipboardText(ws.to!string.toStringz);
|
||||
}
|
||||
|
||||
bool callback;
|
||||
int callidx = 0;
|
||||
|
||||
//プチコン内部表現はRGB5_A1
|
||||
static uint toGLColor(GLenum format, ubyte r, ubyte g, ubyte b, ubyte a)
|
||||
{
|
||||
|
||||
@@ -1191,4 +1191,8 @@ class Sprite
|
||||
id = spid(id);
|
||||
sprites[id].callback = callback;
|
||||
}
|
||||
Callback getCallback(int id)
|
||||
{
|
||||
return sprites[spid(id)].callback;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,9 @@ class SystemVariable
|
||||
@property
|
||||
void value(Value value)
|
||||
{
|
||||
//v3.3.2
|
||||
//TIME$=1,TIME$="1"=>Type mismatch(runtime)
|
||||
//MAINCNT=1,MAINCNT="1"=>Syntax error(runtime)
|
||||
throw new TypeMismatch();
|
||||
}
|
||||
}
|
||||
@@ -139,3 +142,10 @@ class ProgramSlot : SystemVariable
|
||||
return Value(vm.petitcomputer.program.currentSlot);
|
||||
}
|
||||
}
|
||||
class CallIndex : SystemVariable
|
||||
{
|
||||
@property override Value value()
|
||||
{
|
||||
return Value(vm.petitcomputer.callidx);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user