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++; } } }
int main(int argc, char *argv[]) { std::cout << "using namespace PRISMS;\n"; std::cout << "// ----------------------------------------------------------------------\n"; std::cout << "// Create an input variable vector, for a function of a single variable. \n"; std::cout << "// PFunctions evalulate with [], so even a function of a single variable \n"; std::cout << "// takes a container as input. \n"; std::cout << "std::vector<double> var(1, 2.1);\n"; std::vector<double> var(1, 2.1); std::cout << "\n"; Quadratic<std::vector<double> > quad; test("quad", quad, "std::vector<double>", "var", var, "double"); std::cout << "\n"; std::cout << "// ----------------------------------------------------------------------\n"; std::cout << "// Add another variable for a function of two variables. \n"; std::cout << "var.push_back(3.5);\n"; var.push_back(3.5); std::cout << "\n"; MyFunc<std::vector<double> > myfunc; test("myfunc", myfunc, "std::vector<double>", "var", var, "double"); std::cout << "\n"; std::cout << "// ----------------------------------------------------------------------\n"; std::cout << "// Use PFunction to hold any function. A PFunction contains a PFuncBase* \n"; std::cout << "// which it deletes upon destruction so you don't have to work with \n"; std::cout << "// pointers. It has the same interface as PFuncBase. \n"; std::cout << "PFunction<std::vector<double>, double> pfunc = MyFunc<std::vector<double> >();\n"; PFunction<std::vector<double>, double> pfunc = MyFunc<std::vector<double> >(); std::cout << "pfunc(" << var << ") = " << pfunc(var) << "\n"; std::cout << "pfunc.grad(" << var << ", 0) = " << pfunc.grad(var, 0) << "\n\n"; std::cout << "// In this case, only the first element of the input container is used.\n"; std::cout << "pfunc = Quadratic<std::vector<double> >();\n"; pfunc = Quadratic<std::vector<double> >(); std::cout << "pfunc(" << var << ") = " << pfunc(var) << "\n"; std::cout << "pfunc.grad(" << var << ", 0) = " << pfunc.grad(var, 0) << "\n\n"; std::cout << "// Assign any type that inherits from PFuncBase to a PFunction.\n"; std::cout << "pfunc = myfunc;\n"; pfunc = myfunc; std::cout << "pfunc() = " << pfunc() << "\n"; std::cout << "pfunc.grad(0) = " << pfunc.grad(0) << "\n\n"; std::cout << "// Assign any type that inherits from PFuncBase to a PFunction.\n"; std::cout << "pfunc = quad;\n"; pfunc = quad; std::cout << "pfunc() = " << pfunc() << "\n"; std::cout << "pfunc.grad(0) = " << pfunc.grad(0) << "\n\n"; std::cout << "finish" << std::endl; return 0; }
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; }
void compile_function_call(UCContext* code, int op, int flags, PExpr ex, bool use_obj=false, PExpr obj=NULL, int icb=0, bool is_dynamic=false) { // *fix 0.9.6 The DCALL function type _forces_ a function to be directly called, virtual or not PExprList args = ex->arg_list(); Type ret_type; Instruction* pi; bool function_ptr_call = op==EXPR || op==EXPR_METHOD; PFunction pf = function_ptr_call ? NULL : ex->function(); int sz = 0; // If this was a method, then the object ptr is at the end of the arguments //*PASOP* Also true for _static methods_??? //*unless we are explicitly given an object ptr, of course. if (!use_obj && (op==METHOD_CALL || op==EXPR_METHOD)) { obj = args->back(); args->pop_back(); } // compile the args in _reverse_ order! ExprList::reverse_iterator ali; if (args != NULL) for (ali = args->rbegin(); ali != args->rend(); ++ali) { code->compile(*ali); if (is_double_number((*ali)->type())) { sz += 2; } else ++sz; } bool was_method_call = obj != NULL || is_dynamic; if (was_method_call) {// the object stack is pushed immediately before the call push_object_ptr(code,obj); // obj ptr onto the object stack } // *change 1.2.0 PUSH_THIS etc has been moved to emit_native_function_call() if (function_ptr_call) { // call via a function ptr... PExpr e1 = ex->arg1(); ret_type = e1->type().as_signature()->return_type(); code->compile(e1); // issue: stdarg?? code->emit(CALLS); // and obviously we gotta do VCALLS.... } else { ret_type = pf->return_type(); // calls to native cdecl-style routines like printf() // require us to push the number of arguments! if (pf->stdarg() && pf->builtin()) code->emit_push_int(sz); // *add 1.2.3b Single-instruction functions can be safely inlined if (Parser::debug.attempt_inline && (pi = CodeGenerator::has_one_instruction(pf)) != NULL) { code->out(pi); } else { // *add 1.2.0 Imported classes may need the VMT-map equivalents! // *add 1.2.4 Virtual calls are proceeded by a 'NOP' carrying the original fun block! if (pf->is_virtual() && op!=DCALL) { if (! Parser::debug.attempt_inline) code->emit(HALT,DIRECT,offset_to_fun_block(pf)); code->emit(dont_use_map(pf) ? VCALL : VCALLX,DIRECT,pf->slot_id()); } else if (icb != 0) { if (icb > 0) code->emit(CCALLV,DIRECT,icb); // vector ctor/dor, else code->emit(dont_use_map(pf) ? CCALL : CCALLX ,DIRECT,offset_to_fun_block(pf)); // scalar ctor w/ VMT. } else { // plain call, no frills. code->emit(CALL,DIRECT,offset_to_fun_block(pf)); } // *add 1.2.3b Correct stack pointer for cdecl calls (remember that builtins get arg sz pushed as well!) int sp_diff,rt; if (pf->stdarg() && (sp_diff = sz - pf->fun_block()->nargs + (pf->builtin() ? 1 : 0)) > 0) { if (is_double_number(ret_type)) rt = 2; else if (ret_type != t_void) rt = 1; else rt = 0; code->emit(ADDSP,NONE,make_word(rt,sp_diff)); } } } // if there's a supplied object, then caller will handle this // CCONTEXT case! if (!use_obj && obj != NULL) code->emit(DOS); if (flags & DROP_VALUE) code->emit_stack_op(DROP,ret_type); }