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 !func.isDead;
|
||||||
return false;
|
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
|
class VM
|
||||||
@@ -501,6 +517,42 @@ class VM
|
|||||||
result.label = label;
|
result.label = label;
|
||||||
return result;
|
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
|
enum CodeType
|
||||||
{
|
{
|
||||||
@@ -1612,38 +1664,7 @@ class CallFunctionCode : Code
|
|||||||
{
|
{
|
||||||
resolve(vm);
|
resolve(vm);
|
||||||
}
|
}
|
||||||
if(func.argCount != this.argCount)
|
vm.call(func, this.argCount, this.outArgCount);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
override string toString(VM vm)
|
override string toString(VM vm)
|
||||||
{
|
{
|
||||||
@@ -1690,34 +1711,7 @@ class CallFunctionS : Code
|
|||||||
}
|
}
|
||||||
void callFunc(Function func, VM vm)
|
void callFunc(Function func, VM vm)
|
||||||
{
|
{
|
||||||
if(func.argCount != this.argCount)
|
vm.call(func, argCount, outArgCount);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
override void execute(VM vm)
|
override void execute(VM vm)
|
||||||
{
|
{
|
||||||
@@ -1759,7 +1753,6 @@ class CallFunctionS : Code
|
|||||||
callBuintinFunc(bfunc, vm);
|
callBuintinFunc(bfunc, vm);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
vm.pushBackTrace(name.name);
|
|
||||||
callFunc(func, vm);
|
callFunc(func, vm);
|
||||||
}
|
}
|
||||||
override string toString(VM vm)
|
override string toString(VM vm)
|
||||||
@@ -2683,3 +2676,70 @@ class ConvertBool : Code
|
|||||||
top.type = ValueType.Integer;
|
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("HARDWARE", new Hardware());
|
||||||
addSystemVariable("MILLISEC", new MilliSecond());
|
addSystemVariable("MILLISEC", new MilliSecond());
|
||||||
addSystemVariable("PRGSLOT", new ProgramSlot());
|
addSystemVariable("PRGSLOT", new ProgramSlot());
|
||||||
|
addSystemVariable("CALLIDX", new CallIndex());
|
||||||
}
|
}
|
||||||
void addSystemVariable(wstring name, SystemVariable var)
|
void addSystemVariable(wstring name, SystemVariable var)
|
||||||
{
|
{
|
||||||
@@ -970,6 +971,16 @@ class Compiler
|
|||||||
genCode(new otya.smilebasic.vm.Linput);
|
genCode(new otya.smilebasic.vm.Linput);
|
||||||
compilePopVar(linput.expression, sc);
|
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)
|
void compileStatement(Statement i, Scope s)
|
||||||
{
|
{
|
||||||
switch(i.type)
|
switch(i.type)
|
||||||
@@ -1247,6 +1258,12 @@ class Compiler
|
|||||||
case NodeType.Linput:
|
case NodeType.Linput:
|
||||||
compileLinput(cast(otya.smilebasic.node.Linput)i, s);
|
compileLinput(cast(otya.smilebasic.node.Linput)i, s);
|
||||||
break;
|
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:
|
default:
|
||||||
stderr.writeln("Compile:NotImpl ", i.type);
|
stderr.writeln("Compile:NotImpl ", i.type);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ enum NodeType
|
|||||||
Exec,
|
Exec,
|
||||||
Use,
|
Use,
|
||||||
Linput,
|
Linput,
|
||||||
|
CallSprite,
|
||||||
|
CallBG,
|
||||||
}
|
}
|
||||||
abstract class Node
|
abstract class Node
|
||||||
{
|
{
|
||||||
@@ -697,3 +699,19 @@ class Linput : Statement
|
|||||||
this.expression = expr;
|
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();
|
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);
|
auto func = new CallFunctionStatement(name, lex.location);
|
||||||
node = func;
|
node = func;
|
||||||
|
|||||||
@@ -1695,6 +1695,9 @@ class PetitComputer
|
|||||||
SDL_SetClipboardText(ws.to!string.toStringz);
|
SDL_SetClipboardText(ws.to!string.toStringz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool callback;
|
||||||
|
int callidx = 0;
|
||||||
|
|
||||||
//プチコン内部表現はRGB5_A1
|
//プチコン内部表現はRGB5_A1
|
||||||
static uint toGLColor(GLenum format, ubyte r, ubyte g, ubyte b, ubyte a)
|
static uint toGLColor(GLenum format, ubyte r, ubyte g, ubyte b, ubyte a)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1191,4 +1191,8 @@ class Sprite
|
|||||||
id = spid(id);
|
id = spid(id);
|
||||||
sprites[id].callback = callback;
|
sprites[id].callback = callback;
|
||||||
}
|
}
|
||||||
|
Callback getCallback(int id)
|
||||||
|
{
|
||||||
|
return sprites[spid(id)].callback;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ class SystemVariable
|
|||||||
@property
|
@property
|
||||||
void value(Value value)
|
void value(Value value)
|
||||||
{
|
{
|
||||||
|
//v3.3.2
|
||||||
|
//TIME$=1,TIME$="1"=>Type mismatch(runtime)
|
||||||
|
//MAINCNT=1,MAINCNT="1"=>Syntax error(runtime)
|
||||||
throw new TypeMismatch();
|
throw new TypeMismatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -139,3 +142,10 @@ class ProgramSlot : SystemVariable
|
|||||||
return Value(vm.petitcomputer.program.currentSlot);
|
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