diff --git a/sol/call.hpp b/sol/call.hpp index 64ee4680..ca5977ed 100644 --- a/sol/call.hpp +++ b/sol/call.hpp @@ -53,7 +53,7 @@ namespace sol { static void call(Args...) {} }; - template + template struct constructor_match { T* obj; @@ -62,7 +62,7 @@ namespace sol { template int operator()(types, index_value, types r, types a, lua_State* L, int, int start) const { detail::default_construct func{}; - return stack::call_into_lua(r, a, L, start, func, obj); + return stack::call_into_lua(r, a, L, start, func, obj); } }; @@ -152,7 +152,7 @@ namespace sol { typedef typename wrap::returns_list returns_list; typedef typename wrap::free_args_list args_list; typedef typename wrap::caller caller; - return stack::call_into_lua(returns_list(), args_list(), L, boost + ( is_index ? 2 : 3 ), caller(), std::forward(f)); + return stack::call_into_lua(returns_list(), args_list(), L, boost + ( is_index ? 2 : 3 ), caller(), std::forward(f)); } template @@ -161,7 +161,7 @@ namespace sol { typedef typename wrap::free_args_list args_list; typedef typename wrap::returns_list returns_list; typedef typename wrap::caller caller; - return stack::call_into_lua<0, checked>(returns_list(), args_list(), L, boost + 1, caller(), std::forward(f)); + return stack::call_into_lua(returns_list(), args_list(), L, boost + 1, caller(), std::forward(f)); } template @@ -219,7 +219,7 @@ namespace sol { typedef typename wrap::returns_list returns_list; typedef typename wrap::args_list args_list; typedef typename wrap::caller caller; - return stack::call_into_lua(returns_list(), args_list(), L, boost + ( is_variable ? 3 : 2 ), caller(), std::forward(f), o); + return stack::call_into_lua(returns_list(), args_list(), L, boost + ( is_variable ? 3 : 2 ), caller(), std::forward(f), o); } template @@ -248,7 +248,7 @@ namespace sol { static int call_assign(std::true_type, lua_State* L, V&& f, object_type& o) { typedef typename wrap::args_list args_list; typedef typename wrap::caller caller; - return stack::call_into_lua(types(), args_list(), L, boost + ( is_variable ? 3 : 2 ), caller(), f, o); + return stack::call_into_lua(types(), args_list(), L, boost + ( is_variable ? 3 : 2 ), caller(), f, o); } template @@ -306,7 +306,7 @@ namespace sol { static int call(lua_State* L, V&& f, object_type& o) { typedef typename wrap::returns_list returns_list; typedef typename wrap::caller caller; - return stack::call_into_lua(returns_list(), types<>(), L, boost + ( is_variable ? 3 : 2 ), caller(), f, o); + return stack::call_into_lua(returns_list(), types<>(), L, boost + ( is_variable ? 3 : 2 ), caller(), f, o); } template @@ -344,7 +344,7 @@ namespace sol { T* obj = reinterpret_cast(pointerpointer + 1); referencepointer = obj; - construct_match(constructor_match(obj), L, argcount, boost + 1 + static_cast(syntax)); + construct_match(constructor_match(obj), L, argcount, boost + 1 + static_cast(syntax)); userdataref.push(); luaL_getmetatable(L, &metakey[0]); @@ -367,13 +367,13 @@ namespace sol { int operator()(types, index_value, types r, types a, lua_State* L, int, int start, F& f) { const auto& metakey = usertype_traits::metatable; T** pointerpointer = reinterpret_cast(lua_newuserdata(L, sizeof(T*) + sizeof(T))); - reference userdataref(L, -1); + stack_reference userdataref(L, -1); T*& referencepointer = *pointerpointer; T* obj = reinterpret_cast(pointerpointer + 1); referencepointer = obj; auto& func = std::get(f.set); - stack::call_into_lua<1, checked>(r, a, L, boost + start, func, detail::implicit_wrapper(obj)); + stack::call_into_lua(r, a, L, boost + start, func, detail::implicit_wrapper(obj)); userdataref.push(); luaL_getmetatable(L, &metakey[0]); diff --git a/sol/function_types_core.hpp b/sol/function_types_core.hpp index cc7cfbfb..24169ea7 100644 --- a/sol/function_types_core.hpp +++ b/sol/function_types_core.hpp @@ -28,11 +28,6 @@ namespace sol { namespace function_detail { - inline decltype(auto) cleanup_key() { - const auto& name = u8"sol.ƒ.♲.🗑.(/¯◡ ‿ ◡)/¯ ~ ┻━┻ (ノ◕ヮ◕)ノ*:・゚✧"; - return name; - } - template inline int call(lua_State* L) { Fx& fx = stack::get>(L, upvalue_index(1)); diff --git a/sol/function_types_stateful.hpp b/sol/function_types_stateful.hpp index a5b92a09..6846ed87 100644 --- a/sol/function_types_stateful.hpp +++ b/sol/function_types_stateful.hpp @@ -38,7 +38,7 @@ namespace sol { functor_function(Function f, Args&&... args) : fx(std::move(f), std::forward(args)...) {} int call(lua_State* L) { - return stack::call_into_lua(meta::tuple_types(), args_lists(), L, 1, fx); + return call_detail::call_wrapped(L, fx); } int operator()(lua_State* L) { @@ -52,35 +52,20 @@ namespace sol { typedef std::remove_pointer_t> function_type; typedef meta::function_return_t return_type; typedef meta::function_args_t args_lists; - struct functor { - function_type invocation; - T member; - - template - functor(function_type f, Args&&... args) : invocation(std::move(f)), member(std::forward(args)...) {} - - template - return_type operator()(Args&&... args) { - auto& mem = detail::unwrap(detail::deref(member)); - return (mem.*invocation)(std::forward(args)...); - } - } fx; + function_type invocation; + T member; template - member_function(function_type f, Args&&... args) : fx(std::move(f), std::forward(args)...) {} + member_function(function_type f, Args&&... args) : invocation(std::move(f)), member(std::forward(args)...) {} int call(lua_State* L) { - return stack::call_into_lua(meta::tuple_types(), args_lists(), L, 1, fx); + return call_detail::call_wrapped(L, invocation, detail::unwrap(detail::deref(member))); } int operator()(lua_State* L) { auto f = [&](lua_State* L) -> int { return this->call(L); }; return detail::trampoline(L, f); } - - ~member_function() { - - } }; template @@ -95,34 +80,13 @@ namespace sol { template member_variable(function_type v, Args&&... args) : var(std::move(v)), member(std::forward(args)...) {} - int set_assignable(std::false_type, lua_State* L, M) { - lua_pop(L, 1); - return luaL_error(L, "sol: cannot write to this type: copy assignment/constructor not available"); - } - - int set_assignable(std::true_type, lua_State* L, M mem) { - (mem.*var) = stack::get(L, 1); - lua_pop(L, 1); - return 0; - } - - int set_variable(std::true_type, lua_State* L, M mem) { - return set_assignable(std::is_assignable, return_type>(), L, mem); - } - - int set_variable(std::false_type, lua_State* L, M) { - lua_pop(L, 1); - return luaL_error(L, "sol: cannot write to a const variable"); - } - int call(lua_State* L) { M mem = detail::unwrap(detail::deref(member)); switch (lua_gettop(L)) { case 0: - stack::push(L, (mem.*var)); - return 1; + return call_detail::call_wrapped(L, var, mem); case 1: - return set_variable(meta::neg>(), L, mem); + return call_detail::call_wrapped(L, var, mem); default: return luaL_error(L, "sol: incorrect number of arguments to member variable function"); } diff --git a/sol/function_types_stateless.hpp b/sol/function_types_stateless.hpp index 0b880975..0b6e9072 100644 --- a/sol/function_types_stateless.hpp +++ b/sol/function_types_stateless.hpp @@ -34,8 +34,7 @@ namespace sol { static int real_call(lua_State* L) { auto udata = stack::stack_detail::get_as_upvalues(L); function_type* fx = udata.first; - int r = stack::call_into_lua(meta::tuple_types(), typename traits_type::args_list(), L, 1, fx); - return r; + return call_detail::call_wrapped(L, fx); } static int call(lua_State* L) { @@ -62,10 +61,7 @@ namespace sol { auto objdata = stack::stack_detail::get_as_upvalues(L, memberdata.second); function_type& memfx = memberdata.first; auto& item = *objdata.first; - auto fx = [&item, &memfx](auto&&... args) -> typename traits_type::return_type { - return (item.*memfx)(std::forward(args)...); - }; - return stack::call_into_lua(meta::tuple_types(), typename traits_type::args_list(), L, 1, fx); + return call_detail::call_wrapped(L, memfx, item); } static int call(lua_State* L) { @@ -77,30 +73,6 @@ namespace sol { } }; - template - int set_assignable(std::false_type, lua_State* L, M&, V&) { - lua_pop(L, N); - return luaL_error(L, "sol: cannot write to this type: copy assignment/constructor not available"); - } - - template - int set_assignable(std::true_type, lua_State* L, M& mem, V& var) { - (mem.*var) = stack::get(L, N); - lua_pop(L, N); - return 0; - } - - template - int set_variable(std::true_type, lua_State* L, M& mem, V& var) { - return set_assignable(std::is_assignable, R>(), L, mem, var); - } - - template - int set_variable(std::false_type, lua_State* L, M&, V&) { - lua_pop(L, N); - return luaL_error(L, "sol: cannot write to a const variable"); - } - template struct upvalue_member_variable { typedef std::remove_pointer_t> function_type; @@ -118,11 +90,9 @@ namespace sol { function_type& var = memberdata.first; switch (lua_gettop(L)) { case 0: - stack::push(L, (mem.*var)); - return 1; + return call_detail::call_wrapped(L, var, mem); case 1: - set_variable<1, typename traits_type::return_type>(meta::neg>(), L, mem, var); - return 0; + return call_detail::call_wrapped(L, var, mem); default: return luaL_error(L, "sol: incorrect number of arguments to member variable function"); } @@ -168,16 +138,12 @@ namespace sol { // Layout: // idx 1...n: verbatim data of member variable pointer auto memberdata = stack::stack_detail::get_as_upvalues(L, 1); - auto& mem = stack::get(L, 1); function_type& var = memberdata.first; switch (lua_gettop(L)) { case 1: - lua_pop(L, 1); - stack::push(L, (mem.*var)); - return 1; + return call_detail::call_wrapped(L, var); case 2: - set_variable<2, typename traits_type::return_type>(meta::neg>(), L, mem, var); - return 0; + return call_detail::call_wrapped(L, var); default: return luaL_error(L, "sol: incorrect number of arguments to member variable function"); } diff --git a/sol/function_types_templated.hpp b/sol/function_types_templated.hpp index bef33f6a..80989408 100644 --- a/sol/function_types_templated.hpp +++ b/sol/function_types_templated.hpp @@ -36,20 +36,17 @@ namespace sol { template inline int call_set_assignable(std::false_type, T&&, lua_State* L) { - lua_pop(L, 2); return luaL_error(L, "cannot write to this type: copy assignment/constructor not available"); } template inline int call_set_assignable(std::true_type, lua_State* L, T&& mem) { (mem.*variable) = stack::get(L, 2); - lua_pop(L, 2); return 0; } template inline int call_set_variable(std::false_type, lua_State* L, T&&) { - lua_pop(L, 2); return luaL_error(L, "cannot write to a const variable"); } @@ -67,7 +64,6 @@ namespace sol { switch (lua_gettop(L)) { case 1: { decltype(auto) r = (mem.*variable); - lua_pop(L, 1); stack::push_reference(L, std::forward(r)); return 1; } case 2: @@ -84,17 +80,7 @@ namespace sol { template inline int call_wrapper_function(std::true_type, lua_State* L) { - typedef meta::bind_traits> traits_type; - typedef typename traits_type::object_type T; - typedef typename traits_type::args_list args_list; - typedef typename traits_type::return_type return_type; - typedef meta::tuple_types return_type_list; - auto mfx = [&](auto&&... args) -> typename traits_type::return_type { - auto& member = stack::get(L, 1); - return (member.*fx)(std::forward(args)...); - }; - int n = stack::call_into_lua<1>(return_type_list(), args_list(), L, 2, mfx); - return n; + return call_detail::call_wrapped(L, fx); } template diff --git a/sol/stack.hpp b/sol/stack.hpp index c421f7dd..bc8858e4 100644 --- a/sol/stack.hpp +++ b/sol/stack.hpp @@ -145,23 +145,19 @@ namespace sol { call(tr, ta, L, static_cast(lua_gettop(L) - sizeof...(Args)), std::forward(fx), std::forward(args)...); } - template + template inline int call_into_lua(types tr, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { call(tr, ta, L, start, std::forward(fx), std::forward(fxargs)...); - int nargs = static_cast(sizeof...(Args)) + additionalpop - meta::count_for_pack::value; - lua_pop(L, nargs); return 0; } - template>::value>> + template>::value>> inline int call_into_lua(types, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { decltype(auto) r = call(types>(), ta, L, start, std::forward(fx), std::forward(fxargs)...); - int nargs = static_cast(sizeof...(Args)) + additionalpop - meta::count_for_pack::value; - lua_pop(L, nargs); return push_reference(L, std::forward(r)); } - template + template inline int call_lua(lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { typedef lua_bind_traits> traits_type; typedef typename traits_type::args_list args_list; diff --git a/sol/stack_check.hpp b/sol/stack_check.hpp index 2e76884b..cf7f7115 100644 --- a/sol/stack_check.hpp +++ b/sol/stack_check.hpp @@ -355,7 +355,7 @@ namespace sol { struct checker, type::poly, C> { template static bool check(lua_State* L, int index, Handler&& handler) { - return stack::check(L, index, no_panic) || stack::check(L, index, std::forward(handler)); + return lua_isnoneornil(L, index) || stack::check(L, index, std::forward(handler)); } }; } // stack diff --git a/sol/stack_check_get.hpp b/sol/stack_check_get.hpp index fba1abaa..ebab0734 100644 --- a/sol/stack_check_get.hpp +++ b/sol/stack_check_get.hpp @@ -95,7 +95,7 @@ namespace sol { template struct getter> { static decltype(auto) get(lua_State* L, int index) { - return check_get(L, index); + return check_get(L, index, no_panic); } }; } // stack diff --git a/sol/stack_push.hpp b/sol/stack_push.hpp index d79d3234..02591a26 100644 --- a/sol/stack_push.hpp +++ b/sol/stack_push.hpp @@ -287,12 +287,14 @@ namespace sol { std::allocator alloc; alloc.construct(data, std::forward(args)...); if (with_meta) { + const auto& name = "\x73\x6F\x6C\x2E\xC6\x92\x2E\xE2\x99\xB2\x2E\xF0\x9F\x97\x91\x2E\x28\x2F\xC2\xAF\xE2\x97\xA1\x20\xE2\x80\xBF\x20\xE2\x97\xA1\x29\x2F\xC2\xAF\x20\x7E\x20\xE2\x94\xBB\xE2\x94\x81\xE2\x94\xBB\x20\x28\xEF\xBE\x89\xE2\x97\x95\xE3\x83\xAE\xE2\x97\x95\x29\xEF\xBE\x89\x2A\x3A\xEF\xBD\xA5\xEF\xBE\x9F\xE2\x9C\xA7"; lua_CFunction cdel = stack_detail::alloc_destroy; // Make sure we have a plain GC set for this data - lua_createtable(L, 0, 1); - lua_pushlightuserdata(L, rawdata); - lua_pushcclosure(L, cdel, 1); - lua_setfield(L, -2, "__gc"); + if (luaL_newmetatable(L, name) != 0) { + lua_pushlightuserdata(L, rawdata); + lua_pushcclosure(L, cdel, 1); + lua_setfield(L, -2, "__gc"); + } lua_setmetatable(L, -2); } return 1; diff --git a/sol/wrapper.hpp b/sol/wrapper.hpp index 3ad82934..7e38d39f 100644 --- a/sol/wrapper.hpp +++ b/sol/wrapper.hpp @@ -93,19 +93,20 @@ namespace sol { return (mem.*fx)(std::forward(args)...); } - static decltype(auto) call(F& fx, object_type& mem) { + template + static decltype(auto) call(Fx&& fx, object_type& mem) { return (mem.*fx); } - template - static void call(F& fx, object_type& mem, Arg&& arg, Args&&...) { + template + static void call(Fx&& fx, object_type& mem, Arg&& arg, Args&&...) { (mem.*fx) = std::forward(arg); } struct caller { - template - decltype(auto) operator()(F& fx, object_type& mem, Args&&... args) const { - return call(fx, mem, std::forward(args)...); + template + decltype(auto) operator()(Fx&& fx, object_type& mem, Args&&... args) const { + return call(std::forward(fx), mem, std::forward(args)...); } }; @@ -131,15 +132,15 @@ namespace sol { return (mem.*fx)(std::forward(args)...); } - template - static R call(F& fx, O& mem, Args&&... args) { + template + static R call(Fx&& fx, O& mem, Args&&... args) { return (mem.*fx)(std::forward(args)...); } struct caller { - template - decltype(auto) operator()(F& fx, O& mem, Args&&... args) const { - return call(fx, mem, std::forward(args)...); + template + decltype(auto) operator()(Fx&& fx, O& mem, Args&&... args) const { + return call(std::forward(fx), mem, std::forward(args)...); } }; diff --git a/tests.cpp b/tests.cpp index cc440242..0698dfe5 100644 --- a/tests.cpp +++ b/tests.cpp @@ -9,6 +9,14 @@ #include #include "test_stack_guard.hpp" +bool func_opt_ret_bool(sol::optional i) { + if (i) + std::cout << i.value() << std::endl; + else + std::cout << "optional isn't set" << std::endl; + return true; +} + TEST_CASE("table/traversal", "ensure that we can chain requests and tunnel down into a value if we desire") { sol::state lua; @@ -536,3 +544,19 @@ TEST_CASE("regressions/std::ref", "Ensure that std::reference_wrapper<> isn't co REQUIRE(vp->a1 == 568); REQUIRE(vr.a1 == 568); } + +TEST_CASE("optional/left-out-args", "Make sure arguments can be left out of optional without tanking miserably") { + + sol::state lua; + lua.open_libraries(sol::lib::base); + + // sol::optional needs an argument no matter what + lua.set_function("func_opt_ret_bool", func_opt_ret_bool); + REQUIRE_NOTHROW( + lua.script(R"( + func_opt_ret_bool(42) + func_opt_ret_bool() + print('ok') + )"); + ); +}