/* * OpenClonk, http://www.openclonk.org * * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/ * Copyright (c) 2009-2016, The OpenClonk Team and contributors * * Distributed under the terms of the ISC license; see accompanying file * "COPYING" for details. * * "Clonk" is a registered trademark of Matthes Bender, used with permission. * See accompanying file "TRADEMARK" for details. * * To redistribute this file separately, substitute the full license texts * for the above references. */ // Template helper to export C++ functions to C4Script #ifndef INC_C4AulDefFunc #define INC_C4AulDefFunc #include "script/C4Aul.h" #include "object/C4Def.h" #include "object/C4DefList.h" #include "script/C4Effect.h" #include inline const static char *FnStringPar(C4String *pString) { return pString ? pString->GetCStr() : ""; } inline C4String *String(const char * str) { return str ? ::Strings.RegString(str) : nullptr; } inline C4Object * Object(C4PropList * _this) { return _this ? _this->GetObject() : nullptr; } StdStrBuf FnStringFormat(C4PropList * _this, C4String *szFormatPar, C4Value * Pars, int ParCount); C4Effect ** FnGetEffectsFor(C4PropList * pTarget); // Nillable: Allow integer and boolean parameters to be nil // pointer parameters represent nil via plain nullptr // other types can use C4Void class C4Void { }; template struct C4ValueConv; template class Nillable { bool _nil; T _val; public: inline Nillable(const T &value) : _nil(!value && !C4Value::IsNullableType(C4ValueConv::Type)), _val(value) {} inline Nillable() : _nil(true), _val(T()) {} inline Nillable(std::nullptr_t) : _nil(true), _val(T()) {} template inline Nillable(const Nillable & n2) : _nil(n2._nil), _val(n2._val) {} inline Nillable(const C4Void &) : _nil(true), _val(T()) {} inline bool IsNil() const { return _nil; } inline operator T() const { return _val; } inline Nillable &operator =(const T &val) { _val = val; _nil = !val && !C4Value::IsNullableType(C4ValueConv::Type); return *this; } inline Nillable &operator =(const Nillable &val) { _val = val._val; _nil = val._nil; return *this; } // Some operators inline Nillable &operator ++() { ++_val; return *this; } inline T operator ++(int) { T v(_val++); return v; } inline Nillable &operator --() { --_val; return *this; } inline T operator --(int) { T v(_val--); return v; } }; // Other functions are callable in object context only. // This exception gets thrown if they are called from anywhere else. class NeedObjectContext : public C4AulExecError { public: NeedObjectContext(const char *function) : C4AulExecError(FormatString("%s: must be called from object context", function).getData()) {} }; // Then there's functions that don't care, but need either defn or object context. // This exception gets thrown if those are called from global scripts. class NeedNonGlobalContext : public C4AulExecError { public: NeedNonGlobalContext(const char *function) : C4AulExecError(FormatString("%s: call must not be from global context", function).getData()) {} }; // For functions taking a C4Object as this, check that they got one template struct ThisImpl; template <> struct ThisImpl { static C4Object* Conv(C4PropList* _this, C4AulFunc* func) { C4Object* Obj = _this ? _this->GetObject() : nullptr; if (Obj) return Obj; else throw NeedObjectContext(func->GetName()); } }; template <> struct ThisImpl { static C4PropList* Conv(C4PropList* _this, C4AulFunc* func) { return _this; } }; // Extracts the parameters from C4Values and wraps the return value in a C4Value template struct ExecImpl { template static C4Value Exec(RType (*pFunc)(ThisType *, ParTypes...), ThisType * _this, C4Value pPars[], std::index_sequence) { return C4Value(pFunc(_this, C4ValueConv::_FromC4V(pPars[Is])...)); (void) pPars; } }; template struct ExecImpl { template static C4Value Exec(void (*pFunc)(ThisType *, ParTypes...), ThisType * _this, C4Value pPars[], std::index_sequence) { pFunc(_this, C4ValueConv::_FromC4V(pPars[Is])...); return C4Value(); (void) pPars; } }; // converter templates template struct C4ValueConv > { inline static Nillable _FromC4V(C4Value &v) { if (v.GetType() == C4V_Nil) return C4Void(); else return C4ValueConv::_FromC4V(v); } static constexpr C4V_Type Type = C4ValueConv::Type; }; template <> struct C4ValueConv { static constexpr C4V_Type Type = C4V_Nil; }; template <> struct C4ValueConv { static constexpr C4V_Type Type = C4V_Int; inline static int _FromC4V(C4Value &v) { return v._getInt(); } }; template <> struct C4ValueConv: public C4ValueConv { }; template <> struct C4ValueConv { static constexpr C4V_Type Type = C4V_Bool; inline static bool _FromC4V(C4Value &v) { return v._getBool(); } }; template <> struct C4ValueConv { static constexpr C4V_Type Type = C4V_PropList; inline static C4ID _FromC4V(C4Value &v) { C4Def * def = v.getDef(); return def ? def->id : C4ID::None; } }; template <> struct C4ValueConv { static constexpr C4V_Type Type = C4V_Object; inline static C4Object *_FromC4V(C4Value &v) { return v._getObj(); } }; template <> struct C4ValueConv { static constexpr C4V_Type Type = C4V_String; inline static C4String *_FromC4V(C4Value &v) { return v._getStr(); } }; template <> struct C4ValueConv { static constexpr C4V_Type Type = C4V_Array; inline static C4ValueArray *_FromC4V(C4Value &v) { return v._getArray(); } }; template <> struct C4ValueConv { static constexpr C4V_Type Type = C4V_Function; inline static C4AulFunc *_FromC4V(C4Value &v) { return v._getFunction(); } }; template <> struct C4ValueConv { static constexpr C4V_Type Type = C4V_PropList; inline static C4PropList *_FromC4V(C4Value &v) { return v._getPropList(); } }; template <> struct C4ValueConv { static constexpr C4V_Type Type = C4V_Effect; inline static C4Effect *_FromC4V(C4Value &v) { C4PropList * p = v._getPropList(); return p ? p->GetEffect() : 0; } }; template <> struct C4ValueConv { static constexpr C4V_Type Type = C4V_Def; inline static C4Def *_FromC4V(C4Value &v) { return v._getDef(); } }; template <> struct C4ValueConv { static constexpr C4V_Type Type = C4V_Any; inline static const C4Value &_FromC4V(C4Value &v) { return v; } }; template <> struct C4ValueConv { static constexpr C4V_Type Type = C4V_Any; inline static C4Value _FromC4V(C4Value &v) { return v; } }; // Wrapper around an ordinary C++ function callable from C4Script template class C4AulEngineFunc: public C4AulFunc { public: /* A pointer to the function which this class wraps */ typedef RType (*Func)(ThisType *, ParTypes...); C4AulEngineFunc(C4PropListStatic * Parent, const char *pName, Func pFunc, bool Public): C4AulFunc(Parent, pName), pFunc(pFunc), ParType {C4ValueConv::Type...}, Public(Public) { Parent->SetPropertyByS(Name, C4VFunction(this)); for(int i = GetParCount(); i < C4AUL_MAX_Par; ++i) ParType[i] = C4V_Any; } virtual int GetParCount() const { return sizeof...(ParTypes); } virtual const C4V_Type* GetParType() const { return ParType; } virtual C4V_Type GetRetType() const { return C4ValueConv::Type; } virtual bool GetPublic() const { return Public; } virtual C4Value Exec(C4PropList * _this, C4Value pPars[], bool fPassErrors) { return ExecImpl::Exec(pFunc, ThisImpl::Conv(_this, this), pPars, std::index_sequence_for{}); } protected: Func pFunc; C4V_Type ParType[C4AUL_MAX_Par];// type of the parameters bool Public; }; template inline void AddFunc(C4PropListStatic * Parent, const char * Name, RType (*pFunc)(ThisType *, ParTypes...), bool Public=true) { new C4AulEngineFunc(Parent, Name, pFunc, Public); } // a definition of a script constant struct C4ScriptConstDef { const char * Identifier; // constant name C4V_Type ValType; // type value long Data; // raw data }; // a definition of a function exported to script struct C4ScriptFnDef { const char * Identifier; // the name of the func in the script bool Public; C4V_Type RetType; // type returned. ignored when C4V C4V_Type ParType[10];// type of the parameters. error when wrong parameter type. C4Value (*FunctionC4V)(C4PropList * _this, C4Value *); }; // defined function class class C4AulDefFunc : C4AulFunc { public: C4ScriptFnDef* Def; C4AulDefFunc(C4PropListStatic * Parent, C4ScriptFnDef* pDef); ~C4AulDefFunc(); virtual bool GetPublic() const { return !!Def->Public; } virtual const C4V_Type* GetParType() const { return Def->ParType; } virtual C4V_Type GetRetType() const { return Def->RetType; } virtual C4Value Exec(C4PropList * p, C4Value pPars[], bool fPassErrors=false); }; #endif