Use PFunction instead of PSymbolActionFunction in DECORATE parser

This commit is contained in:
Randy Heit 2013-08-14 22:00:16 -05:00
parent aba691ad72
commit cf87d0f1e9
8 changed files with 169 additions and 172 deletions

View file

@ -81,7 +81,7 @@ static void UnloadDehSupp ();
// This is a list of all the action functions used by each of Doom's states. // This is a list of all the action functions used by each of Doom's states.
static TArray<PSymbolActionFunction *> Actions; static TArray<PFunction *> Actions;
// These are the original heights of every Doom 2 thing. They are used if a patch // These are the original heights of every Doom 2 thing. They are used if a patch
// specifies that a thing should be hanging from the ceiling but doesn't specify // specifies that a thing should be hanging from the ceiling but doesn't specify
@ -788,8 +788,8 @@ void SetDehParams(FState *state, int codepointer)
FScriptPosition *pos = new FScriptPosition(FString("DEHACKED"), 0); FScriptPosition *pos = new FScriptPosition(FString("DEHACKED"), 0);
// Let's identify the codepointer we're dealing with. // Let's identify the codepointer we're dealing with.
PSymbolActionFunction *sym; PFunction *sym;
sym = dyn_cast<PSymbolActionFunction>(RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(FName(MBFCodePointers[codepointer].name), true)); sym = dyn_cast<PFunction>(RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(FName(MBFCodePointers[codepointer].name), true));
if (sym == NULL) return; if (sym == NULL) return;
if (codepointer < 0 || codepointer >= countof(MBFCodePointerFactories)) if (codepointer < 0 || codepointer >= countof(MBFCodePointerFactories))
@ -809,7 +809,7 @@ void SetDehParams(FState *state, int codepointer)
buildit.Emit(OP_PARAM, 0, REGT_POINTER, 2); buildit.Emit(OP_PARAM, 0, REGT_POINTER, 2);
// Emit code for action parameters. // Emit code for action parameters.
int argcount = MBFCodePointerFactories[codepointer](buildit, value1, value2); int argcount = MBFCodePointerFactories[codepointer](buildit, value1, value2);
buildit.Emit(OP_TAIL_K, buildit.GetConstantAddress(sym->Function, ATAG_OBJECT), NAP + argcount, 0); buildit.Emit(OP_TAIL_K, buildit.GetConstantAddress(sym->Variants[0].Implementation, ATAG_OBJECT), NAP + argcount, 0);
// Attach it to the state. // Attach it to the state.
VMScriptFunction *sfunc = buildit.MakeFunction(); VMScriptFunction *sfunc = buildit.MakeFunction();
sfunc->NumArgs = NAP; sfunc->NumArgs = NAP;
@ -1711,7 +1711,7 @@ static int PatchWeapon (int weapNum)
return result; return result;
} }
static void SetPointer(FState *state, PSymbolActionFunction *sym, int frame = 0) static void SetPointer(FState *state, PFunction *sym, int frame = 0)
{ {
if (sym == NULL) if (sym == NULL)
{ {
@ -1720,7 +1720,7 @@ static void SetPointer(FState *state, PSymbolActionFunction *sym, int frame = 0)
} }
else else
{ {
state->SetAction(sym->Function); state->SetAction(sym->Variants[0].Implementation);
for (unsigned int i = 0; i < MBFCodePointers.Size(); i++) for (unsigned int i = 0; i < MBFCodePointers.Size(); i++)
{ {
@ -2103,15 +2103,15 @@ static int PatchCodePtrs (int dummy)
// This skips the action table and goes directly to the internal symbol table // This skips the action table and goes directly to the internal symbol table
// DEH compatible functions are easy to recognize. // DEH compatible functions are easy to recognize.
PSymbolActionFunction *sym = dyn_cast<PSymbolActionFunction>(RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(symname, true)); PFunction *sym = dyn_cast<PFunction>(RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(symname, true));
if (sym == NULL) if (sym == NULL)
{ {
Printf("Frame %d: Unknown code pointer '%s'\n", frame, Line2); Printf("Frame %d: Unknown code pointer '%s'\n", frame, Line2);
} }
else else
{ {
FString &args = sym->Arguments; TArray<DWORD> &args = sym->Variants[0].ArgFlags;
if (args.Len() != 0 && (args[0] < 'a' || args[0] > 'z')) if (args.Size() != 0 && !(args[0] & VARF_Optional))
{ {
Printf("Frame %d: Incompatible code pointer '%s'\n", frame, Line2); Printf("Frame %d: Incompatible code pointer '%s'\n", frame, Line2);
sym = NULL; sym = NULL;
@ -2680,15 +2680,15 @@ static bool LoadDehSupp ()
// or AActor so this will find all of them. // or AActor so this will find all of them.
FString name = "A_"; FString name = "A_";
name << sc.String; name << sc.String;
PSymbolActionFunction *sym = dyn_cast<PSymbolActionFunction>(RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(name, true)); PFunction *sym = dyn_cast<PFunction>(RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(name, true));
if (sym == NULL) if (sym == NULL)
{ {
sc.ScriptError("Unknown code pointer '%s'", sc.String); sc.ScriptError("Unknown code pointer '%s'", sc.String);
} }
else else
{ {
FString &args = sym->Arguments; TArray<DWORD> &args = sym->Variants[0].ArgFlags;
if (args.Len() != 0 && (args[0] < 'a' || args[0] > 'z')) if (args.Size() != 0 && !(args[0] & VARF_Optional))
{ {
sc.ScriptError("Incompatible code pointer '%s'", sc.String); sc.ScriptError("Incompatible code pointer '%s'", sc.String);
} }

View file

@ -1145,6 +1145,25 @@ size_t PFunction::PropagateMark()
return Variants.Size() * sizeof(Variants[0]) + Super::PropagateMark(); return Variants.Size() * sizeof(Variants[0]) + Super::PropagateMark();
} }
//==========================================================================
//
// PFunction :: AddVariant
//
// Adds a new variant for this function. Does not check if a matching
// variant already exists.
//
//==========================================================================
unsigned PFunction::AddVariant(PPrototype *proto, TArray<DWORD> &argflags, VMFunction *impl)
{
Variant variant;
variant.Proto = proto;
variant.ArgFlags = argflags;
variant.Implementation = impl;
return Variants.Push(variant);
}
/* PClass *****************************************************************/ /* PClass *****************************************************************/
IMPLEMENT_POINTY_CLASS(PClass) IMPLEMENT_POINTY_CLASS(PClass)
@ -1814,9 +1833,6 @@ CCMD(typetable)
IMPLEMENT_ABSTRACT_CLASS(PSymbol); IMPLEMENT_ABSTRACT_CLASS(PSymbol);
IMPLEMENT_CLASS(PSymbolConst); IMPLEMENT_CLASS(PSymbolConst);
IMPLEMENT_CLASS(PSymbolVariable); IMPLEMENT_CLASS(PSymbolVariable);
IMPLEMENT_POINTY_CLASS(PSymbolActionFunction)
DECLARE_POINTER(Function)
END_POINTERS
IMPLEMENT_POINTY_CLASS(PSymbolVMFunction) IMPLEMENT_POINTY_CLASS(PSymbolVMFunction)
DECLARE_POINTER(Function) DECLARE_POINTER(Function)
END_POINTERS END_POINTERS

View file

@ -64,23 +64,7 @@ public:
}; };
// An action function ------------------------------------------------------- // An action function -------------------------------------------------------
//
// The Arguments string is a string of characters as understood by
// the DECORATE parser:
//
// If the letter is uppercase, it is required. Lowercase letters are optional.
// i = integer
// f = fixed point
// s = sound name
// m = actor name
// t = string
// l = jump label
// c = color
// x = expression
// y = expression
// If the final character is a +, the previous parameter is repeated indefinitely,
// and an "imaginary" first parameter is inserted containing the total number of
// parameters passed.
struct FState; struct FState;
struct StateCallData; struct StateCallData;
class VMFrameStack; class VMFrameStack;
@ -89,18 +73,6 @@ struct VMReturn;
typedef int (*actionf_p)(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret);/*(VM_ARGS)*/ typedef int (*actionf_p)(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret);/*(VM_ARGS)*/
class VMFunction; class VMFunction;
class PSymbolActionFunction : public PSymbol
{
DECLARE_CLASS(PSymbolActionFunction, PSymbol);
HAS_OBJECT_POINTERS;
public:
FString Arguments;
VMFunction *Function;
PSymbolActionFunction(FName name) : PSymbol(name) {}
PSymbolActionFunction() : PSymbol(NAME_None) {}
};
// A VM function ------------------------------------------------------------ // A VM function ------------------------------------------------------------
class PSymbolVMFunction : public PSymbol class PSymbolVMFunction : public PSymbol
@ -469,6 +441,7 @@ public:
TArray<Variant> Variants; TArray<Variant> Variants;
DWORD Flags; DWORD Flags;
unsigned AddVariant(PPrototype *proto, TArray<DWORD> &argflags, VMFunction *impl);
size_t PropagateMark(); size_t PropagateMark();

View file

@ -233,24 +233,24 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
{ {
if (extra.bExplosive) if (extra.bExplosive)
{ {
type->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_Explode")->Function); type->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_Explode")->Variants[0].Implementation);
} }
} }
else else
{ {
// The first frame plays the death sound and // The first frame plays the death sound and
// the second frame makes it nonsolid. // the second frame makes it nonsolid.
type->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_Scream")->Function); type->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_Scream")->Variants[0].Implementation);
if (extra.bSolidOnDeath) if (extra.bSolidOnDeath)
{ {
} }
else if (extra.DeathStart + 1 < extra.DeathEnd) else if (extra.DeathStart + 1 < extra.DeathEnd)
{ {
type->OwnedStates[extra.DeathStart+1].SetAction(FindGlobalActionFunction("A_NoBlocking")->Function); type->OwnedStates[extra.DeathStart+1].SetAction(FindGlobalActionFunction("A_NoBlocking")->Variants[0].Implementation);
} }
else else
{ {
type->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_ScreamAndUnblock")->Function); type->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_ScreamAndUnblock")->Variants[0].Implementation);
} }
if (extra.DeathHeight == 0) if (extra.DeathHeight == 0)
@ -282,17 +282,17 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
// The first frame plays the burn sound and // The first frame plays the burn sound and
// the second frame makes it nonsolid. // the second frame makes it nonsolid.
type->OwnedStates[extra.FireDeathStart].SetAction(FindGlobalActionFunction("A_ActiveSound")->Function); type->OwnedStates[extra.FireDeathStart].SetAction(FindGlobalActionFunction("A_ActiveSound")->Variants[0].Implementation);
if (extra.bSolidOnBurn) if (extra.bSolidOnBurn)
{ {
} }
else if (extra.FireDeathStart + 1 < extra.FireDeathEnd) else if (extra.FireDeathStart + 1 < extra.FireDeathEnd)
{ {
type->OwnedStates[extra.FireDeathStart+1].SetAction(FindGlobalActionFunction("A_NoBlocking")->Function); type->OwnedStates[extra.FireDeathStart+1].SetAction(FindGlobalActionFunction("A_NoBlocking")->Variants[0].Implementation);
} }
else else
{ {
type->OwnedStates[extra.FireDeathStart].SetAction(FindGlobalActionFunction("A_ActiveAndUnblock")->Function); type->OwnedStates[extra.FireDeathStart].SetAction(FindGlobalActionFunction("A_ActiveAndUnblock")->Variants[0].Implementation);
} }
if (extra.BurnHeight == 0) extra.BurnHeight = ((AActor*)(type->Defaults))->height; if (extra.BurnHeight == 0) extra.BurnHeight = ((AActor*)(type->Defaults))->height;
@ -313,14 +313,14 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
type->OwnedStates[i].Tics = 5; type->OwnedStates[i].Tics = 5;
type->OwnedStates[i].TicRange = 0; type->OwnedStates[i].TicRange = 0;
type->OwnedStates[i].Misc1 = 0; type->OwnedStates[i].Misc1 = 0;
type->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeath")->Function); type->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeath")->Variants[0].Implementation);
i = type->NumOwnedStates - 1; i = type->NumOwnedStates - 1;
type->OwnedStates[i].NextState = &type->OwnedStates[i]; type->OwnedStates[i].NextState = &type->OwnedStates[i];
type->OwnedStates[i].Tics = 1; type->OwnedStates[i].Tics = 1;
type->OwnedStates[i].TicRange = 0; type->OwnedStates[i].TicRange = 0;
type->OwnedStates[i].Misc1 = 0; type->OwnedStates[i].Misc1 = 0;
type->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeathChunks")->Function); type->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeathChunks")->Variants[0].Implementation);
bag.statedef.SetStateLabel("Ice", &type->OwnedStates[extra.IceDeathStart]); bag.statedef.SetStateLabel("Ice", &type->OwnedStates[extra.IceDeathStart]);
} }
else if (extra.bGenericIceDeath) else if (extra.bGenericIceDeath)

View file

@ -188,7 +188,7 @@ 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);
PSymbolActionFunction *FindGlobalActionFunction(const char *name); PFunction *FindGlobalActionFunction(const char *name);
//========================================================================== //==========================================================================
// //
@ -201,7 +201,7 @@ void SetReplacement(FScanner &sc, PClassActor *info, FName replaceName);
void HandleActorFlag(FScanner &sc, Baggage &bag, const char *part1, const char *part2, int mod); void HandleActorFlag(FScanner &sc, Baggage &bag, const char *part1, const char *part2, int mod);
void FinishActor(const FScriptPosition &sc, PClassActor *info, Baggage &bag); void FinishActor(const FScriptPosition &sc, PClassActor *info, Baggage &bag);
FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, char type, bool constant); FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool constant);
enum enum

View file

@ -553,9 +553,9 @@ FVariableInfo *FindVariable(const char * string, const PClass *cls)
// //
//========================================================================== //==========================================================================
PSymbolActionFunction *FindGlobalActionFunction(const char *name) PFunction *FindGlobalActionFunction(const char *name)
{ {
return dyn_cast<PSymbolActionFunction>(RUNTIME_CLASS(AActor)->Symbols.FindSymbol(name, false)); return dyn_cast<PFunction>(RUNTIME_CLASS(AActor)->Symbols.FindSymbol(name, false));
} }

View file

@ -67,35 +67,46 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def);
// //
//========================================================================== //==========================================================================
FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, char type, bool constant) FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool constant)
{ {
FxExpression *x = NULL; FxExpression *x = NULL;
int v; int v;
switch(type) if (type == TypeSound)
{ {
case 'S':
case 's': // Sound name
sc.MustGetString(); sc.MustGetString();
x = new FxConstant(FSoundID(sc.String), sc); x = new FxConstant(FSoundID(sc.String), sc);
break; }
else if (type == TypeSInt32 || type == TypeFloat64)
case 'M': {
case 'm': // Actor name x = ParseExpression (sc, cls);
if (constant && !x->isConstant())
{
sc.ScriptMessage("Default parameter must be constant.");
FScriptPosition::ErrorCounter++;
}
// Do automatic coercion between ints and floats.
if (type == TypeSInt32)
{
if (x->ValueType != VAL_Int)
{
x = new FxIntCast(x);
}
}
else
{
if (x->ValueType != VAL_Float)
{
x = new FxFloatCast(x);
}
}
}
else if (type == TypeName || type == TypeString)
{
sc.SetEscape(true); sc.SetEscape(true);
sc.MustGetString(); sc.MustGetString();
sc.SetEscape(false); sc.SetEscape(false);
x = new FxClassTypeCast(RUNTIME_CLASS(AActor), new FxConstant(FName(sc.String), sc)); if (type == TypeName)
break;
case 'N':
case 'n': // name
case 'T':
case 't': // String
sc.SetEscape(true);
sc.MustGetString();
sc.SetEscape(false);
if (type == 'n' || type == 'N')
{ {
x = new FxConstant(sc.String[0] ? FName(sc.String) : NAME_None, sc); x = new FxConstant(sc.String[0] ? FName(sc.String) : NAME_None, sc);
} }
@ -103,10 +114,9 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, char type, bool con
{ {
x = new FxConstant(strbin1(sc.String), sc); x = new FxConstant(strbin1(sc.String), sc);
} }
break; }
else if (type == TypeColor)
case 'C': {
case 'c': // Color
sc.MustGetString (); sc.MustGetString ();
if (sc.Compare("none")) if (sc.Compare("none"))
{ {
@ -122,16 +132,12 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, char type, bool con
// 0 needs to be the default so we have to mark the color. // 0 needs to be the default so we have to mark the color.
v = MAKEARGB(1, RPART(c), GPART(c), BPART(c)); v = MAKEARGB(1, RPART(c), GPART(c), BPART(c));
} }
{ ExpVal val;
ExpVal val; val.Type = VAL_Color;
val.Type = VAL_Color; val.Int = v;
val.Int = v; x = new FxConstant(val, sc);
x = new FxConstant(val, sc); }
break; else if (type == TypeState)
}
case 'L':
case 'l':
{ {
// This forces quotation marks around the state name. // This forces quotation marks around the state name.
sc.MustGetToken(TK_StringConst); sc.MustGetToken(TK_StringConst);
@ -151,39 +157,18 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, char type, bool con
{ {
x = new FxMultiNameState(sc.String, sc); x = new FxMultiNameState(sc.String, sc);
} }
break;
} }
else if (type->GetClass() == RUNTIME_CLASS(PClassPointer))
case 'X': { // Actor name
case 'x': sc.SetEscape(true);
case 'Y': sc.MustGetString();
case 'y': sc.SetEscape(false);
x = ParseExpression (sc, cls); x = new FxClassTypeCast(static_cast<PClassPointer *>(type)->ClassRestriction, new FxConstant(FName(sc.String), sc));
if (constant && !x->isConstant()) }
{ else
sc.ScriptMessage("Default parameter must be constant."); {
FScriptPosition::ErrorCounter++; assert(false && "Unknown parameter type");
} x = NULL;
// Do automatic coercion between ints and floats.
if (type == 'x' || type == 'X')
{
if (x->ValueType != VAL_Int)
{
x = new FxIntCast(x);
}
}
else
{
if (x->ValueType != VAL_Float)
{
x = new FxFloatCast(x);
}
}
break;
default:
assert(false);
return NULL;
} }
return x; return x;
} }
@ -917,15 +902,12 @@ static void ParseActorProperty(FScanner &sc, Baggage &bag)
static void ParseActionDef (FScanner &sc, PClassActor *cls) static void ParseActionDef (FScanner &sc, PClassActor *cls)
{ {
enum
{
OPTIONAL = 1
};
bool error = false; bool error = false;
const AFuncDesc *afd; const AFuncDesc *afd;
FName funcname; FName funcname;
FString args; TArray<PType *> rets;
TArray<PType *> args;
TArray<DWORD> argflags;
if (sc.LumpNum == -1 || Wads.GetLumpFile(sc.LumpNum) > 0) if (sc.LumpNum == -1 || Wads.GetLumpFile(sc.LumpNum) > 0)
{ {
@ -934,6 +916,11 @@ static void ParseActionDef (FScanner &sc, PClassActor *cls)
} }
sc.MustGetToken(TK_Native); sc.MustGetToken(TK_Native);
// check for a return value
if (sc.CheckToken(TK_Int) || sc.CheckToken(TK_Bool))
{
rets.Push(TypeSInt32);
}
sc.MustGetToken(TK_Identifier); sc.MustGetToken(TK_Identifier);
funcname = sc.String; funcname = sc.String;
afd = FindFunction(sc.String); afd = FindFunction(sc.String);
@ -942,13 +929,18 @@ static void ParseActionDef (FScanner &sc, PClassActor *cls)
sc.ScriptMessage ("The function '%s' has not been exported from the executable.", sc.String); sc.ScriptMessage ("The function '%s' has not been exported from the executable.", sc.String);
error++; error++;
} }
args.Push(NewClassPointer(cls)), argflags.Push(0); // implied self pointer
args.Push(NewClassPointer(RUNTIME_CLASS(AActor))), argflags.Push(0); // implied stateowner pointer
args.Push(TypeState), argflags.Push(0); // implied callingstate pointer
sc.MustGetToken('('); sc.MustGetToken('(');
if (!sc.CheckToken(')')) if (!sc.CheckToken(')'))
{ {
while (sc.TokenType != ')') while (sc.TokenType != ')')
{ {
int flags = 0; int flags = 0;
char type = '@'; PType *type = NULL;
PClass *restrict = NULL;
// Retrieve flags before type name // Retrieve flags before type name
for (;;) for (;;)
@ -967,32 +959,42 @@ static void ParseActionDef (FScanner &sc, PClassActor *cls)
{ {
case TK_Bool: case TK_Bool:
case TK_Int: case TK_Int:
type = 'x'; type = TypeSInt32;
break; break;
case TK_Float: case TK_Float:
type = 'y'; type = TypeFloat64;
break; break;
case TK_Sound: type = 's'; break; case TK_Sound: type = TypeSound; break;
case TK_String: type = 't'; break; case TK_String: type = TypeString; break;
case TK_Name: type = 'n'; break; case TK_Name: type = TypeName; break;
case TK_State: type = 'l'; break; case TK_State: type = TypeState; break;
case TK_Color: type = 'c'; break; case TK_Color: type = TypeColor; break;
case TK_Class: case TK_Class:
sc.MustGetToken('<'); sc.MustGetToken('<');
sc.MustGetToken(TK_Identifier); // Skip class name, since the parser doesn't care sc.MustGetToken(TK_Identifier); // Get class name
restrict = PClass::FindClass(sc.String);
if (restrict == NULL)
{
sc.ScriptMessage("Unknown class type %s", sc.String);
FScriptPosition::ErrorCounter++;
}
else
{
type = NewClassPointer(restrict);
}
sc.MustGetToken('>'); sc.MustGetToken('>');
type = 'm';
break; break;
case TK_Ellipsis: case TK_Ellipsis:
type = '+'; // Making the final type NULL signals a varargs function.
type = NULL;
sc.MustGetToken(')'); sc.MustGetToken(')');
sc.UnGet(); sc.UnGet();
break; break;
default: default:
sc.ScriptMessage ("Unknown variable type %s", sc.TokenName(sc.TokenType, sc.String).GetChars()); sc.ScriptMessage ("Unknown variable type %s", sc.TokenName(sc.TokenType, sc.String).GetChars());
type = 'x'; type = TypeSInt32;
FScriptPosition::ErrorCounter++; FScriptPosition::ErrorCounter++;
break; break;
} }
@ -1008,16 +1010,13 @@ static void ParseActionDef (FScanner &sc, PClassActor *cls)
if (sc.CheckToken('=')) if (sc.CheckToken('='))
{ {
flags |= OPTIONAL; flags |= VARF_Optional;
FxExpression *def = ParseParameter(sc, cls, type, true); FxExpression *def = ParseParameter(sc, cls, type, true);
delete def; delete def;
} }
if (!(flags & OPTIONAL) && type != '+') args.Push(type);
{ argflags.Push(flags);
type -= 'a' - 'A';
}
args += type;
sc.MustGetAnyToken(); sc.MustGetAnyToken();
if (sc.TokenType != ',' && sc.TokenType != ')') if (sc.TokenType != ',' && sc.TokenType != ')')
{ {
@ -1028,14 +1027,14 @@ static void ParseActionDef (FScanner &sc, PClassActor *cls)
sc.MustGetToken(';'); sc.MustGetToken(';');
if (afd != NULL) if (afd != NULL)
{ {
PSymbolActionFunction *sym = new PSymbolActionFunction(funcname); PFunction *sym = new PFunction(funcname);
sym->Arguments = args; sym->AddVariant(NewPrototype(rets, args), argflags, *(afd->VMPointer));
sym->Function = *(afd->VMPointer); sym->Flags = VARF_Method | VARF_Action;
if (error) if (error)
{ {
FScriptPosition::ErrorCounter++; FScriptPosition::ErrorCounter++;
} }
else if (cls->Symbols.AddSymbol (sym) == NULL) else if (cls->Symbols.AddSymbol(sym) == NULL)
{ {
delete sym; delete sym;
sc.ScriptMessage ("'%s' is already defined in class '%s'.", sc.ScriptMessage ("'%s' is already defined in class '%s'.",

View file

@ -100,7 +100,7 @@ bool DoActionSpecials(FScanner &sc, FState & state, Baggage &bag, FStateTempCall
sc.ScriptError ("Too many arguments to %s", specname.GetChars()); sc.ScriptError ("Too many arguments to %s", specname.GetChars());
} }
tcall->Function = FindGlobalActionFunction("A_CallSpecial")->Function; tcall->Function = FindGlobalActionFunction("A_CallSpecial")->Variants[0].Implementation;
return true; return true;
} }
return false; return false;
@ -312,18 +312,29 @@ do_stop:
goto endofstate; goto endofstate;
} }
PSymbolActionFunction *afd = dyn_cast<PSymbolActionFunction>(bag.Info->Symbols.FindSymbol (FName(sc.String, true), true)); PFunction *afd = dyn_cast<PFunction>(bag.Info->Symbols.FindSymbol(FName(sc.String, true), true));
if (afd != NULL) if (afd != NULL)
{ {
tcall->Function = afd->Function; tcall->Function = afd->Variants[0].Implementation;
if (!afd->Arguments.IsEmpty()) const TArray<PType *> &params = afd->Variants[0].Proto->ArgumentTypes;
const TArray<DWORD> &paramflags = afd->Variants[0].ArgFlags;
int numparams = (int)params.Size();
int pnum = 0;
if (afd->Flags & VARF_Method)
{
numparams--;
pnum++;
}
if (afd->Flags & VARF_Action)
{
numparams -= 2;
pnum += 2;
}
if (numparams > 0)
{ {
const char *params = afd->Arguments.GetChars();
int numparams = (int)afd->Arguments.Len();
int v; int v;
if (!islower(*params)) if (!(paramflags[pnum] & VARF_Optional))
{ {
sc.MustGetStringName("("); sc.MustGetStringName("(");
} }
@ -335,13 +346,10 @@ do_stop:
} }
} }
bool varargs = params[numparams - 1] == '+'; while (numparams > 0)
int varargcount = 0;
while (*params)
{ {
FxExpression *x; FxExpression *x;
if ((*params == 'l' || *params == 'L') && sc.CheckNumber()) if (params[pnum] == TypeState && sc.CheckNumber())
{ {
// Special case: State label as an offset // Special case: State label as an offset
if (sc.Number > 0 && statestring.Len() > 1) if (sc.Number > 0 && statestring.Len() > 1)
@ -349,7 +357,7 @@ do_stop:
sc.ScriptError("You cannot use state jumps commands with a jump offset on multistate definitions\n"); sc.ScriptError("You cannot use state jumps commands with a jump offset on multistate definitions\n");
} }
v=sc.Number; v = sc.Number;
if (v<0) if (v<0)
{ {
sc.ScriptError("Negative jump offsets are not allowed"); sc.ScriptError("Negative jump offsets are not allowed");
@ -367,22 +375,23 @@ do_stop:
else else
{ {
// Use the generic parameter parser for everything else // Use the generic parameter parser for everything else
x = ParseParameter(sc, bag.Info, *params, false); x = ParseParameter(sc, bag.Info, params[pnum], false);
} }
tcall->Parameters.Push(new FxParameter(x)); tcall->Parameters.Push(new FxParameter(x));
params++; pnum++;
varargcount++; numparams--;
if (*params) if (numparams > 0)
{ {
if (*params == '+') if (params[pnum] == NULL)
{ { // varargs function
if (sc.CheckString(")")) if (sc.CheckString(")"))
{ {
goto endofstate; goto endofstate;
} }
params--; pnum--;
numparams++;
} }
else if ((islower(*params) || *params=='!') && sc.CheckString(")")) else if ((paramflags[pnum] & VARF_Optional) && sc.CheckString(")"))
{ {
goto endofstate; goto endofstate;
} }