diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 7709bfa8f..4dcb904d5 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2490,14 +2490,14 @@ size_t PFunction::PropagateMark() // //========================================================================== -unsigned PFunction::AddVariant(PPrototype *proto, TArray &argflags, VMFunction *impl) +unsigned PFunction::AddVariant(PPrototype *proto, TArray &argflags, TArray &argnames, VMFunction *impl) { Variant variant; - //variant.Proto = proto; + variant.Proto = proto; variant.ArgFlags = argflags; variant.Implementation = impl; - impl->Proto = proto; + if (impl != nullptr) impl->Proto = proto; return Variants.Push(variant); } diff --git a/src/dobjtype.h b/src/dobjtype.h index aee2d0ae2..9a51fa88a 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -692,14 +692,15 @@ class PFunction : public PSymbol public: struct Variant { - //PPrototype *Proto; + PPrototype *Proto; VMFunction *Implementation; TArray ArgFlags; // Should be the same length as Proto->ArgumentTypes + TArray ArgNames; // we need the names to access them later when the function gets compiled. }; TArray Variants; DWORD Flags; - unsigned AddVariant(PPrototype *proto, TArray &argflags, VMFunction *impl); + unsigned AddVariant(PPrototype *proto, TArray &argflags, TArray &argnames, VMFunction *impl); size_t PropagateMark(); diff --git a/src/namedef.h b/src/namedef.h index eedbaf899..43856aad1 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -717,7 +717,7 @@ xx(Max_10_Exp) // implicit function parameters xx(self) -xx(caller) +xx(invoker) xx(stateinfo) xx(__decorate_internal_int__) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 2a6cf51aa..0034de8a4 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -3883,7 +3883,7 @@ FxVMFunctionCall::~FxVMFunctionCall() PPrototype *FxVMFunctionCall::ReturnProto() { EmitTail = true; - return Function->Variants[0].Implementation->Proto; + return Function->Variants[0].Proto; } //========================================================================== @@ -3916,7 +3916,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); bool failed = false; - auto proto = Function->Variants[0].Implementation->Proto; + auto proto = Function->Variants[0].Proto; auto argtypes = proto->ArgumentTypes; int implicit; diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index e48d4d856..f547956dd 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -458,6 +458,7 @@ void ParseFunctionDef(FScanner &sc, PClassActor *cls, FName funcname, const AFuncDesc *afd; TArray args; TArray argflags; + TArray argnames; afd = FindFunction(funcname); if (afd == NULL) @@ -467,13 +468,14 @@ void ParseFunctionDef(FScanner &sc, PClassActor *cls, FName funcname, } sc.MustGetToken('('); - SetImplicitArgs(&args, &argflags, cls, funcflags); + SetImplicitArgs(&args, &argflags, &argnames, cls, funcflags); + // This function will be removed once all internal classes have been ported so don't bother filling in the function's argument names, because for anything going through here they'll never be used. ParseArgListDef(sc, cls, args, argflags); if (afd != NULL) { PFunction *sym = new PFunction(funcname); - sym->AddVariant(NewPrototype(rets, args), argflags, *(afd->VMPointer)); + sym->AddVariant(NewPrototype(rets, args), argflags, argnames, *(afd->VMPointer)); sym->Flags = funcflags; if (cls->Symbols.AddSymbol(sym) == NULL) { diff --git a/src/scripting/decorate/thingdef_states.cpp b/src/scripting/decorate/thingdef_states.cpp index f2dda5548..ada9462e0 100644 --- a/src/scripting/decorate/thingdef_states.cpp +++ b/src/scripting/decorate/thingdef_states.cpp @@ -322,7 +322,8 @@ do_stop: endofstate: if (ScriptCode != nullptr) { - state.ActionFunc = FunctionBuildList.AddFunction(actor, ScriptCode, FStringf("%s.StateFunction.%d", actor->TypeName.GetChars(), bag.statedef.GetStateCount()), true); + auto funcsym = CreateAnonymousFunction(actor, nullptr, VARF_Method | VARF_Action); + state.ActionFunc = FunctionBuildList.AddFunction(funcsym, ScriptCode, FStringf("%s.StateFunction.%d", actor->TypeName.GetChars(), bag.statedef.GetStateCount()), true); } int count = bag.statedef.AddStates(&state, statestring); if (count < 0) @@ -595,7 +596,7 @@ FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, B void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray &out_params, PFunction *afd, FString statestring, FStateDefinitions *statedef) { - const TArray ¶ms = afd->Variants[0].Implementation->Proto->ArgumentTypes; + const TArray ¶ms = afd->Variants[0].Proto->ArgumentTypes; const TArray ¶mflags = afd->Variants[0].ArgFlags; int numparams = (int)params.Size(); int pnum = 0; diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index f62997816..182bfbd12 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -80,34 +80,74 @@ PClassActor *QuestItemClasses[31]; // //========================================================================== -void SetImplicitArgs(TArray *args, TArray *argflags, PClass *cls, DWORD funcflags) +void SetImplicitArgs(TArray *args, TArray *argflags, TArray *argnames, PClass *cls, DWORD funcflags) { // Must be called before adding any other arguments. - assert(args == NULL || args->Size() == 0); - assert(argflags == NULL || argflags->Size() == 0); + assert(args == nullptr || args->Size() == 0); + assert(argflags == nullptr || argflags->Size() == 0); if (funcflags & VARF_Method) { // implied self pointer - if (args != NULL) args->Push(NewClassPointer(cls)); - if (argflags != NULL) argflags->Push(VARF_Implicit); + if (args != nullptr) args->Push(cls); + if (argflags != nullptr) argflags->Push(VARF_Implicit); + if (argnames != nullptr) argnames->Push(NAME_self); } if (funcflags & VARF_Action) { // implied caller and callingstate pointers - if (args != NULL) + if (args != nullptr) { - args->Insert(0, NewClassPointer(RUNTIME_CLASS(AActor))); // the caller must go before self due to an old design mistake. - args->Push(TypeState); + // Special treatment for weapons and CustomInventorys: 'self' is not the defining class but the actual user of the item, so this pointer must be of type 'Actor' + /* if (cls->IsDescendantOf(RUNTIME_CLASS(AStateProvider))) + { + args->Insert(0, RUNTIME_CLASS(AActor)); // this must go in before the real pointer to the containing class. + } + else*/ + { + args->Push(cls); + } + args->Push(TypeState/*Info*/); // fixme: TypeState is not the correct type here!!! } - if (argflags != NULL) + if (argflags != nullptr) { argflags->Push(VARF_Implicit); argflags->Push(VARF_Implicit); } + if (argnames != nullptr) + { + argnames->Push(NAME_invoker); + argnames->Push(NAME_stateinfo); + } } } +//========================================================================== +// +// CreateAnonymousFunction +// +// Creates a function symbol for an anonymous function +// This contains actual info about the implied variables which is needed +// during code generation. +// +//========================================================================== + +PFunction *CreateAnonymousFunction(PClass *containingclass, PType *returntype, int flags) +{ + TArray rets(1); + TArray args; + TArray argflags; + TArray argnames; + + rets[0] = returntype != nullptr? returntype : TypeError; // Use TypeError as placeholder if we do not know the return type yet. + SetImplicitArgs(&args, &argflags, &argnames, containingclass, flags); + + PFunction *sym = new PFunction(NAME_None); // anonymous functions do not have names. + sym->AddVariant(NewPrototype(rets, args), argflags, argnames, nullptr); + sym->Flags = VARF_Action; + return sym; +} + //========================================================================== // // LoadActors diff --git a/src/scripting/thingdef.h b/src/scripting/thingdef.h index 4a984dd5c..d5b189d47 100644 --- a/src/scripting/thingdef.h +++ b/src/scripting/thingdef.h @@ -150,7 +150,8 @@ void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray *args, TArray *argflags, PClass *cls, DWORD funcflags); +void SetImplicitArgs(TArray *args, TArray *argflags, TArray *argnames, PClass *cls, DWORD funcflags); +PFunction *CreateAnonymousFunction(PClass *containingclass, PType *returntype, int flags); //========================================================================== // diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 833a2d381..34f424ab4 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -657,7 +657,8 @@ DEFINE_PROPERTY(damage, X, Actor) } else { - defaults->DamageFunc = FunctionBuildList.AddFunction(bag.Info, id, FStringf("%s.DamageFunction", bag.Info->TypeName.GetChars()), false); + auto funcsym = CreateAnonymousFunction(bag.Info, TypeSInt32, VARF_Method); + defaults->DamageFunc = FunctionBuildList.AddFunction(funcsym, id, FStringf("%s.DamageFunction", bag.Info->TypeName.GetChars()), false); } } diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/vm/vmbuilder.cpp index 4351723f8..76fd84072 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/vm/vmbuilder.cpp @@ -649,7 +649,7 @@ void VMFunctionBuilder::BackpatchToHere(size_t loc) //========================================================================== FFunctionBuildList FunctionBuildList; -VMFunction *FFunctionBuildList::AddFunction(PClass *cls, FxExpression *code, const FString &name, bool statecall) +VMFunction *FFunctionBuildList::AddFunction(PFunction *functype, FxExpression *code, const FString &name, bool statecall) { auto func = code->GetDirectFunction(); if (func != nullptr) @@ -661,7 +661,7 @@ VMFunction *FFunctionBuildList::AddFunction(PClass *cls, FxExpression *code, con //Printf("Adding %s\n", name.GetChars()); Item it; - it.Class = cls; + it.Func = functype; it.Code = code; it.DumpName = name; it.Function = new VMScriptFunction; @@ -684,8 +684,11 @@ void FFunctionBuildList::Build() { assert(item.Code != NULL); + // This needs to be fixed, so that the compile context receives the entire function symbol, including the containing class, the prototype and argument names, which will be needed to run the code generator + // As a first step this just needs to get working so fetch the class type from the prototype's argument list. + auto cls = static_cast(item.Func->Variants[0].Proto->ArgumentTypes[!!(item.Func->Flags & VARF_Action)]); // We don't know the return type in advance for anonymous functions. - FCompileContext ctx(item.Class, nullptr); + FCompileContext ctx(cls, nullptr); item.Code = item.Code->Resolve(ctx); item.Proto = ctx.ReturnProto; @@ -695,32 +698,15 @@ void FFunctionBuildList::Build() VMFunctionBuilder buildit(true); assert(item.Proto != nullptr); - - int numargs; - int flags; - - // Kludge alert. This needs to be done in a more universal fashion. - // Right now there's only action and damage functions, so for the time being - // this will do to get the whole thing started first. - - if (item.type == 1) // anonymous action function - { - numargs = NAP; - flags = VARF_Method | VARF_Action; - } - else - { - numargs = 1; - flags = VARF_Method; - } + auto numargs = item.Func->Variants[0].Proto->ArgumentTypes.Size(); // Generate prototype for this anonymous function + // Fixme: This later needs to do proper allocation for the function's entire argument list, once non-anonymous functions can be done. buildit.Registers[REGT_POINTER].Get(numargs); - TArray args(numargs); - SetImplicitArgs(&args, nullptr, item.Class, flags); VMScriptFunction *sfunc = item.Function; - item.Function->Proto = NewPrototype(item.Proto->ReturnTypes, args); + // create a new prototype from the now known return type and the argument list of the function's template prototype. + item.Function->Proto = NewPrototype(item.Proto->ReturnTypes, item.Func->Variants[0].Proto->ArgumentTypes); // Emit code item.Code->Emit(&buildit); @@ -731,7 +717,7 @@ void FFunctionBuildList::Build() { char label[64]; int labellen = mysnprintf(label, countof(label), item.DumpName, - item.Class->TypeName.GetChars()); + cls->TypeName.GetChars()); DumpFunction(dump, sfunc, label, labellen); codesize += sfunc->CodeSize; } diff --git a/src/scripting/vm/vmbuilder.h b/src/scripting/vm/vmbuilder.h index 59e9fbe79..6b9a0aa68 100644 --- a/src/scripting/vm/vmbuilder.h +++ b/src/scripting/vm/vmbuilder.h @@ -101,7 +101,7 @@ class FFunctionBuildList { struct Item { - PClass *Class = nullptr; + PFunction *Func = nullptr; FxExpression *Code = nullptr; PPrototype *Proto = nullptr; VMScriptFunction *Function = nullptr; @@ -112,7 +112,7 @@ class FFunctionBuildList TArray mItems; public: - VMFunction *AddFunction(PClass *cls, FxExpression *code, const FString &name, bool statecall = false); + VMFunction *AddFunction(PFunction *func, FxExpression *code, const FString &name, bool statecall = false); void Build(); }; diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index f2f7b4d4b..23bdce3b5 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1870,7 +1870,7 @@ void ZCCCompiler::InitFunctions() TArray rets(1); TArray args; TArray argflags; - TArray argnames; + TArray argnames; for (auto c : Classes) { @@ -1925,20 +1925,7 @@ void ZCCCompiler::InitFunctions() Error(f, "The function '%s' has not been exported from the executable.", FName(f->Name).GetChars()); } } - SetImplicitArgs(&args, &argflags, c->Type(), varflags); - // Give names to the implicit parameters. - // Note that 'self' is the second argument on action functions, because this is the one referring to the owning class. - if (varflags & VARF_Action) - { - argnames.Push(NAME_caller); - argnames.Push(NAME_self); - argnames.Push(NAME_stateinfo); - } - else if (varflags & VARF_Method) - { - argnames.Push(NAME_self); - } - + SetImplicitArgs(&args, &argflags, &argnames, c->Type(), varflags); auto p = f->Params; if (p != nullptr) { @@ -1974,7 +1961,7 @@ void ZCCCompiler::InitFunctions() } PFunction *sym = new PFunction(f->Name); - sym->AddVariant(NewPrototype(rets, args), argflags, afd == nullptr? nullptr : *(afd->VMPointer)); + sym->AddVariant(NewPrototype(rets, args), argflags, argnames, afd == nullptr? nullptr : *(afd->VMPointer)); sym->Flags = varflags; c->Type()->Symbols.ReplaceSymbol(sym); @@ -2025,7 +2012,7 @@ FxExpression *ZCCCompiler::SetupActionFunction(PClassActor *cls, ZCC_TreeNode *a { if (fc->Parameters == nullptr && (afd->Flags & VARF_Action)) { - // This is the simple case which doesn't require work on the tree. + // We can use this function directly without wrapping it in a caller. return new FxVMFunctionCall(afd, nullptr, *af, true); } } @@ -2040,6 +2027,7 @@ FxExpression *ZCCCompiler::SetupActionFunction(PClassActor *cls, ZCC_TreeNode *a // Action specials fall through to the code generator. } } + ConvertClass = cls; return ConvertAST(af); //Error(af, "Complex action functions not supported yet."); @@ -2173,7 +2161,8 @@ void ZCCCompiler::CompileStates() auto code = SetupActionFunction(static_cast(c->Type()), sl->Action); if (code != nullptr) { - state.ActionFunc = FunctionBuildList.AddFunction(c->Type(), code, FStringf("%s.StateFunction.%d", c->Type()->TypeName.GetChars(), statedef.GetStateCount()), true); + auto funcsym = CreateAnonymousFunction(c->Type(), nullptr, VARF_Method | VARF_Action); + state.ActionFunc = FunctionBuildList.AddFunction(funcsym, code, FStringf("%s.StateFunction.%d", c->Type()->TypeName.GetChars(), statedef.GetStateCount()), true); } } @@ -2289,10 +2278,10 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) case AST_ExprFuncCall: { auto fcall = static_cast(ast); - //return ConvertFunctionCall(fcall); assert(fcall->Function->NodeType == AST_ExprID); // of course this cannot remain. Right now nothing more complex can come along but later this will have to be decomposed into 'self' and the actual function name. auto fname = static_cast(fcall->Function)->Identifier; return new FxFunctionCall(nullptr, fname, ConvertNodeList(fcall->Parameters), *ast); + //return ConvertFunctionCall(fcall->Function, ConvertNodeList(fcall->Parameters), ConvertClass, *ast); } case AST_FuncParm: diff --git a/src/scripting/zscript/zcc_compile.h b/src/scripting/zscript/zcc_compile.h index 12e570330..4ecd63227 100644 --- a/src/scripting/zscript/zcc_compile.h +++ b/src/scripting/zscript/zcc_compile.h @@ -143,6 +143,7 @@ private: FArgumentList *ConvertNodeList(ZCC_TreeNode *head); DObject *Outer; + PClass *ConvertClass; // class type to be used when resoving symbold while converting an AST PSymbolTable *GlobalTreeNodes; PSymbolTable *OutputSymbols; ZCC_AST &AST;