void ParseFunctionDef(FScanner &sc, PClassActor *cls, FName funcname, TArray<PType *> &rets, DWORD funcflags) { assert(cls != NULL); const AFuncDesc *afd; TArray<PType *> args; TArray<DWORD> argflags; afd = FindFunction(funcname); if (afd == NULL) { sc.ScriptMessage ("The function '%s' has not been exported from the executable.", funcname.GetChars()); FScriptPosition::ErrorCounter++; } sc.MustGetToken('('); SetImplicitArgs(&args, &argflags, cls, funcflags); ParseArgListDef(sc, cls, args, argflags); if (afd != NULL) { PFunction *sym = new PFunction(funcname); sym->AddVariant(NewPrototype(rets, args), argflags, *(afd->VMPointer)); sym->Flags = funcflags; if (cls->Symbols.AddSymbol(sym) == NULL) { delete sym; sc.ScriptMessage ("'%s' is already defined in class '%s'.", funcname.GetChars(), cls->TypeName.GetChars()); FScriptPosition::ErrorCounter++; } } }
PFunction *CreateAnonymousFunction(PClass *containingclass, PType *returntype, int flags) { TArray<PType *> rets(1); TArray<PType *> args; TArray<uint32_t> argflags; TArray<FName> argnames; // Functions that only get flagged for actors do not need the additional two context parameters. int fflags = (flags& (SUF_OVERLAY | SUF_WEAPON | SUF_ITEM)) ? VARF_Action | VARF_Method : VARF_Method; rets[0] = returntype != nullptr? returntype : TypeError; // Use TypeError as placeholder if we do not know the return type yet. SetImplicitArgs(&args, &argflags, &argnames, containingclass, fflags, flags); PFunction *sym = new PFunction(containingclass, NAME_None); // anonymous functions do not have names. sym->AddVariant(NewPrototype(rets, args), argflags, argnames, nullptr, fflags, flags); return sym; }
static void FinishThingdef() { int errorcount = 0; unsigned i; int codesize = 0; FILE *dump = NULL; if (Args->CheckParm("-dumpdisasm")) dump = fopen("disasm.txt", "w"); for (i = 0; i < StateTempCalls.Size(); ++i) { FStateTempCall *tcall = StateTempCalls[i]; VMFunction *func; assert(tcall->Code != NULL); // 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(); if (func == NULL) { FCompileContext ctx(tcall->ActorClass); tcall->Code = tcall->Code->Resolve(ctx); // Make sure resolving it didn't obliterate it. if (tcall->Code != NULL) { VMFunctionBuilder buildit; // Allocate registers used to pass parameters in. // self, stateowner, state (all are pointers) buildit.Registers[REGT_POINTER].Get(3); // 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) { char label[64]; int labellen = mysnprintf(label, countof(label), "Function %s.States[%d] (*%d)", tcall->ActorClass->TypeName.GetChars(), tcall->FirstState, tcall->NumStates); DumpFunction(dump, sfunc, label, labellen); codesize += sfunc->CodeSize; } } } if (tcall->Code != NULL) { delete tcall->Code; tcall->Code = NULL; for (int k = 0; k < tcall->NumStates; ++k) { tcall->ActorClass->OwnedStates[tcall->FirstState + k].SetAction(func); } } } for (i = 0; i < PClassActor::AllActorClasses.Size(); i++) { PClassActor *ti = PClassActor::AllActorClasses[i]; if (ti->Size == TentativeClass) { Printf(TEXTCOLOR_RED "Class %s referenced but not defined\n", ti->TypeName.GetChars()); errorcount++; continue; } AActor *def = GetDefaultByType(ti); if (!def) { Printf("No ActorInfo defined for class '%s'\n", ti->TypeName.GetChars()); errorcount++; continue; } if (def->Damage != NULL) { FxDamageValue *dmg = (FxDamageValue *)ActorDamageFuncs[(uintptr_t)def->Damage - 1]; VMScriptFunction *sfunc; sfunc = dmg->GetFunction(); if (sfunc == NULL) { FCompileContext ctx(ti); dmg->Resolve(ctx); VMFunctionBuilder buildit; buildit.Registers[REGT_POINTER].Get(1); // The self pointer 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); } def->Damage = sfunc; if (dump != NULL && sfunc != NULL) { char label[64]; int labellen = mysnprintf(label, countof(label), "Function %s.Damage", ti->TypeName.GetChars()); DumpFunction(dump, sfunc, label, labellen); codesize += sfunc->CodeSize; } } } if (dump != NULL) { fprintf(dump, "\n*************************************************************************\n%i code bytes\n", codesize * 4); fclose(dump); } if (errorcount > 0) { I_Error("%d errors during actor postprocessing", errorcount); } ActorDamageFuncs.DeleteAndClear(); StateTempCalls.DeleteAndClear(); // Since these are defined in DECORATE now the table has to be initialized here. for(int i = 0; i < 31; i++) { char fmt[20]; mysnprintf(fmt, countof(fmt), "QuestItem%d", i+1); QuestItemClasses[i] = PClass::FindActor(fmt); } }