Update catch, move yielding check up one level to avoid problems with trampoline and exception handling, and add a new test/example from an issue. Closes #906. Closes #917.

This commit is contained in:
ThePhD 2020-01-17 05:22:52 -05:00
parent 1c89390356
commit c77b5b432e
No known key found for this signature in database
GPG Key ID: 1509DB1C0F702BFA
9 changed files with 164 additions and 20 deletions

View File

@ -28,7 +28,7 @@ include(Common/Core)
if (Catch_FIND_VERSION) if (Catch_FIND_VERSION)
set(catch_version ${Catch_FIND_VERSION}) set(catch_version ${Catch_FIND_VERSION})
else() else()
set(catch_version 2.11.0) set(catch_version 2.11.1)
endif() endif()
set(catch_lib catch_lib_${catch_version}) set(catch_lib catch_lib_${catch_version})

View File

@ -26,7 +26,7 @@ cmake_minimum_required(VERSION 3.5.0)
find_package(Python3 COMPONENTS Interpreter) find_package(Python3 COMPONENTS Interpreter)
if (NOT Python3_Interpreter_FOUND) if (NOT Python3_FOUND AND NOT Python3_Interpreter_FOUND)
message(FATAL_ERROR "sol2 documentation cannot be generated as python 3 has not been found: install or set the python 3 interpreter for the docs to find it and be sure to pip install sphinx") message(FATAL_ERROR "sol2 documentation cannot be generated as python 3 has not been found: install or set the python 3 interpreter for the docs to find it and be sure to pip install sphinx")
endif() endif()

View File

@ -0,0 +1,46 @@
#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>
#include "assert.hpp"
#include <memory>
#include <iostream>
struct Shape {
virtual ~Shape() = default;
};
struct Box : Shape {};
SOL_BASE_CLASSES(Box, Shape);
SOL_DERIVED_CLASSES(Shape, Box);
int main() {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_usertype<Shape>("Shape", sol::no_constructor);
lua.new_usertype<Box>("Box", sol::factories([&]() {
auto b = std::make_shared<Box>();
std::cout << "create Box@" << std::hex << b.get() << '\n';
return b;
}));
lua.set_function("inspect_shape_table", [](const sol::table& args) {
std::shared_ptr<Shape> defbox = nullptr;
// check if there's a field with the name "shape"
auto s = args.get<sol::optional<std::shared_ptr<Shape>>>("shape");
std::cout << "has : " << std::boolalpha << s.has_value() << '\n';
// get the field named "shape" or use the default value
std::cout << "get_or: " << std::hex << args.get_or<std::shared_ptr<Shape>>("shape", defbox).get() << '\n';
// this works but I can't test for existence beforehand...
std::cout << "get : " << std::hex << args.get<std::shared_ptr<Shape>>("shape").get() << '\n';
});
sol::protected_function_result result = lua.safe_script("inspect_shape_table({shape=Box.new()})");
c_assert(result.valid());
return 0;
}

View File

@ -867,8 +867,7 @@ namespace sol {
if constexpr (meta::is_specialization_of_v<uFx, yielding_t>) { if constexpr (meta::is_specialization_of_v<uFx, yielding_t>) {
using real_fx = meta::unqualified_t<decltype(std::forward<Fx>(fx).func)>; using real_fx = meta::unqualified_t<decltype(std::forward<Fx>(fx).func)>;
lua_call_wrapper<T, real_fx, is_index, is_variable, checked, boost, clean_stack> lcw{}; lua_call_wrapper<T, real_fx, is_index, is_variable, checked, boost, clean_stack> lcw{};
int nr = lcw.call(L, std::forward<Fx>(fx).func, std::forward<Args>(args)...); return lcw.call(L, std::forward<Fx>(fx).func, std::forward<Args>(args)...);
return lua_yield(L, nr);
} }
else { else {
lua_call_wrapper<T, uFx, is_index, is_variable, checked, boost, clean_stack> lcw{}; lua_call_wrapper<T, uFx, is_index, is_variable, checked, boost, clean_stack> lcw{};
@ -880,7 +879,14 @@ namespace sol {
bool clean_stack = true> bool clean_stack = true>
inline int call_user(lua_State* L) { inline int call_user(lua_State* L) {
auto& fx = stack::unqualified_get<user<F>>(L, upvalue_index(start)); auto& fx = stack::unqualified_get<user<F>>(L, upvalue_index(start));
return call_wrapped<T, is_index, is_variable, 0, checked, clean_stack>(L, fx); using uFx = meta::unqualified_t<F>;
int nr = call_wrapped<T, is_index, is_variable, 0, checked, clean_stack>(L, fx);
if constexpr (meta::is_specialization_of_v<uFx, yielding_t>) {
return lua_yield(L, nr);
}
else {
return nr;
}
} }
template <typename T, typename = void> template <typename T, typename = void>

View File

@ -59,8 +59,25 @@ namespace sol { namespace stack {
template <typename T> template <typename T>
struct qualified_getter<optional<T>> { struct qualified_getter<optional<T>> {
static decltype(auto) get(lua_State* L, int index, record& tracking) { static optional<T> get(lua_State* L, int index, record& tracking) {
return check_get<T>(L, index, no_panic, tracking); if constexpr (is_lua_reference_v<T>) {
// actually check if it's none here, otherwise
// we'll have a none object inside an optional!
bool success = lua_isnoneornil(L, index) == 0 && stack::check<T>(L, index, no_panic);
if (!success) {
// expected type, actual type
tracking.use(static_cast<int>(success));
return nullopt;
}
return stack_detail::unchecked_get<T>(L, index, tracking);
}
else {
if (!check<T>(L, index, &no_panic)) {
tracking.use(static_cast<int>(!lua_isnone(L, index)));
return nullopt;
}
return stack_detail::unchecked_get<T>(L, index, tracking);
}
} }
}; };

View File

@ -918,6 +918,20 @@ namespace sol {
} }
} }
template <typename T, typename... Args>
int push_userdata(lua_State* L, T&& t, Args&&... args) {
using U = meta::unqualified_t<T>;
using Tr = meta::conditional_t<std::is_pointer<U>::value, detail::as_pointer_tag<std::remove_pointer_t<U>>, detail::as_value_tag<U>>;
return stack::push<Tr>(L, std::forward<T>(t), std::forward<Args>(args)...);
}
template <typename T, typename Arg, typename... Args>
int push_userdata(lua_State* L, Arg&& arg, Args&&... args) {
using U = meta::unqualified_t<T>;
using Tr = meta::conditional_t<std::is_pointer<U>::value, detail::as_pointer_tag<std::remove_pointer_t<U>>, detail::as_value_tag<U>>;
return stack::push<Tr>(L, std::forward<Arg>(arg), std::forward<Args>(args)...);
}
namespace stack_detail { namespace stack_detail {
template <typename T, typename Arg, typename... Args> template <typename T, typename Arg, typename... Args>

View File

@ -97,7 +97,13 @@ namespace sol { namespace u_detail {
template <bool is_index = true, bool is_variable = false> template <bool is_index = true, bool is_variable = false>
static inline int call(lua_State* L) { static inline int call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&call_<is_index, is_variable>), (&call_<is_index, is_variable>)>(L); int r = detail::typed_static_trampoline<decltype(&call_<is_index, is_variable>), (&call_<is_index, is_variable>)>(L);
if constexpr (meta::is_specialization_of_v<uF, yielding_t>) {
return lua_yield(L, r);
}
else {
return r;
}
} }
template <bool is_index = true, bool is_variable = false> template <bool is_index = true, bool is_variable = false>
@ -132,7 +138,13 @@ namespace sol { namespace u_detail {
template <bool is_index = true, bool is_variable = false> template <bool is_index = true, bool is_variable = false>
static inline int index_call(lua_State* L) { static inline int index_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&index_call_<is_index, is_variable>), (&index_call_<is_index, is_variable>)>(L); int r = detail::typed_static_trampoline<decltype(&index_call_<is_index, is_variable>), (&index_call_<is_index, is_variable>)>(L);
if constexpr (meta::is_specialization_of_v<uF, yielding_t>) {
return lua_yield(L, r);
}
else {
return r;
}
} }
}; };

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script. // This file was generated with a script.
// Generated 2020-01-08 11:39:55.025761 UTC // Generated 2020-01-17 10:21:31.165776 UTC
// This header was generated with sol v3.2.0 (revision 43f215c) // This header was generated with sol v3.2.0 (revision 1c89390)
// https://github.com/ThePhD/sol2 // https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP #ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script. // This file was generated with a script.
// Generated 2020-01-08 11:39:54.499598 UTC // Generated 2020-01-17 10:21:30.504542 UTC
// This header was generated with sol v3.2.0 (revision 43f215c) // This header was generated with sol v3.2.0 (revision 1c89390)
// https://github.com/ThePhD/sol2 // https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_HPP #ifndef SOL_SINGLE_INCLUDE_HPP
@ -10361,6 +10361,20 @@ namespace sol {
} }
} }
template <typename T, typename... Args>
int push_userdata(lua_State* L, T&& t, Args&&... args) {
using U = meta::unqualified_t<T>;
using Tr = meta::conditional_t<std::is_pointer<U>::value, detail::as_pointer_tag<std::remove_pointer_t<U>>, detail::as_value_tag<U>>;
return stack::push<Tr>(L, std::forward<T>(t), std::forward<Args>(args)...);
}
template <typename T, typename Arg, typename... Args>
int push_userdata(lua_State* L, Arg&& arg, Args&&... args) {
using U = meta::unqualified_t<T>;
using Tr = meta::conditional_t<std::is_pointer<U>::value, detail::as_pointer_tag<std::remove_pointer_t<U>>, detail::as_value_tag<U>>;
return stack::push<Tr>(L, std::forward<Arg>(arg), std::forward<Args>(args)...);
}
namespace stack_detail { namespace stack_detail {
template <typename T, typename Arg, typename... Args> template <typename T, typename Arg, typename... Args>
@ -13053,8 +13067,25 @@ namespace sol { namespace stack {
template <typename T> template <typename T>
struct qualified_getter<optional<T>> { struct qualified_getter<optional<T>> {
static decltype(auto) get(lua_State* L, int index, record& tracking) { static optional<T> get(lua_State* L, int index, record& tracking) {
return check_get<T>(L, index, no_panic, tracking); if constexpr (is_lua_reference_v<T>) {
// actually check if it's none here, otherwise
// we'll have a none object inside an optional!
bool success = lua_isnoneornil(L, index) == 0 && stack::check<T>(L, index, no_panic);
if (!success) {
// expected type, actual type
tracking.use(static_cast<int>(success));
return nullopt;
}
return stack_detail::unchecked_get<T>(L, index, tracking);
}
else {
if (!check<T>(L, index, &no_panic)) {
tracking.use(static_cast<int>(!lua_isnone(L, index)));
return nullopt;
}
return stack_detail::unchecked_get<T>(L, index, tracking);
}
} }
}; };
@ -16991,8 +17022,7 @@ namespace sol {
if constexpr (meta::is_specialization_of_v<uFx, yielding_t>) { if constexpr (meta::is_specialization_of_v<uFx, yielding_t>) {
using real_fx = meta::unqualified_t<decltype(std::forward<Fx>(fx).func)>; using real_fx = meta::unqualified_t<decltype(std::forward<Fx>(fx).func)>;
lua_call_wrapper<T, real_fx, is_index, is_variable, checked, boost, clean_stack> lcw{}; lua_call_wrapper<T, real_fx, is_index, is_variable, checked, boost, clean_stack> lcw{};
int nr = lcw.call(L, std::forward<Fx>(fx).func, std::forward<Args>(args)...); return lcw.call(L, std::forward<Fx>(fx).func, std::forward<Args>(args)...);
return lua_yield(L, nr);
} }
else { else {
lua_call_wrapper<T, uFx, is_index, is_variable, checked, boost, clean_stack> lcw{}; lua_call_wrapper<T, uFx, is_index, is_variable, checked, boost, clean_stack> lcw{};
@ -17004,7 +17034,14 @@ namespace sol {
bool clean_stack = true> bool clean_stack = true>
inline int call_user(lua_State* L) { inline int call_user(lua_State* L) {
auto& fx = stack::unqualified_get<user<F>>(L, upvalue_index(start)); auto& fx = stack::unqualified_get<user<F>>(L, upvalue_index(start));
return call_wrapped<T, is_index, is_variable, 0, checked, clean_stack>(L, fx); using uFx = meta::unqualified_t<F>;
int nr = call_wrapped<T, is_index, is_variable, 0, checked, clean_stack>(L, fx);
if constexpr (meta::is_specialization_of_v<uFx, yielding_t>) {
return lua_yield(L, nr);
}
else {
return nr;
}
} }
template <typename T, typename = void> template <typename T, typename = void>
@ -21251,7 +21288,13 @@ namespace sol { namespace u_detail {
template <bool is_index = true, bool is_variable = false> template <bool is_index = true, bool is_variable = false>
static inline int call(lua_State* L) { static inline int call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&call_<is_index, is_variable>), (&call_<is_index, is_variable>)>(L); int r = detail::typed_static_trampoline<decltype(&call_<is_index, is_variable>), (&call_<is_index, is_variable>)>(L);
if constexpr (meta::is_specialization_of_v<uF, yielding_t>) {
return lua_yield(L, r);
}
else {
return r;
}
} }
template <bool is_index = true, bool is_variable = false> template <bool is_index = true, bool is_variable = false>
@ -21286,7 +21329,13 @@ namespace sol { namespace u_detail {
template <bool is_index = true, bool is_variable = false> template <bool is_index = true, bool is_variable = false>
static inline int index_call(lua_State* L) { static inline int index_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&index_call_<is_index, is_variable>), (&index_call_<is_index, is_variable>)>(L); int r = detail::typed_static_trampoline<decltype(&index_call_<is_index, is_variable>), (&index_call_<is_index, is_variable>)>(L);
if constexpr (meta::is_specialization_of_v<uF, yielding_t>) {
return lua_yield(L, r);
}
else {
return r;
}
} }
}; };