Use action function return value to make state jumps happen

- The A_Jump family of action functions now return the state to jump
  to (NULL if no jump is to be taken) instead of jumping directly.
  It is the caller's responsibility to handle the jump. This will
  make it possible to use their results in if statements and
  do something other than jump.
- DECORATE return statements can now return the result of a function
  (but not any random expression--it must be a function call). To
  make a jump happen from inside a multi-action block, you must
  return the value of an A_Jump function. e.g.:
    { return A_Jump(128, "SomeState"); }
- The VMFunction class now contains its prototype instead of storing
  it at a higher level in PFunction. This is so that
  FState::CallAction can easily tell if a function returns a state.
- Removed the FxTailable class because with explicit return
  statements, it's not useful anymore.
This commit is contained in:
Randy Heit 2016-02-18 20:39:40 -06:00
commit b2ccd0bd28
18 changed files with 662 additions and 534 deletions

View file

@ -277,11 +277,11 @@ static void FinishThingdef()
// Can we call this function directly without wrapping it in an
// anonymous function? e.g. Are we passing any parameters to it?
func = tcall->Code->GetDirectFunction();
func = NULL;//tcall->Code->GetDirectFunction();
if (func == NULL)
{
FCompileContext ctx(tcall->ActorClass);
tcall->Code = static_cast<FxTailable *>(tcall->Code->Resolve(ctx));
tcall->Code = tcall->Code->Resolve(ctx);
// Make sure resolving it didn't obliterate it.
if (tcall->Code != NULL)
@ -292,11 +292,25 @@ static void FinishThingdef()
// self, stateowner, state (all are pointers)
buildit.Registers[REGT_POINTER].Get(3);
// Emit a tail call via FxVMFunctionCall
tcall->Code->Emit(&buildit, true);
// Emit code
tcall->Code->Emit(&buildit);
VMScriptFunction *sfunc = buildit.MakeFunction();
sfunc->NumArgs = NAP;
// Generate prototype for this anonymous function
TArray<PType *> args(3);
SetImplicitArgs(&args, NULL, tcall->ActorClass, VARF_Method | VARF_Action);
if (tcall->Proto != NULL)
{
sfunc->Proto = NewPrototype(tcall->Proto->ReturnTypes, args);
}
else
{
TArray<PType *> norets(0);
sfunc->Proto = NewPrototype(norets, args);
}
func = sfunc;
if (dump != NULL)
@ -354,6 +368,7 @@ static void FinishThingdef()
dmg->Emit(&buildit);
sfunc = buildit.MakeFunction();
sfunc->NumArgs = 1;
sfunc->Proto = NULL; ///FIXME: Need a proper prototype here
// Save this function in case this damage value was reused
// (which happens quite easily with inheritance).
dmg->SetFunction(sfunc);