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