Re-allow indexes as state parameter in sequences

This commit is contained in:
Leonard2 2016-08-05 17:26:33 +02:00 committed by Christoph Oelckers
parent a4142ad9fb
commit db9f4c1385
4 changed files with 120 additions and 11 deletions

View file

@ -654,6 +654,7 @@ xx(DecoCallLineSpecial)
xx(DecoNameToClass) xx(DecoNameToClass)
xx(DecoFindMultiNameState) xx(DecoFindMultiNameState)
xx(DecoFindSingleNameState) xx(DecoFindSingleNameState)
xx(DecoHandleRuntimeState)
xx(Damage) xx(Damage)
// basic type names // basic type names

View file

@ -1058,6 +1058,24 @@ public:
FxExpression *Resolve(FCompileContext&); FxExpression *Resolve(FCompileContext&);
}; };
//==========================================================================
//
// Same as above except for expressions which means it will have to be
// evaluated at runtime
//
//==========================================================================
class FxRuntimeStateIndex : public FxExpression
{
FxExpression *Index;
public:
FxRuntimeStateIndex(FxExpression *index);
~FxRuntimeStateIndex();
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
};
//========================================================================== //==========================================================================
// //
// //

View file

@ -4429,6 +4429,89 @@ FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx)
return x; return x;
} }
//==========================================================================
//
//
//
//==========================================================================
FxRuntimeStateIndex::FxRuntimeStateIndex(FxExpression *index)
: FxExpression(index->ScriptPosition), Index(index)
{
ValueType = TypeState;
}
FxRuntimeStateIndex::~FxRuntimeStateIndex()
{
SAFE_DELETE(Index);
}
FxExpression *FxRuntimeStateIndex::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(Index, ctx);
if (!Index->IsNumeric())
{
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
delete this;
return nullptr;
}
else if (Index->ValueType->GetRegType() != REGT_INT)
{ // Float.
Index = new FxIntCast(Index);
SAFE_RESOLVE(Index, ctx);
}
return this;
}
static int DecoHandleRuntimeState(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret)
{
PARAM_PROLOGUE;
PARAM_OBJECT(stateowner, AActor);
PARAM_POINTER(stateinfo, FStateParamInfo);
PARAM_INT(index);
if (index == 0 || !stateowner->GetClass()->OwnsState(stateinfo->mCallingState + index))
{
// Null is returned if the location was invalid which means that no jump will be performed
// if used as return value
// 0 always meant the same thing so we handle it here for compatibility
ret->SetPointer(nullptr, ATAG_STATE);
}
else
{
ret->SetPointer(stateinfo->mCallingState + index, ATAG_STATE);
}
return 1;
}
ExpEmit FxRuntimeStateIndex::Emit(VMFunctionBuilder *build)
{
assert(build->Registers[REGT_POINTER].GetMostUsed() >= 3);
ExpEmit out(build, REGT_POINTER);
build->Emit(OP_PARAM, 0, REGT_POINTER, 1); // stateowner
build->Emit(OP_PARAM, 0, REGT_POINTER, 2); // stateinfo
ExpEmit id = Index->Emit(build);
build->Emit(OP_PARAM, 0, REGT_INT | (id.Konst ? REGT_KONST : 0), id.RegNum); // index
VMFunction *callfunc;
PSymbol *sym;
sym = FindDecorateBuiltinFunction(NAME_DecoHandleRuntimeState, DecoHandleRuntimeState);
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
callfunc = ((PSymbolVMFunction *)sym)->Function;
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1);
build->Emit(OP_RESULT, 0, REGT_POINTER, out.RegNum);
return out;
}
//========================================================================== //==========================================================================
// //

View file

@ -138,23 +138,30 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c
else if (type == TypeState) else if (type == TypeState)
{ {
// This forces quotation marks around the state name. // This forces quotation marks around the state name.
sc.MustGetToken(TK_StringConst); if (sc.CheckToken(TK_StringConst))
if (sc.String[0] == 0 || sc.Compare("None"))
{ {
x = new FxConstant((FState*)NULL, sc); if (sc.String[0] == 0 || sc.Compare("None"))
}
else if (sc.Compare("*"))
{
if (constant)
{ {
x = new FxConstant((FState*)(intptr_t)-1, sc); x = new FxConstant((FState*)NULL, sc);
}
else if (sc.Compare("*"))
{
if (constant)
{
x = new FxConstant((FState*)(intptr_t)-1, sc);
}
else sc.ScriptError("Invalid state name '*'");
}
else
{
x = new FxMultiNameState(sc.String, sc);
} }
else sc.ScriptError("Invalid state name '*'");
} }
else else if (!constant)
{ {
x = new FxMultiNameState(sc.String, sc); x = new FxRuntimeStateIndex(ParseExpression(sc, cls));
} }
else sc.MustGetToken(TK_StringConst); // This is for the error.
} }
else if (type->GetClass() == RUNTIME_CLASS(PClassPointer)) else if (type->GetClass() == RUNTIME_CLASS(PClassPointer))
{ // Actor name { // Actor name