1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 // Template helper to export C++ functions to C4Script
17 
18 #ifndef INC_C4AulDefFunc
19 #define INC_C4AulDefFunc
20 
21 #include "script/C4Aul.h"
22 #include "object/C4Def.h"
23 #include "object/C4DefList.h"
24 #include "script/C4Effect.h"
25 
FnStringPar(C4String * pString)26 inline const static char *FnStringPar(C4String *pString)
27 {
28 	return pString ? pString->GetCStr() : "";
29 }
String(const char * str)30 inline C4String *String(const char * str)
31 {
32 	return str ? ::Strings.RegString(str) : nullptr;
33 }
Object(C4PropList * _this)34 inline C4Object * Object(C4PropList * _this)
35 {
36 	return _this ? _this->GetObject() : nullptr;
37 }
38 StdStrBuf FnStringFormat(C4PropList * _this, C4String *szFormatPar, C4Value * Pars, int ParCount);
39 C4Effect ** FnGetEffectsFor(C4PropList * pTarget);
40 
41 // Nillable: Allow integer and boolean parameters to be nil
42 // pointer parameters represent nil via plain nullptr
43 // other types can use C4Void
44 class C4Void { };
45 template <typename T> struct C4ValueConv;
46 template <typename T>
47 class Nillable
48 {
49 	bool _nil;
50 	T _val;
51 public:
Nillable(const T & value)52 	inline Nillable(const T &value) : _nil(!value && !C4Value::IsNullableType(C4ValueConv<T>::Type)), _val(value) {}
Nillable()53 	inline Nillable() : _nil(true), _val(T()) {}
Nillable(std::nullptr_t)54 	inline Nillable(std::nullptr_t) : _nil(true), _val(T()) {}
Nillable(const Nillable<T2> & n2)55 	template <typename T2> inline Nillable(const Nillable<T2> & n2) : _nil(n2._nil), _val(n2._val) {}
Nillable(const C4Void &)56 	inline Nillable(const C4Void &) : _nil(true), _val(T()) {}
IsNil()57 	inline bool IsNil() const { return _nil; }
T()58 	inline operator T() const { return _val; }
59 	inline Nillable<T> &operator =(const T &val)
60 	{
61 		_val = val;
62 		_nil = !val && !C4Value::IsNullableType(C4ValueConv<T>::Type);
63 		return *this;
64 	}
65 	inline Nillable<T> &operator =(const Nillable<T> &val)
66 	{
67 		_val = val._val;
68 		_nil = val._nil;
69 		return *this;
70 	}
71 	// Some operators
72 	inline Nillable<T> &operator ++() { ++_val; return *this; }
73 	inline T operator ++(int) { T v(_val++); return v; }
74 	inline Nillable<T> &operator --() { --_val; return *this; }
75 	inline T operator --(int) { T v(_val--); return v; }
76 };
77 
78 // Other functions are callable in object context only.
79 // This exception gets thrown if they are called from anywhere else.
80 class NeedObjectContext : public C4AulExecError
81 {
82 public:
NeedObjectContext(const char * function)83 	NeedObjectContext(const char *function) : C4AulExecError(FormatString("%s: must be called from object context", function).getData()) {}
84 };
85 
86 // Then there's functions that don't care, but need either defn or object context.
87 // This exception gets thrown if those are called from global scripts.
88 class NeedNonGlobalContext : public C4AulExecError
89 {
90 public:
NeedNonGlobalContext(const char * function)91 	NeedNonGlobalContext(const char *function) : C4AulExecError(FormatString("%s: call must not be from global context", function).getData()) {}
92 };
93 
94 // For functions taking a C4Object as this, check that they got one
95 template <typename ThisType> struct ThisImpl;
96 template <> struct ThisImpl<C4Object>
97 {
98 	static C4Object* Conv(C4PropList* _this, C4AulFunc* func)
99 	{
100 		C4Object* Obj = _this ? _this->GetObject() : nullptr;
101 		if (Obj)
102 			return Obj;
103 		else
104 			throw NeedObjectContext(func->GetName());
105 	}
106 };
107 template <> struct ThisImpl<C4PropList>
108 {
109 	static C4PropList* Conv(C4PropList* _this, C4AulFunc* func)
110 	{
111 		return _this;
112 	}
113 };
114 
115 // Extracts the parameters from C4Values and wraps the return value in a C4Value
116 template <typename RType, typename ThisType, typename ...ParTypes>
117 struct ExecImpl
118 {
119 	template <std::size_t... Is>
120 	static C4Value Exec(RType (*pFunc)(ThisType *, ParTypes...), ThisType * _this, C4Value pPars[], std::index_sequence<Is...>)
121 	{
122 		return C4Value(pFunc(_this, C4ValueConv<ParTypes>::_FromC4V(pPars[Is])...));
123 		(void) pPars;
124 	}
125 };
126 template <typename ThisType, typename ...ParTypes>
127 struct ExecImpl<void, ThisType, ParTypes...>
128 {
129 	template <std::size_t... Is>
130 	static C4Value Exec(void (*pFunc)(ThisType *, ParTypes...), ThisType * _this, C4Value pPars[], std::index_sequence<Is...>)
131 	{
132 		pFunc(_this, C4ValueConv<ParTypes>::_FromC4V(pPars[Is])...);
133 		return C4Value();
134 		(void) pPars;
135 	}
136 };
137 
138 // converter templates
139 template <typename T>
140 struct C4ValueConv<Nillable<T> >
141 {
142 	inline static Nillable<T> _FromC4V(C4Value &v) { if (v.GetType() == C4V_Nil) return C4Void(); else return C4ValueConv<T>::_FromC4V(v); }
143 	static constexpr C4V_Type Type = C4ValueConv<T>::Type;
144 };
145 template <> struct C4ValueConv<void>
146 {
147 	static constexpr C4V_Type Type = C4V_Nil;
148 };
149 template <> struct C4ValueConv<int>
150 {
151 	static constexpr C4V_Type Type = C4V_Int;
152 	inline static int _FromC4V(C4Value &v) { return v._getInt(); }
153 };
154 template <> struct C4ValueConv<long>: public C4ValueConv<int> { };
155 template <> struct C4ValueConv<bool>
156 {
157 	static constexpr C4V_Type Type = C4V_Bool;
158 	inline static bool _FromC4V(C4Value &v) { return v._getBool(); }
159 };
160 template <> struct C4ValueConv<C4ID>
161 {
162 	static constexpr C4V_Type Type = C4V_PropList;
163 	inline static C4ID _FromC4V(C4Value &v) { C4Def * def = v.getDef(); return def ? def->id : C4ID::None; }
164 };
165 template <> struct C4ValueConv<C4Object *>
166 {
167 	static constexpr C4V_Type Type = C4V_Object;
168 	inline static C4Object *_FromC4V(C4Value &v) { return v._getObj(); }
169 };
170 template <> struct C4ValueConv<C4String *>
171 {
172 	static constexpr C4V_Type Type = C4V_String;
173 	inline static C4String *_FromC4V(C4Value &v) { return v._getStr(); }
174 };
175 template <> struct C4ValueConv<C4ValueArray *>
176 {
177 	static constexpr C4V_Type Type = C4V_Array;
178 	inline static C4ValueArray *_FromC4V(C4Value &v) { return v._getArray(); }
179 };
180 template <> struct C4ValueConv<C4AulFunc *>
181 {
182 	static constexpr C4V_Type Type = C4V_Function;
183 	inline static C4AulFunc *_FromC4V(C4Value &v) { return v._getFunction(); }
184 };
185 template <> struct C4ValueConv<C4PropList *>
186 {
187 	static constexpr C4V_Type Type = C4V_PropList;
188 	inline static C4PropList *_FromC4V(C4Value &v) { return v._getPropList(); }
189 };
190 template <> struct C4ValueConv<C4Effect *>
191 {
192 	static constexpr C4V_Type Type = C4V_Effect;
193 	inline static C4Effect *_FromC4V(C4Value &v) { C4PropList * p = v._getPropList(); return p ? p->GetEffect() : nullptr; }
194 };
195 template <> struct C4ValueConv<C4Def *>
196 {
197 	static constexpr C4V_Type Type = C4V_Def;
198 	inline static C4Def *_FromC4V(C4Value &v) { return v._getDef(); }
199 };
200 template <> struct C4ValueConv<const C4Value &>
201 {
202 	static constexpr C4V_Type Type = C4V_Any;
203 	inline static const C4Value &_FromC4V(C4Value &v) { return v; }
204 };
205 template <> struct C4ValueConv<C4Value>
206 {
207 	static constexpr C4V_Type Type = C4V_Any;
208 	inline static C4Value _FromC4V(C4Value &v) { return v; }
209 };
210 
211 // Wrapper around an ordinary C++ function callable from C4Script
212 template <typename RType, typename ThisType, typename ...ParTypes>
213 class C4AulEngineFunc: public C4AulFunc
214 {
215 public:
216 	/* A pointer to the function which this class wraps */
217 	typedef RType (*Func)(ThisType *, ParTypes...);
218 
219 	C4AulEngineFunc(C4PropListStatic * Parent, const char *pName, Func pFunc, bool Public):
220 		C4AulFunc(Parent, pName),
221 		pFunc(pFunc), ParType {C4ValueConv<ParTypes>::Type...}, Public(Public)
222 	{
223 		Parent->SetPropertyByS(Name, C4VFunction(this));
224 		for(int i = GetParCount(); i < C4AUL_MAX_Par; ++i)
225 			ParType[i] = C4V_Any;
226 	}
227 
228 	int GetParCount() const override
229 	{
230 		return sizeof...(ParTypes);
231 	}
232 
233 	const C4V_Type* GetParType() const override
234 	{
235 		return ParType;
236 	}
237 
238 	C4V_Type GetRetType() const override
239 	{
240 		return C4ValueConv<RType>::Type;
241 	}
242 
243 	bool GetPublic() const override
244 	{
245 		return Public;
246 	}
247 
248 	C4Value Exec(C4PropList * _this, C4Value pPars[], bool fPassErrors) override
249 	{
250 		return ExecImpl<RType, ThisType, ParTypes...>::Exec(pFunc, ThisImpl<ThisType>::Conv(_this, this),
251 								    pPars, std::index_sequence_for<ParTypes...>{});
252 	}
253 protected:
254 	Func pFunc;
255 	C4V_Type ParType[C4AUL_MAX_Par];// type of the parameters
256 	bool Public;
257 };
258 
259 template <typename RType, typename ThisType, typename ...ParTypes>
260 inline void AddFunc(C4PropListStatic * Parent, const char * Name, RType (*pFunc)(ThisType *, ParTypes...), bool Public=true)
261 {
262 	new C4AulEngineFunc<RType, ThisType, ParTypes...>(Parent, Name, pFunc, Public);
263 }
264 
265 // a definition of a script constant
266 struct C4ScriptConstDef
267 {
268 	const char * Identifier; // constant name
269 	C4V_Type ValType;       // type value
270 	long Data;               // raw data
271 };
272 
273 // a definition of a function exported to script
274 struct C4ScriptFnDef
275 {
276 	const char * Identifier; // the name of the func in the script
277 	bool Public;
278 	C4V_Type RetType; // type returned. ignored when C4V
279 	C4V_Type ParType[10];// type of the parameters. error when wrong parameter type.
280 	C4Value (*FunctionC4V)(C4PropList * _this, C4Value *);
281 };
282 
283 // defined function class
284 class C4AulDefFunc : C4AulFunc
285 {
286 public:
287 	C4ScriptFnDef* Def;
288 
289 	C4AulDefFunc(C4PropListStatic * Parent, C4ScriptFnDef* pDef);
290 	~C4AulDefFunc() override;
291 
292 	bool GetPublic() const override { return !!Def->Public; }
293 	const C4V_Type* GetParType() const override { return Def->ParType; }
294 	C4V_Type GetRetType() const override { return Def->RetType; }
295 
296 	C4Value Exec(C4PropList * p, C4Value pPars[], bool fPassErrors=false) override;
297 };
298 
299 #endif
300