1 // Copyright (c) 2003 Daniel Wallin and Arvid Norberg
2 
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the "Software"),
5 // to deal in the Software without restriction, including without limitation
6 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 // and/or sell copies of the Software, and to permit persons to whom the
8 // Software is furnished to do so, subject to the following conditions:
9 
10 // The above copyright notice and this permission notice shall be included
11 // in all copies or substantial portions of the Software.
12 
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
14 // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
15 // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16 // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
17 // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
18 // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
21 // OR OTHER DEALINGS IN THE SOFTWARE.
22 
23 
24 #if !BOOST_PP_IS_ITERATING
25 
26 #ifndef LUABIND_CALL_FUNCTION_HPP_INCLUDED
27 #define LUABIND_CALL_FUNCTION_HPP_INCLUDED
28 
29 #include <luabind/config.hpp>
30 
31 #include <boost/mpl/if.hpp>
32 #include <boost/tuple/tuple.hpp>
33 #include <boost/mpl/or.hpp>
34 #include <boost/preprocessor/repeat.hpp>
35 #include <boost/preprocessor/iteration/iterate.hpp>
36 #include <boost/preprocessor/repetition/enum.hpp>
37 #include <boost/preprocessor/repetition/enum_params.hpp>
38 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
39 #include <boost/preprocessor/punctuation/comma_if.hpp>
40 
41 #include <luabind/error.hpp>
42 #include <luabind/detail/convert_to_lua.hpp>
43 #include <luabind/detail/pcall.hpp>
44 
45 namespace luabind
46 {
47 	namespace detail
48 	{
49 
50 		// if the proxy_function_caller returns non-void
51 			template<class Ret, class Tuple>
52 			class proxy_function_caller
53 			{
54 //			friend class luabind::object;
55 			public:
56 
57 				typedef int(*function_t)(lua_State*, int, int);
58 
proxy_function_caller(lua_State * L,int params,function_t fun,const Tuple args)59 				proxy_function_caller(
60 					lua_State* L
61 					, int params
62 					, function_t fun
63 					, const Tuple args)
64 					: m_state(L)
65 					, m_params(params)
66 					, m_fun(fun)
67 					, m_args(args)
68 					, m_called(false)
69 				{
70 				}
71 
proxy_function_caller(const proxy_function_caller & rhs)72 				proxy_function_caller(const proxy_function_caller& rhs)
73 					: m_state(rhs.m_state)
74 					, m_params(rhs.m_params)
75 					, m_fun(rhs.m_fun)
76 					, m_args(rhs.m_args)
77 					, m_called(rhs.m_called)
78 				{
79 					rhs.m_called = true;
80 				}
81 
~proxy_function_caller()82 				~proxy_function_caller()
83 				{
84 					if (m_called) return;
85 
86 					m_called = true;
87 					lua_State* L = m_state;
88 
89 					int top = lua_gettop(L);
90 
91 					push_args_from_tuple<1>::apply(L, m_args);
92 					if (m_fun(L, boost::tuples::length<Tuple>::value, 0))
93 					{
94 						assert(lua_gettop(L) == top - m_params + 1);
95 #ifndef LUABIND_NO_EXCEPTIONS
96 						throw luabind::error(L);
97 #else
98 						error_callback_fun e = get_error_callback();
99 						if (e) e(L);
100 
101 						assert(0 && "the lua function threw an error and exceptions are disabled."
102 									" If you want to handle the error you can use luabind::set_error_callback()");
103 						std::terminate();
104 
105 #endif
106 					}
107 
108 					// pops the return values from the function call
109 					stack_pop pop(L, lua_gettop(L) - top + m_params);
110 				}
111 
operator Ret()112 				operator Ret()
113 				{
114 					typename mpl::apply_wrap2<default_policy,Ret,lua_to_cpp>::type converter;
115 
116 					m_called = true;
117 					lua_State* L = m_state;
118 
119 					int top = lua_gettop(L);
120 
121 					push_args_from_tuple<1>::apply(L, m_args);
122 					if (m_fun(L, boost::tuples::length<Tuple>::value, 1))
123 					{
124 						assert(lua_gettop(L) == top - m_params + 1);
125 #ifndef LUABIND_NO_EXCEPTIONS
126 						throw luabind::error(L);
127 #else
128 						error_callback_fun e = get_error_callback();
129 						if (e) e(L);
130 
131 						assert(0 && "the lua function threw an error and exceptions are disabled."
132 								" If you want to handle the error you can use luabind::set_error_callback()");
133 						std::terminate();
134 #endif
135 					}
136 
137 					// pops the return values from the function call
138 					stack_pop pop(L, lua_gettop(L) - top + m_params);
139 
140 #ifndef LUABIND_NO_ERROR_CHECKING
141 
142 					if (converter.match(L, LUABIND_DECORATE_TYPE(Ret), -1) < 0)
143 					{
144 #ifndef LUABIND_NO_EXCEPTIONS
145 						throw cast_failed(L, typeid(Ret));
146 #else
147 						cast_failed_callback_fun e = get_cast_failed_callback();
148 						if (e) e(L, typeid(Ret));
149 
150 						assert(0 && "the lua function's return value could not be converted."
151 									" If you want to handle the error you can use luabind::set_error_callback()");
152 						std::terminate();
153 
154 #endif
155 					}
156 #endif
157 					return converter.apply(L, LUABIND_DECORATE_TYPE(Ret), -1);
158 				}
159 
160 				template<class Policies>
operator [](const Policies & p)161 				Ret operator[](const Policies& p)
162 				{
163 					typedef typename detail::find_conversion_policy<0, Policies>::type converter_policy;
164 					typename mpl::apply_wrap2<converter_policy,Ret,lua_to_cpp>::type converter;
165 
166 					m_called = true;
167 					lua_State* L = m_state;
168 
169 					int top = lua_gettop(L);
170 
171 					detail::push_args_from_tuple<1>::apply(L, m_args, p);
172 					if (m_fun(L, boost::tuples::length<Tuple>::value, 1))
173 					{
174 						assert(lua_gettop(L) == top - m_params + 1);
175 #ifndef LUABIND_NO_EXCEPTIONS
176 						throw error(L);
177 #else
178 						error_callback_fun e = get_error_callback();
179 						if (e) e(L);
180 
181 						assert(0 && "the lua function threw an error and exceptions are disabled."
182 								" If you want to handle the error you can use luabind::set_error_callback()");
183 						std::terminate();
184 #endif
185 					}
186 
187 					// pops the return values from the function call
188 					stack_pop pop(L, lua_gettop(L) - top + m_params);
189 
190 #ifndef LUABIND_NO_ERROR_CHECKING
191 
192 					if (converter.match(L, LUABIND_DECORATE_TYPE(Ret), -1) < 0)
193 					{
194 #ifndef LUABIND_NO_EXCEPTIONS
195 						throw cast_failed(L, typeid(Ret));
196 #else
197 						cast_failed_callback_fun e = get_cast_failed_callback();
198 						if (e) e(L, typeid(Ret));
199 
200 						assert(0 && "the lua function's return value could not be converted."
201 									" If you want to handle the error you can use luabind::set_error_callback()");
202 						std::terminate();
203 
204 #endif
205 					}
206 #endif
207 					return converter.apply(L, LUABIND_DECORATE_TYPE(Ret), -1);
208 				}
209 
210 			private:
211 
212 				lua_State* m_state;
213 				int m_params;
214 				function_t m_fun;
215 				Tuple m_args;
216 				mutable bool m_called;
217 
218 			};
219 
220 		// if the proxy_member_caller returns void
221 			template<class Tuple>
222 			class proxy_function_void_caller
223 			{
224 			friend class luabind::object;
225 			public:
226 
227 				typedef int(*function_t)(lua_State*, int, int);
228 
proxy_function_void_caller(lua_State * L,int params,function_t fun,const Tuple args)229 				proxy_function_void_caller(
230 					lua_State* L
231 					, int params
232 					, function_t fun
233 					, const Tuple args)
234 					: m_state(L)
235 					, m_params(params)
236 					, m_fun(fun)
237 					, m_args(args)
238 					, m_called(false)
239 				{
240 				}
241 
proxy_function_void_caller(const proxy_function_void_caller & rhs)242 				proxy_function_void_caller(const proxy_function_void_caller& rhs)
243 					: m_state(rhs.m_state)
244 					, m_params(rhs.m_params)
245 					, m_fun(rhs.m_fun)
246 					, m_args(rhs.m_args)
247 					, m_called(rhs.m_called)
248 				{
249 					rhs.m_called = true;
250 				}
251 
~proxy_function_void_caller()252 				~proxy_function_void_caller()
253 				{
254 					if (m_called) return;
255 
256 					m_called = true;
257 					lua_State* L = m_state;
258 
259 					int top = lua_gettop(L);
260 
261 					push_args_from_tuple<1>::apply(L, m_args);
262 					if (m_fun(L, boost::tuples::length<Tuple>::value, 0))
263 					{
264 						assert(lua_gettop(L) == top - m_params + 1);
265 #ifndef LUABIND_NO_EXCEPTIONS
266 						throw luabind::error(L);
267 #else
268 						error_callback_fun e = get_error_callback();
269 						if (e) e(L);
270 
271 						assert(0 && "the lua function threw an error and exceptions are disabled."
272 								" If you want to handle the error you can use luabind::set_error_callback()");
273 						std::terminate();
274 #endif
275 					}
276 					// pops the return values from the function call
277 					stack_pop pop(L, lua_gettop(L) - top + m_params);
278 				}
279 
280 				template<class Policies>
operator [](const Policies & p)281 				void operator[](const Policies& p)
282 				{
283 					m_called = true;
284 					lua_State* L = m_state;
285 
286 					int top = lua_gettop(L);
287 
288 					detail::push_args_from_tuple<1>::apply(L, m_args, p);
289 					if (m_fun(L, boost::tuples::length<Tuple>::value, 0))
290 					{
291 						assert(lua_gettop(L) == top - m_params + 1);
292 #ifndef LUABIND_NO_EXCEPTIONS
293 						throw error(L);
294 #else
295 						error_callback_fun e = get_error_callback();
296 						if (e) e(L);
297 
298 						assert(0 && "the lua function threw an error and exceptions are disabled."
299 							" If you want to handle the error you can use luabind::set_error_callback()");
300 						std::terminate();
301 #endif
302 					}
303 					// pops the return values from the function call
304 					stack_pop pop(L, lua_gettop(L) - top + m_params);
305 				}
306 
307 			private:
308 
309 				lua_State* m_state;
310 				int m_params;
311 				function_t m_fun;
312 				Tuple m_args;
313 				mutable bool m_called;
314 
315 			};
316 
317 	}
318 
319 	#define BOOST_PP_ITERATION_PARAMS_1 (4, (0, LUABIND_MAX_ARITY, <luabind/detail/call_function.hpp>, 1))
320 	#include BOOST_PP_ITERATE()
321 
322 }
323 
324 #endif // LUABIND_CALL_FUNCTION_HPP_INCLUDED
325 
326 #else
327 #if BOOST_PP_ITERATION_FLAGS() == 1
328 
329 #define LUABIND_TUPLE_PARAMS(z, n, data) const A##n *
330 #define LUABIND_OPERATOR_PARAMS(z, n, data) const A##n & a##n
331 
332 
333 	template<class Ret BOOST_PP_COMMA_IF(BOOST_PP_ITERATION()) BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), class A)>
334 	typename boost::mpl::if_<boost::is_void<Ret>
335 			, luabind::detail::proxy_function_void_caller<boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> >
336 			, luabind::detail::proxy_function_caller<Ret, boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> > >::type
call_function(lua_State * L,const char * name BOOST_PP_COMMA_IF (BOOST_PP_ITERATION ())BOOST_PP_ENUM (BOOST_PP_ITERATION (),LUABIND_OPERATOR_PARAMS,_))337 	call_function(lua_State* L, const char* name BOOST_PP_COMMA_IF(BOOST_PP_ITERATION()) BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_OPERATOR_PARAMS, _) )
338 	{
339 		assert(name && "luabind::call_function() expects a function name");
340 		typedef boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> tuple_t;
341 #if BOOST_PP_ITERATION() == 0
342 		tuple_t args;
343 #else
344 		tuple_t args(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), &a));
345 #endif
346 		typedef typename boost::mpl::if_<boost::is_void<Ret>
347 			, luabind::detail::proxy_function_void_caller<boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> >
348 			, luabind::detail::proxy_function_caller<Ret, boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> > >::type proxy_type;
349 
350 		lua_pushstring(L, name);
351 		lua_gettable(L, LUA_GLOBALSINDEX);
352 
353 		return proxy_type(L, 1, &detail::pcall, args);
354 	}
355 
356 	template<class Ret BOOST_PP_COMMA_IF(BOOST_PP_ITERATION()) BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), class A)>
357 	typename boost::mpl::if_<boost::is_void<Ret>
358 			, luabind::detail::proxy_function_void_caller<boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> >
359 			, luabind::detail::proxy_function_caller<Ret, boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> > >::type
call_function(luabind::object const & obj BOOST_PP_COMMA_IF (BOOST_PP_ITERATION ())BOOST_PP_ENUM (BOOST_PP_ITERATION (),LUABIND_OPERATOR_PARAMS,_))360 	call_function(luabind::object const& obj BOOST_PP_COMMA_IF(BOOST_PP_ITERATION()) BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_OPERATOR_PARAMS, _) )
361 	{
362 		typedef boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> tuple_t;
363 #if BOOST_PP_ITERATION() == 0
364 		tuple_t args;
365 #else
366 		tuple_t args(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), &a));
367 #endif
368 		typedef typename boost::mpl::if_<boost::is_void<Ret>
369 			, luabind::detail::proxy_function_void_caller<boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> >
370 			, luabind::detail::proxy_function_caller<Ret, boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> > >::type proxy_type;
371 
372 		obj.push(obj.interpreter());
373 		return proxy_type(obj.interpreter(), 1, &detail::pcall, args);
374 	}
375 
376 	template<class Ret BOOST_PP_COMMA_IF(BOOST_PP_ITERATION()) BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), class A)>
377 	typename boost::mpl::if_<boost::is_void<Ret>
378 			, luabind::detail::proxy_function_void_caller<boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> >
379 			, luabind::detail::proxy_function_caller<Ret, boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> > >::type
resume_function(lua_State * L,const char * name BOOST_PP_COMMA_IF (BOOST_PP_ITERATION ())BOOST_PP_ENUM (BOOST_PP_ITERATION (),LUABIND_OPERATOR_PARAMS,_))380 	resume_function(lua_State* L, const char* name BOOST_PP_COMMA_IF(BOOST_PP_ITERATION()) BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_OPERATOR_PARAMS, _) )
381 	{
382 		assert(name && "luabind::resume_function() expects a function name");
383 		typedef boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> tuple_t;
384 #if BOOST_PP_ITERATION() == 0
385 		tuple_t args;
386 #else
387 		tuple_t args(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), &a));
388 #endif
389 		typedef typename boost::mpl::if_<boost::is_void<Ret>
390 			, luabind::detail::proxy_function_void_caller<boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> >
391 			, luabind::detail::proxy_function_caller<Ret, boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> > >::type proxy_type;
392 
393 		lua_pushstring(L, name);
394 		lua_gettable(L, LUA_GLOBALSINDEX);
395 
396 		return proxy_type(L, 1, &detail::resume_impl, args);
397 	}
398 
399 	template<class Ret BOOST_PP_COMMA_IF(BOOST_PP_ITERATION()) BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), class A)>
400 	typename boost::mpl::if_<boost::is_void<Ret>
401 			, luabind::detail::proxy_function_void_caller<boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> >
402 			, luabind::detail::proxy_function_caller<Ret, boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> > >::type
resume_function(luabind::object const & obj BOOST_PP_COMMA_IF (BOOST_PP_ITERATION ())BOOST_PP_ENUM (BOOST_PP_ITERATION (),LUABIND_OPERATOR_PARAMS,_))403 	resume_function(luabind::object const& obj BOOST_PP_COMMA_IF(BOOST_PP_ITERATION()) BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_OPERATOR_PARAMS, _) )
404 	{
405 		typedef boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> tuple_t;
406 #if BOOST_PP_ITERATION() == 0
407 		tuple_t args;
408 #else
409 		tuple_t args(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), &a));
410 #endif
411 		typedef typename boost::mpl::if_<boost::is_void<Ret>
412 			, luabind::detail::proxy_function_void_caller<boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> >
413 			, luabind::detail::proxy_function_caller<Ret, boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> > >::type proxy_type;
414 
415 		obj.push(obj.interpreter());
416 		return proxy_type(obj.interpreter(), 1, &detail::resume_impl, args);
417 	}
418 
419 	template<class Ret BOOST_PP_COMMA_IF(BOOST_PP_ITERATION()) BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), class A)>
420 	typename boost::mpl::if_<boost::is_void<Ret>
421 			, luabind::detail::proxy_function_void_caller<boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> >
422 			, luabind::detail::proxy_function_caller<Ret, boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> > >::type
resume(lua_State * L BOOST_PP_COMMA_IF (BOOST_PP_ITERATION ())BOOST_PP_ENUM (BOOST_PP_ITERATION (),LUABIND_OPERATOR_PARAMS,_))423 	resume(lua_State* L BOOST_PP_COMMA_IF(BOOST_PP_ITERATION()) BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_OPERATOR_PARAMS, _) )
424 	{
425 		typedef boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> tuple_t;
426 #if BOOST_PP_ITERATION() == 0
427 		tuple_t args;
428 #else
429 		tuple_t args(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), &a));
430 #endif
431 		typedef typename boost::mpl::if_<boost::is_void<Ret>
432 			, luabind::detail::proxy_function_void_caller<boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> >
433 			, luabind::detail::proxy_function_caller<Ret, boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> > >::type proxy_type;
434 
435 		return proxy_type(L, 0, &detail::resume_impl, args);
436 	}
437 
438 
439 #undef LUABIND_OPERATOR_PARAMS
440 #undef LUABIND_TUPLE_PARAMS
441 
442 
443 #endif
444 #endif
445 
446