From db9f4c13857f785b589bfdb01684c38557611a79 Mon Sep 17 00:00:00 2001 From: Leonard2 Date: Fri, 5 Aug 2016 17:26:33 +0200 Subject: [PATCH] Re-allow indexes as state parameter in sequences --- src/namedef.h | 1 + src/thingdef/thingdef_exp.h | 18 ++++++ src/thingdef/thingdef_expression.cpp | 83 ++++++++++++++++++++++++++++ src/thingdef/thingdef_parse.cpp | 29 ++++++---- 4 files changed, 120 insertions(+), 11 deletions(-) diff --git a/src/namedef.h b/src/namedef.h index cd0d5615b..e5b6c452a 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -654,6 +654,7 @@ xx(DecoCallLineSpecial) xx(DecoNameToClass) xx(DecoFindMultiNameState) xx(DecoFindSingleNameState) +xx(DecoHandleRuntimeState) xx(Damage) // basic type names diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index b878e50f1..c1e8863e8 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -1058,6 +1058,24 @@ public: 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); +}; + //========================================================================== // // diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index b57618575..d40b7605c 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -4428,7 +4428,90 @@ FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx) delete this; 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; +} //========================================================================== // diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 566643b8e..b99f1a384 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -138,23 +138,30 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c else if (type == TypeState) { // This forces quotation marks around the state name. - sc.MustGetToken(TK_StringConst); - if (sc.String[0] == 0 || sc.Compare("None")) + if (sc.CheckToken(TK_StringConst)) { - x = new FxConstant((FState*)NULL, sc); - } - else if (sc.Compare("*")) - { - if (constant) + if (sc.String[0] == 0 || sc.Compare("None")) { - 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)) { // Actor name