mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-28 23:12:24 +00:00
Allow multiple actions per frame
- You can now call several actions from one frame by grouping them between curly braces. i.e. : POSS G 3 { A_Pain; A_Log("Ow! That hurt!"); } I will probably add an `if (something) { blah; blah; } else { wah; wah; }` construct later, but that's the extent of the munging I plan for DECORATE. The real work goes to the scripting language, not here. But if this branch is getting merged to master sooner than later, here's an immediate benefit from it right now.
This commit is contained in:
parent
9044ac9503
commit
7d0faa5bd5
5 changed files with 209 additions and 58 deletions
|
@ -289,17 +289,15 @@ static void FinishThingdef()
|
||||||
FStateTempCall *tcall = StateTempCalls[i];
|
FStateTempCall *tcall = StateTempCalls[i];
|
||||||
VMFunction *func;
|
VMFunction *func;
|
||||||
|
|
||||||
assert(tcall->Call != NULL);
|
assert(tcall->Code != NULL);
|
||||||
if (tcall->Call->GetArgCount() == 0)
|
|
||||||
{
|
// Can we call this function directly without wrapping it in an
|
||||||
// There are no arguments, so we can call this function directly
|
// anonymous function? e.g. Are we passing any parameters to it?
|
||||||
// without wrapping it in an anonymous function.
|
func = tcall->Code->GetDirectFunction();
|
||||||
func = tcall->Call->GetVMFunction();
|
if (func == NULL)
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
FCompileContext ctx(tcall->ActorClass);
|
FCompileContext ctx(tcall->ActorClass);
|
||||||
tcall->Call->Resolve(ctx);
|
tcall->Code->Resolve(ctx);
|
||||||
VMFunctionBuilder buildit;
|
VMFunctionBuilder buildit;
|
||||||
|
|
||||||
// Allocate registers used to pass parameters in.
|
// Allocate registers used to pass parameters in.
|
||||||
|
@ -307,7 +305,7 @@ static void FinishThingdef()
|
||||||
buildit.Registers[REGT_POINTER].Get(3);
|
buildit.Registers[REGT_POINTER].Get(3);
|
||||||
|
|
||||||
// Emit a tail call via FxVMFunctionCall
|
// Emit a tail call via FxVMFunctionCall
|
||||||
tcall->Call->Emit(&buildit, true);
|
tcall->Code->Emit(&buildit, true);
|
||||||
|
|
||||||
VMScriptFunction *sfunc = buildit.MakeFunction();
|
VMScriptFunction *sfunc = buildit.MakeFunction();
|
||||||
sfunc->NumArgs = NAP;
|
sfunc->NumArgs = NAP;
|
||||||
|
@ -322,8 +320,8 @@ static void FinishThingdef()
|
||||||
codesize += sfunc->CodeSize;
|
codesize += sfunc->CodeSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete tcall->Call;
|
delete tcall->Code;
|
||||||
tcall->Call = NULL;
|
tcall->Code = NULL;
|
||||||
for (int k = 0; k < tcall->NumStates; ++k)
|
for (int k = 0; k < tcall->NumStates; ++k)
|
||||||
{
|
{
|
||||||
tcall->ActorClass->OwnedStates[tcall->FirstState + k].SetAction(func);
|
tcall->ActorClass->OwnedStates[tcall->FirstState + k].SetAction(func);
|
||||||
|
|
|
@ -119,10 +119,10 @@ public:
|
||||||
|
|
||||||
struct FStateTempCall
|
struct FStateTempCall
|
||||||
{
|
{
|
||||||
FStateTempCall() : ActorClass(NULL), Call(NULL), FirstState(0), NumStates(0) {}
|
FStateTempCall() : ActorClass(NULL), Code(NULL), FirstState(0), NumStates(0) {}
|
||||||
|
|
||||||
PClassActor *ActorClass;
|
PClassActor *ActorClass;
|
||||||
class FxVMFunctionCall *Call;
|
class FxTailable *Code;
|
||||||
int FirstState;
|
int FirstState;
|
||||||
int NumStates;
|
int NumStates;
|
||||||
};
|
};
|
||||||
|
@ -189,7 +189,8 @@ AFuncDesc *FindFunction(const char * string);
|
||||||
void ParseStates(FScanner &sc, PClassActor *actor, AActor *defaults, Baggage &bag);
|
void ParseStates(FScanner &sc, PClassActor *actor, AActor *defaults, Baggage &bag);
|
||||||
void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray<FxExpression *> &out_params,
|
void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray<FxExpression *> &out_params,
|
||||||
PFunction *afd, FString statestring, FStateDefinitions *statedef);
|
PFunction *afd, FString statestring, FStateDefinitions *statedef);
|
||||||
bool ParseAction(FScanner &sc, FState state, FString statestring, FStateTempCall *tcall, Baggage &bag);
|
void ParseActions(FScanner &sc, FState state, FString statestring, FStateTempCall *tcall, Baggage &bag);
|
||||||
|
class FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, Baggage &bag);
|
||||||
|
|
||||||
PFunction *FindGlobalActionFunction(const char *name);
|
PFunction *FindGlobalActionFunction(const char *name);
|
||||||
|
|
||||||
|
|
|
@ -782,28 +782,6 @@ public:
|
||||||
ExpEmit Emit(VMFunctionBuilder *build);
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
};
|
};
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// FxVMFunctionCall
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
class FxVMFunctionCall : public FxExpression
|
|
||||||
{
|
|
||||||
PFunction *Function;
|
|
||||||
FArgumentList *ArgList;
|
|
||||||
PType *ReturnType;
|
|
||||||
|
|
||||||
public:
|
|
||||||
FxVMFunctionCall(PFunction *func, FArgumentList *args, const FScriptPosition &pos);
|
|
||||||
~FxVMFunctionCall();
|
|
||||||
FxExpression *Resolve(FCompileContext&);
|
|
||||||
virtual ExpEmit Emit(VMFunctionBuilder *build);
|
|
||||||
ExpEmit Emit(VMFunctionBuilder *build, bool tailcall);
|
|
||||||
unsigned GetArgCount() { return ArgList == NULL ? 0 : ArgList->Size(); }
|
|
||||||
VMFunction *GetVMFunction() { return Function->Variants[0].Implementation; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// FxGlobalFunctionCall
|
// FxGlobalFunctionCall
|
||||||
|
@ -823,6 +801,62 @@ public:
|
||||||
ExpEmit Emit(VMFunctionBuilder *build);
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FxTailable
|
||||||
|
//
|
||||||
|
// An expression that can produce a tail call
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
class FxTailable : public FxExpression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FxTailable(const FScriptPosition &pos) : FxExpression(pos) {}
|
||||||
|
virtual ExpEmit Emit(VMFunctionBuilder *build, bool tailcall) = 0;
|
||||||
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
|
virtual VMFunction *GetDirectFunction();
|
||||||
|
};
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FxVMFunctionCall
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
class FxVMFunctionCall : public FxTailable
|
||||||
|
{
|
||||||
|
PFunction *Function;
|
||||||
|
FArgumentList *ArgList;
|
||||||
|
PType *ReturnType;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FxVMFunctionCall(PFunction *func, FArgumentList *args, const FScriptPosition &pos);
|
||||||
|
~FxVMFunctionCall();
|
||||||
|
FxExpression *Resolve(FCompileContext&);
|
||||||
|
ExpEmit Emit(VMFunctionBuilder *build, bool tailcall);
|
||||||
|
unsigned GetArgCount() { return ArgList == NULL ? 0 : ArgList->Size(); }
|
||||||
|
VMFunction *GetVMFunction() { return Function->Variants[0].Implementation; }
|
||||||
|
VMFunction *GetDirectFunction();
|
||||||
|
};
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FxSequence
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
class FxSequence : public FxTailable
|
||||||
|
{
|
||||||
|
TDeletingArray<FxTailable *> Expressions;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FxSequence(const FScriptPosition &pos) : FxTailable(pos) {}
|
||||||
|
FxExpression *Resolve(FCompileContext&);
|
||||||
|
ExpEmit Emit(VMFunctionBuilder *build, bool tailcall);
|
||||||
|
void Add(FxTailable *expr) { Expressions.Push(expr); }
|
||||||
|
VMFunction *GetDirectFunction();
|
||||||
|
};
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
|
|
|
@ -3004,6 +3004,28 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build)
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
ExpEmit FxTailable::Emit(VMFunctionBuilder *build)
|
||||||
|
{
|
||||||
|
return Emit(build, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
VMFunction *FxTailable::GetDirectFunction()
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// FxVMFunctionCall
|
// FxVMFunctionCall
|
||||||
|
@ -3011,7 +3033,7 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build)
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
FxVMFunctionCall::FxVMFunctionCall(PFunction *func, FArgumentList *args, const FScriptPosition &pos)
|
FxVMFunctionCall::FxVMFunctionCall(PFunction *func, FArgumentList *args, const FScriptPosition &pos)
|
||||||
: FxExpression(pos)
|
: FxTailable(pos)
|
||||||
{
|
{
|
||||||
Function = func;
|
Function = func;
|
||||||
ArgList = args;
|
ArgList = args;
|
||||||
|
@ -3082,15 +3104,10 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
|
|
||||||
{
|
|
||||||
return Emit(build, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall)
|
ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall)
|
||||||
{
|
{
|
||||||
assert(build->Registers[REGT_POINTER].GetMostUsed() >= 3);
|
assert(build->Registers[REGT_POINTER].GetMostUsed() >= 3);
|
||||||
int count = ArgList->Size();
|
int count = GetArgCount();
|
||||||
|
|
||||||
// Emit code to pass implied parameters
|
// Emit code to pass implied parameters
|
||||||
if (Function->Flags & VARF_Method)
|
if (Function->Flags & VARF_Method)
|
||||||
|
@ -3105,10 +3122,13 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall)
|
||||||
count += 2;
|
count += 2;
|
||||||
}
|
}
|
||||||
// Emit code to pass explicit parameters
|
// Emit code to pass explicit parameters
|
||||||
|
if (ArgList != NULL)
|
||||||
|
{
|
||||||
for (unsigned i = 0; i < ArgList->Size(); ++i)
|
for (unsigned i = 0; i < ArgList->Size(); ++i)
|
||||||
{
|
{
|
||||||
(*ArgList)[i]->Emit(build);
|
(*ArgList)[i]->Emit(build);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Get a constant register for this function
|
// Get a constant register for this function
|
||||||
int funcaddr = build->GetConstantAddress(Function->Variants[0].Implementation, ATAG_OBJECT);
|
int funcaddr = build->GetConstantAddress(Function->Variants[0].Implementation, ATAG_OBJECT);
|
||||||
// Emit the call
|
// Emit the call
|
||||||
|
@ -3132,6 +3152,24 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FxVMFunctionCall :: GetDirectFunction
|
||||||
|
//
|
||||||
|
// If the function is not passed any explicit arguments, returns the
|
||||||
|
// function. Otherwise returns NULL.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
VMFunction *FxVMFunctionCall::GetDirectFunction()
|
||||||
|
{
|
||||||
|
if (GetArgCount() == 0)
|
||||||
|
{
|
||||||
|
return GetVMFunction();
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
@ -3221,6 +3259,58 @@ ExpEmit FxGlobalFunctionCall::Emit(VMFunctionBuilder *build)
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FxSequence :: Resolve
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FxExpression *FxSequence::Resolve(FCompileContext &ctx)
|
||||||
|
{
|
||||||
|
CHECKRESOLVED();
|
||||||
|
for (unsigned i = 0; i < Expressions.Size(); ++i)
|
||||||
|
{
|
||||||
|
if (NULL == (Expressions[i] = static_cast<FxTailable *>(Expressions[i]->Resolve(ctx))))
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FxSequence :: Emit
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
ExpEmit FxSequence::Emit(VMFunctionBuilder *build, bool tailcall)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < Expressions.Size(); ++i)
|
||||||
|
{
|
||||||
|
ExpEmit v = Expressions[i]->Emit(build, tailcall ? i == Expressions.Size()-1 : false);
|
||||||
|
// Throw away any result. We don't care about it.
|
||||||
|
v.Free(build);
|
||||||
|
}
|
||||||
|
return ExpEmit();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FxSequence :: GetDirectFunction
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
VMFunction *FxSequence::GetDirectFunction()
|
||||||
|
{
|
||||||
|
if (Expressions.Size() == 1)
|
||||||
|
{
|
||||||
|
return Expressions[0]->GetDirectFunction();
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -314,11 +314,9 @@ do_stop:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ParseAction(sc, state, statestring, tcall, bag))
|
ParseActions(sc, state, statestring, tcall, bag);
|
||||||
{
|
|
||||||
goto endofstate;
|
goto endofstate;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
sc.UnGet();
|
sc.UnGet();
|
||||||
endofstate:
|
endofstate:
|
||||||
int count = bag.statedef.AddStates(&state, statestring);
|
int count = bag.statedef.AddStates(&state, statestring);
|
||||||
|
@ -327,7 +325,7 @@ endofstate:
|
||||||
sc.ScriptError ("Invalid frame character string '%s'", statestring.GetChars());
|
sc.ScriptError ("Invalid frame character string '%s'", statestring.GetChars());
|
||||||
count = -count;
|
count = -count;
|
||||||
}
|
}
|
||||||
if (tcall->Call != NULL)
|
if (tcall->Code != NULL)
|
||||||
{
|
{
|
||||||
tcall->ActorClass = actor;
|
tcall->ActorClass = actor;
|
||||||
tcall->FirstState = bag.statedef.GetStateCount() - count;
|
tcall->FirstState = bag.statedef.GetStateCount() - count;
|
||||||
|
@ -348,21 +346,51 @@ endofstate:
|
||||||
sc.SetEscape(true); // re-enable escape sequences
|
sc.SetEscape(true); // re-enable escape sequences
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// ParseActions
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void ParseActions(FScanner &sc, FState state, FString statestring, FStateTempCall *tcall, Baggage &bag)
|
||||||
|
{
|
||||||
|
// If it's not a '{', then it should be a single action.
|
||||||
|
// Otherwise, it's a sequence of actions.
|
||||||
|
if (!sc.Compare("{"))
|
||||||
|
{
|
||||||
|
tcall->Code = ParseAction(sc, state, statestring, bag);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FxSequence *seq = new FxSequence(sc);
|
||||||
|
sc.MustGetString();
|
||||||
|
while (!sc.Compare("}"))
|
||||||
|
{
|
||||||
|
FxVMFunctionCall *call = ParseAction(sc, state, statestring, bag);
|
||||||
|
seq->Add(call);
|
||||||
|
sc.MustGetStringName(";");
|
||||||
|
sc.MustGetString();
|
||||||
|
}
|
||||||
|
tcall->Code = seq;
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// ParseAction
|
// ParseAction
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
bool ParseAction(FScanner &sc, FState state, FString statestring, FStateTempCall *tcall, Baggage &bag)
|
FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, Baggage &bag)
|
||||||
{
|
{
|
||||||
|
FxVMFunctionCall *call;
|
||||||
|
|
||||||
// Make the action name lowercase
|
// Make the action name lowercase
|
||||||
strlwr (sc.String);
|
strlwr (sc.String);
|
||||||
|
|
||||||
tcall->Call = DoActionSpecials(sc, state, bag);
|
call = DoActionSpecials(sc, state, bag);
|
||||||
if (tcall->Call != NULL)
|
if (call != NULL)
|
||||||
{
|
{
|
||||||
return true;
|
return call;
|
||||||
}
|
}
|
||||||
|
|
||||||
PFunction *afd = dyn_cast<PFunction>(bag.Info->Symbols.FindSymbol(FName(sc.String, true), true));
|
PFunction *afd = dyn_cast<PFunction>(bag.Info->Symbols.FindSymbol(FName(sc.String, true), true));
|
||||||
|
@ -370,15 +398,15 @@ bool ParseAction(FScanner &sc, FState state, FString statestring, FStateTempCall
|
||||||
{
|
{
|
||||||
FArgumentList *args = new FArgumentList;
|
FArgumentList *args = new FArgumentList;
|
||||||
ParseFunctionParameters(sc, bag.Info, *args, afd, statestring, &bag.statedef);
|
ParseFunctionParameters(sc, bag.Info, *args, afd, statestring, &bag.statedef);
|
||||||
tcall->Call = new FxVMFunctionCall(afd, args->Size() > 0 ? args : NULL, sc);
|
call = new FxVMFunctionCall(afd, args->Size() > 0 ? args : NULL, sc);
|
||||||
if (args->Size() == 0)
|
if (args->Size() == 0)
|
||||||
{
|
{
|
||||||
delete args;
|
delete args;
|
||||||
}
|
}
|
||||||
return true;
|
return call;
|
||||||
}
|
}
|
||||||
sc.ScriptError("Invalid state parameter %s\n", sc.String);
|
sc.ScriptError("Invalid state parameter %s\n", sc.String);
|
||||||
return false;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
Loading…
Reference in a new issue