diff --git a/src/common/scripting/core/types.cpp b/src/common/scripting/core/types.cpp index 72b80482b9..efe4dfec54 100644 --- a/src/common/scripting/core/types.cpp +++ b/src/common/scripting/core/types.cpp @@ -2883,6 +2883,12 @@ static FString MakeFunctionPointerDescriptiveName(PPrototype * proto,const TArra return mDescriptiveName; } + +FString PFunctionPointer::GenerateNameForError(const PFunction * from) +{ + return MakeFunctionPointerDescriptiveName(from->Variants[0].Proto, from->Variants[0].ArgFlags, FScopeBarrier::SideFromFlags(from->Variants[0].Flags)); +} + PFunctionPointer::PFunctionPointer(PPrototype * proto, TArray && argflags, int scope) : PPointer(proto ? (PType*) proto : TypeVoid, false), ArgFlags(std::move(argflags)), Scope(scope) { diff --git a/src/common/scripting/core/types.h b/src/common/scripting/core/types.h index d338405961..e24bcd38bb 100644 --- a/src/common/scripting/core/types.h +++ b/src/common/scripting/core/types.h @@ -605,6 +605,8 @@ public: //PointedType = PPrototype or TypeVoid PFunctionPointer(PPrototype * proto, TArray &&argflags, int scope); + static FString GenerateNameForError(const PFunction * from); + TArray ArgFlags; int Scope; diff --git a/src/scripting/zscript/zcc_compile_doom.cpp b/src/scripting/zscript/zcc_compile_doom.cpp index 8c21659dcd..4becfc4fe1 100644 --- a/src/scripting/zscript/zcc_compile_doom.cpp +++ b/src/scripting/zscript/zcc_compile_doom.cpp @@ -70,6 +70,7 @@ int ZCCDoomCompiler::Compile() InitDefaults(); InitFunctions(); CompileStates(); + InitDefaultFunctionPointers(); return FScriptPosition::ErrorCounter; } @@ -395,6 +396,46 @@ void ZCCDoomCompiler::DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *pr // //========================================================================== +PFunction * FindFunctionPointer(PClass * cls, int fn_name); +PFunction *NativeFunctionPointerCast(PFunction *from, const PFunctionPointer *to); + +struct FunctionPointerProperties +{ + ZCC_PropertyStmt *prop; + PClass * cls; + FName name; + const PFunctionPointer * type; + PFunction ** addr; +}; + +TArray DefaultFunctionPointers; + +void ZCCDoomCompiler::InitDefaultFunctionPointers() +{ + for(auto &d : DefaultFunctionPointers) + { + PFunction * fn = FindFunctionPointer(d.cls, d.name.GetIndex()); + if(!fn) + { + Error(d.prop, "Could not find function '%s' in class '%s'",d.name.GetChars(), d.cls->TypeName.GetChars()); + } + else + { + PFunction * casted = NativeFunctionPointerCast(fn,d.type); + if(!casted) + { + FString fn_proto_name = PFunctionPointer::GenerateNameForError(fn); + Error(d.prop, "Function has incompatible types, cannot convert from '%s' to '%s'",fn_proto_name.GetChars(), d.type->DescriptiveName()); + } + else + { + (*d.addr) = casted; + } + } + } + DefaultFunctionPointers.Clear(); +} + void ZCCDoomCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *property, AActor *defaults, Baggage &bag) { ZCC_ExprConstant one; @@ -608,6 +649,44 @@ void ZCCDoomCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt * *(PClass**)addr = cls; } } + else if (f->Type->isFunctionPointer()) + { + const char * fn_str = GetStringConst(ex, ctx); + if (*fn_str == 0 || !stricmp(fn_str, "none")) + { + *(PFunction**)addr = nullptr; + } + else + { + TArray fn_info(FString(fn_str).Split("::", FString::TOK_SKIPEMPTY)); + if(fn_info.Size() != 2) + { + Error(property, "Malformed function pointer property \"%s\", must be \"Class::Function\"",fn_str); + } + PClass * cls = PClass::FindClass(fn_info[0]); + if(!cls) + { + Error(property, "Could not find class '%s'",fn_info[0].GetChars()); + *(PFunction**)addr = nullptr; + } + else + { + FName fn_name(fn_info[1], true); + if(fn_name.GetIndex() == 0) + { + Error(property, "Could not find function '%s' in class '%s'",fn_info[1].GetChars(),fn_info[0].GetChars()); + *(PFunction**)addr = nullptr; + } + else + { + DefaultFunctionPointers.Push({property, cls, fn_name, static_cast(f->Type), (PFunction**)addr}); + *(PFunction**)addr = nullptr; + } + + } + } + + } else { Error(property, "unhandled property type %s", f->Type->DescriptiveName()); diff --git a/src/scripting/zscript/zcc_compile_doom.h b/src/scripting/zscript/zcc_compile_doom.h index 36d7a4680f..1fb8943728 100644 --- a/src/scripting/zscript/zcc_compile_doom.h +++ b/src/scripting/zscript/zcc_compile_doom.h @@ -25,6 +25,7 @@ private: void ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *prop, Baggage &bag); void ProcessDefaultFlag(PClassActor *cls, ZCC_FlagStmt *flg); void InitDefaults() override final; + void InitDefaultFunctionPointers(); FxExpression *SetupActionFunction(PClass *cls, ZCC_TreeNode *af, int StateFlags); void CompileStates(); int CheckActionKeyword(ZCC_FuncDeclarator *f, uint32_t &varflags, int useflags, ZCC_StructWork *c);