"automatic usertypes" are now applied everywhere, regardless of what happens

new sol::filters (currently undocumented)
new gc tests, new plain_type tests
core abstractions over usertypes streamlined
SOL_STRINGS_ARE_NUMBERS triggers added
update single
This commit is contained in:
ThePhD 2017-08-21 15:25:43 -04:00
parent 488edd9cd1
commit 0c9d567d0a
50 changed files with 3534 additions and 1856 deletions

View File

@ -121,6 +121,7 @@ Thanks to `Eric (EToreo) for the suggestion on this one`_!
sol::load_result load(lua_Reader reader, void* data, const std::string& chunk_name = "[string]", load_mode mode = load_mode::any); sol::load_result load(lua_Reader reader, void* data, const std::string& chunk_name = "[string]", load_mode mode = load_mode::any);
sol::load_result load(const string_view& code, const std::string& chunk_name = "[string]", load_mode mode = load_mode::any); sol::load_result load(const string_view& code, const std::string& chunk_name = "[string]", load_mode mode = load_mode::any);
sol::load_result load_buffer(const char* buff, std::size_t buffsize, const std::string& chunk_name = "[string]", load_mode mode = load_mode::any);
sol::load_result load_file(const std::string& filename, load_mode mode = load_mode::any); sol::load_result load_file(const std::string& filename, load_mode mode = load_mode::any);
These functions *load* the desired blob of either code that is in a string, or code that comes from a filename, on the ``lua_State*``. That blob will be turned into a Lua Function. It will not be run: it returns a ``load_result`` proxy that can be called to actually run the code, when you are ready. It can also be turned into a ``sol::function``, a ``sol::protected_function``, or some other abstraction that can serve to call the function. If it is called, it will run on the object's current ``lua_State*``: it is not isolated. If you need isolation, consider using :doc:`sol::environment<environment>`, creating a new state, or other Lua sandboxing techniques. These functions *load* the desired blob of either code that is in a string, or code that comes from a filename, on the ``lua_State*``. That blob will be turned into a Lua Function. It will not be run: it returns a ``load_result`` proxy that can be called to actually run the code, when you are ready. It can also be turned into a ``sol::function``, a ``sol::protected_function``, or some other abstraction that can serve to call the function. If it is called, it will run on the object's current ``lua_State*``: it is not isolated. If you need isolation, consider using :doc:`sol::environment<environment>`, creating a new state, or other Lua sandboxing techniques.

View File

@ -16,7 +16,14 @@ Note that you can obtain safety with regards to functions you bind by using the
``SOL_SAFE_FUNCTION`` triggers the following change: ``SOL_SAFE_FUNCTION`` triggers the following change:
* All uses of ``sol::function`` and ``sol::stack_function`` will default to ``sol::protected_function`` and ``sol::stack_protected_function``, respectively, rather than ``sol::unsafe_function`` and ``sol::stack_unsafe_function``. * All uses of ``sol::function`` and ``sol::stack_function`` will default to ``sol::protected_function`` and ``sol::stack_protected_function``, respectively, rather than ``sol::unsafe_function`` and ``sol::stack_unsafe_function``.
* **Not** turned on by default under any detectible compiler settings: *you must turn this one on manually* * **Not** turned on by default under any detectible compiler settings: *you MUST turn this one on manually*
``SOL_STRINGS_ARE_NUMBERS`` triggers the following changes:
* ``sol::stack::get`` and ``sol::stack::check_get`` will allow anything that Lua thinks is number-worthy to be number-worthy
* This includes: integers, numbers, and strings
* Does **not** include: booleans, types with ``__tostring`` enabled, and everything else
* Overrides ``SOL_CHECK_ARGUMENTS`` and always applies if it is turned on
* **Not** turned on by default under any settings: *you MUST be turned on manually*
``SOL_CHECK_ARGUMENTS`` triggers the following changes: ``SOL_CHECK_ARGUMENTS`` triggers the following changes:
* ``sol::stack::get`` (used everywhere) defaults to using ``sol::stack::check_get`` and dereferencing the argument. It uses ``sol::type_panic`` as the handler if something goes wrong * ``sol::stack::get`` (used everywhere) defaults to using ``sol::stack::check_get`` and dereferencing the argument. It uses ``sol::type_panic`` as the handler if something goes wrong

File diff suppressed because it is too large Load Diff

View File

@ -25,14 +25,66 @@
#include "protect.hpp" #include "protect.hpp"
#include "wrapper.hpp" #include "wrapper.hpp"
#include "property.hpp" #include "property.hpp"
#include "filters.hpp"
#include "stack.hpp" #include "stack.hpp"
namespace sol { namespace sol {
namespace usertype_detail {
} // usertype_detail
namespace filter_detail {
template <int I, int... In>
inline void handle_filter(static_stack_dependencies<I, In...>, lua_State* L, int&) {
if (sizeof...(In) == 0) {
return;
}
absolute_index ai(L, I);
if (type_of(L, ai) != type::userdata) {
return;
}
lua_createtable(L, static_cast<int>(sizeof...(In)), 0);
stack_reference deps(L, -1);
auto per_dep = [&L, &deps](int i) {
lua_pushvalue(L, i);
luaL_ref(L, deps.stack_index());
};
(void)per_dep;
(void)detail::swallow{ int(), (per_dep(In), int())... };
lua_setuservalue(L, ai);
}
template <int... In>
inline void handle_filter(returns_self_with<In...>, lua_State* L, int& pushed) {
pushed = stack::push(L, raw_index(1));
handle_filter(static_stack_dependencies<-1, In...>(), L, pushed);
}
inline void handle_filter(const stack_dependencies& sdeps, lua_State* L, int&) {
absolute_index ai(L, sdeps.target);
if (type_of(L, ai) != type::userdata) {
return;
}
lua_createtable(L, static_cast<int>(sdeps.size()), 0);
stack_reference deps(L, -1);
for (std::size_t i = 0; i < sdeps.size(); ++i) {
lua_pushvalue(L, sdeps.stack_indices[i]);
luaL_ref(L, deps.stack_index());
}
lua_setuservalue(L, ai);
}
template <typename P, meta::disable<std::is_base_of<detail::filter_base_tag, meta::unqualified_t<P>>> = meta::enabler>
inline void handle_filter(P&& p, lua_State* L, int& pushed) {
pushed = std::forward<P>(p)(L, pushed);
}
} // filter_detail
namespace function_detail { namespace function_detail {
inline int no_construction_error(lua_State* L) { inline int no_construction_error(lua_State* L) {
return luaL_error(L, "sol: cannot call this constructor (tagged as non-constructible)"); return luaL_error(L, "sol: cannot call this constructor (tagged as non-constructible)");
} }
} } // function_detail
namespace call_detail { namespace call_detail {
@ -54,7 +106,7 @@ namespace sol {
static void call(Args...) {} static void call(Args...) {}
}; };
template <typename T> template <typename T, bool checked, bool clean_stack>
struct constructor_match { struct constructor_match {
T* obj; T* obj;
@ -63,7 +115,7 @@ namespace sol {
template <typename Fx, std::size_t I, typename... R, typename... Args> template <typename Fx, std::size_t I, typename... R, typename... Args>
int operator()(types<Fx>, index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) const { int operator()(types<Fx>, index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) const {
detail::default_construct func{}; detail::default_construct func{};
return stack::call_into_lua<stack::stack_detail::default_check_arguments>(r, a, L, start, func, obj); return stack::call_into_lua<checked, clean_stack>(r, a, L, start, func, obj);
} }
}; };
@ -149,7 +201,7 @@ namespace sol {
return overload_match_arity<decltype(void_call<T, TypeLists>::call)...>(std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...); return overload_match_arity<decltype(void_call<T, TypeLists>::call)...>(std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
} }
template <typename T, typename... TypeLists> template <typename T, bool checked, bool clean_stack, typename... TypeLists>
inline int construct(lua_State* L) { inline int construct(lua_State* L) {
static const auto& meta = usertype_traits<T>::metatable(); static const auto& meta = usertype_traits<T>::metatable();
int argcount = lua_gettop(L); int argcount = lua_gettop(L);
@ -163,7 +215,7 @@ namespace sol {
reference userdataref(L, -1); reference userdataref(L, -1);
userdataref.pop(); userdataref.pop();
construct_match<T, TypeLists...>(constructor_match<T>(obj), L, argcount, 1 + static_cast<int>(syntax)); construct_match<T, TypeLists...>(constructor_match<T, checked, clean_stack>(obj), L, argcount, 1 + static_cast<int>(syntax));
userdataref.push(); userdataref.push();
luaL_getmetatable(L, &meta[0]); luaL_getmetatable(L, &meta[0]);
@ -176,7 +228,7 @@ namespace sol {
return 1; return 1;
} }
template <typename F, bool is_index, bool is_variable, bool checked, int boost, typename = void> template <typename F, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename = void>
struct agnostic_lua_call_wrapper { struct agnostic_lua_call_wrapper {
template <typename Fx, typename... Args> template <typename Fx, typename... Args>
static int call(lua_State* L, Fx&& f, Args&&... args) { static int call(lua_State* L, Fx&& f, Args&&... args) {
@ -184,23 +236,30 @@ namespace sol {
typedef typename wrap::returns_list returns_list; typedef typename wrap::returns_list returns_list;
typedef typename wrap::free_args_list args_list; typedef typename wrap::free_args_list args_list;
typedef typename wrap::caller caller; typedef typename wrap::caller caller;
return stack::call_into_lua<checked>(returns_list(), args_list(), L, boost + 1, caller(), std::forward<Fx>(f), std::forward<Args>(args)...); return stack::call_into_lua<checked, clean_stack>(returns_list(), args_list(), L, boost + 1, caller(), std::forward<Fx>(f), std::forward<Args>(args)...);
} }
}; };
template <typename T, bool is_variable, bool checked, int boost, typename C> template <typename T, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct agnostic_lua_call_wrapper<var_wrapper<T>, true, is_variable, checked, boost, C> { struct agnostic_lua_call_wrapper<var_wrapper<T>, true, is_variable, checked, boost, clean_stack, C> {
template <typename F> template <typename F>
static int call(lua_State* L, F&& f) { static int call(lua_State* L, F&& f) {
typedef is_stack_based<meta::unqualified_t<decltype(detail::unwrap(f.value))>> is_stack;
if (clean_stack && !is_stack::value) {
lua_settop(L, 0);
}
return stack::push_reference(L, detail::unwrap(f.value)); return stack::push_reference(L, detail::unwrap(f.value));
} }
}; };
template <typename T, bool is_variable, bool checked, int boost, typename C> template <typename T, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct agnostic_lua_call_wrapper<var_wrapper<T>, false, is_variable, checked, boost, C> { struct agnostic_lua_call_wrapper<var_wrapper<T>, false, is_variable, checked, boost, clean_stack, C> {
template <typename V> template <typename V>
static int call_assign(std::true_type, lua_State* L, V&& f) { static int call_assign(std::true_type, lua_State* L, V&& f) {
detail::unwrap(f.value) = stack::get<meta::unwrapped_t<T>>(L, boost + (is_variable ? 3 : 1)); detail::unwrap(f.value) = stack::get<meta::unwrapped_t<T>>(L, boost + (is_variable ? 3 : 1));
if (clean_stack) {
lua_settop(L, 0);
}
return 0; return 0;
} }
@ -226,63 +285,63 @@ namespace sol {
} }
}; };
template <bool is_index, bool is_variable, bool checked, int boost, typename C> template <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct agnostic_lua_call_wrapper<lua_r_CFunction, is_index, is_variable, checked, boost, C> { struct agnostic_lua_call_wrapper<lua_r_CFunction, is_index, is_variable, checked, boost, clean_stack, C> {
static int call(lua_State* L, lua_r_CFunction f) { static int call(lua_State* L, lua_r_CFunction f) {
return f(L); return f(L);
} }
}; };
template <bool is_index, bool is_variable, bool checked, int boost, typename C> template <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct agnostic_lua_call_wrapper<lua_CFunction, is_index, is_variable, checked, boost, C> { struct agnostic_lua_call_wrapper<lua_CFunction, is_index, is_variable, checked, boost, clean_stack, C> {
static int call(lua_State* L, lua_CFunction f) { static int call(lua_State* L, lua_CFunction f) {
return f(L); return f(L);
} }
}; };
#ifdef SOL_NOEXCEPT_FUNCTION_TYPE #ifdef SOL_NOEXCEPT_FUNCTION_TYPE
template <bool is_index, bool is_variable, bool checked, int boost, typename C> template <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct agnostic_lua_call_wrapper<detail::lua_CFunction_noexcept, is_index, is_variable, checked, boost, C> { struct agnostic_lua_call_wrapper<detail::lua_CFunction_noexcept, is_index, is_variable, checked, boost, clean_stack, C> {
static int call(lua_State* L, detail::lua_CFunction_noexcept f) { static int call(lua_State* L, detail::lua_CFunction_noexcept f) {
return f(L); return f(L);
} }
}; };
#endif // noexcept function types #endif // noexcept function types
template <bool is_index, bool is_variable, bool checked, int boost, typename C> template <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct agnostic_lua_call_wrapper<no_prop, is_index, is_variable, checked, boost, C> { struct agnostic_lua_call_wrapper<no_prop, is_index, is_variable, checked, boost, clean_stack, C> {
static int call(lua_State* L, const no_prop&) { static int call(lua_State* L, const no_prop&) {
return luaL_error(L, is_index ? "sol: cannot read from a writeonly property" : "sol: cannot write to a readonly property"); return luaL_error(L, is_index ? "sol: cannot read from a writeonly property" : "sol: cannot write to a readonly property");
} }
}; };
template <bool is_index, bool is_variable, bool checked, int boost, typename C> template <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct agnostic_lua_call_wrapper<no_construction, is_index, is_variable, checked, boost, C> { struct agnostic_lua_call_wrapper<no_construction, is_index, is_variable, checked, boost, clean_stack, C> {
static int call(lua_State* L, const no_construction&) { static int call(lua_State* L, const no_construction&) {
return function_detail::no_construction_error(L); return function_detail::no_construction_error(L);
} }
}; };
template <typename... Args, bool is_index, bool is_variable, bool checked, int boost, typename C> template <typename... Args, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct agnostic_lua_call_wrapper<bases<Args...>, is_index, is_variable, checked, boost, C> { struct agnostic_lua_call_wrapper<bases<Args...>, is_index, is_variable, checked, boost, clean_stack, C> {
static int call(lua_State*, const bases<Args...>&) { static int call(lua_State*, const bases<Args...>&) {
// Uh. How did you even call this, lul // Uh. How did you even call this, lul
return 0; return 0;
} }
}; };
template <typename T, bool is_index, bool is_variable, bool checked, int boost, typename C> template <typename T, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct agnostic_lua_call_wrapper<std::reference_wrapper<T>, is_index, is_variable, checked, boost, C> { struct agnostic_lua_call_wrapper<std::reference_wrapper<T>, is_index, is_variable, checked, boost, clean_stack, C> {
static int call(lua_State* L, std::reference_wrapper<T> f) { static int call(lua_State* L, std::reference_wrapper<T> f) {
return agnostic_lua_call_wrapper<T, is_index, is_variable, checked, boost>{}.call(L, f.get()); return agnostic_lua_call_wrapper<T, is_index, is_variable, checked, boost, clean_stack>{}.call(L, f.get());
} }
}; };
template <typename T, typename F, bool is_index, bool is_variable, bool checked = stack::stack_detail::default_check_arguments, int boost = 0, typename = void> template <typename T, typename F, bool is_index, bool is_variable, bool checked = stack::stack_detail::default_check_arguments, int boost = 0, bool clean_stack = true, typename = void>
struct lua_call_wrapper : agnostic_lua_call_wrapper<F, is_index, is_variable, checked, boost> {}; struct lua_call_wrapper : agnostic_lua_call_wrapper<F, is_index, is_variable, checked, boost, clean_stack> {};
template <typename T, typename F, bool is_index, bool is_variable, bool checked, int boost> template <typename T, typename F, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack>
struct lua_call_wrapper<T, F, is_index, is_variable, checked, boost, std::enable_if_t<std::is_member_function_pointer<F>::value>> { struct lua_call_wrapper<T, F, is_index, is_variable, checked, boost, clean_stack, std::enable_if_t<std::is_member_function_pointer<F>::value>> {
typedef wrapper<meta::unqualified_t<F>> wrap; typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::object_type object_type; typedef typename wrap::object_type object_type;
@ -291,7 +350,7 @@ namespace sol {
typedef typename wrap::returns_list returns_list; typedef typename wrap::returns_list returns_list;
typedef typename wrap::args_list args_list; typedef typename wrap::args_list args_list;
typedef typename wrap::caller caller; typedef typename wrap::caller caller;
return stack::call_into_lua<checked>(returns_list(), args_list(), L, boost + ( is_variable ? 3 : 2 ), caller(), std::forward<Fx>(f), o); return stack::call_into_lua<checked, clean_stack>(returns_list(), args_list(), L, boost + ( is_variable ? 3 : 2 ), caller(), std::forward<Fx>(f), o);
} }
template <typename Fx> template <typename Fx>
@ -311,8 +370,8 @@ namespace sol {
} }
}; };
template <typename T, typename F, bool is_variable, bool checked, int boost> template <typename T, typename F, bool is_variable, bool checked, int boost, bool clean_stack>
struct lua_call_wrapper<T, F, false, is_variable, checked, boost, std::enable_if_t<std::is_member_object_pointer<F>::value>> { struct lua_call_wrapper<T, F, false, is_variable, checked, boost, clean_stack, std::enable_if_t<std::is_member_object_pointer<F>::value>> {
typedef lua_bind_traits<F> traits_type; typedef lua_bind_traits<F> traits_type;
typedef wrapper<meta::unqualified_t<F>> wrap; typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::object_type object_type; typedef typename wrap::object_type object_type;
@ -321,7 +380,7 @@ namespace sol {
static int call_assign(std::true_type, lua_State* L, V&& f, object_type& o) { 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::args_list args_list;
typedef typename wrap::caller caller; typedef typename wrap::caller caller;
return stack::call_into_lua<checked>(types<void>(), args_list(), L, boost + ( is_variable ? 3 : 2 ), caller(), f, o); return stack::call_into_lua<checked, clean_stack>(types<void>(), args_list(), L, boost + ( is_variable ? 3 : 2 ), caller(), f, o);
} }
template <typename V> template <typename V>
@ -370,8 +429,8 @@ namespace sol {
} }
}; };
template <typename T, typename F, bool is_variable, bool checked, int boost> template <typename T, typename F, bool is_variable, bool checked, int boost, bool clean_stack>
struct lua_call_wrapper<T, F, true, is_variable, checked, boost, std::enable_if_t<std::is_member_object_pointer<F>::value>> { struct lua_call_wrapper<T, F, true, is_variable, checked, boost, clean_stack, std::enable_if_t<std::is_member_object_pointer<F>::value>> {
typedef lua_bind_traits<F> traits_type; typedef lua_bind_traits<F> traits_type;
typedef wrapper<meta::unqualified_t<F>> wrap; typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::object_type object_type; typedef typename wrap::object_type object_type;
@ -381,7 +440,7 @@ namespace sol {
typedef typename wrap::returns_list returns_list; typedef typename wrap::returns_list returns_list;
typedef typename wrap::caller caller; typedef typename wrap::caller caller;
F f(std::forward<V>(v)); F f(std::forward<V>(v));
return stack::call_into_lua<checked>(returns_list(), types<>(), L, boost + ( is_variable ? 3 : 2 ), caller(), f, o); return stack::call_into_lua<checked, clean_stack>(returns_list(), types<>(), L, boost + ( is_variable ? 3 : 2 ), caller(), f, o);
} }
template <typename V> template <typename V>
@ -404,8 +463,8 @@ namespace sol {
} }
}; };
template <typename T, typename F, bool is_variable, bool checked, int boost, typename C> template <typename T, typename F, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct lua_call_wrapper<T, readonly_wrapper<F>, false, is_variable, checked, boost, C> { struct lua_call_wrapper<T, readonly_wrapper<F>, false, is_variable, checked, boost, clean_stack, C> {
typedef lua_bind_traits<F> traits_type; typedef lua_bind_traits<F> traits_type;
typedef wrapper<meta::unqualified_t<F>> wrap; typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::object_type object_type; typedef typename wrap::object_type object_type;
@ -421,13 +480,13 @@ namespace sol {
} }
}; };
template <typename T, typename F, bool is_variable, bool checked, int boost, typename C> template <typename T, typename F, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct lua_call_wrapper<T, readonly_wrapper<F>, true, is_variable, checked, boost, C> : lua_call_wrapper<T, F, true, is_variable, checked, boost, C> { struct lua_call_wrapper<T, readonly_wrapper<F>, true, is_variable, checked, boost, clean_stack, C> : lua_call_wrapper<T, F, true, is_variable, checked, boost, clean_stack, C> {
}; };
template <typename T, typename... Args, bool is_index, bool is_variable, bool checked, int boost, typename C> template <typename T, typename... Args, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct lua_call_wrapper<T, constructor_list<Args...>, is_index, is_variable, checked, boost, C> { struct lua_call_wrapper<T, constructor_list<Args...>, is_index, is_variable, checked, boost, clean_stack, C> {
typedef constructor_list<Args...> F; typedef constructor_list<Args...> F;
static int call(lua_State* L, F&) { static int call(lua_State* L, F&) {
@ -442,7 +501,7 @@ namespace sol {
T* obj = reinterpret_cast<T*>(pointerpointer + 1); T* obj = reinterpret_cast<T*>(pointerpointer + 1);
referencepointer = obj; referencepointer = obj;
construct_match<T, Args...>(constructor_match<T>(obj), L, argcount, boost + 1 + static_cast<int>(syntax)); construct_match<T, Args...>(constructor_match<T, false, clean_stack>(obj), L, argcount, boost + 1 + static_cast<int>(syntax));
userdataref.push(); userdataref.push();
luaL_getmetatable(L, &metakey[0]); luaL_getmetatable(L, &metakey[0]);
@ -456,8 +515,8 @@ namespace sol {
} }
}; };
template <typename T, typename... Cxs, bool is_index, bool is_variable, bool checked, int boost, typename C> template <typename T, typename... Cxs, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct lua_call_wrapper<T, constructor_wrapper<Cxs...>, is_index, is_variable, checked, boost, C> { struct lua_call_wrapper<T, constructor_wrapper<Cxs...>, is_index, is_variable, checked, boost, clean_stack, C> {
typedef constructor_wrapper<Cxs...> F; typedef constructor_wrapper<Cxs...> F;
struct onmatch { struct onmatch {
@ -471,7 +530,7 @@ namespace sol {
referencepointer = obj; referencepointer = obj;
auto& func = std::get<I>(f.functions); auto& func = std::get<I>(f.functions);
stack::call_into_lua<checked>(r, a, L, boost + start, func, detail::implicit_wrapper<T>(obj)); stack::call_into_lua<checked, clean_stack>(r, a, L, boost + start, func, detail::implicit_wrapper<T>(obj));
userdataref.push(); userdataref.push();
luaL_getmetatable(L, &metakey[0]); luaL_getmetatable(L, &metakey[0]);
@ -496,17 +555,17 @@ namespace sol {
}; };
template <typename T, typename Fx, bool is_index, bool is_variable, bool checked, int boost> template <typename T, typename Fx, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack>
struct lua_call_wrapper<T, destructor_wrapper<Fx>, is_index, is_variable, checked, boost, std::enable_if_t<std::is_void<Fx>::value>> { struct lua_call_wrapper<T, destructor_wrapper<Fx>, is_index, is_variable, checked, boost, clean_stack, std::enable_if_t<std::is_void<Fx>::value>> {
typedef destructor_wrapper<Fx> F; typedef destructor_wrapper<Fx> F;
static int call(lua_State* L, const F&) { static int call(lua_State* L, const F&) {
return detail::usertype_alloc_destroy<T>(L); return detail::usertype_alloc_destruct<T>(L);
} }
}; };
template <typename T, typename Fx, bool is_index, bool is_variable, bool checked, int boost> template <typename T, typename Fx, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack>
struct lua_call_wrapper<T, destructor_wrapper<Fx>, is_index, is_variable, checked, boost, std::enable_if_t<!std::is_void<Fx>::value>> { struct lua_call_wrapper<T, destructor_wrapper<Fx>, is_index, is_variable, checked, boost, clean_stack, std::enable_if_t<!std::is_void<Fx>::value>> {
typedef destructor_wrapper<Fx> F; typedef destructor_wrapper<Fx> F;
static int call(lua_State* L, const F& f) { static int call(lua_State* L, const F& f) {
@ -516,8 +575,8 @@ namespace sol {
} }
}; };
template <typename T, typename... Fs, bool is_index, bool is_variable, bool checked, int boost, typename C> template <typename T, typename... Fs, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct lua_call_wrapper<T, overload_set<Fs...>, is_index, is_variable, checked, boost, C> { struct lua_call_wrapper<T, overload_set<Fs...>, is_index, is_variable, checked, boost, clean_stack, C> {
typedef overload_set<Fs...> F; typedef overload_set<Fs...> F;
struct on_match { struct on_match {
@ -533,15 +592,15 @@ namespace sol {
} }
}; };
template <typename T, typename... Fs, bool is_index, bool is_variable, bool checked, int boost, typename C> template <typename T, typename... Fs, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct lua_call_wrapper<T, factory_wrapper<Fs...>, is_index, is_variable, checked, boost, C> { struct lua_call_wrapper<T, factory_wrapper<Fs...>, is_index, is_variable, checked, boost, clean_stack, C> {
typedef factory_wrapper<Fs...> F; typedef factory_wrapper<Fs...> F;
struct on_match { struct on_match {
template <typename Fx, std::size_t I, typename... R, typename... Args> template <typename Fx, std::size_t I, typename... R, typename... Args>
int operator()(types<Fx>, index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int, F& fx) { int operator()(types<Fx>, index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int, F& fx) {
auto& f = std::get<I>(fx.functions); auto& f = std::get<I>(fx.functions);
return lua_call_wrapper<T, Fx, is_index, is_variable, checked, boost>{}.call(L, f); return lua_call_wrapper<T, Fx, is_index, is_variable, checked, boost, clean_stack>{}.call(L, f);
} }
}; };
@ -550,8 +609,8 @@ namespace sol {
} }
}; };
template <typename T, typename R, typename W, bool is_index, bool is_variable, bool checked, int boost, typename C> template <typename T, typename R, typename W, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct lua_call_wrapper<T, property_wrapper<R, W>, is_index, is_variable, checked, boost, C> { struct lua_call_wrapper<T, property_wrapper<R, W>, is_index, is_variable, checked, boost, clean_stack, C> {
typedef std::conditional_t<is_index, R, W> P; typedef std::conditional_t<is_index, R, W> P;
typedef meta::unqualified_t<P> U; typedef meta::unqualified_t<P> U;
typedef wrapper<U> wrap; typedef wrapper<U> wrap;
@ -564,7 +623,7 @@ namespace sol {
typedef typename traits_type::free_args_list args_list; typedef typename traits_type::free_args_list args_list;
typedef typename wrap::returns_list returns_list; typedef typename wrap::returns_list returns_list;
typedef typename wrap::caller caller; typedef typename wrap::caller caller;
return stack::call_into_lua<checked>(returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), f); return stack::call_into_lua<checked, clean_stack>(returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), f);
} }
template <typename F> template <typename F>
@ -585,7 +644,7 @@ namespace sol {
#endif // Safety #endif // Safety
typedef typename wrap::returns_list returns_list; typedef typename wrap::returns_list returns_list;
typedef typename wrap::caller caller; typedef typename wrap::caller caller;
return stack::call_into_lua<checked>(returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), f, *o); return stack::call_into_lua<checked, clean_stack>(returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), f, *o);
} }
template <typename F, typename... Args> template <typename F, typename... Args>
@ -596,7 +655,7 @@ namespace sol {
template <typename F, typename... Args> template <typename F, typename... Args>
static int defer_call(std::true_type, lua_State* L, F&& f, Args&&... args) { static int defer_call(std::true_type, lua_State* L, F&& f, Args&&... args) {
auto& p = pick(meta::boolean<is_index>(), std::forward<F>(f)); auto& p = pick(meta::boolean<is_index>(), std::forward<F>(f));
return lua_call_wrapper<T, meta::unqualified_t<decltype(p)>, is_index, is_variable, checked, boost>{}.call(L, p, std::forward<Args>(args)...); return lua_call_wrapper<T, meta::unqualified_t<decltype(p)>, is_index, is_variable, checked, boost, clean_stack>{}.call(L, p, std::forward<Args>(args)...);
} }
template <typename F, typename... Args> template <typename F, typename... Args>
@ -613,33 +672,50 @@ namespace sol {
} }
}; };
template <typename T, typename V, bool is_index, bool is_variable, bool checked, int boost, typename C> template <typename T, typename V, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct lua_call_wrapper<T, protect_t<V>, is_index, is_variable, checked, boost, C> { struct lua_call_wrapper<T, protect_t<V>, is_index, is_variable, checked, boost, clean_stack, C> {
typedef protect_t<V> F; typedef protect_t<V> F;
template <typename... Args> template <typename... Args>
static int call(lua_State* L, F& fx, Args&&... args) { static int call(lua_State* L, F& fx, Args&&... args) {
return lua_call_wrapper<T, V, is_index, is_variable, true, boost>{}.call(L, fx.value, std::forward<Args>(args)...); return lua_call_wrapper<T, V, is_index, is_variable, true, boost, clean_stack>{}.call(L, fx.value, std::forward<Args>(args)...);
} }
}; };
template <typename T, typename Sig, typename P, bool is_index, bool is_variable, bool checked, int boost, typename C> template <typename T, typename F, typename... Filters, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct lua_call_wrapper<T, function_arguments<Sig, P>, is_index, is_variable, checked, boost, C> { struct lua_call_wrapper<T, filter_wrapper<F, Filters...>, is_index, is_variable, checked, boost, clean_stack, C> {
typedef filter_wrapper<F, Filters...> P;
template <std::size_t... In>
static int call(std::index_sequence<In...>, lua_State* L, P& fx) {
int pushed = lua_call_wrapper<T, F, is_index, is_variable, checked, boost, false, C>{}.call(L, fx.value);
(void)detail::swallow{ int(), (filter_detail::handle_filter(std::get<In>(fx.filters), L, pushed), int())... };
return pushed;
}
static int call(lua_State* L, P& fx) {
typedef typename P::indices indices;
return call(indices(), L, fx);
}
};
template <typename T, typename Sig, typename P, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct lua_call_wrapper<T, function_arguments<Sig, P>, is_index, is_variable, checked, boost, clean_stack, C> {
template <typename F> template <typename F>
static int call(lua_State* L, F&& f) { static int call(lua_State* L, F&& f) {
return lua_call_wrapper<T, meta::unqualified_t<P>, is_index, is_variable, stack::stack_detail::default_check_arguments, boost>{}.call(L, std::get<0>(f.arguments)); return lua_call_wrapper<T, meta::unqualified_t<P>, is_index, is_variable, checked, boost, clean_stack>{}.call(L, std::get<0>(f.arguments));
} }
}; };
template <typename T, bool is_index, bool is_variable, int boost = 0, typename Fx, typename... Args> template <typename T, bool is_index, bool is_variable, int boost = 0, bool checked = stack::stack_detail::default_check_arguments, bool clean_stack = true, typename Fx, typename... Args>
inline int call_wrapped(lua_State* L, Fx&& fx, Args&&... args) { inline int call_wrapped(lua_State* L, Fx&& fx, Args&&... args) {
return lua_call_wrapper<T, meta::unqualified_t<Fx>, is_index, is_variable, stack::stack_detail::default_check_arguments, boost>{}.call(L, std::forward<Fx>(fx), std::forward<Args>(args)...); return lua_call_wrapper<T, meta::unqualified_t<Fx>, is_index, is_variable, checked, boost, clean_stack>{}.call(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
} }
template <typename T, bool is_index, bool is_variable, typename F, int start = 1> template <typename T, bool is_index, bool is_variable, typename F, int start = 1, bool checked = stack::stack_detail::default_check_arguments, bool clean_stack = true>
inline int call_user(lua_State* L) { inline int call_user(lua_State* L) {
auto& fx = stack::get<user<F>>(L, upvalue_index(start)); auto& fx = stack::get<user<F>>(L, upvalue_index(start));
return call_wrapped<T, is_index, is_variable>(L, fx); return call_wrapped<T, is_index, is_variable, 0, checked, clean_stack>(L, fx);
} }
template <typename T, typename = void> template <typename T, typename = void>
@ -658,7 +734,10 @@ namespace sol {
struct is_var_bind<var_wrapper<T>> : std::true_type {}; struct is_var_bind<var_wrapper<T>> : std::true_type {};
template <typename T> template <typename T>
struct is_var_bind<readonly_wrapper<T>> : is_var_bind<T> {}; struct is_var_bind<readonly_wrapper<T>> : is_var_bind<meta::unqualified_t<T>> {};
template <typename F, typename... Filters>
struct is_var_bind<filter_wrapper<F, Filters...>> : is_var_bind<meta::unqualified_t<F>> {};
} // call_detail } // call_detail
template <typename T> template <typename T>

View File

@ -276,7 +276,7 @@ namespace sol {
{ "add", &meta_cumt::add_call }, { "add", &meta_cumt::add_call },
{ "find", &meta_cumt::find_call }, { "find", &meta_cumt::find_call },
{ "erase", &meta_cumt::erase_call }, { "erase", &meta_cumt::erase_call },
std::is_pointer<T>::value ? luaL_Reg{ nullptr, nullptr } : luaL_Reg{ "__gc", &detail::usertype_alloc_destroy<T> }, std::is_pointer<T>::value ? luaL_Reg{ nullptr, nullptr } : luaL_Reg{ "__gc", &detail::usertype_alloc_destruct<T> },
{ nullptr, nullptr } { nullptr, nullptr }
} }; } };

View File

@ -88,8 +88,8 @@ namespace sol {
name.replace(0, 6, "", 0); name.replace(0, 6, "", 0);
if (name.find("class", 0) == 0) if (name.find("class", 0) == 0)
name.replace(0, 5, "", 0); name.replace(0, 5, "", 0);
while (!name.empty() && std::isblank(name.front())) name.erase(name.begin()); while (!name.empty() && isblank(name.front())) name.erase(name.begin());
while (!name.empty() && std::isblank(name.back())) name.pop_back(); while (!name.empty() && isblank(name.back())) name.pop_back();
for (std::size_t r = 0; r < removals.size(); ++r) { for (std::size_t r = 0; r < removals.size(); ++r) {
auto found = name.find(removals[r]); auto found = name.find(removals[r]);

86
sol/filters.hpp Normal file
View File

@ -0,0 +1,86 @@
// The MIT License (MIT)
// Copyright (c) 2013-2017 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_FILTERS_HPP
#define SOL_FILTERS_HPP
#include "traits.hpp"
#include <array>
namespace sol {
namespace detail {
struct filter_base_tag {};
} // detail
template <int Target, int... In>
struct static_stack_dependencies : detail::filter_base_tag {};
typedef static_stack_dependencies<-1, 1> self_dependency;
template <int... In>
struct returns_self_with : detail::filter_base_tag {};
typedef returns_self_with<> returns_self;
struct stack_dependencies : detail::filter_base_tag {
int target;
std::array<int, 64> stack_indices;
std::size_t len;
template <typename... Args>
stack_dependencies(int stack_target, Args&&... args) : target(stack_target), stack_indices(), len(sizeof...(Args)) {
std::size_t i = 0;
(void)detail::swallow{ int(), (stack_indices[i++] = static_cast<int>(std::forward<Args>(args)), int() )... };
}
int& operator[] (std::size_t i) {
return stack_indices[i];
}
const int& operator[] (std::size_t i) const {
return stack_indices[i];
}
std::size_t size() const {
return len;
}
};
template <typename F, typename... Filters>
struct filter_wrapper {
typedef std::make_integer_sequence<std::size_t, sizeof...(Filters)> indices;
F value;
std::tuple<Filters...> filters;
template <typename Fx, typename... Args, meta::enable<meta::neg<std::is_same<meta::unqualified_t<Fx>, filter_wrapper>>> = meta::enabler>
filter_wrapper(Fx&& fx, Args&&... args) : value(std::forward<Fx>(fx)), filters(std::forward<Args>(args)...) {}
filter_wrapper(const filter_wrapper&) = default;
filter_wrapper& operator=(const filter_wrapper&) = default;
filter_wrapper(filter_wrapper&&) = default;
filter_wrapper& operator=(filter_wrapper&&) = default;
};
template <typename F, typename... Args>
auto filters(F&& f, Args&&... args) {
return filter_wrapper<std::decay_t<F>, std::decay_t<Args>...>( std::forward<F>(f), std::forward<Args>(args)... );
}
} // sol
#endif // SOL_FILTERS_HPP

View File

@ -110,7 +110,10 @@ namespace sol {
struct user; struct user;
template <typename T> template <typename T>
struct as_args_t; struct as_args_t;
template <typename T>
struct protect_t;
template <typename F, typename... Filters>
struct filter_wrapper;
} // sol } // sol
#endif // SOL_FORWARD_HPP #endif // SOL_FORWARD_HPP

54
sol/forward_detail.hpp Normal file
View File

@ -0,0 +1,54 @@
// The MIT License (MIT)
// Copyright (c) 2013-2017 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_FORWARD_DETAIL_HPP
#define SOL_FORWARD_DETAIL_HPP
#include "feature_test.hpp"
#include "forward.hpp"
#include "traits.hpp"
namespace sol {
namespace meta {
namespace meta_detail {
} // meta_detail
} // meta
namespace stack {
namespace stack_detail {
template <typename T>
struct undefined_metatable;
} // stack_detail
} // stack
namespace usertype_detail {
template <typename T, typename Regs, typename Fx>
void insert_default_registrations(Regs& l, int& index, Fx&& fx);
template <typename T, typename Regs, meta::enable<meta::neg<std::is_pointer<T>>, std::is_destructible<T>> = meta::enabler>
void make_destructor(Regs& l, int& index);
template <typename T, typename Regs, meta::disable<meta::neg<std::is_pointer<T>>, std::is_destructible<T>> = meta::enabler>
void make_destructor(Regs& l, int& index);
} // usertype_detail
} // sol
#endif // SOL_FORWARD_DETAIL_HPP

View File

@ -391,7 +391,7 @@ namespace sol {
template <typename T, typename... Lists> template <typename T, typename... Lists>
struct pusher<detail::tagged<T, constructor_list<Lists...>>> { struct pusher<detail::tagged<T, constructor_list<Lists...>>> {
static int push(lua_State* L, detail::tagged<T, constructor_list<Lists...>>) { static int push(lua_State* L, detail::tagged<T, constructor_list<Lists...>>) {
lua_CFunction cf = call_detail::construct<T, Lists...>; lua_CFunction cf = call_detail::construct<T, stack_detail::default_check_arguments, true, Lists...>;
return stack::push(L, cf); return stack::push(L, cf);
} }
}; };
@ -411,7 +411,7 @@ namespace sol {
template <typename T> template <typename T>
struct pusher<detail::tagged<T, destructor_wrapper<void>>> { struct pusher<detail::tagged<T, destructor_wrapper<void>>> {
static int push(lua_State* L, destructor_wrapper<void>) { static int push(lua_State* L, destructor_wrapper<void>) {
lua_CFunction cf = detail::usertype_alloc_destroy<T>; lua_CFunction cf = detail::usertype_alloc_destruct<T>;
return stack::push(L, cf); return stack::push(L, cf);
} }
}; };
@ -427,6 +427,26 @@ namespace sol {
} }
}; };
template <typename F, typename... Filters>
struct pusher<filter_wrapper<F, Filters...>> {
typedef filter_wrapper<F, Filters...> P;
static int push(lua_State* L, const P& p) {
lua_CFunction cf = call_detail::call_user<void, false, false, P, 2>;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::push<user<P>>(L, p);
return stack::push(L, c_closure(cf, upvalues));
}
static int push(lua_State* L, P&& p) {
lua_CFunction cf = call_detail::call_user<void, false, false, P, 2>;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::push<user<P>>(L, std::move(p));
return stack::push(L, c_closure(cf, upvalues));
}
};
} // stack } // stack
} // sol } // sol

View File

@ -43,6 +43,19 @@ namespace sol {
tbl.traverse_set(std::get<I>(key)..., std::forward<T>(value)); tbl.traverse_set(std::get<I>(key)..., std::forward<T>(value));
} }
auto setup_table(std::true_type) {
auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(lua_state(), key, tbl.stack_index());
lua_pop(lua_state(), p.levels);
return p;
}
bool is_valid(std::false_type) {
auto pp = stack::push_pop(tbl);
auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(lua_state(), key, lua_gettop(lua_state()));
lua_pop(lua_state(), p.levels);
return p;
}
public: public:
Table tbl; Table tbl;
key_type key; key_type key;

View File

@ -22,9 +22,10 @@
#ifndef SOL_RAII_HPP #ifndef SOL_RAII_HPP
#define SOL_RAII_HPP #define SOL_RAII_HPP
#include <memory>
#include "traits.hpp" #include "traits.hpp"
#include <memory>
namespace sol { namespace sol {
namespace detail { namespace detail {
struct default_construct { struct default_construct {

View File

@ -69,17 +69,23 @@ namespace sol {
struct push_popper_n<true> { struct push_popper_n<true> {
push_popper_n(lua_State*, int) { } push_popper_n(lua_State*, int) { }
}; };
template <bool top_level, typename T> template <bool, typename T, typename = void>
struct push_popper { struct push_popper {
T t; T t;
push_popper(T x) : t(x) { t.push(); } push_popper(T x) : t(x) { t.push(); }
~push_popper() { t.pop(); } ~push_popper() { t.pop(); }
}; };
template <typename T> template <typename T, typename C>
struct push_popper<true, T> { struct push_popper<true, T, C> {
push_popper(T) {} push_popper(T) {}
~push_popper() {} ~push_popper() {}
}; };
template <typename T>
struct push_popper<false, T, std::enable_if_t<std::is_base_of<stack_reference, meta::unqualified_t<T>>::value>> {
push_popper(T) {}
~push_popper() {}
};
template <bool top_level = false, typename T> template <bool top_level = false, typename T>
push_popper<top_level, T> push_pop(T&& x) { push_popper<top_level, T> push_pop(T&& x) {
return push_popper<top_level, T>(std::forward<T>(x)); return push_popper<top_level, T>(std::forward<T>(x));

View File

@ -322,7 +322,7 @@ namespace sol {
private: private:
template<std::size_t... I, typename Tuple> template<std::size_t... I, typename Tuple>
simple_usertype_metatable(usertype_detail::verified_tag, std::index_sequence<I...>, lua_State* L, Tuple&& args) simple_usertype_metatable(detail::verified_tag, std::index_sequence<I...>, lua_State* L, Tuple&& args)
: callconstructfunc(lua_nil), : callconstructfunc(lua_nil),
indexfunc(lua_nil), newindexfunc(lua_nil), indexfunc(lua_nil), newindexfunc(lua_nil),
indexbase(&usertype_detail::simple_core_indexing_call<T, true>), newindexbase(&usertype_detail::simple_core_indexing_call<T, false>), indexbase(&usertype_detail::simple_core_indexing_call<T, true>), newindexbase(&usertype_detail::simple_core_indexing_call<T, false>),
@ -337,33 +337,33 @@ namespace sol {
} }
template<typename... Args> template<typename... Args>
simple_usertype_metatable(lua_State* L, usertype_detail::verified_tag v, Args&&... args) : simple_usertype_metatable(v, std::make_index_sequence<sizeof...(Args) / 2>(), L, std::forward_as_tuple(std::forward<Args>(args)...)) {} simple_usertype_metatable(lua_State* L, detail::verified_tag v, Args&&... args) : simple_usertype_metatable(v, std::make_index_sequence<sizeof...(Args) / 2>(), L, std::forward_as_tuple(std::forward<Args>(args)...)) {}
template<typename... Args> template<typename... Args>
simple_usertype_metatable(lua_State* L, usertype_detail::add_destructor_tag, Args&&... args) : simple_usertype_metatable(L, usertype_detail::verified, std::forward<Args>(args)..., "__gc", default_destructor) {} simple_usertype_metatable(lua_State* L, detail::add_destructor_tag, Args&&... args) : simple_usertype_metatable(L, detail::verified, std::forward<Args>(args)..., "__gc", default_destructor) {}
template<typename... Args> template<typename... Args>
simple_usertype_metatable(lua_State* L, usertype_detail::check_destructor_tag, Args&&... args) : simple_usertype_metatable(L, meta::condition<meta::all<std::is_destructible<T>, meta::neg<usertype_detail::has_destructor<Args...>>>, usertype_detail::add_destructor_tag, usertype_detail::verified_tag>(), std::forward<Args>(args)...) {} simple_usertype_metatable(lua_State* L, detail::check_destructor_tag, Args&&... args) : simple_usertype_metatable(L, meta::condition<meta::all<std::is_destructible<T>, meta::neg<detail::has_destructor<Args...>>>, detail::add_destructor_tag, detail::verified_tag>(), std::forward<Args>(args)...) {}
public: public:
simple_usertype_metatable(lua_State* L) : simple_usertype_metatable(L, meta::condition<meta::all<std::is_default_constructible<T>>, decltype(default_constructor), usertype_detail::check_destructor_tag>()) {} simple_usertype_metatable(lua_State* L) : simple_usertype_metatable(L, meta::condition<meta::all<std::is_default_constructible<T>>, decltype(default_constructor), detail::check_destructor_tag>()) {}
template<typename Arg, typename... Args, meta::disable_any< template<typename Arg, typename... Args, meta::disable_any<
meta::any_same<meta::unqualified_t<Arg>, meta::any_same<meta::unqualified_t<Arg>,
usertype_detail::verified_tag, detail::verified_tag,
usertype_detail::add_destructor_tag, detail::add_destructor_tag,
usertype_detail::check_destructor_tag detail::check_destructor_tag
>, >,
meta::is_specialization_of<constructors, meta::unqualified_t<Arg>>, meta::is_specialization_of<constructors, meta::unqualified_t<Arg>>,
meta::is_specialization_of<constructor_wrapper, meta::unqualified_t<Arg>> meta::is_specialization_of<constructor_wrapper, meta::unqualified_t<Arg>>
> = meta::enabler> > = meta::enabler>
simple_usertype_metatable(lua_State* L, Arg&& arg, Args&&... args) : simple_usertype_metatable(L, meta::condition<meta::all<std::is_default_constructible<T>, meta::neg<usertype_detail::has_constructor<Args...>>>, decltype(default_constructor), usertype_detail::check_destructor_tag>(), std::forward<Arg>(arg), std::forward<Args>(args)...) {} simple_usertype_metatable(lua_State* L, Arg&& arg, Args&&... args) : simple_usertype_metatable(L, meta::condition<meta::all<std::is_default_constructible<T>, meta::neg<detail::has_constructor<Args...>>>, decltype(default_constructor), detail::check_destructor_tag>(), std::forward<Arg>(arg), std::forward<Args>(args)...) {}
template<typename... Args, typename... CArgs> template<typename... Args, typename... CArgs>
simple_usertype_metatable(lua_State* L, constructors<CArgs...> constructorlist, Args&&... args) : simple_usertype_metatable(L, usertype_detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) {} simple_usertype_metatable(lua_State* L, constructors<CArgs...> constructorlist, Args&&... args) : simple_usertype_metatable(L, detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) {}
template<typename... Args, typename... Fxs> template<typename... Args, typename... Fxs>
simple_usertype_metatable(lua_State* L, constructor_wrapper<Fxs...> constructorlist, Args&&... args) : simple_usertype_metatable(L, usertype_detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) {} simple_usertype_metatable(lua_State* L, constructor_wrapper<Fxs...> constructorlist, Args&&... args) : simple_usertype_metatable(L, detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) {}
simple_usertype_metatable(const simple_usertype_metatable&) = default; simple_usertype_metatable(const simple_usertype_metatable&) = default;
simple_usertype_metatable(simple_usertype_metatable&&) = default; simple_usertype_metatable(simple_usertype_metatable&&) = default;
@ -420,7 +420,8 @@ namespace sol {
for (std::size_t i = 1; i < properties.size(); ++i) { for (std::size_t i = 1; i < properties.size(); ++i) {
mf = static_cast<meta_function>(i); mf = static_cast<meta_function>(i);
const std::string& mfname = to_string(mf); const std::string& mfname = to_string(mf);
if (mfname == first) { if (mfname != first)
continue;
properties[i] = true; properties[i] = true;
switch (mf) { switch (mf) {
case meta_function::index: case meta_function::index:
@ -432,7 +433,6 @@ namespace sol {
default: default:
break; break;
} }
}
break; break;
} }
switch (i) { switch (i) {
@ -474,34 +474,10 @@ namespace sol {
auto& second = std::get<1>(kvp); auto& second = std::get<1>(kvp);
register_kvp(i, t, first, second); register_kvp(i, t, first, second);
} }
luaL_Reg opregs[29]{}; luaL_Reg opregs[32]{};
int opregsindex = 0; int opregsindex = 0;
if (!properties[static_cast<int>(meta_function::less_than)]) { auto prop_fx = [&](meta_function mf) { return !properties[static_cast<int>(mf)]; };
const char* name = to_string(meta_function::less_than).c_str(); usertype_detail::insert_default_registrations<T>(opregs, opregsindex, prop_fx);
usertype_detail::make_reg_op<T, std::less<>, meta::supports_op_less<T>>(opregs, opregsindex, name);
}
if (!properties[static_cast<int>(meta_function::less_than_or_equal_to)]) {
const char* name = to_string(meta_function::less_than_or_equal_to).c_str();
usertype_detail::make_reg_op<T, std::less_equal<>, meta::supports_op_less_equal<T>>(opregs, opregsindex, name);
}
if (!properties[static_cast<int>(meta_function::equal_to)]) {
const char* name = to_string(meta_function::equal_to).c_str();
usertype_detail::make_reg_op<T, std::conditional_t<meta::supports_op_equal<T>::value, std::equal_to<>, usertype_detail::no_comp>, std::true_type>(opregs, opregsindex, name);
}
if (!properties[static_cast<int>(meta_function::pairs)]) {
const char* name = to_string(meta_function::pairs).c_str();
opregs[opregsindex] = { name, container_usertype_metatable<as_container_t<T>>::pairs_call };
++opregsindex;
}
if (!properties[static_cast<int>(meta_function::length)]) {
usertype_detail::make_length_op<T>(opregs, opregsindex);
}
if (!properties[static_cast<int>(meta_function::to_string)]) {
usertype_detail::make_to_string_op<T, meta::supports_ostream_op<T>>(opregs, opregsindex);
}
if (!properties[static_cast<int>(meta_function::call)]) {
usertype_detail::make_call_op<T>(opregs, opregsindex);
}
t.push(); t.push();
luaL_setfuncs(L, opregs, 0); luaL_setfuncs(L, opregs, 0);
t.pop(); t.pop();

View File

@ -159,34 +159,41 @@ namespace sol {
template <bool check_args = stack_detail::default_check_arguments, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>> template <bool check_args = stack_detail::default_check_arguments, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>>
inline decltype(auto) call_from_top(types<R> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) { inline decltype(auto) call_from_top(types<R> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) {
return call<check_args>(tr, ta, L, static_cast<int>(lua_gettop(L) - sizeof...(Args)), std::forward<Fx>(fx), std::forward<FxArgs>(args)...); typedef meta::count_for_pack<lua_size, Args...> expected_count;
return call<check_args>(tr, ta, L, (std::max)(static_cast<int>(lua_gettop(L) - expected_count::value), static_cast<int>(0)), std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
} }
template <bool check_args = stack_detail::default_check_arguments, typename... Args, typename Fx, typename... FxArgs> template <bool check_args = stack_detail::default_check_arguments, typename... Args, typename Fx, typename... FxArgs>
inline void call_from_top(types<void> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) { inline void call_from_top(types<void> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) {
call<check_args>(tr, ta, L, static_cast<int>(lua_gettop(L) - sizeof...(Args)), std::forward<Fx>(fx), std::forward<FxArgs>(args)...); typedef meta::count_for_pack<lua_size, Args...> expected_count;
call<check_args>(tr, ta, L, (std::max)(static_cast<int>(lua_gettop(L) - expected_count::value), static_cast<int>(0)), std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
} }
template<bool check_args = stack_detail::default_check_arguments, typename... Args, typename Fx, typename... FxArgs> template<bool check_args = stack_detail::default_check_arguments, bool clean_stack = true, typename... Args, typename Fx, typename... FxArgs>
inline int call_into_lua(types<void> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { inline int call_into_lua(types<void> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) {
call<check_args>(tr, ta, L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...); call<check_args>(tr, ta, L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
if (clean_stack) {
lua_settop(L, 0); lua_settop(L, 0);
}
return 0; return 0;
} }
template<bool check_args = stack_detail::default_check_arguments, typename Ret0, typename... Ret, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<meta::neg<std::is_void<Ret0>>::value>> template<bool check_args = stack_detail::default_check_arguments, bool clean_stack = true, typename Ret0, typename... Ret, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<meta::neg<std::is_void<Ret0>>::value>>
inline int call_into_lua(types<Ret0, Ret...>, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { inline int call_into_lua(types<Ret0, Ret...>, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) {
decltype(auto) r = call<check_args>(types<meta::return_type_t<Ret0, Ret...>>(), ta, L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...); decltype(auto) r = call<check_args>(types<meta::return_type_t<Ret0, Ret...>>(), ta, L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
typedef is_stack_based<meta::unqualified_t<decltype(r)>> is_stack;
if (clean_stack && !is_stack::value) {
lua_settop(L, 0); lua_settop(L, 0);
}
return push_reference(L, std::forward<decltype(r)>(r)); return push_reference(L, std::forward<decltype(r)>(r));
} }
template<bool check_args = stack_detail::default_check_arguments, typename Fx, typename... FxArgs> template<bool check_args = stack_detail::default_check_arguments, bool clean_stack = true, typename Fx, typename... FxArgs>
inline int call_lua(lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { inline int call_lua(lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) {
typedef lua_bind_traits<meta::unqualified_t<Fx>> traits_type; typedef lua_bind_traits<meta::unqualified_t<Fx>> traits_type;
typedef typename traits_type::args_list args_list; typedef typename traits_type::args_list args_list;
typedef typename traits_type::returns_list returns_list; typedef typename traits_type::returns_list returns_list;
return call_into_lua<check_args>(returns_list(), args_list(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...); return call_into_lua<check_args, clean_stack>(returns_list(), args_list(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
} }
inline call_syntax get_call_syntax(lua_State* L, const std::string& key, int index) { inline call_syntax get_call_syntax(lua_State* L, const std::string& key, int index) {

View File

@ -87,18 +87,45 @@ namespace sol {
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1); tracking.use(1);
#if SOL_LUA_VERSION >= 503 #if SOL_LUA_VERSION >= 503
if (lua_isinteger(L, index) != 0) { #ifdef SOL_STRINGS_ARE_NUMBERS
int isnum = 0;
lua_tointegerx(L, index, &isnum);
const bool success = isnum != 0;
#else
// this check is precise, does not convert
if (lua_isinteger(L, index) == 1) {
return true; return true;
} }
#endif const bool success = false;
int isnum = 0; #endif // If numbers are enabled, use the imprecise check
const lua_Number v = lua_tonumberx(L, index, &isnum);
const bool success = isnum != 0 && static_cast<lua_Number>(std::llround(v)) == v;
if (!success) { if (!success) {
// expected type, actual type // expected type, actual type
handler(L, index, type::number, type_of(L, index)); handler(L, index, type::number, type_of(L, index));
} }
return success; return success;
#else
#ifndef SOL_STRINGS_ARE_NUMBERS
// must pre-check, because it will convert
type t = type_of(L, index);
if (t != type::number) {
// expected type, actual type
handler(L, index, type::number, t);
return false;
}
#endif // Do not allow strings to be numbers
int isnum = 0;
const lua_Number v = lua_tonumberx(L, index, &isnum);
const bool success = isnum != 0 && static_cast<lua_Number>(llround(v)) == v;
if (!success) {
// expected type, actual type
#ifndef SOL_STRINGS_ARE_NUMBERS
handler(L, index, type::number, t);
#else
handler(L, index, type::number, type_of(L, index));
#endif
}
return success;
#endif
} }
}; };
@ -107,12 +134,22 @@ namespace sol {
template <typename Handler> template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1); tracking.use(1);
#ifdef SOL_STRINGS_ARE_NUMBERS
type t = type_of(L, index);
bool success = t == type::number;
if (!success) {
// expected type, actual type
handler(L, index, type::number, t);
}
return success;
#else
bool success = lua_isnumber(L, index) == 1; bool success = lua_isnumber(L, index) == 1;
if (!success) { if (!success) {
// expected type, actual type // expected type, actual type
handler(L, index, type::number, type_of(L, index)); handler(L, index, type::number, type_of(L, index));
} }
return success; return success;
#endif
} }
}; };

View File

@ -67,7 +67,7 @@ namespace sol {
const lua_Number value = lua_tonumberx(L, index, &isnum); const lua_Number value = lua_tonumberx(L, index, &isnum);
if (isnum != 0) { if (isnum != 0) {
#if 1 // defined(SOL_CHECK_ARGUMENTS) && !defined(SOL_NO_CHECK_NUMBER_PRECISION) #if 1 // defined(SOL_CHECK_ARGUMENTS) && !defined(SOL_NO_CHECK_NUMBER_PRECISION)
const auto integer_value = std::llround(value); const auto integer_value = llround(value);
if (static_cast<lua_Number>(integer_value) == value) { if (static_cast<lua_Number>(integer_value) == value) {
tracking.use(1); tracking.use(1);
return static_cast<T>(integer_value); return static_cast<T>(integer_value);

View File

@ -29,9 +29,13 @@
#include "traits.hpp" #include "traits.hpp"
#include "tie.hpp" #include "tie.hpp"
#include "stack_guard.hpp" #include "stack_guard.hpp"
#include "demangle.hpp"
#include "forward_detail.hpp"
#include <vector> #include <vector>
#include <forward_list> #include <forward_list>
#include <string> #include <string>
#include <algorithm>
namespace sol { namespace sol {
namespace detail { namespace detail {
@ -52,17 +56,8 @@ namespace sol {
return 0; return 0;
} }
template <typename T, typename Real>
inline void usertype_unique_alloc_destroy(void* memory) {
T** pointerpointer = static_cast<T**>(memory);
unique_destructor* dx = static_cast<unique_destructor*>(static_cast<void*>(pointerpointer + 1));
Real* target = static_cast<Real*>(static_cast<void*>(dx + 1));
std::allocator<Real> alloc;
alloc.destroy(target);
}
template <typename T> template <typename T>
inline int user_alloc_destroy(lua_State* L) { inline int user_alloc_destruct(lua_State* L) {
void* rawdata = lua_touserdata(L, 1); void* rawdata = lua_touserdata(L, 1);
T* data = static_cast<T*>(rawdata); T* data = static_cast<T*>(rawdata);
std::allocator<T> alloc; std::allocator<T> alloc;
@ -71,7 +66,7 @@ namespace sol {
} }
template <typename T> template <typename T>
inline int usertype_alloc_destroy(lua_State* L) { inline int usertype_alloc_destruct(lua_State* L) {
void* rawdata = lua_touserdata(L, 1); void* rawdata = lua_touserdata(L, 1);
T** pdata = static_cast<T**>(rawdata); T** pdata = static_cast<T**>(rawdata);
T* data = *pdata; T* data = *pdata;
@ -80,6 +75,20 @@ namespace sol {
return 0; return 0;
} }
template <typename T>
inline int cannot_destruct(lua_State* L) {
return luaL_error(L, "cannot call the destructor for '%s': it is either hidden (protected/private) or removed with '= delete' and thusly this type is being destroyed without properly destructing, invoking undefined behavior", detail::demangle<T>().data());
}
template <typename T, typename Real>
inline void usertype_unique_alloc_destroy(void* memory) {
T** pointerpointer = static_cast<T**>(memory);
unique_destructor* dx = static_cast<unique_destructor*>(static_cast<void*>(pointerpointer + 1));
Real* target = static_cast<Real*>(static_cast<void*>(dx + 1));
std::allocator<Real> alloc;
alloc.destroy(target);
}
template <typename T> template <typename T>
void reserve(T&, std::size_t) {} void reserve(T&, std::size_t) {}

View File

@ -68,7 +68,7 @@ namespace sol {
return static_cast<T>(lua_tointeger(L, index)); return static_cast<T>(lua_tointeger(L, index));
} }
#endif #endif
return static_cast<T>(std::llround(lua_tonumber(L, index))); return static_cast<T>(llround(lua_tonumber(L, index)));
} }
}; };

View File

@ -26,6 +26,8 @@
#include "raii.hpp" #include "raii.hpp"
#include "optional.hpp" #include "optional.hpp"
#include "usertype_traits.hpp" #include "usertype_traits.hpp"
#include "filters.hpp"
#include <memory> #include <memory>
#include <type_traits> #include <type_traits>
#include <cassert> #include <cassert>
@ -83,10 +85,8 @@ namespace sol {
template <typename K, typename... Args> template <typename K, typename... Args>
static int push_keyed(lua_State* L, K&& k, Args&&... args) { static int push_keyed(lua_State* L, K&& k, Args&&... args) {
return push_fx(L, [&L, &k]() { stack_detail::undefined_metatable<T> fx(L, &k[0]);
luaL_newmetatable(L, &k[0]); return push_fx(L, fx, std::forward<Args>(args)...);
lua_setmetatable(L, -2);
}, std::forward<Args>(args)...);
} }
template <typename... Args> template <typename... Args>
@ -97,6 +97,8 @@ namespace sol {
template <typename T> template <typename T>
struct pusher<detail::as_pointer_tag<T>> { struct pusher<detail::as_pointer_tag<T>> {
typedef meta::unqualified_t<T> U;
template <typename F> template <typename F>
static int push_fx(lua_State* L, F&& f, T* obj) { static int push_fx(lua_State* L, F&& f, T* obj) {
if (obj == nullptr) if (obj == nullptr)
@ -109,14 +111,12 @@ namespace sol {
template <typename K> template <typename K>
static int push_keyed(lua_State* L, K&& k, T* obj) { static int push_keyed(lua_State* L, K&& k, T* obj) {
return push_fx(L, [&L, &k]() { stack_detail::undefined_metatable<U*> fx(L, &k[0]);
luaL_newmetatable(L, &k[0]); return push_fx(L, fx, obj);
lua_setmetatable(L, -2);
}, obj);
} }
static int push(lua_State* L, T* obj) { static int push(lua_State* L, T* obj) {
return push_keyed(L, usertype_traits<meta::unqualified_t<T>*>::metatable(), obj); return push_keyed(L, usertype_traits<U*>::metatable(), obj);
} }
}; };
@ -171,7 +171,12 @@ namespace sol {
detail::default_construct::construct(mem, std::forward<Args>(args)...); detail::default_construct::construct(mem, std::forward<Args>(args)...);
*pref = unique_usertype_traits<T>::get(*mem); *pref = unique_usertype_traits<T>::get(*mem);
if (luaL_newmetatable(L, &usertype_traits<detail::unique_usertype<P>>::metatable()[0]) == 1) { if (luaL_newmetatable(L, &usertype_traits<detail::unique_usertype<P>>::metatable()[0]) == 1) {
set_field(L, "__gc", detail::unique_destruct<P>); luaL_Reg l[32]{};
int index = 0;
auto prop_fx = [](meta_function) { return true; };
usertype_detail::insert_default_registrations<P>(l, index, prop_fx);
usertype_detail::make_destructor<T>(l, index);
luaL_setfuncs(L, l, 0);
} }
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
return 1; return 1;
@ -213,7 +218,7 @@ namespace sol {
} }
#endif #endif
#if defined(SOL_CHECK_ARGUMENTS) && !defined(SOL_NO_CHECK_NUMBER_PRECISION) #if defined(SOL_CHECK_ARGUMENTS) && !defined(SOL_NO_CHECK_NUMBER_PRECISION)
if (static_cast<T>(std::llround(static_cast<lua_Number>(value))) != value) { if (static_cast<T>(llround(static_cast<lua_Number>(value))) != value) {
#ifndef SOL_NO_EXCEPTIONS #ifndef SOL_NO_EXCEPTIONS
throw sol::error("The integer will be misrepresented in lua."); throw sol::error("The integer will be misrepresented in lua.");
#else #else
@ -437,7 +442,7 @@ namespace sol {
std::allocator<T> alloc; std::allocator<T> alloc;
alloc.construct(data, std::forward<Args>(args)...); alloc.construct(data, std::forward<Args>(args)...);
if (with_meta) { if (with_meta) {
lua_CFunction cdel = detail::user_alloc_destroy<T>; lua_CFunction cdel = detail::user_alloc_destruct<T>;
// Make sure we have a plain GC set for this data // Make sure we have a plain GC set for this data
if (luaL_newmetatable(L, name) != 0) { if (luaL_newmetatable(L, name) != 0) {
lua_pushcclosure(L, cdel, 0); lua_pushcclosure(L, cdel, 0);
@ -561,6 +566,30 @@ namespace sol {
} }
}; };
template <>
struct pusher<absolute_index> {
static int push(lua_State* L, absolute_index ai) {
lua_pushvalue(L, ai);
return 1;
}
};
template <>
struct pusher<raw_index> {
static int push(lua_State* L, raw_index ri) {
lua_pushvalue(L, ri);
return 1;
}
};
template <>
struct pusher<ref_index> {
static int push(lua_State* L, ref_index ri) {
lua_rawgeti(L, LUA_REGISTRYINDEX, ri);
return 1;
}
};
#ifdef SOL_CODECVT_SUPPORT #ifdef SOL_CODECVT_SUPPORT
template<> template<>
struct pusher<const wchar_t*> { struct pusher<const wchar_t*> {

View File

@ -32,9 +32,10 @@ namespace sol {
(void)L; (void)L;
return -1; return -1;
#else #else
const char* message = lua_tostring(L, -1); size_t messagesize;
const char* message = lua_tolstring(L, -1, &messagesize);
if (message) { if (message) {
std::string err = message; std::string err(message, messagesize);
lua_settop(L, 0); lua_settop(L, 0);
throw error(err); throw error(err);
} }

View File

@ -450,6 +450,10 @@ namespace sol {
return load_result(L, absolute_index(L, -1), 1, 1, x); return load_result(L, absolute_index(L, -1), 1, 1, x);
} }
load_result load_buffer(const char* buff, size_t size, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
return load(string_view(buff, size), chunkname, mode);
}
load_result load_file(const std::string& filename, load_mode mode = load_mode::any) { load_result load_file(const std::string& filename, load_mode mode = load_mode::any) {
load_status x = static_cast<load_status>(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str())); load_status x = static_cast<load_status>(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str()));
return load_result(L, absolute_index(L, -1), 1, 1, x); return load_result(L, absolute_index(L, -1), 1, 1, x);
@ -457,7 +461,7 @@ namespace sol {
load_result load(lua_Reader reader, void* data, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { load_result load(lua_Reader reader, void* data, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
char basechunkname[17] = {}; char basechunkname[17] = {};
const char* chunknametarget = detail::make_chunk_name("lua_reader", chunkname, basechunkname); const char* chunknametarget = detail::make_chunk_name("lua_Reader", chunkname, basechunkname);
#if SOL_LUA_VERSION > 501 #if SOL_LUA_VERSION > 501
load_status x = static_cast<load_status>(lua_load(L, reader, data, chunknametarget, to_string(mode).c_str())); load_status x = static_cast<load_status>(lua_load(L, reader, data, chunknametarget, to_string(mode).c_str()));
#else #else

View File

@ -176,7 +176,7 @@ namespace sol {
basic_table_core& operator=(basic_table_core&&) = default; basic_table_core& operator=(basic_table_core&&) = default;
basic_table_core(const stack_reference& r) : basic_table_core(r.lua_state(), r.stack_index()) {} basic_table_core(const stack_reference& r) : basic_table_core(r.lua_state(), r.stack_index()) {}
basic_table_core(stack_reference&& r) : basic_table_core(r.lua_state(), r.stack_index()) {} basic_table_core(stack_reference&& r) : basic_table_core(r.lua_state(), r.stack_index()) {}
template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<std::is_same<meta::unqualified_t<T>, ref_index>>> = meta::enabler> template <typename T, meta::enable<meta::neg<is_lua_index<meta::unqualified_t<T>>>> = meta::enabler>
basic_table_core(lua_State* L, T&& r) : basic_table_core(L, sol::ref_index(r.registry_index())) {} basic_table_core(lua_State* L, T&& r) : basic_table_core(L, sol::ref_index(r.registry_index())) {}
basic_table_core(lua_State* L, new_table nt) : base_t(L, (lua_createtable(L, nt.sequence_hint, nt.map_hint), -1)) { basic_table_core(lua_State* L, new_table nt) : base_t(L, (lua_createtable(L, nt.sequence_hint, nt.map_hint), -1)) {
if (!std::is_base_of<stack_reference, base_type>::value) { if (!std::is_base_of<stack_reference, base_type>::value) {

View File

@ -261,7 +261,7 @@ namespace sol {
using no = struct { char s[2]; }; using no = struct { char s[2]; };
struct F { void operator()(); }; struct F { void operator()(); };
struct Derived : T, F {}; struct Derived : T, F { ~Derived() = delete; };
template<typename U, U> struct Check; template<typename U, U> struct Check;
template<typename V> template<typename V>
@ -382,6 +382,35 @@ namespace sol {
static const bool value = sizeof(test<T>(0)) == sizeof(char); static const bool value = sizeof(test<T>(0)) == sizeof(char);
}; };
template <typename T>
struct has_to_string_test {
private:
typedef std::array<char, 1> one;
typedef std::array<char, 2> two;
template <typename C> static one test(decltype(std::declval<C>().to_string())*);
template <typename C> static two test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(char);
};
#if defined(_MSC_VER) && _MSC_VER <= 1910
template <typename T, typename U, typename = decltype(std::declval<T&>() < std::declval<U&>())>
std::true_type supports_op_less_test(std::reference_wrapper<T>, std::reference_wrapper<U>);
std::false_type supports_op_less_test(...);
template <typename T, typename U, typename = decltype(std::declval<T&>() == std::declval<U&>())>
std::true_type supports_op_equal_test(std::reference_wrapper<T>, std::reference_wrapper<U>);
std::false_type supports_op_equal_test(...);
template <typename T, typename U, typename = decltype(std::declval<T&>() <= std::declval<U&>())>
std::true_type supports_op_less_equal_test(std::reference_wrapper<T>, std::reference_wrapper<U>);
std::false_type supports_op_less_equal_test(...);
template <typename T, typename OS, typename = decltype(std::declval<OS&>() << std::declval<T&>())>
std::true_type supports_ostream_op(std::reference_wrapper<T>, std::reference_wrapper<OS>);
std::false_type supports_ostream_op(...);
template <typename T, typename = decltype(to_string(std::declval<T&>()))>
std::true_type supports_adl_to_string(std::reference_wrapper<T>);
std::false_type supports_adl_to_string(...);
#else
template <typename T, typename U, typename = decltype(std::declval<T&>() < std::declval<U&>())> template <typename T, typename U, typename = decltype(std::declval<T&>() < std::declval<U&>())>
std::true_type supports_op_less_test(const T&, const U&); std::true_type supports_op_less_test(const T&, const U&);
std::false_type supports_op_less_test(...); std::false_type supports_op_less_test(...);
@ -394,9 +423,24 @@ namespace sol {
template <typename T, typename OS, typename = decltype(std::declval<OS&>() << std::declval<T&>())> template <typename T, typename OS, typename = decltype(std::declval<OS&>() << std::declval<T&>())>
std::true_type supports_ostream_op(const T&, const OS&); std::true_type supports_ostream_op(const T&, const OS&);
std::false_type supports_ostream_op(...); std::false_type supports_ostream_op(...);
template <typename T, typename = decltype(to_string(std::declval<T&>()))>
std::true_type supports_adl_to_string(const T&);
std::false_type supports_adl_to_string(...);
#endif
} // meta_detail } // meta_detail
#if defined(_MSC_VER) && _MSC_VER <= 1910
template <typename T, typename U = T>
using supports_op_less = decltype(meta_detail::supports_op_less_test(std::ref(std::declval<T&>()), std::ref(std::declval<U&>())));
template <typename T, typename U = T>
using supports_op_equal = decltype(meta_detail::supports_op_equal_test(std::ref(std::declval<T&>()), std::ref(std::declval<U&>())));
template <typename T, typename U = T>
using supports_op_less_equal = decltype(meta_detail::supports_op_less_equal_test(std::ref(std::declval<T&>()), std::ref(std::declval<U&>())));
template <typename T, typename U = std::ostream>
using supports_ostream_op = decltype(meta_detail::supports_ostream_op(std::ref(std::declval<T&>()), std::ref(std::declval<U&>())));
template <typename T>
using supports_adl_to_string = decltype(meta_detail::supports_adl_to_string(std::ref(std::declval<T&>())));
#else
template <typename T, typename U = T> template <typename T, typename U = T>
using supports_op_less = decltype(meta_detail::supports_op_less_test(std::declval<T&>(), std::declval<U&>())); using supports_op_less = decltype(meta_detail::supports_op_less_test(std::declval<T&>(), std::declval<U&>()));
template <typename T, typename U = T> template <typename T, typename U = T>
@ -405,6 +449,11 @@ namespace sol {
using supports_op_less_equal = decltype(meta_detail::supports_op_less_equal_test(std::declval<T&>(), std::declval<U&>())); using supports_op_less_equal = decltype(meta_detail::supports_op_less_equal_test(std::declval<T&>(), std::declval<U&>()));
template <typename T, typename U = std::ostream> template <typename T, typename U = std::ostream>
using supports_ostream_op = decltype(meta_detail::supports_ostream_op(std::declval<T&>(), std::declval<U&>())); using supports_ostream_op = decltype(meta_detail::supports_ostream_op(std::declval<T&>(), std::declval<U&>()));
template <typename T>
using supports_adl_to_string = decltype(meta_detail::supports_adl_to_string(std::declval<T&>()));
#endif
template <typename T>
using supports_to_string_member = meta::boolean<meta_detail::has_to_string_test<T>::value>;
template<typename T> template<typename T>
struct is_callable : boolean<meta_detail::is_callable<T>::value> {}; struct is_callable : boolean<meta_detail::is_callable<T>::value> {};

View File

@ -26,8 +26,12 @@
#include "optional.hpp" #include "optional.hpp"
#include "compatibility.hpp" #include "compatibility.hpp"
#include "forward.hpp" #include "forward.hpp"
#include "forward_detail.hpp"
#include "traits.hpp" #include "traits.hpp"
#include "string_shim.hpp" #include "string_shim.hpp"
#include "raii.hpp"
#include "filters.hpp"
#include <array> #include <array>
#include <string> #include <string>
#ifdef SOL_CXX17_FEATURES #ifdef SOL_CXX17_FEATURES
@ -1042,6 +1046,13 @@ namespace sol {
template <> template <>
struct is_lua_index<upvalue_index> : std::true_type {}; struct is_lua_index<upvalue_index> : std::true_type {};
template <typename T>
struct is_stack_based : std::is_base_of<stack_reference, T> {};
template <>
struct is_stack_based<raw_index> : std::true_type {};
template <>
struct is_stack_based<absolute_index> : std::true_type {};
template <typename Signature> template <typename Signature>
struct lua_bind_traits : meta::bind_traits<Signature> { struct lua_bind_traits : meta::bind_traits<Signature> {
private: private:
@ -1083,6 +1094,48 @@ namespace sol {
inline type type_of() { inline type type_of() {
return lua_type_of<meta::unqualified_t<T>>::value; return lua_type_of<meta::unqualified_t<T>>::value;
} }
namespace detail {
template <typename T>
struct is_non_factory_constructor : std::false_type {};
template <typename... Args>
struct is_non_factory_constructor<constructors<Args...>> : std::true_type {};
template <typename... Args>
struct is_non_factory_constructor<constructor_wrapper<Args...>> : std::true_type {};
template <>
struct is_non_factory_constructor<no_construction> : std::true_type {};
template <typename T>
struct is_constructor : is_non_factory_constructor<T> {};
template <typename... Args>
struct is_constructor<factory_wrapper<Args...>> : std::true_type {};
template <typename T>
struct is_constructor<protect_t<T>> : is_constructor<meta::unqualified_t<T>> {};
template <typename F, typename... Filters>
struct is_constructor<filter_wrapper<F, Filters...>> : is_constructor<meta::unqualified_t<F>> {};
template <typename... Args>
using has_constructor = meta::any<is_constructor<meta::unqualified_t<Args>>...>;
template <typename T>
struct is_destructor : std::false_type {};
template <typename Fx>
struct is_destructor<destructor_wrapper<Fx>> : std::true_type {};
template <typename... Args>
using has_destructor = meta::any<is_destructor<meta::unqualified_t<Args>>...>;
struct add_destructor_tag {};
struct check_destructor_tag {};
struct verified_tag {} const verified{};
} // detail
} // sol } // sol
#endif // SOL_TYPES_HPP #endif // SOL_TYPES_HPP

View File

@ -81,7 +81,7 @@ namespace sol {
basic_function& operator=(basic_function&&) = default; basic_function& operator=(basic_function&&) = default;
basic_function(const stack_reference& r) : basic_function(r.lua_state(), r.stack_index()) {} basic_function(const stack_reference& r) : basic_function(r.lua_state(), r.stack_index()) {}
basic_function(stack_reference&& r) : basic_function(r.lua_state(), r.stack_index()) {} basic_function(stack_reference&& r) : basic_function(r.lua_state(), r.stack_index()) {}
template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<std::is_same<T, ref_index>>> = meta::enabler> template <typename T, meta::enable<meta::neg<is_lua_index<meta::unqualified_t<T>>>> = meta::enabler>
basic_function(lua_State* L, T&& r) : basic_function(L, sol::ref_index(r.registry_index())) {} basic_function(lua_State* L, T&& r) : basic_function(L, sol::ref_index(r.registry_index())) {}
basic_function(lua_State* L, int index = -1) : base_t(L, index) { basic_function(lua_State* L, int index = -1) : base_t(L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS

View File

@ -48,7 +48,7 @@ namespace sol {
basic_userdata& operator=(basic_userdata&&) = default; basic_userdata& operator=(basic_userdata&&) = default;
basic_userdata(const stack_reference& r) : basic_userdata(r.lua_state(), r.stack_index()) {} basic_userdata(const stack_reference& r) : basic_userdata(r.lua_state(), r.stack_index()) {}
basic_userdata(stack_reference&& r) : basic_userdata(r.lua_state(), r.stack_index()) {} basic_userdata(stack_reference&& r) : basic_userdata(r.lua_state(), r.stack_index()) {}
template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<std::is_same<meta::unqualified_t<T>, ref_index>>> = meta::enabler> template <typename T, meta::enable<meta::neg<is_lua_index<meta::unqualified_t<T>>>> = meta::enabler>
basic_userdata(lua_State* L, T&& r) : basic_userdata(L, sol::ref_index(r.registry_index())) {} basic_userdata(lua_State* L, T&& r) : basic_userdata(L, sol::ref_index(r.registry_index())) {}
basic_userdata(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) { basic_userdata(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
@ -85,7 +85,7 @@ namespace sol {
basic_lightuserdata& operator=(basic_lightuserdata&&) = default; basic_lightuserdata& operator=(basic_lightuserdata&&) = default;
basic_lightuserdata(const stack_reference& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) {} basic_lightuserdata(const stack_reference& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) {}
basic_lightuserdata(stack_reference&& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) {} basic_lightuserdata(stack_reference&& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) {}
template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<std::is_same<meta::unqualified_t<T>, ref_index>>> = meta::enabler> template <typename T, meta::enable<meta::neg<is_lua_index<T>>> = meta::enabler>
basic_lightuserdata(lua_State* L, T&& r) : basic_lightuserdata(L, sol::ref_index(r.registry_index())) {} basic_lightuserdata(lua_State* L, T&& r) : basic_lightuserdata(L, sol::ref_index(r.registry_index())) {}
basic_lightuserdata(lua_State* L, int index = -1) : base_t(L, index) { basic_lightuserdata(lua_State* L, int index = -1) : base_t(L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS

View File

@ -36,24 +36,26 @@ namespace sol {
std::unique_ptr<usertype_detail::registrar, detail::deleter> metatableregister; std::unique_ptr<usertype_detail::registrar, detail::deleter> metatableregister;
template<typename... Args> template<typename... Args>
usertype(usertype_detail::verified_tag, Args&&... args) : metatableregister(detail::make_unique_deleter<usertype_metatable<T, std::make_index_sequence<sizeof...(Args) / 2>, Args...>, detail::deleter>(std::forward<Args>(args)...)) {} usertype(detail::verified_tag, Args&&... args) : metatableregister(detail::make_unique_deleter<usertype_metatable<T, std::make_index_sequence<sizeof...(Args) / 2>, Args...>, detail::deleter>(std::forward<Args>(args)...)) {
static_assert(detail::has_destructor<Args...>::value, "this type does not have an explicit destructor declared; please pass a custom destructor function wrapped in sol::destruct, especially if the type does not have an accessible (private) destructor");
}
template<typename... Args> template<typename... Args>
usertype(usertype_detail::add_destructor_tag, Args&&... args) : usertype(usertype_detail::verified, std::forward<Args>(args)..., "__gc", default_destructor) {} usertype(detail::add_destructor_tag, Args&&... args) : usertype(detail::verified, std::forward<Args>(args)..., "__gc", default_destructor) {}
template<typename... Args> template<typename... Args>
usertype(usertype_detail::check_destructor_tag, Args&&... args) : usertype(meta::condition<meta::all<std::is_destructible<T>, meta::neg<usertype_detail::has_destructor<Args...>>>, usertype_detail::add_destructor_tag, usertype_detail::verified_tag>(), std::forward<Args>(args)...) {} usertype(detail::check_destructor_tag, Args&&... args) : usertype(meta::condition<meta::all<std::is_destructible<T>, meta::neg<detail::has_destructor<Args...>>>, detail::add_destructor_tag, detail::verified_tag>(), std::forward<Args>(args)...) {}
public: public:
template<typename... Args> template<typename... Args>
usertype(Args&&... args) : usertype(meta::condition<meta::all<std::is_default_constructible<T>, meta::neg<usertype_detail::has_constructor<Args...>>>, decltype(default_constructor), usertype_detail::check_destructor_tag>(), std::forward<Args>(args)...) {} usertype(Args&&... args) : usertype(meta::condition<meta::all<std::is_default_constructible<T>, meta::neg<detail::has_constructor<Args...>>>, decltype(default_constructor), detail::check_destructor_tag>(), std::forward<Args>(args)...) {}
template<typename... Args, typename... CArgs> template<typename... Args, typename... CArgs>
usertype(constructors<CArgs...> constructorlist, Args&&... args) : usertype(usertype_detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) {} usertype(constructors<CArgs...> constructorlist, Args&&... args) : usertype(detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) {}
template<typename... Args, typename... Fxs> template<typename... Args, typename... Fxs>
usertype(constructor_wrapper<Fxs...> constructorlist, Args&&... args) : usertype(usertype_detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) {} usertype(constructor_wrapper<Fxs...> constructorlist, Args&&... args) : usertype(detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) {}
template<typename... Args> template<typename... Args>
usertype(simple_tag, lua_State* L, Args&&... args) : metatableregister(detail::make_unique_deleter<simple_usertype_metatable<T>, detail::deleter>(L, std::forward<Args>(args)...)) {} usertype(simple_tag, lua_State* L, Args&&... args) : metatableregister(detail::make_unique_deleter<simple_usertype_metatable<T>, detail::deleter>(L, std::forward<Args>(args)...)) {}

235
sol/usertype_core.hpp Normal file
View File

@ -0,0 +1,235 @@
// The MIT License (MIT)
// Copyright (c) 2013-2017 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_USERTYPE_CORE_HPP
#define SOL_USERTYPE_CORE_HPP
#include "wrapper.hpp"
#include "call.hpp"
#include "stack.hpp"
#include "types.hpp"
#include "stack_reference.hpp"
#include "usertype_traits.hpp"
#include "inheritance.hpp"
#include "raii.hpp"
#include "deprecate.hpp"
#include "object.hpp"
#include <sstream>
namespace sol {
namespace usertype_detail {
struct no_comp {
template <typename A, typename B>
bool operator()(A&&, B&&) const {
return false;
}
};
template <typename T>
inline int member_default_to_string(std::true_type, lua_State* L) {
std::string ts = stack::get<T>(L, 1).to_string();
return stack::push(L, std::move(ts));
}
template <typename T>
inline int member_default_to_string(std::false_type, lua_State* L) {
return luaL_error(L, "cannot perform to_string on '%s': no 'to_string' overload in namespace, 'to_string' member function, or operator<<(ostream&, ...) present", detail::demangle<T>().data());
}
template <typename T>
inline int adl_default_to_string(std::true_type, lua_State* L) {
using std::to_string;
std::string ts = to_string(stack::get<T>(L, 1));
return stack::push(L, std::move(ts));
}
template <typename T>
inline int adl_default_to_string(std::false_type, lua_State* L) {
return member_default_to_string<T>(meta::supports_to_string_member<T>(), L);
}
template <typename T>
inline int oss_default_to_string(std::true_type, lua_State* L) {
std::ostringstream oss;
oss << stack::get<T>(L, 1);
return stack::push(L, oss.str());
}
template <typename T>
inline int oss_default_to_string(std::false_type, lua_State* L) {
return adl_default_to_string<T>(meta::supports_adl_to_string<T>(), L);
}
template <typename T>
inline int default_to_string(lua_State* L) {
return oss_default_to_string<T>(meta::supports_ostream_op<T>(), L);
}
template <typename T, typename Op>
int comparsion_operator_wrap(lua_State* L) {
auto maybel = stack::check_get<T>(L, 1);
if (maybel) {
auto mayber = stack::check_get<T>(L, 2);
if (mayber) {
auto& l = *maybel;
auto& r = *mayber;
if (std::is_same<no_comp, Op>::value) {
return stack::push(L, detail::ptr(l) == detail::ptr(r));
}
else {
Op op;
return stack::push(L, (detail::ptr(l) == detail::ptr(r)) || op(detail::deref(l), detail::deref(r)));
}
}
}
return stack::push(L, false);
}
template <typename T, typename Op, typename Supports, typename Regs, meta::enable<Supports> = meta::enabler>
inline void make_reg_op(Regs& l, int& index, const char* name) {
lua_CFunction f = &comparsion_operator_wrap<T, Op>;
l[index] = luaL_Reg{ name, f };
++index;
}
template <typename T, typename Op, typename Supports, typename Regs, meta::disable<Supports> = meta::enabler>
inline void make_reg_op(Regs&, int&, const char*) {
// Do nothing if there's no support
}
template <typename T, typename Supports, typename Regs, meta::enable<Supports> = meta::enabler>
inline void make_to_string_op(Regs& l, int& index) {
const char* name = to_string(meta_function::to_string).c_str();
lua_CFunction f = &detail::static_trampoline<&default_to_string<T>>;
l[index] = luaL_Reg{ name, f };
++index;
}
template <typename T, typename Supports, typename Regs, meta::disable<Supports> = meta::enabler>
inline void make_to_string_op(Regs&, int&) {
// Do nothing if there's no support
}
template <typename T, typename Regs, meta::enable<meta::has_deducible_signature<T>> = meta::enabler>
inline void make_call_op(Regs& l, int& index) {
const char* name = to_string(meta_function::call).c_str();
lua_CFunction f = &c_call<decltype(&T::operator()), &T::operator()>;
l[index] = luaL_Reg{ name, f };
++index;
}
template <typename T, typename Regs, meta::disable<meta::has_deducible_signature<T>> = meta::enabler>
inline void make_call_op(Regs&, int&) {
// Do nothing if there's no support
}
template <typename T, typename Regs, meta::enable<meta::has_size<T>> = meta::enabler>
inline void make_length_op(Regs& l, int& index) {
const char* name = to_string(meta_function::length).c_str();
l[index] = luaL_Reg{ name, &c_call<decltype(&T::size), &T::size> };
++index;
}
template <typename T, typename Regs, meta::disable<meta::has_size<T>> = meta::enabler>
inline void make_length_op(Regs&, int&) {
// Do nothing if there's no support
}
template <typename T, typename Regs, meta::enable<meta::neg<std::is_pointer<T>>, std::is_destructible<T>>>
void make_destructor(Regs& l, int& index) {
const char* name = to_string(meta_function::garbage_collect).c_str();
l[index] = luaL_Reg{ name, is_unique_usertype<T>::value ? &detail::unique_destruct<T> : &detail::usertype_alloc_destruct<T> };
++index;
}
template <typename T, typename Regs, meta::disable<meta::neg<std::is_pointer<T>>, std::is_destructible<T>>>
void make_destructor(Regs& l, int& index) {
if (!std::is_destructible<T>::value) {
// if the value is not destructible, plant an erroring __gc method
// to warn the user of a problem when it comes around
// this won't trigger if the user performs `new_usertype` / `new_simple_usertype` and
// rigs the class up properly
const char* name = to_string(meta_function::garbage_collect).c_str();
l[index] = luaL_Reg{ name, &detail::cannot_destruct<T> };
++index;
}
}
template <typename T, typename Regs, typename Fx>
void insert_default_registrations(Regs& l, int& index, Fx&& fx) {
if (fx(meta_function::less_than)) {
const char* name = to_string(meta_function::less_than).c_str();
usertype_detail::make_reg_op<T, std::less<>, meta::supports_op_less<T>>(l, index, name);
}
if (fx(meta_function::less_than_or_equal_to)) {
const char* name = to_string(meta_function::less_than_or_equal_to).c_str();
usertype_detail::make_reg_op<T, std::less_equal<>, meta::supports_op_less_equal<T>>(l, index, name);
}
if (fx(meta_function::equal_to)) {
const char* name = to_string(meta_function::equal_to).c_str();
usertype_detail::make_reg_op<T, std::conditional_t<meta::supports_op_equal<T>::value, std::equal_to<>, usertype_detail::no_comp>, std::true_type>(l, index, name);
}
if (fx(meta_function::pairs)) {
const char* name = to_string(meta_function::pairs).c_str();
l[index] = luaL_Reg{ name, container_usertype_metatable<as_container_t<T>>::pairs_call };
++index;
}
if (fx(meta_function::length)) {
usertype_detail::make_length_op<T>(l, index);
}
if (fx(meta_function::to_string)) {
usertype_detail::make_to_string_op<T, meta::any<meta::supports_to_string_member<T>, meta::supports_adl_to_string<T>, meta::supports_ostream_op<T>>>(l, index);
}
if (fx(meta_function::call_function)) {
usertype_detail::make_call_op<T>(l, index);
}
}
} // usertype_detail
namespace stack {
namespace stack_detail {
template <typename T>
struct undefined_metatable {
typedef meta::all<meta::neg<std::is_pointer<T>>, std::is_destructible<T>> is_destructible;
typedef std::remove_pointer_t<T> P;
lua_State* L;
const char* key;
undefined_metatable(lua_State* l, const char* k) : L(l), key(k) {}
void operator () () const {
if (luaL_newmetatable(L, key) == 1) {
luaL_Reg l[32]{};
int index = 0;
auto fx = [](meta_function) { return true; };
usertype_detail::insert_default_registrations<P>(l, index, fx);
usertype_detail::make_destructor<T>(l, index);
luaL_setfuncs(L, l, 0);
}
lua_setmetatable(L, -2);
}
};
} // stack_detail
} // stack
} // sol
#endif // SOL_USERTYPE_CORE_HPP

View File

@ -33,6 +33,7 @@
#include "deprecate.hpp" #include "deprecate.hpp"
#include "object.hpp" #include "object.hpp"
#include "container_usertype_metatable.hpp" #include "container_usertype_metatable.hpp"
#include "usertype_core.hpp"
#include <unordered_map> #include <unordered_map>
#include <cstdio> #include <cstdio>
#include <sstream> #include <sstream>
@ -102,13 +103,6 @@ namespace sol {
index(std::move(i)), newindex(std::move(ni)), index(std::move(i)), newindex(std::move(ni)),
indexbaseclasspropogation(index), newindexbaseclasspropogation(newindex) {} indexbaseclasspropogation(index), newindexbaseclasspropogation(newindex) {}
}; };
template <typename T>
inline int default_to_string(lua_State* L) {
std::ostringstream oss;
oss << stack::get<T>(L, 1);
return stack::push(L, oss.str());
}
} // usertype_detail } // usertype_detail
struct usertype_metatable_core { struct usertype_metatable_core {
@ -134,47 +128,6 @@ namespace sol {
namespace usertype_detail { namespace usertype_detail {
const lua_Integer toplevel_magic = static_cast<lua_Integer>(0xCCC2CCC1); const lua_Integer toplevel_magic = static_cast<lua_Integer>(0xCCC2CCC1);
struct add_destructor_tag {};
struct check_destructor_tag {};
struct verified_tag {} const verified{};
template <typename T>
struct is_non_factory_constructor : std::false_type {};
template <typename... Args>
struct is_non_factory_constructor<constructors<Args...>> : std::true_type {};
template <typename... Args>
struct is_non_factory_constructor<constructor_wrapper<Args...>> : std::true_type {};
template <>
struct is_non_factory_constructor<no_construction> : std::true_type {};
template <typename T>
struct is_constructor : is_non_factory_constructor<T> {};
template <typename... Args>
struct is_constructor<factory_wrapper<Args...>> : std::true_type {};
template <typename... Args>
using has_constructor = meta::any<is_constructor<meta::unqualified_t<Args>>...>;
template <typename T>
struct is_destructor : std::false_type {};
template <typename Fx>
struct is_destructor<destructor_wrapper<Fx>> : std::true_type {};
template <typename... Args>
using has_destructor = meta::any<is_destructor<meta::unqualified_t<Args>>...>;
struct no_comp {
template <typename A, typename B>
bool operator()(A&&, B&&) const {
return false;
}
};
inline int is_indexer(string_detail::string_shim s) { inline int is_indexer(string_detail::string_shim s) {
if (s == to_string(meta_function::index)) { if (s == to_string(meta_function::index)) {
return 1; return 1;
@ -409,76 +362,6 @@ namespace sol {
(void)accessor; (void)accessor;
(void)detail::swallow{ 0, (walk_single_base<is_index, Bases>(L, found, ret, accessor), 0)... }; (void)detail::swallow{ 0, (walk_single_base<is_index, Bases>(L, found, ret, accessor), 0)... };
} }
template <typename T, typename Op>
int operator_wrap(lua_State* L) {
auto maybel = stack::check_get<T>(L, 1);
if (maybel) {
auto mayber = stack::check_get<T>(L, 2);
if (mayber) {
auto& l = *maybel;
auto& r = *mayber;
if (std::is_same<no_comp, Op>::value) {
return stack::push(L, detail::ptr(l) == detail::ptr(r));
}
else {
Op op;
return stack::push(L, (detail::ptr(l) == detail::ptr(r)) || op(detail::deref(l), detail::deref(r)));
}
}
}
return stack::push(L, false);
}
template <typename T, typename Op, typename Supports, typename Regs, meta::enable<Supports> = meta::enabler>
inline void make_reg_op(Regs& l, int& index, const char* name) {
lua_CFunction f = &operator_wrap<T, Op>;
l[index] = luaL_Reg{ name, f };
++index;
}
template <typename T, typename Op, typename Supports, typename Regs, meta::disable<Supports> = meta::enabler>
inline void make_reg_op(Regs&, int&, const char*) {
// Do nothing if there's no support
}
template <typename T, typename Supports, typename Regs, meta::enable<Supports> = meta::enabler>
inline void make_to_string_op(Regs& l, int& index) {
const char* name = to_string(meta_function::to_string).c_str();
lua_CFunction f = &detail::static_trampoline<&default_to_string<T>>;
l[index] = luaL_Reg{ name, f };
++index;
}
template <typename T, typename Supports, typename Regs, meta::disable<Supports> = meta::enabler>
inline void make_to_string_op(Regs&, int&) {
// Do nothing if there's no support
}
template <typename T, typename Regs, meta::enable<meta::has_deducible_signature<T>> = meta::enabler>
inline void make_call_op(Regs& l, int& index) {
const char* name = to_string(meta_function::call).c_str();
lua_CFunction f = &c_call<decltype(&T::operator()), &T::operator()>;
l[index] = luaL_Reg{ name, f };
++index;
}
template <typename T, typename Regs, meta::disable<meta::has_deducible_signature<T>> = meta::enabler>
inline void make_call_op(Regs&, int&) {
// Do nothing if there's no support
}
template <typename T, typename Regs, meta::enable<meta::has_size<T>> = meta::enabler>
inline void make_length_op(Regs& l, int& index) {
const char* name = to_string(meta_function::length).c_str();
l[index] = luaL_Reg{ name, &c_call<decltype(&T::size), &T::size> };
++index;
}
template <typename T, typename Regs, meta::disable<meta::has_size<T>> = meta::enabler>
inline void make_length_op(Regs&, int&) {
// Do nothing if there's no support
}
} // usertype_detail } // usertype_detail
template <typename T> template <typename T>
@ -536,32 +419,8 @@ namespace sol {
} }
int finish_regs(regs_t& l, int& index) { int finish_regs(regs_t& l, int& index) {
if (!properties[static_cast<int>(meta_function::less_than)]) { auto prop_fx = [&](meta_function mf) { return !properties[static_cast<int>(mf)]; };
const char* name = to_string(meta_function::less_than).c_str(); usertype_detail::insert_default_registrations<T>(l, index, prop_fx);
usertype_detail::make_reg_op<T, std::less<>, meta::supports_op_less<T>>(l, index, name);
}
if (!properties[static_cast<int>(meta_function::less_than_or_equal_to)]) {
const char* name = to_string(meta_function::less_than_or_equal_to).c_str();
usertype_detail::make_reg_op<T, std::less_equal<>, meta::supports_op_less_equal<T>>(l, index, name);
}
if (!properties[static_cast<int>(meta_function::equal_to)]) {
const char* name = to_string(meta_function::equal_to).c_str();
usertype_detail::make_reg_op<T, std::conditional_t<meta::supports_op_equal<T>::value, std::equal_to<>, usertype_detail::no_comp>, std::true_type>(l, index, name);
}
if (!properties[static_cast<int>(meta_function::pairs)]) {
const char* name = to_string(meta_function::pairs).c_str();
l[index] = luaL_Reg{ name, container_usertype_metatable<as_container_t<T>>::pairs_call };
++index;
}
if (!properties[static_cast<int>(meta_function::length)]) {
usertype_detail::make_length_op<T>(l, index);
}
if (!properties[static_cast<int>(meta_function::to_string)]) {
usertype_detail::make_to_string_op<T, meta::supports_ostream_op<T>>(l, index);
}
if (!properties[static_cast<int>(meta_function::call)]) {
usertype_detail::make_call_op<T>(l, index);
}
if (destructfunc != nullptr) { if (destructfunc != nullptr) {
l[index] = luaL_Reg{ to_string(meta_function::garbage_collect).c_str(), destructfunc }; l[index] = luaL_Reg{ to_string(meta_function::garbage_collect).c_str(), destructfunc };
++index; ++index;
@ -732,7 +591,7 @@ namespace sol {
typedef meta::unqualified_tuple_element_t<Idx - 1, Tuple> K; typedef meta::unqualified_tuple_element_t<Idx - 1, Tuple> K;
typedef meta::unqualified_tuple_element_t<Idx, Tuple> F; typedef meta::unqualified_tuple_element_t<Idx, Tuple> F;
static const int boost = static const int boost =
!usertype_detail::is_non_factory_constructor<F>::value !detail::is_non_factory_constructor<F>::value
&& std::is_same<K, call_construction>::value ? && std::is_same<K, call_construction>::value ?
1 : 0; 1 : 0;
auto& f = std::get<Idx>(um.functions); auto& f = std::get<Idx>(um.functions);

View File

@ -1,4 +1,4 @@
#define SOL_CHECK_ARGUMENTS #define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp> #include <sol.hpp>
#include <catch.hpp> #include <catch.hpp>
@ -94,7 +94,7 @@ namespace sol {
template <typename T> template <typename T>
void sequence_container_check(sol::state& lua, T& items) { void sequence_container_check(sol::state& lua, T& items) {
{ {
auto r1 = lua.script(R"( auto r1 = lua.safe_script(R"(
for i=1,#c do for i=1,#c do
v = c[i] v = c[i]
assert(v == (i + 10)) assert(v == (i + 10))
@ -104,45 +104,45 @@ end
} }
{ {
auto ffind = [&]() { auto ffind = [&]() {
auto r1 = lua.script("i1 = c:find(11)", sol::script_pass_on_error); auto r1 = lua.safe_script("i1 = c:find(11)", sol::script_pass_on_error);
REQUIRE(r1.valid()); REQUIRE(r1.valid());
auto r2 = lua.script("i2 = c:find(14)", sol::script_pass_on_error); auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error);
REQUIRE(r2.valid()); REQUIRE(r2.valid());
}; };
auto fget = [&]() { auto fget = [&]() {
auto r1 = lua.script("v1 = c:get(1)", sol::script_pass_on_error); auto r1 = lua.safe_script("v1 = c:get(1)", sol::script_pass_on_error);
REQUIRE(r1.valid()); REQUIRE(r1.valid());
auto r2 = lua.script("v2 = c:get(3)", sol::script_pass_on_error); auto r2 = lua.safe_script("v2 = c:get(3)", sol::script_pass_on_error);
REQUIRE(r2.valid()); REQUIRE(r2.valid());
}; };
auto fset = [&]() { auto fset = [&]() {
auto r1 = lua.script("c:set(2, 20)", sol::script_pass_on_error); auto r1 = lua.safe_script("c:set(2, 20)", sol::script_pass_on_error);
REQUIRE(r1.valid()); REQUIRE(r1.valid());
auto r2 = lua.script("c:set(6, 16)", sol::script_pass_on_error); auto r2 = lua.safe_script("c:set(6, 16)", sol::script_pass_on_error);
REQUIRE(r2.valid()); REQUIRE(r2.valid());
}; };
auto ferase = [&]() { auto ferase = [&]() {
auto r5 = lua.script("s1 = #c", sol::script_pass_on_error); auto r5 = lua.safe_script("s1 = #c", sol::script_pass_on_error);
REQUIRE(r5.valid()); REQUIRE(r5.valid());
auto r1 = lua.script("c:erase(i1)", sol::script_pass_on_error); auto r1 = lua.safe_script("c:erase(i1)", sol::script_pass_on_error);
REQUIRE(r1.valid()); REQUIRE(r1.valid());
auto r3 = lua.script("s2 = #c", sol::script_pass_on_error); auto r3 = lua.safe_script("s2 = #c", sol::script_pass_on_error);
REQUIRE(r3.valid()); REQUIRE(r3.valid());
auto r2 = lua.script("c:erase(i2)", sol::script_pass_on_error); auto r2 = lua.safe_script("c:erase(i2)", sol::script_pass_on_error);
REQUIRE(r2.valid()); REQUIRE(r2.valid());
auto r4 = lua.script("s3 = #c", sol::script_pass_on_error); auto r4 = lua.safe_script("s3 = #c", sol::script_pass_on_error);
REQUIRE(r4.valid()); REQUIRE(r4.valid());
}; };
auto fadd = [&]() { auto fadd = [&]() {
auto r = lua.script("c:add(17)", sol::script_pass_on_error); auto r = lua.safe_script("c:add(17)", sol::script_pass_on_error);
REQUIRE(r.valid()); REQUIRE(r.valid());
}; };
auto fopset = [&]() { auto fopset = [&]() {
auto r = lua.script("c[#c + 1] = 18", sol::script_pass_on_error); auto r = lua.safe_script("c[#c + 1] = 18", sol::script_pass_on_error);
REQUIRE(r.valid()); REQUIRE(r.valid());
}; };
auto fopget = [&]() { auto fopget = [&]() {
auto r = lua.script("v3 = c[#c]", sol::script_pass_on_error); auto r = lua.safe_script("v3 = c[#c]", sol::script_pass_on_error);
REQUIRE(r.valid()); REQUIRE(r.valid());
}; };
REQUIRE_NOTHROW(ffind()); REQUIRE_NOTHROW(ffind());
@ -203,7 +203,7 @@ end
template <typename T> template <typename T>
void ordered_container_check(sol::state& lua, T& items) { void ordered_container_check(sol::state& lua, T& items) {
{ {
auto r1 = lua.script(R"( auto r1 = lua.safe_script(R"(
for i=1,#c do for i=1,#c do
v = c[(i + 10)] v = c[(i + 10)]
assert(v == (i + 10)) assert(v == (i + 10))
@ -213,45 +213,45 @@ end
} }
{ {
auto ffind = [&]() { auto ffind = [&]() {
auto r1 = lua.script("i1 = c:find(11)", sol::script_pass_on_error); auto r1 = lua.safe_script("i1 = c:find(11)", sol::script_pass_on_error);
REQUIRE(r1.valid()); REQUIRE(r1.valid());
auto r2 = lua.script("i2 = c:find(14)", sol::script_pass_on_error); auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error);
REQUIRE(r2.valid()); REQUIRE(r2.valid());
}; };
auto fget = [&]() { auto fget = [&]() {
auto r1 = lua.script("v1 = c:get(11)", sol::script_pass_on_error); auto r1 = lua.safe_script("v1 = c:get(11)", sol::script_pass_on_error);
REQUIRE(r1.valid()); REQUIRE(r1.valid());
auto r2 = lua.script("v2 = c:get(13)", sol::script_pass_on_error); auto r2 = lua.safe_script("v2 = c:get(13)", sol::script_pass_on_error);
REQUIRE(r2.valid()); REQUIRE(r2.valid());
}; };
auto fset = [&]() { auto fset = [&]() {
auto r1 = lua.script("c:set(20)", sol::script_pass_on_error); auto r1 = lua.safe_script("c:set(20)", sol::script_pass_on_error);
REQUIRE(r1.valid()); REQUIRE(r1.valid());
auto r2 = lua.script("c:set(16)", sol::script_pass_on_error); auto r2 = lua.safe_script("c:set(16)", sol::script_pass_on_error);
REQUIRE(r2.valid()); REQUIRE(r2.valid());
}; };
auto ferase = [&]() { auto ferase = [&]() {
auto r5 = lua.script("s1 = #c", sol::script_pass_on_error); auto r5 = lua.safe_script("s1 = #c", sol::script_pass_on_error);
REQUIRE(r5.valid()); REQUIRE(r5.valid());
auto r1 = lua.script("c:erase(i1)", sol::script_pass_on_error); auto r1 = lua.safe_script("c:erase(i1)", sol::script_pass_on_error);
REQUIRE(r1.valid()); REQUIRE(r1.valid());
auto r3 = lua.script("s2 = #c", sol::script_pass_on_error); auto r3 = lua.safe_script("s2 = #c", sol::script_pass_on_error);
REQUIRE(r3.valid()); REQUIRE(r3.valid());
auto r2 = lua.script("c:erase(i2)", sol::script_pass_on_error); auto r2 = lua.safe_script("c:erase(i2)", sol::script_pass_on_error);
REQUIRE(r2.valid()); REQUIRE(r2.valid());
auto r4 = lua.script("s3 = #c", sol::script_pass_on_error); auto r4 = lua.safe_script("s3 = #c", sol::script_pass_on_error);
REQUIRE(r4.valid()); REQUIRE(r4.valid());
}; };
auto fadd = [&]() { auto fadd = [&]() {
auto r = lua.script("c:add(17)", sol::script_pass_on_error); auto r = lua.safe_script("c:add(17)", sol::script_pass_on_error);
REQUIRE(r.valid()); REQUIRE(r.valid());
}; };
auto fopset = [&]() { auto fopset = [&]() {
auto r = lua.script("c[18] = true", sol::script_pass_on_error); auto r = lua.safe_script("c[18] = true", sol::script_pass_on_error);
REQUIRE(r.valid()); REQUIRE(r.valid());
}; };
auto fopget = [&]() { auto fopget = [&]() {
auto r = lua.script("v3 = c[20]", sol::script_pass_on_error); auto r = lua.safe_script("v3 = c[20]", sol::script_pass_on_error);
REQUIRE(r.valid()); REQUIRE(r.valid());
}; };
REQUIRE_NOTHROW(ffind()); REQUIRE_NOTHROW(ffind());
@ -313,45 +313,45 @@ template <typename T>
void unordered_container_check(sol::state& lua, T& items) { void unordered_container_check(sol::state& lua, T& items) {
{ {
auto ffind = [&]() { auto ffind = [&]() {
auto r1 = lua.script("i1 = c:find(11)", sol::script_pass_on_error); auto r1 = lua.safe_script("i1 = c:find(11)", sol::script_pass_on_error);
REQUIRE(r1.valid()); REQUIRE(r1.valid());
auto r2 = lua.script("i2 = c:find(14)", sol::script_pass_on_error); auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error);
REQUIRE(r2.valid()); REQUIRE(r2.valid());
}; };
auto fget = [&]() { auto fget = [&]() {
auto r1 = lua.script("v1 = c:get(11)", sol::script_pass_on_error); auto r1 = lua.safe_script("v1 = c:get(11)", sol::script_pass_on_error);
REQUIRE(r1.valid()); REQUIRE(r1.valid());
auto r2 = lua.script("v2 = c:get(13)", sol::script_pass_on_error); auto r2 = lua.safe_script("v2 = c:get(13)", sol::script_pass_on_error);
REQUIRE(r2.valid()); REQUIRE(r2.valid());
}; };
auto fset = [&]() { auto fset = [&]() {
auto r1 = lua.script("c:set(20)", sol::script_pass_on_error); auto r1 = lua.safe_script("c:set(20)", sol::script_pass_on_error);
REQUIRE(r1.valid()); REQUIRE(r1.valid());
auto r2 = lua.script("c:set(16)", sol::script_pass_on_error); auto r2 = lua.safe_script("c:set(16)", sol::script_pass_on_error);
REQUIRE(r2.valid()); REQUIRE(r2.valid());
}; };
auto ferase = [&]() { auto ferase = [&]() {
auto r5 = lua.script("s1 = #c", sol::script_pass_on_error); auto r5 = lua.safe_script("s1 = #c", sol::script_pass_on_error);
REQUIRE(r5.valid()); REQUIRE(r5.valid());
auto r1 = lua.script("c:erase(i1)", sol::script_pass_on_error); auto r1 = lua.safe_script("c:erase(i1)", sol::script_pass_on_error);
REQUIRE(r1.valid()); REQUIRE(r1.valid());
auto r3 = lua.script("s2 = #c", sol::script_pass_on_error); auto r3 = lua.safe_script("s2 = #c", sol::script_pass_on_error);
REQUIRE(r3.valid()); REQUIRE(r3.valid());
auto r2 = lua.script("c:erase(i2)", sol::script_pass_on_error); auto r2 = lua.safe_script("c:erase(i2)", sol::script_pass_on_error);
REQUIRE(r2.valid()); REQUIRE(r2.valid());
auto r4 = lua.script("s3 = #c", sol::script_pass_on_error); auto r4 = lua.safe_script("s3 = #c", sol::script_pass_on_error);
REQUIRE(r4.valid()); REQUIRE(r4.valid());
}; };
auto fadd = [&]() { auto fadd = [&]() {
auto r = lua.script("c:add(17)", sol::script_pass_on_error); auto r = lua.safe_script("c:add(17)", sol::script_pass_on_error);
REQUIRE(r.valid()); REQUIRE(r.valid());
}; };
auto fopset = [&]() { auto fopset = [&]() {
auto r = lua.script("c[18] = true", sol::script_pass_on_error); auto r = lua.safe_script("c[18] = true", sol::script_pass_on_error);
REQUIRE(r.valid()); REQUIRE(r.valid());
}; };
auto fopget = [&]() { auto fopget = [&]() {
auto r = lua.script("v3 = c[20]", sol::script_pass_on_error); auto r = lua.safe_script("v3 = c[20]", sol::script_pass_on_error);
REQUIRE(r.valid()); REQUIRE(r.valid());
}; };
REQUIRE_NOTHROW(ffind()); REQUIRE_NOTHROW(ffind());
@ -398,7 +398,7 @@ void unordered_container_check(sol::state& lua, T& items) {
template <typename T> template <typename T>
void associative_ordered_container_check(sol::state& lua, T& items) { void associative_ordered_container_check(sol::state& lua, T& items) {
{ {
auto r1 = lua.script(R"( auto r1 = lua.safe_script(R"(
for i=1,#c do for i=1,#c do
v = c[(i + 10)] v = c[(i + 10)]
assert(v == (i + 20)) assert(v == (i + 20))
@ -408,47 +408,47 @@ end
} }
{ {
auto ffind = [&]() { auto ffind = [&]() {
auto r1 = lua.script("i1 = c:find(11)", sol::script_pass_on_error); auto r1 = lua.safe_script("i1 = c:find(11)", sol::script_pass_on_error);
REQUIRE(r1.valid()); REQUIRE(r1.valid());
auto r2 = lua.script("i2 = c:find(14)", sol::script_pass_on_error); auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error);
REQUIRE(r2.valid()); REQUIRE(r2.valid());
}; };
auto fget = [&]() { auto fget = [&]() {
auto r1 = lua.script("v1 = c:get(11)", sol::script_pass_on_error); auto r1 = lua.safe_script("v1 = c:get(11)", sol::script_pass_on_error);
REQUIRE(r1.valid()); REQUIRE(r1.valid());
auto r2 = lua.script("v2 = c:get(13)", sol::script_pass_on_error); auto r2 = lua.safe_script("v2 = c:get(13)", sol::script_pass_on_error);
REQUIRE(r2.valid()); REQUIRE(r2.valid());
}; };
auto fset = [&]() { auto fset = [&]() {
auto r1 = lua.script("c:set(20, 30)", sol::script_pass_on_error); auto r1 = lua.safe_script("c:set(20, 30)", sol::script_pass_on_error);
REQUIRE(r1.valid()); REQUIRE(r1.valid());
auto r2 = lua.script("c:set(16, 26)", sol::script_pass_on_error); auto r2 = lua.safe_script("c:set(16, 26)", sol::script_pass_on_error);
REQUIRE(r2.valid()); REQUIRE(r2.valid());
auto r3 = lua.script("c:set(12, 31)", sol::script_pass_on_error); auto r3 = lua.safe_script("c:set(12, 31)", sol::script_pass_on_error);
REQUIRE(r3.valid()); REQUIRE(r3.valid());
}; };
auto ferase = [&]() { auto ferase = [&]() {
auto r5 = lua.script("s1 = #c", sol::script_pass_on_error); auto r5 = lua.safe_script("s1 = #c", sol::script_pass_on_error);
REQUIRE(r5.valid()); REQUIRE(r5.valid());
auto r1 = lua.script("c:erase(11)", sol::script_pass_on_error); auto r1 = lua.safe_script("c:erase(11)", sol::script_pass_on_error);
REQUIRE(r1.valid()); REQUIRE(r1.valid());
auto r3 = lua.script("s2 = #c", sol::script_pass_on_error); auto r3 = lua.safe_script("s2 = #c", sol::script_pass_on_error);
REQUIRE(r3.valid()); REQUIRE(r3.valid());
auto r2 = lua.script("c:erase(14)", sol::script_pass_on_error); auto r2 = lua.safe_script("c:erase(14)", sol::script_pass_on_error);
REQUIRE(r2.valid()); REQUIRE(r2.valid());
auto r4 = lua.script("s3 = #c", sol::script_pass_on_error); auto r4 = lua.safe_script("s3 = #c", sol::script_pass_on_error);
REQUIRE(r4.valid()); REQUIRE(r4.valid());
}; };
auto fadd = [&]() { auto fadd = [&]() {
auto r = lua.script("c:add(17, 27)", sol::script_pass_on_error); auto r = lua.safe_script("c:add(17, 27)", sol::script_pass_on_error);
REQUIRE(r.valid()); REQUIRE(r.valid());
}; };
auto fopset = [&]() { auto fopset = [&]() {
auto r = lua.script("c[18] = 28", sol::script_pass_on_error); auto r = lua.safe_script("c[18] = 28", sol::script_pass_on_error);
REQUIRE(r.valid()); REQUIRE(r.valid());
}; };
auto fopget = [&]() { auto fopget = [&]() {
auto r = lua.script("v3 = c[20]", sol::script_pass_on_error); auto r = lua.safe_script("v3 = c[20]", sol::script_pass_on_error);
REQUIRE(r.valid()); REQUIRE(r.valid());
}; };
REQUIRE_NOTHROW(ffind()); REQUIRE_NOTHROW(ffind());
@ -518,47 +518,47 @@ template <typename T>
void associative_unordered_container_check(sol::state& lua, T& items) { void associative_unordered_container_check(sol::state& lua, T& items) {
{ {
auto ffind = [&]() { auto ffind = [&]() {
auto r1 = lua.script("i1 = c:find(11)", sol::script_pass_on_error); auto r1 = lua.safe_script("i1 = c:find(11)", sol::script_pass_on_error);
REQUIRE(r1.valid()); REQUIRE(r1.valid());
auto r2 = lua.script("i2 = c:find(14)", sol::script_pass_on_error); auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error);
REQUIRE(r2.valid()); REQUIRE(r2.valid());
}; };
auto fget = [&]() { auto fget = [&]() {
auto r1 = lua.script("v1 = c:get(11)", sol::script_pass_on_error); auto r1 = lua.safe_script("v1 = c:get(11)", sol::script_pass_on_error);
REQUIRE(r1.valid()); REQUIRE(r1.valid());
auto r2 = lua.script("v2 = c:get(13)", sol::script_pass_on_error); auto r2 = lua.safe_script("v2 = c:get(13)", sol::script_pass_on_error);
REQUIRE(r2.valid()); REQUIRE(r2.valid());
}; };
auto fset = [&]() { auto fset = [&]() {
auto r1 = lua.script("c:set(20, 30)", sol::script_pass_on_error); auto r1 = lua.safe_script("c:set(20, 30)", sol::script_pass_on_error);
REQUIRE(r1.valid()); REQUIRE(r1.valid());
auto r2 = lua.script("c:set(16, 26)", sol::script_pass_on_error); auto r2 = lua.safe_script("c:set(16, 26)", sol::script_pass_on_error);
REQUIRE(r2.valid()); REQUIRE(r2.valid());
auto r3 = lua.script("c:set(12, 31)", sol::script_pass_on_error); auto r3 = lua.safe_script("c:set(12, 31)", sol::script_pass_on_error);
REQUIRE(r3.valid()); REQUIRE(r3.valid());
}; };
auto ferase = [&]() { auto ferase = [&]() {
auto r5 = lua.script("s1 = #c", sol::script_pass_on_error); auto r5 = lua.safe_script("s1 = #c", sol::script_pass_on_error);
REQUIRE(r5.valid()); REQUIRE(r5.valid());
auto r1 = lua.script("c:erase(11)", sol::script_pass_on_error); auto r1 = lua.safe_script("c:erase(11)", sol::script_pass_on_error);
REQUIRE(r1.valid()); REQUIRE(r1.valid());
auto r3 = lua.script("s2 = #c", sol::script_pass_on_error); auto r3 = lua.safe_script("s2 = #c", sol::script_pass_on_error);
REQUIRE(r3.valid()); REQUIRE(r3.valid());
auto r2 = lua.script("c:erase(14)", sol::script_pass_on_error); auto r2 = lua.safe_script("c:erase(14)", sol::script_pass_on_error);
REQUIRE(r2.valid()); REQUIRE(r2.valid());
auto r4 = lua.script("s3 = #c", sol::script_pass_on_error); auto r4 = lua.safe_script("s3 = #c", sol::script_pass_on_error);
REQUIRE(r4.valid()); REQUIRE(r4.valid());
}; };
auto fadd = [&]() { auto fadd = [&]() {
auto r = lua.script("c:add(17, 27)", sol::script_pass_on_error); auto r = lua.safe_script("c:add(17, 27)", sol::script_pass_on_error);
REQUIRE(r.valid()); REQUIRE(r.valid());
}; };
auto fopset = [&]() { auto fopset = [&]() {
auto r = lua.script("c[18] = 28", sol::script_pass_on_error); auto r = lua.safe_script("c[18] = 28", sol::script_pass_on_error);
REQUIRE(r.valid()); REQUIRE(r.valid());
}; };
auto fopget = [&]() { auto fopget = [&]() {
auto r = lua.script("v3 = c[20]", sol::script_pass_on_error); auto r = lua.safe_script("v3 = c[20]", sol::script_pass_on_error);
REQUIRE(r.valid()); REQUIRE(r.valid());
}; };
REQUIRE_NOTHROW(ffind()); REQUIRE_NOTHROW(ffind());
@ -612,7 +612,7 @@ void associative_unordered_container_check(sol::state& lua, T& items) {
template <typename T> template <typename T>
void fixed_container_check(sol::state& lua, T& items) { void fixed_container_check(sol::state& lua, T& items) {
{ {
auto r1 = lua.script(R"( auto r1 = lua.safe_script(R"(
for i=1,#c do for i=1,#c do
v = c[i] v = c[i]
assert(v == (i + 10)) assert(v == (i + 10))
@ -622,45 +622,45 @@ end
} }
{ {
auto ffind = [&]() { auto ffind = [&]() {
auto r1 = lua.script("i1 = c:find(11)", sol::script_pass_on_error); auto r1 = lua.safe_script("i1 = c:find(11)", sol::script_pass_on_error);
REQUIRE(r1.valid()); REQUIRE(r1.valid());
auto r2 = lua.script("i2 = c:find(14)", sol::script_pass_on_error); auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error);
REQUIRE(r2.valid()); REQUIRE(r2.valid());
}; };
auto fget = [&]() { auto fget = [&]() {
auto r1 = lua.script("v1 = c:get(2)", sol::script_pass_on_error); auto r1 = lua.safe_script("v1 = c:get(2)", sol::script_pass_on_error);
REQUIRE(r1.valid()); REQUIRE(r1.valid());
auto r2 = lua.script("v2 = c:get(5)", sol::script_pass_on_error); auto r2 = lua.safe_script("v2 = c:get(5)", sol::script_pass_on_error);
REQUIRE(r2.valid()); REQUIRE(r2.valid());
}; };
auto fset = [&]() { auto fset = [&]() {
auto r1 = lua.script("c:set(2, 20)", sol::script_pass_on_error); auto r1 = lua.safe_script("c:set(2, 20)", sol::script_pass_on_error);
REQUIRE(r1.valid()); REQUIRE(r1.valid());
auto r2 = lua.script("c:set(6, 16)", sol::script_pass_on_error); auto r2 = lua.safe_script("c:set(6, 16)", sol::script_pass_on_error);
REQUIRE_FALSE(r2.valid()); REQUIRE_FALSE(r2.valid());
}; };
auto ferase = [&]() { auto ferase = [&]() {
auto r5 = lua.script("s1 = #c", sol::script_pass_on_error); auto r5 = lua.safe_script("s1 = #c", sol::script_pass_on_error);
REQUIRE(r5.valid()); REQUIRE(r5.valid());
auto r1 = lua.script("c:erase(i1)", sol::script_pass_on_error); auto r1 = lua.safe_script("c:erase(i1)", sol::script_pass_on_error);
REQUIRE_FALSE(r1.valid()); REQUIRE_FALSE(r1.valid());
auto r3 = lua.script("s2 = #c", sol::script_pass_on_error); auto r3 = lua.safe_script("s2 = #c", sol::script_pass_on_error);
REQUIRE(r3.valid()); REQUIRE(r3.valid());
auto r2 = lua.script("c:erase(i2)", sol::script_pass_on_error); auto r2 = lua.safe_script("c:erase(i2)", sol::script_pass_on_error);
REQUIRE_FALSE(r2.valid()); REQUIRE_FALSE(r2.valid());
auto r4 = lua.script("s3 = #c", sol::script_pass_on_error); auto r4 = lua.safe_script("s3 = #c", sol::script_pass_on_error);
REQUIRE(r4.valid()); REQUIRE(r4.valid());
}; };
auto fadd = [&]() { auto fadd = [&]() {
auto r = lua.script("c:add(17)", sol::script_pass_on_error); auto r = lua.safe_script("c:add(17)", sol::script_pass_on_error);
REQUIRE_FALSE(r.valid()); REQUIRE_FALSE(r.valid());
}; };
auto fopset = [&]() { auto fopset = [&]() {
auto r = lua.script("c[5] = 18", sol::script_pass_on_error); auto r = lua.safe_script("c[5] = 18", sol::script_pass_on_error);
REQUIRE(r.valid()); REQUIRE(r.valid());
}; };
auto fopget = [&]() { auto fopget = [&]() {
auto r = lua.script("v3 = c[4]", sol::script_pass_on_error); auto r = lua.safe_script("v3 = c[4]", sol::script_pass_on_error);
REQUIRE(r.valid()); REQUIRE(r.valid());
}; };
REQUIRE_NOTHROW(ffind()); REQUIRE_NOTHROW(ffind());
@ -892,7 +892,7 @@ TEST_CASE("containers/auxiliary functions test", "make sure the manipulation fun
sol::state lua; sol::state lua;
lua.open_libraries(); lua.open_libraries();
lua.script(R"( lua.safe_script(R"(
function g (x) function g (x)
x:add(20) x:add(20)
end end
@ -962,7 +962,7 @@ end
REQUIRE(set.empty()); REQUIRE(set.empty());
REQUIRE_NOTHROW([&]() { REQUIRE_NOTHROW([&]() {
lua.script(R"( lua.safe_script(R"(
c_arr[1] = 7 c_arr[1] = 7
c_arr[2] = 7 c_arr[2] = 7
c_arr[3] = 7 c_arr[3] = 7

View File

@ -36,7 +36,7 @@ TEST_CASE("containers/returns", "make sure that even references to vectors are b
lua.set_function("f", [&]() -> std::vector<int>& { lua.set_function("f", [&]() -> std::vector<int>& {
return v; return v;
}); });
lua.script("x = f()"); lua.safe_script("x = f()");
sol::object x = lua["x"]; sol::object x = lua["x"];
sol::type xt = x.get_type(); sol::type xt = x.get_type();
REQUIRE(xt == sol::type::userdata); REQUIRE(xt == sol::type::userdata);
@ -62,8 +62,8 @@ TEST_CASE("containers/table conversion", "test table conversions with as_table a
return sol::as_nested(std::vector<std::string>{"bark", "woof"}); return sol::as_nested(std::vector<std::string>{"bark", "woof"});
}); });
lua.script("v1 = bark()"); lua.safe_script("v1 = bark()");
lua.script("v2 = woof()"); lua.safe_script("v2 = woof()");
sol::as_table_t<std::vector<std::string>> as_table_strings = lua["v1"]; sol::as_table_t<std::vector<std::string>> as_table_strings = lua["v1"];
sol::nested<std::vector<std::string>> nested_strings = lua["v2"]; sol::nested<std::vector<std::string>> nested_strings = lua["v2"];
@ -79,7 +79,7 @@ TEST_CASE("containers/vector roundtrip", "make sure vectors can be round-tripped
lua.set_function("f", [&]() -> std::vector<int>& { lua.set_function("f", [&]() -> std::vector<int>& {
return v; return v;
}); });
lua.script("x = f()"); lua.safe_script("x = f()");
std::vector<int> x = lua["x"]; std::vector<int> x = lua["x"];
bool areequal = x == v; bool areequal = x == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -91,7 +91,7 @@ TEST_CASE("containers/deque roundtrip", "make sure deques can be round-tripped")
lua.set_function("f", [&]() -> std::deque<int>& { lua.set_function("f", [&]() -> std::deque<int>& {
return v; return v;
}); });
lua.script("x = f()"); lua.safe_script("x = f()");
std::deque<int> x = lua["x"]; std::deque<int> x = lua["x"];
bool areequal = x == v; bool areequal = x == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -103,7 +103,7 @@ TEST_CASE("containers/array roundtrip", "make sure arrays can be round-tripped")
lua.set_function("f", [&]() -> std::array<int, 3>& { lua.set_function("f", [&]() -> std::array<int, 3>& {
return v; return v;
}); });
lua.script("x = f()"); lua.safe_script("x = f()");
std::array<int, 3> x = lua["x"]; std::array<int, 3> x = lua["x"];
bool areequal = x == v; bool areequal = x == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -115,7 +115,7 @@ TEST_CASE("containers/list roundtrip", "make sure lists can be round-tripped") {
lua.set_function("f", [&]() -> std::list<int>& { lua.set_function("f", [&]() -> std::list<int>& {
return v; return v;
}); });
lua.script("x = f()"); lua.safe_script("x = f()");
std::list <int> x = lua["x"]; std::list <int> x = lua["x"];
bool areequal = x == v; bool areequal = x == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -127,7 +127,7 @@ TEST_CASE("containers/forward_list roundtrip", "make sure forward_lists can be r
lua.set_function("f", [&]() -> std::forward_list<int>& { lua.set_function("f", [&]() -> std::forward_list<int>& {
return v; return v;
}); });
lua.script("x = f()"); lua.safe_script("x = f()");
std::forward_list <int> x = lua["x"]; std::forward_list <int> x = lua["x"];
bool areequal = x == v; bool areequal = x == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -139,7 +139,7 @@ TEST_CASE("containers/map roundtrip", "make sure maps can be round-tripped") {
lua.set_function("f", [&]() -> std::map<std::string, int>& { lua.set_function("f", [&]() -> std::map<std::string, int>& {
return v; return v;
}); });
lua.script("x = f()"); lua.safe_script("x = f()");
std::map<std::string, int> x = lua["x"]; std::map<std::string, int> x = lua["x"];
bool areequal = x == v; bool areequal = x == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -151,7 +151,7 @@ TEST_CASE("containers/unordered_map roundtrip", "make sure unordered_maps can be
lua.set_function("f", [&]() -> std::unordered_map<std::string, int>& { lua.set_function("f", [&]() -> std::unordered_map<std::string, int>& {
return v; return v;
}); });
lua.script("x = f()"); lua.safe_script("x = f()");
std::unordered_map<std::string, int> x = lua["x"]; std::unordered_map<std::string, int> x = lua["x"];
bool areequal = x == v; bool areequal = x == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -163,7 +163,7 @@ TEST_CASE("containers/unordered_set roundtrip", "make sure unordered_sets can be
lua.set_function("f", [&]() -> std::unordered_set<int>& { lua.set_function("f", [&]() -> std::unordered_set<int>& {
return v; return v;
}); });
lua.script("x = f()"); lua.safe_script("x = f()");
std::unordered_set<int> x = lua["x"]; std::unordered_set<int> x = lua["x"];
bool areequal = x == v; bool areequal = x == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -175,7 +175,7 @@ TEST_CASE("containers/set roundtrip", "make sure sets can be round-tripped") {
lua.set_function("f", [&]() -> std::set<int>& { lua.set_function("f", [&]() -> std::set<int>& {
return v; return v;
}); });
lua.script("x = f()"); lua.safe_script("x = f()");
std::set<int> x = lua["x"]; std::set<int> x = lua["x"];
bool areequal = x == v; bool areequal = x == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -187,7 +187,7 @@ TEST_CASE("containers/vector table roundtrip", "make sure vectors can be round-t
lua.set_function("f", [&]() { lua.set_function("f", [&]() {
return sol::as_table(v); return sol::as_table(v);
}); });
lua.script("x = f()"); lua.safe_script("x = f()");
sol::as_table_t<std::vector<int>> x = lua["x"]; sol::as_table_t<std::vector<int>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.source == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -199,7 +199,7 @@ TEST_CASE("containers/deque table roundtrip", "make sure deques can be round-tri
lua.set_function("f", [&]() { lua.set_function("f", [&]() {
return sol::as_table(v); return sol::as_table(v);
}); });
lua.script("x = f()"); lua.safe_script("x = f()");
sol::as_table_t<std::deque<int>> x = lua["x"]; sol::as_table_t<std::deque<int>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.source == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -211,7 +211,7 @@ TEST_CASE("containers/array table roundtrip", "make sure arrays can be round-tri
lua.set_function("f", [&]() { lua.set_function("f", [&]() {
return sol::as_table(v); return sol::as_table(v);
}); });
lua.script("x = f()"); lua.safe_script("x = f()");
sol::as_table_t<std::array<int, 3>> x = lua["x"]; sol::as_table_t<std::array<int, 3>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.source == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -223,7 +223,7 @@ TEST_CASE("containers/list table roundtrip", "make sure lists can be round-tripp
lua.set_function("f", [&]() { lua.set_function("f", [&]() {
return sol::as_table(v); return sol::as_table(v);
}); });
lua.script("x = f()"); lua.safe_script("x = f()");
sol::as_table_t<std::list <int>> x = lua["x"]; sol::as_table_t<std::list <int>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.source == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -235,7 +235,7 @@ TEST_CASE("containers/forward_list table roundtrip", "make sure forward_lists ca
lua.set_function("f", [&]() { lua.set_function("f", [&]() {
return sol::as_table(v); return sol::as_table(v);
}); });
lua.script("x = f()"); lua.safe_script("x = f()");
sol::as_table_t<std::forward_list<int>> x = lua["x"]; sol::as_table_t<std::forward_list<int>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.source == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -247,7 +247,7 @@ TEST_CASE("containers/map table roundtrip", "make sure maps can be round-tripped
lua.set_function("f", [&]() { lua.set_function("f", [&]() {
return sol::as_table(v); return sol::as_table(v);
}); });
lua.script("x = f()"); lua.safe_script("x = f()");
sol::as_table_t<std::map<std::string, int>> x = lua["x"]; sol::as_table_t<std::map<std::string, int>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.source == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -259,7 +259,7 @@ TEST_CASE("containers/unordered_map table roundtrip", "make sure unordered_maps
lua.set_function("f", [&]() { lua.set_function("f", [&]() {
return sol::as_table(v); return sol::as_table(v);
}); });
lua.script("x = f()"); lua.safe_script("x = f()");
sol::as_table_t<std::unordered_map<std::string, int>> x = lua["x"]; sol::as_table_t<std::unordered_map<std::string, int>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.source == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -271,7 +271,7 @@ TEST_CASE("containers/unordered_set table roundtrip", "make sure unordered_sets
lua.set_function("f", [&]() { lua.set_function("f", [&]() {
return sol::as_table(v); return sol::as_table(v);
}); });
lua.script("x = f()"); lua.safe_script("x = f()");
sol::as_table_t<std::unordered_set<int>> x = lua["x"]; sol::as_table_t<std::unordered_set<int>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.source == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -283,7 +283,7 @@ TEST_CASE("containers/set table roundtrip", "make sure sets can be round-tripped
lua.set_function("f", [&]() { lua.set_function("f", [&]() {
return sol::as_table(v); return sol::as_table(v);
}); });
lua.script("x = f()"); lua.safe_script("x = f()");
sol::as_table_t<std::set<int>> x = lua["x"]; sol::as_table_t<std::set<int>> x = lua["x"];
bool areequal = x.source == v; bool areequal = x.source == v;
REQUIRE(areequal); REQUIRE(areequal);
@ -304,11 +304,11 @@ TEST_CASE("containers/custom usertype", "make sure container usertype metatables
); );
bark obj{ { 24, 50 } }; bark obj{ { 24, 50 } };
lua.set("a", &obj); lua.set("a", &obj);
REQUIRE_NOTHROW(lua.script("assert(a:at(24) == 50)")); REQUIRE_NOTHROW(lua.safe_script("assert(a:at(24) == 50)"));
REQUIRE_NOTHROW(lua.script("a:something()")); REQUIRE_NOTHROW(lua.safe_script("a:something()"));
lua.set("a", obj); lua.set("a", obj);
REQUIRE_NOTHROW(lua.script("assert(a:at(24) == 50)")); REQUIRE_NOTHROW(lua.safe_script("assert(a:at(24) == 50)"));
REQUIRE_NOTHROW(lua.script("a:something()")); REQUIRE_NOTHROW(lua.safe_script("a:something()"));
} }
TEST_CASE("containers/const serialization kvp", "make sure const keys / values are respected") { TEST_CASE("containers/const serialization kvp", "make sure const keys / values are respected") {
@ -318,10 +318,10 @@ TEST_CASE("containers/const serialization kvp", "make sure const keys / values a
lua.open_libraries(); lua.open_libraries();
bark obj{ { 24, 50 } }; bark obj{ { 24, 50 } };
lua.set("a", &obj); lua.set("a", &obj);
REQUIRE_NOTHROW(lua.script("assert(a[24] == 50)")); REQUIRE_NOTHROW(lua.safe_script("assert(a[24] == 50)"));
auto result = lua.safe_script("a[24] = 51", sol::script_pass_on_error); auto result = lua.safe_script("a[24] = 51", sol::script_pass_on_error);
REQUIRE_FALSE(result.valid()); REQUIRE_FALSE(result.valid());
REQUIRE_NOTHROW(lua.script("assert(a[24] == 50)")); REQUIRE_NOTHROW(lua.safe_script("assert(a[24] == 50)"));
} }
TEST_CASE("containers/basic serialization", "make sure containers are turned into proper userdata and have basic hooks established") { TEST_CASE("containers/basic serialization", "make sure containers are turned into proper userdata and have basic hooks established") {
@ -330,20 +330,20 @@ TEST_CASE("containers/basic serialization", "make sure containers are turned int
lua.open_libraries(); lua.open_libraries();
lua.set("b", woof{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 }); lua.set("b", woof{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 });
REQUIRE_NOTHROW( REQUIRE_NOTHROW(
lua.script("for k = 1, #b do assert(k == b[k]) end") lua.safe_script("for k = 1, #b do assert(k == b[k]) end")
); );
woof w{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 }; woof w{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 };
lua.set("b", w); lua.set("b", w);
REQUIRE_NOTHROW( REQUIRE_NOTHROW(
lua.script("for k = 1, #b do assert(k == b[k]) end") lua.safe_script("for k = 1, #b do assert(k == b[k]) end")
); );
lua.set("b", &w); lua.set("b", &w);
REQUIRE_NOTHROW( REQUIRE_NOTHROW(
lua.script("for k = 1, #b do assert(k == b[k]) end") lua.safe_script("for k = 1, #b do assert(k == b[k]) end")
); );
lua.set("b", std::ref(w)); lua.set("b", std::ref(w));
REQUIRE_NOTHROW( REQUIRE_NOTHROW(
lua.script("for k = 1, #b do assert(k == b[k]) end") lua.safe_script("for k = 1, #b do assert(k == b[k]) end")
); );
} }
@ -354,7 +354,7 @@ TEST_CASE("containers/const serialization", "make sure containers are turned int
lua.open_libraries(); lua.open_libraries();
lua.set("b", woof{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 }); lua.set("b", woof{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 });
REQUIRE_NOTHROW( REQUIRE_NOTHROW(
lua.script("for k, v in pairs(b) do assert(k == v) end"); lua.safe_script("for k, v in pairs(b) do assert(k == v) end");
); );
auto result = lua.safe_script("b[1] = 20", sol::script_pass_on_error); auto result = lua.safe_script("b[1] = 20", sol::script_pass_on_error);
REQUIRE_FALSE(result.valid()); REQUIRE_FALSE(result.valid());
@ -367,20 +367,20 @@ TEST_CASE("containers/table serialization", "ensure types can be serialized as t
lua.open_libraries(); lua.open_libraries();
lua.set("b", sol::as_table(woof{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 })); lua.set("b", sol::as_table(woof{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 }));
REQUIRE_NOTHROW( REQUIRE_NOTHROW(
lua.script("for k, v in ipairs(b) do assert(k == v) end") lua.safe_script("for k, v in ipairs(b) do assert(k == v) end")
); );
woof w{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 }; woof w{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 };
lua.set("b", sol::as_table(w)); lua.set("b", sol::as_table(w));
REQUIRE_NOTHROW( REQUIRE_NOTHROW(
lua.script("for k, v in ipairs(b) do assert(k == v) end") lua.safe_script("for k, v in ipairs(b) do assert(k == v) end")
); );
lua.set("b", sol::as_table(&w)); lua.set("b", sol::as_table(&w));
REQUIRE_NOTHROW( REQUIRE_NOTHROW(
lua.script("for k, v in ipairs(b) do assert(k == v) end") lua.safe_script("for k, v in ipairs(b) do assert(k == v) end")
); );
lua.set("b", sol::as_table(std::ref(w))); lua.set("b", sol::as_table(std::ref(w)));
REQUIRE_NOTHROW( REQUIRE_NOTHROW(
lua.script("for k, v in ipairs(b) do assert(k == v) end") lua.safe_script("for k, v in ipairs(b) do assert(k == v) end")
); );
} }
@ -404,7 +404,7 @@ TEST_CASE("containers/const correctness", "usertype metatable names should reaso
std::vector<Vec const *> bar; std::vector<Vec const *> bar;
bar.push_back(&vec); bar.push_back(&vec);
lua.script(R"( lua.safe_script(R"(
func = function(vecs) func = function(vecs)
for i = 1, #vecs do for i = 1, #vecs do
vec = vecs[i] vec = vecs[i]
@ -427,20 +427,20 @@ TEST_CASE("containers/arbitrary creation", "userdata and tables should be usable
lua.set_function("test_three", test_table_return_three); lua.set_function("test_three", test_table_return_three);
lua.set_function("test_four", test_table_return_four); lua.set_function("test_four", test_table_return_four);
REQUIRE_NOTHROW(lua.script("a = test_one()")); REQUIRE_NOTHROW(lua.safe_script("a = test_one()"));
REQUIRE_NOTHROW(lua.script("b = test_two()")); REQUIRE_NOTHROW(lua.safe_script("b = test_two()"));
REQUIRE_NOTHROW(lua.script("c = test_three()")); REQUIRE_NOTHROW(lua.safe_script("c = test_three()"));
REQUIRE_NOTHROW(lua.script("d = test_four()")); REQUIRE_NOTHROW(lua.safe_script("d = test_four()"));
REQUIRE_NOTHROW(lua.script("assert(#a == 10, 'error')")); REQUIRE_NOTHROW(lua.safe_script("assert(#a == 10, 'error')"));
REQUIRE_NOTHROW(lua.script("assert(a[3] == 3, 'error')")); REQUIRE_NOTHROW(lua.safe_script("assert(a[3] == 3, 'error')"));
REQUIRE_NOTHROW(lua.script("assert(b.one == 1, 'error')")); REQUIRE_NOTHROW(lua.safe_script("assert(b.one == 1, 'error')"));
REQUIRE_NOTHROW(lua.script("assert(b.three == 3, 'error')")); REQUIRE_NOTHROW(lua.safe_script("assert(b.three == 3, 'error')"));
REQUIRE_NOTHROW(lua.script("assert(c.name == 'Rapptz', 'error')")); REQUIRE_NOTHROW(lua.safe_script("assert(c.name == 'Rapptz', 'error')"));
REQUIRE_NOTHROW(lua.script("assert(c.project == 'sol', 'error')")); REQUIRE_NOTHROW(lua.safe_script("assert(c.project == 'sol', 'error')"));
REQUIRE_NOTHROW(lua.script("assert(d.one == 1, 'error')")); REQUIRE_NOTHROW(lua.safe_script("assert(d.one == 1, 'error')"));
REQUIRE_NOTHROW(lua.script("assert(d.three == 3, 'error')")); REQUIRE_NOTHROW(lua.safe_script("assert(d.three == 3, 'error')"));
REQUIRE_NOTHROW(lua.script("assert(d.four == 4, 'error')")); REQUIRE_NOTHROW(lua.safe_script("assert(d.four == 4, 'error')"));
sol::table a = lua.get<sol::table>("a"); sol::table a = lua.get<sol::table>("a");
sol::table b = lua.get<sol::table>("b"); sol::table b = lua.get<sol::table>("b");
@ -483,7 +483,7 @@ TEST_CASE("containers/usertype transparency", "Make sure containers pass their a
"a_list", &B::a_list "a_list", &B::a_list
); );
lua.script(R"( lua.safe_script(R"(
b = B.new() b = B.new()
a_ref = b.a_list[2] a_ref = b.a_list[2]
)"); )");
@ -548,7 +548,7 @@ TEST_CASE("containers/is container", "make sure the is_container trait behaves p
machine m; machine m;
lua["machine"] = &m; lua["machine"] = &m;
lua.script(R"( lua.safe_script(R"(
machine:opt():output_help() machine:opt():output_help()
)"); )");
@ -577,7 +577,7 @@ TEST_CASE("containers/readonly", "make sure readonly members are stored appropri
); );
lua["value"] = std::list<bar>{ {},{},{} }; lua["value"] = std::list<bar>{ {},{},{} };
lua.script(R"( lua.safe_script(R"(
a = foo.new() a = foo.new()
x = a.seq x = a.seq
a.seq = value a.seq = value
@ -597,7 +597,7 @@ TEST_CASE("containers/to_args", "Test that the to_args abstractions works") {
sol::state lua; sol::state lua;
lua.open_libraries(); lua.open_libraries();
lua.script("function f (a, b, c, d) print(a, b, c, d) return a, b, c, d end"); lua.safe_script("function f (a, b, c, d) print(a, b, c, d) return a, b, c, d end");
sol::function f = lua["f"]; sol::function f = lua["f"];
int a, b, c, d; int a, b, c, d;
@ -637,11 +637,11 @@ TEST_CASE("containers/ipairs test", "ensure that abstractions roundtrip properly
return std::vector<thing*>(5, &t); return std::vector<thing*>(5, &t);
}); });
lua.script(R"( lua.safe_script(R"(
c = f() c = f()
)"); )");
lua.script(R"( lua.safe_script(R"(
check = {} check = {}
local i = 1 local i = 1
while c[i] do while c[i] do
@ -660,7 +660,7 @@ end
TEST_CASE("containers/append idiom", "ensure the append-idiom works as intended") { TEST_CASE("containers/append idiom", "ensure the append-idiom works as intended") {
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.script( lua.safe_script(
R"( R"(
function f_fill(vec) function f_fill(vec)
print("#vec in lua: " .. #vec) print("#vec in lua: " .. #vec)
@ -817,13 +817,13 @@ TEST_CASE("containers/input iterators", "test shitty input iterators that are al
not_really_a_container c; not_really_a_container c;
lua["c"] = &c; lua["c"] = &c;
#if SOL_LUA_VERSION > 502 #if SOL_LUA_VERSION > 502
lua.script(R"lua( lua.safe_script(R"lua(
for k, v in pairs(c) do for k, v in pairs(c) do
assert((k - 1) == v:val()) assert((k - 1) == v:val())
end end
)lua"); )lua");
#endif #endif
lua.script(R"lua( lua.safe_script(R"lua(
for k=1,#c do for k=1,#c do
v = c[k] v = c[k]
assert((k - 1) == v:val()) assert((k - 1) == v:val())
@ -849,10 +849,10 @@ TEST_CASE("containers/pairs", "test how well pairs work with the underlying syst
lua["c"] = std::ref(c); lua["c"] = std::ref(c);
lua["d"] = &d; lua["d"] = &d;
lua.script("av1, av2 = a:get(1)"); lua.safe_script("av1, av2 = a:get(1)");
lua.script("bv1, bv2 = b:get(1)"); lua.safe_script("bv1, bv2 = b:get(1)");
lua.script("cv1, cv2 = c:get(1)"); lua.safe_script("cv1, cv2 = c:get(1)");
lua.script("dv1, dv2 = d:get(1)"); lua.safe_script("dv1, dv2 = d:get(1)");
std::vector<std::pair<std::string, int>>& la = lua["a"]; std::vector<std::pair<std::string, int>>& la = lua["a"];
std::array<std::pair<std::string, int>, 5>& lb = lua["b"]; std::array<std::pair<std::string, int>, 5>& lb = lua["b"];

View File

@ -18,7 +18,7 @@ end
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::coroutine); lua.open_libraries(sol::lib::base, sol::lib::coroutine);
lua.script(script); lua.safe_script(script);
sol::coroutine cr = lua["loop"]; sol::coroutine cr = lua["loop"];
int counter; int counter;
@ -47,7 +47,7 @@ end
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::coroutine); lua.open_libraries(sol::lib::base, sol::lib::coroutine);
lua.script(script); lua.safe_script(script);
sol::thread runner = sol::thread::create(lua.lua_state()); sol::thread runner = sol::thread::create(lua.lua_state());
sol::state_view runnerstate = runner.state(); sol::state_view runnerstate = runner.state();
sol::coroutine cr = runnerstate["loop"]; sol::coroutine cr = runnerstate["loop"];

View File

@ -68,7 +68,7 @@ TEST_CASE("customization/split struct", "using the newly documented customizatio
sol::state lua; sol::state lua;
// Create a pass-through style of function // Create a pass-through style of function
lua.script("function f ( a, b, c ) return a + c, b end"); lua.safe_script("function f ( a, b, c ) return a + c, b end");
lua.set_function("g", [](int a, bool b, int c, double d) { lua.set_function("g", [](int a, bool b, int c, double d) {
return std::make_tuple(a + c, b, d + 2.5); return std::make_tuple(a + c, b, d + 2.5);
}); });

View File

@ -1,7 +1,8 @@
#define SOL_CHECK_ARGUMENTS #define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <catch.hpp> #include <catch.hpp>
#include <sol.hpp>
#include <iostream> #include <iostream>
#include "test_stack_guard.hpp" #include "test_stack_guard.hpp"
@ -11,7 +12,7 @@ TEST_CASE("environments/get", "Envronments can be taken out of things like Lua f
sol::stack_guard luasg(lua); sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.script("f = function() return test end"); lua.safe_script("f = function() return test end");
sol::function f = lua["f"]; sol::function f = lua["f"];
sol::environment env_f(lua, sol::create); sol::environment env_f(lua, sol::create);
@ -21,7 +22,7 @@ TEST_CASE("environments/get", "Envronments can be taken out of things like Lua f
int result = f(); int result = f();
REQUIRE(result == 31); REQUIRE(result == 31);
lua.script("g = function() test = 5 end"); lua.safe_script("g = function() test = 5 end");
sol::function g = lua["g"]; sol::function g = lua["g"];
sol::environment env_g(lua, sol::create); sol::environment env_g(lua, sol::create);
env_g.set_on(g); env_g.set_on(g);
@ -35,7 +36,7 @@ TEST_CASE("environments/get", "Envronments can be taken out of things like Lua f
sol::object global_test = lua["test"]; sol::object global_test = lua["test"];
REQUIRE(!global_test.valid()); REQUIRE(!global_test.valid());
lua.script("h = function() end"); lua.safe_script("h = function() end");
lua.set_function("check_f_env", lua.set_function("check_f_env",
[&lua, &env_f](sol::object target) { [&lua, &env_f](sol::object target) {
@ -67,9 +68,9 @@ TEST_CASE("environments/get", "Envronments can be taken out of things like Lua f
); );
REQUIRE_NOTHROW([&lua]() { REQUIRE_NOTHROW([&lua]() {
lua.script("check_f_env(f)"); lua.safe_script("check_f_env(f)");
lua.script("check_g_env(g)"); lua.safe_script("check_g_env(g)");
lua.script("check_h_env(h)"); lua.safe_script("check_h_env(h)");
}()); }());
} }
@ -80,7 +81,7 @@ TEST_CASE("environments/shadowing", "Environments can properly shadow and fallba
SECTION("no fallback") { SECTION("no fallback") {
sol::environment plain_env(lua, sol::create); sol::environment plain_env(lua, sol::create);
lua.script("a = 24", plain_env); lua.safe_script("a = 24", plain_env);
sol::optional<int> maybe_env_a = plain_env["a"]; sol::optional<int> maybe_env_a = plain_env["a"];
sol::optional<int> maybe_global_a = lua["a"]; sol::optional<int> maybe_global_a = lua["a"];
sol::optional<int> maybe_env_b = plain_env["b"]; sol::optional<int> maybe_env_b = plain_env["b"];
@ -96,7 +97,7 @@ TEST_CASE("environments/shadowing", "Environments can properly shadow and fallba
} }
SECTION("fallback") { SECTION("fallback") {
sol::environment env_with_fallback(lua, sol::create, lua.globals()); sol::environment env_with_fallback(lua, sol::create, lua.globals());
lua.script("a = 56", env_with_fallback, sol::script_default_on_error); lua.safe_script("a = 56", env_with_fallback, sol::script_default_on_error);
sol::optional<int> maybe_env_a = env_with_fallback["a"]; sol::optional<int> maybe_env_a = env_with_fallback["a"];
sol::optional<int> maybe_global_a = lua["a"]; sol::optional<int> maybe_global_a = lua["a"];
sol::optional<int> maybe_env_b = env_with_fallback["b"]; sol::optional<int> maybe_env_b = env_with_fallback["b"];
@ -115,7 +116,7 @@ TEST_CASE("environments/shadowing", "Environments can properly shadow and fallba
sol::environment env_with_fallback(lua, sol::create, lua.globals()); sol::environment env_with_fallback(lua, sol::create, lua.globals());
lua["env"] = env_with_fallback; lua["env"] = env_with_fallback;
sol::environment env = lua["env"]; sol::environment env = lua["env"];
lua.script("a = 56", env, sol::script_default_on_error); lua.safe_script("a = 56", env, sol::script_default_on_error);
sol::optional<int> maybe_env_a = env["a"]; sol::optional<int> maybe_env_a = env["a"];
sol::optional<int> maybe_global_a = lua["a"]; sol::optional<int> maybe_global_a = lua["a"];
sol::optional<int> maybe_env_b = env["b"]; sol::optional<int> maybe_env_b = env["b"];
@ -133,7 +134,7 @@ TEST_CASE("environments/shadowing", "Environments can properly shadow and fallba
SECTION("name with newtable") { SECTION("name with newtable") {
lua["blank_env"] = sol::new_table(0, 1); lua["blank_env"] = sol::new_table(0, 1);
sol::environment plain_env = lua["blank_env"]; sol::environment plain_env = lua["blank_env"];
lua.script("a = 24", plain_env); lua.safe_script("a = 24", plain_env);
sol::optional<int> maybe_env_a = plain_env["a"]; sol::optional<int> maybe_env_a = plain_env["a"];
sol::optional<int> maybe_global_a = lua["a"]; sol::optional<int> maybe_global_a = lua["a"];
sol::optional<int> maybe_env_b = plain_env["b"]; sol::optional<int> maybe_env_b = plain_env["b"];
@ -154,7 +155,7 @@ TEST_CASE("environments/functions", "see if environments on functions are workin
SECTION("basic") { SECTION("basic") {
sol::state lua; sol::state lua;
lua.script("a = function() return 5 end"); lua.safe_script("a = function() return 5 end");
sol::function a = lua["a"]; sol::function a = lua["a"];
@ -170,7 +171,7 @@ TEST_CASE("environments/functions", "see if environments on functions are workin
SECTION("return environment value") { SECTION("return environment value") {
sol::state lua; sol::state lua;
lua.script("a = function() return test end"); lua.safe_script("a = function() return test end");
sol::function a = lua["a"]; sol::function a = lua["a"];
sol::environment env(lua, sol::create); sol::environment env(lua, sol::create);
@ -184,7 +185,7 @@ TEST_CASE("environments/functions", "see if environments on functions are workin
SECTION("set environment value") { SECTION("set environment value") {
sol::state lua; sol::state lua;
lua.script("a = function() test = 5 end"); lua.safe_script("a = function() test = 5 end");
sol::function a = lua["a"]; sol::function a = lua["a"];
sol::environment env(lua, sol::create); sol::environment env(lua, sol::create);
@ -220,7 +221,7 @@ TEST_CASE("environments/this_environment", "test various situations of pulling o
lua["x"] = 5; lua["x"] = 5;
e["x"] = 20; e["x"] = 20;
SECTION("from Lua script") { SECTION("from Lua script") {
int value = lua.script(code, e); int value = lua.safe_script(code, e);
REQUIRE(value == 30); REQUIRE(value == 30);
} }
SECTION("from C++") { SECTION("from C++") {

236
test_filters.cpp Normal file
View File

@ -0,0 +1,236 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <catch.hpp>
#include <iostream>
#include <string>
TEST_CASE("filters/self", "ensure we return a direct reference to the lua userdata rather than creating a new one") {
struct vec2 {
float x = 20.f;
float y = 20.f;
vec2& normalize() {
float len2 = x * x + y * y;
if (len2 != 0) {
float len = sqrtf(len2);
x /= len;
y /= len;
}
return *this;
}
~vec2() {
x = std::numeric_limits<float>::lowest();
y = std::numeric_limits<float>::lowest();
}
};
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_usertype<vec2>("vec2",
"x", &vec2::x,
"y", &vec2::y,
"normalize", sol::filters(&vec2::normalize, sol::returns_self())
);
REQUIRE_NOTHROW([&]() {
lua.safe_script(R"(
v1 = vec2.new()
print('v1:', v1.x, v1.y)
v2 = v1:normalize()
print('v1:', v1.x, v1.y)
print('v2:', v2.x, v2.y)
print(v1, v2)
assert(rawequal(v1, v2))
v1 = nil
collectgarbage()
print(v2) -- v2 points to same, is not destroyed
)");
}());
}
TEST_CASE("filters/self_dependency", "ensure we can keep a userdata instance alive by attaching it to the lifetime of another userdata") {
struct dep;
struct gc_test;
static std::vector<dep*> deps_destroyed;
static std::vector<gc_test*> gc_tests_destroyed;
struct dep {
int value = 20;
~dep() {
std::cout << "\t" << "[C++] ~dep" << std::endl;
value = std::numeric_limits<int>::max();
deps_destroyed.push_back(this);
}
};
struct gc_test {
dep d;
~gc_test() {
std::cout << "\t" << "[C++] ~gc_test" << std::endl;
gc_tests_destroyed.push_back(this);
}
};
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_usertype<dep>("dep",
"value", &dep::value,
sol::meta_function::to_string, [](dep& d) {
return "{ " + std::to_string(d.value) + " }";
}
);
lua.new_usertype<gc_test>("gc_test",
"d", sol::filters(&gc_test::d, sol::self_dependency()),
sol::meta_function::to_string, [](gc_test& g) {
return "{ d: { " + std::to_string(g.d.value) + " } }";
}
);
lua.safe_script(R"(
g = gc_test.new()
d = g.d
print("new gc_test, d = g.d")
print("", g)
)");
REQUIRE(deps_destroyed.empty());
REQUIRE(gc_tests_destroyed.empty());
gc_test* g = lua["g"];
dep* d = lua["d"];
lua.safe_script(R"(
print("g = nil, collectgarbage")
g = nil
collectgarbage()
print("", d)
)");
REQUIRE(deps_destroyed.empty());
REQUIRE(gc_tests_destroyed.empty());
lua.safe_script(R"(
print("d = nil, collectgarbage")
d = nil
collectgarbage()
)");
REQUIRE(deps_destroyed.size() == 1);
REQUIRE(gc_tests_destroyed.size() == 1);
REQUIRE(deps_destroyed[0] == d);
REQUIRE(gc_tests_destroyed[0] == g);
}
TEST_CASE("filters/stack_dependencies", "ensure we can take dependencies even to arguments pushed on the stack") {
struct holder;
struct depends_on_reference;
struct composition_related;
static std::vector<composition_related*> composition_relateds_destroyed;
static std::vector<holder*> holders_destroyed;
static std::vector<depends_on_reference*> depends_on_references_destroyed;
struct composition_related {
std::string text = "bark";
~composition_related() {
std::cout << "[C++] ~composition_related" << std::endl;
text = "";
composition_relateds_destroyed.push_back(this);
}
};
struct holder {
int value = 20;
~holder() {
std::cout << "[C++] ~holder" << std::endl;
value = std::numeric_limits<int>::max();
holders_destroyed.push_back(this);
}
};
struct depends_on_reference {
std::reference_wrapper<holder> href;
composition_related comp;
depends_on_reference(holder& h) : href(h) {}
~depends_on_reference() {
std::cout << "[C++] ~depends_on_reference" << std::endl;
depends_on_references_destroyed.push_back(this);
}
};
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_usertype<holder>("holder",
"value", &holder::value
);
lua.new_usertype<depends_on_reference>("depends_on_reference",
"new", sol::filters(sol::constructors<depends_on_reference(holder&)>(), sol::stack_dependencies(-1, 1)),
"comp", &depends_on_reference::comp
);
lua.safe_script(R"(
h = holder.new()
dor = depends_on_reference.new(h)
c = dor.comp
)");
REQUIRE(composition_relateds_destroyed.empty());
REQUIRE(holders_destroyed.empty());
REQUIRE(depends_on_references_destroyed.empty());
holder* h = lua["h"];
composition_related* c = lua["c"];
depends_on_reference* dor = lua["dor"];
REQUIRE(h == &dor->href.get());
REQUIRE(c == &dor->comp);
lua.safe_script(R"(
h = nil
collectgarbage()
)");
REQUIRE(composition_relateds_destroyed.empty());
REQUIRE(holders_destroyed.empty());
REQUIRE(depends_on_references_destroyed.empty());
lua.safe_script(R"(
c = nil
collectgarbage()
)");
REQUIRE(composition_relateds_destroyed.empty());
REQUIRE(holders_destroyed.empty());
REQUIRE(depends_on_references_destroyed.empty());
lua.safe_script(R"(
dor = nil
collectgarbage()
)");
REQUIRE(composition_relateds_destroyed.size() == 1);
REQUIRE(holders_destroyed.size() == 1);
REQUIRE(depends_on_references_destroyed.size() == 1);
REQUIRE(composition_relateds_destroyed[0] == c);
REQUIRE(holders_destroyed[0] == h);
REQUIRE(depends_on_references_destroyed[0] == dor);
}
int always_return_24(lua_State* L, int) {
return sol::stack::push(L, 24);
}
TEST_CASE("filters/custom", "ensure we can return dependencies on multiple things in the stack") {
sol::state lua;
lua.set_function("f", sol::filters([]() { return std::string("hi there"); }, always_return_24));
int value = lua["f"]();
REQUIRE(value == 24);
}

View File

@ -1,7 +1,9 @@
#define SOL_CHECK_ARGUMENTS #define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <catch.hpp> #include <catch.hpp>
#include <sol.hpp>
#include <iostream> #include <iostream>
#include "test_stack_guard.hpp" #include "test_stack_guard.hpp"
@ -105,7 +107,7 @@ static int raw_noexcept_function(lua_State* L) noexcept {
TEST_CASE("functions/tuple returns", "Make sure tuple returns are ordered properly") { TEST_CASE("functions/tuple returns", "Make sure tuple returns are ordered properly") {
sol::state lua; sol::state lua;
lua.script("function f() return '3', 4 end"); lua.safe_script("function f() return '3', 4 end");
std::tuple<std::string, int> result = lua["f"](); std::tuple<std::string, int> result = lua["f"]();
auto s = std::get<0>(result); auto s = std::get<0>(result);
@ -119,28 +121,28 @@ TEST_CASE("functions/overload resolution", "Check if overloaded function resolut
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.set_function("non_overloaded", non_overloaded); lua.set_function("non_overloaded", non_overloaded);
REQUIRE_NOTHROW(lua.script("x = non_overloaded(1, 2, 3)\nprint(x)")); REQUIRE_NOTHROW(lua.safe_script("x = non_overloaded(1, 2, 3)\nprint(x)"));
/* /*
// Cannot reasonably support: clang++ refuses to try enough // Cannot reasonably support: clang++ refuses to try enough
// deductions to make this work // deductions to make this work
lua.set_function<int>("overloaded", overloaded); lua.set_function<int>("overloaded", overloaded);
REQUIRE_NOTHROW(lua.script("print(overloaded(1))")); REQUIRE_NOTHROW(lua.safe_script("print(overloaded(1))"));
lua.set_function<int, int>("overloaded", overloaded); lua.set_function<int, int>("overloaded", overloaded);
REQUIRE_NOTHROW(lua.script("print(overloaded(1, 2))")); REQUIRE_NOTHROW(lua.safe_script("print(overloaded(1, 2))"));
lua.set_function<int, int, int>("overloaded", overloaded); lua.set_function<int, int, int>("overloaded", overloaded);
REQUIRE_NOTHROW(lua.script("print(overloaded(1, 2, 3))")); REQUIRE_NOTHROW(lua.safe_script("print(overloaded(1, 2, 3))"));
*/ */
lua.set_function("overloaded", sol::resolve<int(int)>(overloaded)); lua.set_function("overloaded", sol::resolve<int(int)>(overloaded));
REQUIRE_NOTHROW(lua.script("print(overloaded(1))")); REQUIRE_NOTHROW(lua.safe_script("print(overloaded(1))"));
lua.set_function("overloaded", sol::resolve<int(int, int)>(overloaded)); lua.set_function("overloaded", sol::resolve<int(int, int)>(overloaded));
REQUIRE_NOTHROW(lua.script("print(overloaded(1, 2))")); REQUIRE_NOTHROW(lua.safe_script("print(overloaded(1, 2))"));
lua.set_function("overloaded", sol::resolve<int(int, int, int)>(overloaded)); lua.set_function("overloaded", sol::resolve<int(int, int, int)>(overloaded));
REQUIRE_NOTHROW(lua.script("print(overloaded(1, 2, 3))")); REQUIRE_NOTHROW(lua.safe_script("print(overloaded(1, 2, 3))"));
} }
TEST_CASE("functions/return order and multi get", "Check if return order is in the same reading order specified in Lua") { TEST_CASE("functions/return order and multi get", "Check if return order is in the same reading order specified in Lua") {
@ -154,7 +156,7 @@ TEST_CASE("functions/return order and multi get", "Check if return order is in t
lua.set_function("h", []() { lua.set_function("h", []() {
return std::make_tuple(10, 10.0f); return std::make_tuple(10, 10.0f);
}); });
lua.script("function g() return 10, 11, 12 end\nx,y,z = g()"); lua.safe_script("function g() return 10, 11, 12 end\nx,y,z = g()");
auto tcpp = lua.get<sol::function>("f").call<int, int, int>(); auto tcpp = lua.get<sol::function>("f").call<int, int, int>();
auto tlua = lua.get<sol::function>("g").call<int, int, int>(); auto tlua = lua.get<sol::function>("g").call<int, int, int>();
auto tcpp2 = lua.get<sol::function>("h").call<int, float>(); auto tcpp2 = lua.get<sol::function>("h").call<int, float>();
@ -180,7 +182,7 @@ TEST_CASE("functions/deducing return order and multi get", "Check if return orde
lua.set_function("f", [] { lua.set_function("f", [] {
return std::make_tuple(10, 11, 12); return std::make_tuple(10, 11, 12);
}); });
lua.script("function g() return 10, 11, 12 end\nx,y,z = g()"); lua.safe_script("function g() return 10, 11, 12 end\nx,y,z = g()");
std::tuple<int, int, int> tcpp = lua.get<sol::function>("f")(); std::tuple<int, int, int> tcpp = lua.get<sol::function>("f")();
std::tuple<int, int, int> tlua = lua.get<sol::function>("g")(); std::tuple<int, int, int> tlua = lua.get<sol::function>("g")();
std::tuple<int, int, int> tluaget = lua.get<int, int, int>("x", "y", "z"); std::tuple<int, int, int> tluaget = lua.get<int, int, int>("x", "y", "z");
@ -197,7 +199,7 @@ TEST_CASE("functions/optional values", "check if optionals can be passed in to b
int v; int v;
}; };
sol::state lua; sol::state lua;
lua.script(R"( function f (a) lua.safe_script(R"( function f (a)
return a return a
end )"); end )");
@ -217,7 +219,7 @@ TEST_CASE("functions/pair and tuple and proxy tests", "Check if sol::reference a
sol::state lua; sol::state lua;
lua.new_usertype<A>("A", lua.new_usertype<A>("A",
"bark", &A::bark); "bark", &A::bark);
lua.script(R"( function f (num_value, a) lua.safe_script(R"( function f (num_value, a)
return num_value * 2, a:bark() return num_value * 2, a:bark()
end end
function h (num_value, a, b) function h (num_value, a, b)
@ -259,10 +261,10 @@ TEST_CASE("functions/sol::function to std::function", "check if conversion to st
lua.set_function("testFunc", test_free_func); lua.set_function("testFunc", test_free_func);
lua.set_function("testFunc2", test_free_func2); lua.set_function("testFunc2", test_free_func2);
lua.script( lua.safe_script(
"testFunc(function() print(\"hello std::function\") end)" "testFunc(function() print(\"hello std::function\") end)"
); );
REQUIRE_NOTHROW(lua.script( REQUIRE_NOTHROW(lua.safe_script(
"function m(a)\n" "function m(a)\n"
" print(\"hello std::function with arg \", a)\n" " print(\"hello std::function with arg \", a)\n"
" return a\n" " return a\n"
@ -278,7 +280,7 @@ TEST_CASE("functions/returning functions from C++", "check to see if returning a
lua.set_function("makefn", makefn); lua.set_function("makefn", makefn);
lua.set_function("takefn", takefn); lua.set_function("takefn", takefn);
lua.script("afx = makefn()\n" lua.safe_script("afx = makefn()\n"
"print(afx())\n" "print(afx())\n"
"takefn(afx)\n"); "takefn(afx)\n");
} }
@ -308,7 +310,7 @@ TEST_CASE("functions/function_result and protected_function_result", "Function r
return handlederrormessage; return handlederrormessage;
}; };
lua.set_function("cpphandler", cpphandlerfx); lua.set_function("cpphandler", cpphandlerfx);
lua.script( lua.safe_script(
std::string("function luahandler ( message )") std::string("function luahandler ( message )")
+ " print('lua handler called with: ' .. message)" + " print('lua handler called with: ' .. message)"
+ " return '" + handlederrormessage + "'" + " return '" + handlederrormessage + "'"
@ -392,85 +394,6 @@ TEST_CASE("functions/function_result and protected_function_result", "Function r
} }
} }
TEST_CASE("functions/destructor tests", "Show that proper copies / destruction happens") {
static int created = 0;
static int destroyed = 0;
static void* last_call = nullptr;
static void* static_call = reinterpret_cast<void*>(0x01);
typedef void(*fptr)();
struct x {
x() { ++created; }
x(const x&) { ++created; }
x(x&&) { ++created; }
x& operator=(const x&) { return *this; }
x& operator=(x&&) { return *this; }
void func() { last_call = static_cast<void*>(this); };
~x() { ++destroyed; }
};
struct y {
y() { ++created; }
y(const x&) { ++created; }
y(x&&) { ++created; }
y& operator=(const x&) { return *this; }
y& operator=(x&&) { return *this; }
static void func() { last_call = static_call; };
void operator()() { func(); }
operator fptr () { return func; }
~y() { ++destroyed; }
};
// stateful functors/member functions should always copy unless specified
{
created = 0;
destroyed = 0;
last_call = nullptr;
{
sol::state lua;
x x1;
lua.set_function("x1copy", &x::func, x1);
lua.script("x1copy()");
REQUIRE(created == 2);
REQUIRE(destroyed == 0);
REQUIRE_FALSE(last_call == &x1);
lua.set_function("x1ref", &x::func, std::ref(x1));
lua.script("x1ref()");
REQUIRE(created == 2);
REQUIRE(destroyed == 0);
REQUIRE(last_call == &x1);
}
REQUIRE(created == 2);
REQUIRE(destroyed == 2);
}
// things convertible to a static function should _never_ be forced to make copies
// therefore, pass through untouched
{
created = 0;
destroyed = 0;
last_call = nullptr;
{
sol::state lua;
y y1;
lua.set_function("y1copy", y1);
lua.script("y1copy()");
REQUIRE(created == 1);
REQUIRE(destroyed == 0);
REQUIRE(last_call == static_call);
last_call = nullptr;
lua.set_function("y1ref", std::ref(y1));
lua.script("y1ref()");
REQUIRE(created == 1);
REQUIRE(destroyed == 0);
REQUIRE(last_call == static_call);
}
REQUIRE(created == 1);
REQUIRE(destroyed == 1);
}
}
TEST_CASE("functions/all kinds", "Register all kinds of functions, make sure they all compile and work") { TEST_CASE("functions/all kinds", "Register all kinds of functions, make sure they all compile and work") {
sol::state lua; sol::state lua;
@ -531,12 +454,12 @@ TEST_CASE("functions/all kinds", "Register all kinds of functions, make sure the
lua.set_function("m", &test_2::a, &t2); lua.set_function("m", &test_2::a, &t2);
lua.set_function("n", sol::c_call<decltype(&non_overloaded), &non_overloaded>); lua.set_function("n", sol::c_call<decltype(&non_overloaded), &non_overloaded>);
lua.script(R"( lua.safe_script(R"(
o1 = test_1.new() o1 = test_1.new()
o2 = test_2.new() o2 = test_2.new()
)"); )");
lua.script(R"( lua.safe_script(R"(
ob = o1:bark() ob = o1:bark()
A = a() A = a()
@ -551,32 +474,32 @@ I = i(o1)
)"); )");
lua.script(R"( lua.safe_script(R"(
J0 = j() J0 = j()
j(24) j(24)
J1 = j() J1 = j()
)"); )");
lua.script(R"( lua.safe_script(R"(
K0 = k(o2) K0 = k(o2)
k(o2, 1024) k(o2, 1024)
K1 = k(o2) K1 = k(o2)
)"); )");
lua.script(R"( lua.safe_script(R"(
L0 = l(o1) L0 = l(o1)
l(o1, 678) l(o1, 678)
L1 = l(o1) L1 = l(o1)
)"); )");
lua.script(R"( lua.safe_script(R"(
M0 = m() M0 = m()
m(256) m(256)
M1 = m() M1 = m()
)"); )");
lua.script(R"( lua.safe_script(R"(
N = n(1, 2, 3) N = n(1, 2, 3)
)"); )");
int ob, A, B, C, D, F, G0, G1, H, I, J0, J1, K0, K1, L0, L1, M0, M1, N; int ob, A, B, C, D, F, G0, G1, H, I, J0, J1, K0, K1, L0, L1, M0, M1, N;
@ -677,9 +600,9 @@ N = n(1, 2, 3)
TEST_CASE("simple/call with parameters", "Lua function is called with a few parameters from C++") { TEST_CASE("simple/call with parameters", "Lua function is called with a few parameters from C++") {
sol::state lua; sol::state lua;
REQUIRE_NOTHROW(lua.script("function my_add(i, j, k) return i + j + k end")); REQUIRE_NOTHROW(lua.safe_script("function my_add(i, j, k) return i + j + k end"));
auto f = lua.get<sol::function>("my_add"); auto f = lua.get<sol::function>("my_add");
REQUIRE_NOTHROW(lua.script("function my_nothing(i, j, k) end")); REQUIRE_NOTHROW(lua.safe_script("function my_nothing(i, j, k) end"));
auto fvoid = lua.get<sol::function>("my_nothing"); auto fvoid = lua.get<sol::function>("my_nothing");
REQUIRE_NOTHROW([&]() { REQUIRE_NOTHROW([&]() {
fvoid(1, 2, 3); fvoid(1, 2, 3);
@ -699,7 +622,7 @@ TEST_CASE("simple/call c++ function", "C++ function is called from lua") {
sol::state lua; sol::state lua;
lua.set_function("plop_xyz", sep::plop_xyz); lua.set_function("plop_xyz", sep::plop_xyz);
lua.script("x = plop_xyz(2, 6, 'hello')"); lua.safe_script("x = plop_xyz(2, 6, 'hello')");
REQUIRE(lua.get<int>("x") == 11); REQUIRE(lua.get<int>("x") == 11);
} }
@ -711,7 +634,7 @@ TEST_CASE("simple/call lambda", "A C++ lambda is exposed to lua and called") {
lua.set_function("foo", [&a] { a = 1; }); lua.set_function("foo", [&a] { a = 1; });
lua.script("foo()"); lua.safe_script("foo()");
REQUIRE(a == 1); REQUIRE(a == 1);
} }
@ -795,7 +718,7 @@ TEST_CASE("advanced/call lambdas", "A C++ lambda is exposed to lua and called")
return 0; return 0;
}); });
lua.script("set_x(9)"); lua.safe_script("set_x(9)");
REQUIRE(x == 9); REQUIRE(x == 9);
} }
@ -816,8 +739,8 @@ TEST_CASE("advanced/call referenced obj", "A C++ object is passed by pointer/ref
}; };
lua.set_function("set_y", &decltype(objy)::operator(), std::ref(objy)); lua.set_function("set_y", &decltype(objy)::operator(), std::ref(objy));
lua.script("set_x(9)"); lua.safe_script("set_x(9)");
lua.script("set_y(9)"); lua.safe_script("set_y(9)");
REQUIRE(x == 9); REQUIRE(x == 9);
REQUIRE(y == 9); REQUIRE(y == 9);
} }
@ -825,7 +748,7 @@ TEST_CASE("advanced/call referenced obj", "A C++ object is passed by pointer/ref
TEST_CASE("functions/tie", "make sure advanced syntax with 'tie' works") { TEST_CASE("functions/tie", "make sure advanced syntax with 'tie' works") {
sol::state lua; sol::state lua;
lua.script(R"(function f () lua.safe_script(R"(function f ()
return 1, 2, 3 return 1, 2, 3
end)"); end)");
sol::function f = lua["f"]; sol::function f = lua["f"];
@ -846,7 +769,7 @@ TEST_CASE("functions/overloading", "Check if overloading works properly for regu
const std::string string_bark = "string: bark"; const std::string string_bark = "string: bark";
REQUIRE_NOTHROW(lua.script( REQUIRE_NOTHROW(lua.safe_script(
"a = func(1)\n" "a = func(1)\n"
"b = func('bark')\n" "b = func('bark')\n"
"c = func(1,2)\n" "c = func(1,2)\n"
@ -868,11 +791,11 @@ TEST_CASE("overloading/c_call", "Make sure that overloading works with c_call fu
lua.set("h", sol::c_call<decltype(&f2), &f2>); lua.set("h", sol::c_call<decltype(&f2), &f2>);
lua.set("obj", fer()); lua.set("obj", fer());
lua.script("r1 = f(1)"); lua.safe_script("r1 = f(1)");
lua.script("r2 = f(1, 2)"); lua.safe_script("r2 = f(1, 2)");
lua.script("r3 = f(obj, 1, 2)"); lua.safe_script("r3 = f(obj, 1, 2)");
lua.script("r4 = g(1)"); lua.safe_script("r4 = g(1)");
lua.script("r5 = h(1, 2)"); lua.safe_script("r5 = h(1, 2)");
int r1 = lua["r1"]; int r1 = lua["r1"];
int r2 = lua["r2"]; int r2 = lua["r2"];
@ -892,8 +815,8 @@ TEST_CASE("functions/stack atomic", "make sure functions don't impede on the sta
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::string); lua.open_libraries(sol::lib::base, sol::lib::string);
lua.script("function ErrorHandler(msg) print('Lua created error msg : ' .. msg) return msg end"); lua.safe_script("function ErrorHandler(msg) print('Lua created error msg : ' .. msg) return msg end");
lua.script("function stringtest(a) if a == nil then error('fuck') end print('Lua recieved content : ' .. a) return a end"); lua.safe_script("function stringtest(a) if a == nil then error('fuck') end print('Lua recieved content : ' .. a) return a end");
// test normal function // test normal function
{ {
@ -941,48 +864,9 @@ TEST_CASE("functions/stack atomic", "make sure functions don't impede on the sta
REQUIRE(sg.check_stack()); REQUIRE(sg.check_stack());
} }
TEST_CASE("functions/same type closures", "make sure destructions are per-object, not per-type, by destroying one type multiple times") {
static std::set<void*> last_my_closures;
static bool checking_closures = false;
static bool check_failed = false;
struct my_closure {
int& n;
my_closure(int& n) : n(n) {}
~my_closure() noexcept(false) {
if (!checking_closures)
return;
void* addr = static_cast<void*>(this);
auto f = last_my_closures.find(addr);
if (f != last_my_closures.cend()) {
check_failed = true;
}
last_my_closures.insert(f, addr);
}
int operator() () {
++n; return n;
}
};
int n = 250;
my_closure a(n);
my_closure b(n);
{
sol::state lua;
lua.set_function("f", a);
lua.set_function("g", b);
checking_closures = true;
}
REQUIRE_FALSE(check_failed);
REQUIRE(last_my_closures.size() == 2);
}
TEST_CASE("functions/stack multi-return", "Make sure the stack is protected after multi-returns") { TEST_CASE("functions/stack multi-return", "Make sure the stack is protected after multi-returns") {
sol::state lua; sol::state lua;
lua.script("function f () return 1, 2, 3, 4, 5 end"); lua.safe_script("function f () return 1, 2, 3, 4, 5 end");
{ {
sol::stack_guard sg(lua); sol::stack_guard sg(lua);
@ -1005,7 +889,7 @@ TEST_CASE("functions/stack multi-return", "Make sure the stack is protected afte
TEST_CASE("functions/protected stack multi-return", "Make sure the stack is protected after multi-returns") { TEST_CASE("functions/protected stack multi-return", "Make sure the stack is protected after multi-returns") {
sol::state lua; sol::state lua;
lua.script("function f () return 1, 2, 3, 4, 5 end"); lua.safe_script("function f () return 1, 2, 3, 4, 5 end");
{ {
sol::stack_guard sg(lua); sol::stack_guard sg(lua);
@ -1030,8 +914,8 @@ TEST_CASE("functions/function_result as arguments", "ensure that function_result
sol::state lua; sol::state lua;
lua.open_libraries(); lua.open_libraries();
lua.script("function f () return 1, 2, 3, 4, 5 end"); lua.safe_script("function f () return 1, 2, 3, 4, 5 end");
lua.script("function g (a, b, c, d, e) assert(a == 1) assert(b == 2) assert(c == 3) assert(d == 4) assert(e == 5) end"); lua.safe_script("function g (a, b, c, d, e) assert(a == 1) assert(b == 2) assert(c == 3) assert(d == 4) assert(e == 5) end");
{ {
sol::stack_guard sg(lua); sol::stack_guard sg(lua);
@ -1059,8 +943,8 @@ TEST_CASE("functions/protected_function_result as arguments", "ensure that prote
sol::state lua; sol::state lua;
lua.open_libraries(); lua.open_libraries();
lua.script("function f () return 1, 2, 3, 4, 5 end"); lua.safe_script("function f () return 1, 2, 3, 4, 5 end");
lua.script("function g (a, b, c, d, e) assert(a == 1) assert(b == 2) assert(c == 3) assert(d == 4) assert(e == 5) end"); lua.safe_script("function g (a, b, c, d, e) assert(a == 1) assert(b == 2) assert(c == 3) assert(d == 4) assert(e == 5) end");
{ {
sol::stack_guard sg(lua); sol::stack_guard sg(lua);
@ -1091,9 +975,9 @@ TEST_CASE("functions/overloaded variadic", "make sure variadics work to some deg
sol::table ssl = lua.create_named_table("ssl"); sol::table ssl = lua.create_named_table("ssl");
ssl.set_function("test", sol::overload(&va_func<int>, &va_func<double>)); ssl.set_function("test", sol::overload(&va_func<int>, &va_func<double>));
lua.script("a = ssl.test(1, 2, 3)"); lua.safe_script("a = ssl.test(1, 2, 3)");
lua.script("b = ssl.test(1, 2)"); lua.safe_script("b = ssl.test(1, 2)");
lua.script("c = ssl.test(2.2)"); lua.safe_script("c = ssl.test(2.2)");
int a = lua["a"]; int a = lua["a"];
int b = lua["b"]; int b = lua["b"];
@ -1117,20 +1001,20 @@ TEST_CASE("functions/sectioning variadic", "make sure variadics can bite off chu
return r; return r;
}); });
lua.script("x = f(1, 2, 3, 4)"); lua.safe_script("x = f(1, 2, 3, 4)");
lua.script("x2 = f(8, 200, 3, 4)"); lua.safe_script("x2 = f(8, 200, 3, 4)");
lua.script("x3 = f(1, 2, 3, 4, 5, 6)"); lua.safe_script("x3 = f(1, 2, 3, 4, 5, 6)");
lua.script("print(x) assert(x == 7)"); lua.safe_script("print(x) assert(x == 7)");
lua.script("print(x2) assert(x2 == 7)"); lua.safe_script("print(x2) assert(x2 == 7)");
lua.script("print(x3) assert(x3 == 18)"); lua.safe_script("print(x3) assert(x3 == 18)");
} }
TEST_CASE("functions/set_function already wrapped", "setting a function returned from Lua code that is already wrapped into a sol::function or similar") { TEST_CASE("functions/set_function already wrapped", "setting a function returned from Lua code that is already wrapped into a sol::function or similar") {
SECTION("test different types") { SECTION("test different types") {
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
sol::function fn = lua.script("return function() return 5 end"); sol::function fn = lua.safe_script("return function() return 5 end");
sol::protected_function pfn = fn; sol::protected_function pfn = fn;
std::function<int()> sfn = fn; std::function<int()> sfn = fn;
@ -1138,23 +1022,23 @@ TEST_CASE("functions/set_function already wrapped", "setting a function returned
lua.set_function("test2", pfn); lua.set_function("test2", pfn);
lua.set_function("test3", sfn); lua.set_function("test3", sfn);
REQUIRE_NOTHROW(lua.script("assert(type(test) == 'function')")); REQUIRE_NOTHROW(lua.safe_script("assert(type(test) == 'function')"));
REQUIRE_NOTHROW(lua.script("assert(test() ~= nil)")); REQUIRE_NOTHROW(lua.safe_script("assert(test() ~= nil)"));
REQUIRE_NOTHROW(lua.script("assert(test() == 5)")); REQUIRE_NOTHROW(lua.safe_script("assert(test() == 5)"));
REQUIRE_NOTHROW(lua.script("assert(type(test2) == 'function')")); REQUIRE_NOTHROW(lua.safe_script("assert(type(test2) == 'function')"));
REQUIRE_NOTHROW(lua.script("assert(test2() ~= nil)")); REQUIRE_NOTHROW(lua.safe_script("assert(test2() ~= nil)"));
REQUIRE_NOTHROW(lua.script("assert(test2() == 5)")); REQUIRE_NOTHROW(lua.safe_script("assert(test2() == 5)"));
REQUIRE_NOTHROW(lua.script("assert(type(test3) == 'function')")); REQUIRE_NOTHROW(lua.safe_script("assert(type(test3) == 'function')"));
REQUIRE_NOTHROW(lua.script("assert(test3() ~= nil)")); REQUIRE_NOTHROW(lua.safe_script("assert(test3() ~= nil)"));
REQUIRE_NOTHROW(lua.script("assert(test3() == 5)")); REQUIRE_NOTHROW(lua.safe_script("assert(test3() == 5)"));
} }
SECTION("getting the value from C++") { SECTION("getting the value from C++") {
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
sol::function fn = lua.script("return function() return 5 end"); sol::function fn = lua.safe_script("return function() return 5 end");
int result = fn(); int result = fn();
REQUIRE(result == 5); REQUIRE(result == 5);
@ -1163,13 +1047,13 @@ TEST_CASE("functions/set_function already wrapped", "setting a function returned
SECTION("setting the function directly") { SECTION("setting the function directly") {
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
sol::function fn = lua.script("return function() return 5 end"); sol::function fn = lua.safe_script("return function() return 5 end");
lua.set_function("test", fn); lua.set_function("test", fn);
REQUIRE_NOTHROW(lua.script("assert(type(test) == 'function')")); REQUIRE_NOTHROW(lua.safe_script("assert(type(test) == 'function')"));
REQUIRE_NOTHROW(lua.script("assert(test() ~= nil)")); REQUIRE_NOTHROW(lua.safe_script("assert(test() ~= nil)"));
REQUIRE_NOTHROW(lua.script("assert(test() == 5)")); REQUIRE_NOTHROW(lua.safe_script("assert(test() == 5)"));
} }
@ -1177,23 +1061,23 @@ TEST_CASE("functions/set_function already wrapped", "setting a function returned
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
sol::function fn2 = lua.script("return function() print('this was executed') end"); sol::function fn2 = lua.safe_script("return function() print('this was executed') end");
lua.set_function("test", fn2); lua.set_function("test", fn2);
REQUIRE_NOTHROW(lua.script("assert(type(test) == 'function')")); REQUIRE_NOTHROW(lua.safe_script("assert(type(test) == 'function')"));
REQUIRE_NOTHROW(lua.script("test()")); REQUIRE_NOTHROW(lua.safe_script("test()"));
} }
SECTION("setting the function indirectly, with the return value cast explicitly") { SECTION("setting the function indirectly, with the return value cast explicitly") {
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
sol::function fn = lua.script("return function() return 5 end"); sol::function fn = lua.safe_script("return function() return 5 end");
lua.set_function("test", [&fn]() { return fn.call<int>(); }); lua.set_function("test", [&fn]() { return fn.call<int>(); });
REQUIRE_NOTHROW(lua.script("assert(type(test) == 'function')")); REQUIRE_NOTHROW(lua.safe_script("assert(type(test) == 'function')"));
REQUIRE_NOTHROW(lua.script("assert(test() ~= nil)")); REQUIRE_NOTHROW(lua.safe_script("assert(test() ~= nil)"));
REQUIRE_NOTHROW(lua.script("assert(test() == 5)")); REQUIRE_NOTHROW(lua.safe_script("assert(test() == 5)"));
} }
} }
@ -1252,15 +1136,15 @@ TEST_CASE("functions/pointer nullptr + nil", "ensure specific semantics for hand
lua["h"] = &nil_test::h; lua["h"] = &nil_test::h;
REQUIRE_NOTHROW([&]() { REQUIRE_NOTHROW([&]() {
lua.script("f(v1)"); lua.safe_script("f(v1)");
lua.script("f(v2)"); lua.safe_script("f(v2)");
lua.script("f(v3)"); lua.safe_script("f(v3)");
lua.script("f(v4)"); lua.safe_script("f(v4)");
lua.script("assert(v1 == nil)"); lua.safe_script("assert(v1 == nil)");
lua.script("assert(v2 == nil)"); lua.safe_script("assert(v2 == nil)");
lua.script("assert(v3 == nil)"); lua.safe_script("assert(v3 == nil)");
lua.script("assert(v4 == nil)"); lua.safe_script("assert(v4 == nil)");
}()); }());
} }
SECTION("throw unique argument") { SECTION("throw unique argument") {
@ -1405,16 +1289,16 @@ TEST_CASE("functions/unique_usertype overloading", "make sure overloading can wo
lua["v4"] = ut.get(); lua["v4"] = ut.get();
REQUIRE_NOTHROW([&]() { REQUIRE_NOTHROW([&]() {
lua.script("f(v1)"); lua.safe_script("f(v1)");
lua.script("g(v1)"); lua.safe_script("g(v1)");
lua.script("g(v2)"); lua.safe_script("g(v2)");
lua.script("g(v3)"); lua.safe_script("g(v3)");
lua.script("g(v4)"); lua.safe_script("g(v4)");
lua.script("h(v1)"); lua.safe_script("h(v1)");
lua.script("h(v2)"); lua.safe_script("h(v2)");
lua.script("h(v3)"); lua.safe_script("h(v3)");
lua.script("h(v4)"); lua.safe_script("h(v4)");
lua.script("i(20, v1)"); lua.safe_script("i(20, v1)");
}()); }());
}; };
// LuaJIT segfaults hard on some Linux machines // LuaJIT segfaults hard on some Linux machines
@ -1473,14 +1357,14 @@ TEST_CASE("functions/noexcept", "allow noexcept functions to be serialized prope
lua.set_function("m", ccall); lua.set_function("m", ccall);
lua["t"] = T(); lua["t"] = T();
lua.script("v1 = f()"); lua.safe_script("v1 = f()");
lua.script("v2 = g(t)"); lua.safe_script("v2 = g(t)");
lua.script("v3 = h()"); lua.safe_script("v3 = h()");
lua.script("v4 = i()"); lua.safe_script("v4 = i()");
lua.script("v5 = j()"); lua.safe_script("v5 = j()");
lua.script("v6 = k()"); lua.safe_script("v6 = k()");
lua.script("v7 = l()"); lua.safe_script("v7 = l()");
lua.script("v8 = m()"); lua.safe_script("v8 = m()");
int v1 = lua["v1"]; int v1 = lua["v1"];
int v2 = lua["v2"]; int v2 = lua["v2"];
int v3 = lua["v3"]; int v3 = lua["v3"];

504
test_gc.cpp Normal file
View File

@ -0,0 +1,504 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <catch.hpp>
#include <iostream>
#include <string>
#include <list>
#include <vector>
#include <memory>
TEST_CASE("gc/destructors", "test if destructors are fired properly through gc of unbound usertypes") {
struct test;
static std::vector<test*> tests_destroyed;
struct test {
int v = 10;
~test() {
tests_destroyed.push_back(this);
}
};
test t;
test* pt = nullptr;
{
sol::state lua;
lua["t"] = test{};
pt = lua["t"];
}
REQUIRE(tests_destroyed.size() == 2);
REQUIRE(tests_destroyed.back() == pt);
{
sol::state lua;
lua["t"] = &t;
pt = lua["t"];
}
REQUIRE(tests_destroyed.size() == 2);
REQUIRE(&t == pt);
{
sol::state lua;
lua["t"] = std::ref(t);
pt = lua["t"];
}
REQUIRE(tests_destroyed.size() == 2);
REQUIRE(&t == pt);
{
sol::state lua;
lua["t"] = t;
pt = lua["t"];
}
REQUIRE(tests_destroyed.size() == 3);
REQUIRE(&t != pt);
REQUIRE(nullptr != pt);
}
TEST_CASE("gc/function argument storage", "ensure functions take references on their types, not ownership, when specified") {
class gc_entity;
static std::vector<gc_entity*> entities;
class gc_entity {
public:
~gc_entity() { entities.push_back(this); }
};
SECTION("plain") {
entities.clear();
sol::state lua;
lua.open_libraries();
sol::function f = lua.safe_script(R"(
return function(e)
end
)");
gc_entity* target = nullptr;
{
gc_entity e;
target = &e;
{
f(e); // same with std::ref(e)!
lua.collect_garbage(); // destroys e for some reason
}
{
f(&e); // same with std::ref(e)!
lua.collect_garbage(); // destroys e for some reason
}
{
f(std::ref(e)); // same with std::ref(e)!
lua.collect_garbage(); // destroys e for some reason
}
}
REQUIRE(entities.size() == 1);
REQUIRE(entities.back() == target);
}
SECTION("regular") {
entities.clear();
sol::state lua;
lua.open_libraries();
lua.new_usertype<gc_entity>("entity");
sol::function f = lua.safe_script(R"(
return function(e)
end
)");
gc_entity* target = nullptr;
{
gc_entity e;
target = &e;
{
f(e); // same with std::ref(e)!
lua.collect_garbage(); // destroys e for some reason
}
{
f(&e); // same with std::ref(e)!
lua.collect_garbage(); // destroys e for some reason
}
{
f(std::ref(e)); // same with std::ref(e)!
lua.collect_garbage(); // destroys e for some reason
}
}
REQUIRE(entities.size() == 1);
REQUIRE(entities.back() == target);
}
SECTION("simple") {
entities.clear();
sol::state lua;
lua.open_libraries();
lua.new_simple_usertype<gc_entity>("entity");
sol::function f = lua.safe_script(R"(
return function(e)
end
)");
gc_entity* target = nullptr;
{
gc_entity e;
target = &e;
{
f(e); // same with std::ref(e)!
lua.collect_garbage(); // destroys e for some reason
}
{
f(&e); // same with std::ref(e)!
lua.collect_garbage(); // destroys e for some reason
}
{
f(std::ref(e)); // same with std::ref(e)!
lua.collect_garbage(); // destroys e for some reason
}
}
REQUIRE(entities.size() == 1);
REQUIRE(entities.back() == target);
}
}
TEST_CASE("gc/function storage", "show that proper copies / destruction happens for function storage (or not)") {
static int created = 0;
static int destroyed = 0;
static void* last_call = nullptr;
static void* static_call = reinterpret_cast<void*>(0x01);
typedef void(*fptr)();
struct x {
x() { ++created; }
x(const x&) { ++created; }
x(x&&) { ++created; }
x& operator=(const x&) { return *this; }
x& operator=(x&&) { return *this; }
void func() { last_call = static_cast<void*>(this); };
~x() { ++destroyed; }
};
struct y {
y() { ++created; }
y(const x&) { ++created; }
y(x&&) { ++created; }
y& operator=(const x&) { return *this; }
y& operator=(x&&) { return *this; }
static void func() { last_call = static_call; };
void operator()() { func(); }
operator fptr () { return func; }
~y() { ++destroyed; }
};
// stateful functors/member functions should always copy unless specified
{
created = 0;
destroyed = 0;
last_call = nullptr;
{
sol::state lua;
x x1;
lua.set_function("x1copy", &x::func, x1);
lua.safe_script("x1copy()");
REQUIRE(created == 2);
REQUIRE(destroyed == 0);
REQUIRE_FALSE(last_call == &x1);
lua.set_function("x1ref", &x::func, std::ref(x1));
lua.safe_script("x1ref()");
REQUIRE(created == 2);
REQUIRE(destroyed == 0);
REQUIRE(last_call == &x1);
}
REQUIRE(created == 2);
REQUIRE(destroyed == 2);
}
// things convertible to a static function should _never_ be forced to make copies
// therefore, pass through untouched
{
created = 0;
destroyed = 0;
last_call = nullptr;
{
sol::state lua;
y y1;
lua.set_function("y1copy", y1);
lua.safe_script("y1copy()");
REQUIRE(created == 1);
REQUIRE(destroyed == 0);
REQUIRE(last_call == static_call);
last_call = nullptr;
lua.set_function("y1ref", std::ref(y1));
lua.safe_script("y1ref()");
REQUIRE(created == 1);
REQUIRE(destroyed == 0);
REQUIRE(last_call == static_call);
}
REQUIRE(created == 1);
REQUIRE(destroyed == 1);
}
}
TEST_CASE("gc/same type closures", "make sure destructions are per-object, not per-type, by destroying one type multiple times") {
static std::set<void*> last_my_closures;
static bool checking_closures = false;
static bool check_failed = false;
struct my_closure {
int& n;
my_closure(int& n) : n(n) {}
~my_closure() noexcept(false) {
if (!checking_closures)
return;
void* addr = static_cast<void*>(this);
auto f = last_my_closures.find(addr);
if (f != last_my_closures.cend()) {
check_failed = true;
}
last_my_closures.insert(f, addr);
}
int operator() () {
++n; return n;
}
};
int n = 250;
my_closure a(n);
my_closure b(n);
{
sol::state lua;
lua.set_function("f", a);
lua.set_function("g", b);
checking_closures = true;
}
REQUIRE_FALSE(check_failed);
REQUIRE(last_my_closures.size() == 2);
}
TEST_CASE("gc/usertypes", "show that proper copies / destruction happens for usertypes") {
static int created = 0;
static int destroyed = 0;
struct x {
x() { ++created; }
x(const x&) { ++created; }
x(x&&) { ++created; }
x& operator=(const x&) { return *this; }
x& operator=(x&&) { return *this; }
~x() { ++destroyed; }
};
SECTION("plain") {
created = 0;
destroyed = 0;
{
sol::state lua;
x x1;
x x2;
lua.set("x1copy", x1, "x2copy", x2, "x1ref", std::ref(x1));
x& x1copyref = lua["x1copy"];
x& x2copyref = lua["x2copy"];
x& x1ref = lua["x1ref"];
REQUIRE(created == 4);
REQUIRE(destroyed == 0);
REQUIRE(std::addressof(x1) == std::addressof(x1ref));
REQUIRE(std::addressof(x1copyref) != std::addressof(x1));
REQUIRE(std::addressof(x2copyref) != std::addressof(x2));
}
REQUIRE(created == 4);
REQUIRE(destroyed == 4);
}
SECTION("regular") {
created = 0;
destroyed = 0;
{
sol::state lua;
lua.new_usertype<x>("x");
x x1;
x x2;
lua.set("x1copy", x1, "x2copy", x2, "x1ref", std::ref(x1));
x& x1copyref = lua["x1copy"];
x& x2copyref = lua["x2copy"];
x& x1ref = lua["x1ref"];
REQUIRE(created == 4);
REQUIRE(destroyed == 0);
REQUIRE(std::addressof(x1) == std::addressof(x1ref));
REQUIRE(std::addressof(x1copyref) != std::addressof(x1));
REQUIRE(std::addressof(x2copyref) != std::addressof(x2));
}
REQUIRE(created == 4);
REQUIRE(destroyed == 4);
}
SECTION("simple") {
created = 0;
destroyed = 0;
{
sol::state lua;
lua.new_simple_usertype<x>("x");
x x1;
x x2;
lua.set("x1copy", x1, "x2copy", x2, "x1ref", std::ref(x1));
x& x1copyref = lua["x1copy"];
x& x2copyref = lua["x2copy"];
x& x1ref = lua["x1ref"];
REQUIRE(created == 4);
REQUIRE(destroyed == 0);
REQUIRE(std::addressof(x1) == std::addressof(x1ref));
REQUIRE(std::addressof(x1copyref) != std::addressof(x1));
REQUIRE(std::addressof(x2copyref) != std::addressof(x2));
}
REQUIRE(created == 4);
REQUIRE(destroyed == 4);
}
}
TEST_CASE("gc/double-deletion tests", "make sure usertypes are properly destructed and don't double-delete memory or segfault") {
class crash_class {
public:
crash_class() {}
~crash_class() { a = 10; }
private:
int a;
};
sol::state lua;
SECTION("regular") {
lua.new_usertype<crash_class>("CrashClass",
sol::call_constructor, sol::constructors<sol::types<>>()
);
lua.safe_script(R"(
function testCrash()
local x = CrashClass()
end
)");
for (int i = 0; i < 1000; ++i) {
lua["testCrash"]();
}
}
SECTION("simple") {
lua.new_simple_usertype<crash_class>("CrashClass",
sol::call_constructor, sol::constructors<sol::types<>>()
);
lua.safe_script(R"(
function testCrash()
local x = CrashClass()
end
)");
for (int i = 0; i < 1000; ++i) {
lua["testCrash"]();
}
}
}
TEST_CASE("gc/shared_ptr regression", "metatables should not screw over unique usertype metatables") {
static int created = 0;
static int destroyed = 0;
struct test {
test() {
++created;
}
~test() {
++destroyed;
}
};
SECTION("regular") {
created = 0;
destroyed = 0;
{
std::list<std::shared_ptr<test>> tests;
sol::state lua;
lua.open_libraries();
lua.new_usertype<test>("test",
"create", [&]() -> std::shared_ptr<test> {
tests.push_back(std::make_shared<test>());
return tests.back();
}
);
REQUIRE(created == 0);
REQUIRE(destroyed == 0);
lua.safe_script("x = test.create()");
REQUIRE(created == 1);
REQUIRE(destroyed == 0);
REQUIRE_FALSE(tests.empty());
std::shared_ptr<test>& x = lua["x"];
std::size_t xuse = x.use_count();
std::size_t tuse = tests.back().use_count();
REQUIRE(xuse == tuse);
}
REQUIRE(created == 1);
REQUIRE(destroyed == 1);
}
SECTION("simple") {
created = 0;
destroyed = 0;
{
std::list<std::shared_ptr<test>> tests;
sol::state lua;
lua.open_libraries();
lua.new_simple_usertype<test>("test",
"create", [&]() -> std::shared_ptr<test> {
tests.push_back(std::make_shared<test>());
return tests.back();
}
);
REQUIRE(created == 0);
REQUIRE(destroyed == 0);
lua.safe_script("x = test.create()");
REQUIRE(created == 1);
REQUIRE(destroyed == 0);
REQUIRE_FALSE(tests.empty());
std::shared_ptr<test>& x = lua["x"];
std::size_t xuse = x.use_count();
std::size_t tuse = tests.back().use_count();
REQUIRE(xuse == tuse);
}
REQUIRE(created == 1);
REQUIRE(destroyed == 1);
}
}
TEST_CASE("gc/double deleter guards", "usertype metatables internally must not rely on C++ state") {
SECTION("regular") {
struct c_a { int xv; };
struct c_b { int yv; };
auto routine = []() {
sol::state lua;
lua.new_usertype<c_a>("c_a", "x", &c_a::xv);
lua.new_usertype<c_b>("c_b", "y", &c_b::yv);
lua = sol::state();
lua.new_usertype<c_a>("c_a", "x", &c_a::xv);
lua.new_usertype<c_b>("c_b", "y", &c_b::yv);
lua = sol::state();
};
REQUIRE_NOTHROW(routine());
}
SECTION("simple") {
struct sc_a { int xv; };
struct sc_b { int yv; };
auto routine = []() {
sol::state lua;
lua.new_simple_usertype<sc_a>("c_a", "x", &sc_a::xv);
lua.new_simple_usertype<sc_b>("c_b", "y", &sc_b::yv);
lua = sol::state();
lua.new_simple_usertype<sc_a>("c_a", "x", &sc_a::xv);
lua.new_simple_usertype<sc_b>("c_b", "y", &sc_b::yv);
lua = sol::state();
};
REQUIRE_NOTHROW(routine());
}
}

View File

@ -42,14 +42,14 @@ TEST_CASE("inheritance/basic", "test that metatables are properly inherited") {
sol::base_classes, sol::bases<C, B, A>() sol::base_classes, sol::bases<C, B, A>()
); );
lua.script("obj = D.new()"); lua.safe_script("obj = D.new()");
lua.script("d = obj:d()"); lua.safe_script("d = obj:d()");
bool d = lua["d"]; bool d = lua["d"];
lua.script("c = obj.c"); lua.safe_script("c = obj.c");
double c = lua["c"]; double c = lua["c"];
lua.script("b = obj:b()"); lua.safe_script("b = obj:b()");
int b = lua["b"]; int b = lua["b"];
lua.script("a = obj.a"); lua.safe_script("a = obj.a");
int a = lua["a"]; int a = lua["a"];
REQUIRE(d); REQUIRE(d);
@ -124,19 +124,19 @@ TEST_CASE("inheritance/multi base", "test that multiple bases all work and overl
lua.set_usertype("TestClass03", s_TestUsertype03); lua.set_usertype("TestClass03", s_TestUsertype03);
lua.script(R"( lua.safe_script(R"(
tc0 = TestClass00() tc0 = TestClass00()
)"); )");
lua.script(R"( lua.safe_script(R"(
tc2 = TestClass02(tc0) tc2 = TestClass02(tc0)
)"); )");
lua.script(R"( lua.safe_script(R"(
tc1 = TestClass01() tc1 = TestClass01()
)"); )");
lua.script(R"( lua.safe_script(R"(
tc3 = TestClass03(tc1) tc3 = TestClass03(tc1)
)"); )");
@ -219,19 +219,19 @@ TEST_CASE("inheritance/simple multi base", "test that multiple bases all work an
lua.set_usertype("TestClass03", s_TestUsertype03); lua.set_usertype("TestClass03", s_TestUsertype03);
lua.script(R"( lua.safe_script(R"(
tc0 = TestClass00() tc0 = TestClass00()
)"); )");
lua.script(R"( lua.safe_script(R"(
tc2 = TestClass02(tc0) tc2 = TestClass02(tc0)
)"); )");
lua.script(R"( lua.safe_script(R"(
tc1 = TestClass01() tc1 = TestClass01()
)"); )");
lua.script(R"( lua.safe_script(R"(
tc3 = TestClass03(tc1) tc3 = TestClass03(tc1)
)"); )");

View File

@ -12,8 +12,8 @@ TEST_CASE("large_integer/bool", "pass bool integral value to and from lua") {
REQUIRE(num == true); REQUIRE(num == true);
return num; return num;
}); });
lua.script("x = f(true)"); lua.safe_script("x = f(true)");
lua.script("assert(x == true)"); lua.safe_script("assert(x == true)");
sol::object x = lua["x"]; sol::object x = lua["x"];
REQUIRE(x.is<bool>()); REQUIRE(x.is<bool>());
REQUIRE(x.as<bool>() == true); REQUIRE(x.as<bool>() == true);
@ -32,8 +32,8 @@ TEST_CASE("large_integers/unsigned32", "pass large unsigned 32bit values to and
REQUIRE(num == 0xFFFFFFFF); REQUIRE(num == 0xFFFFFFFF);
return num; return num;
}); });
lua.script("x = f(0xFFFFFFFF)"); lua.safe_script("x = f(0xFFFFFFFF)");
lua.script("assert(x == 0xFFFFFFFF)"); lua.safe_script("assert(x == 0xFFFFFFFF)");
sol::object x = lua["x"]; sol::object x = lua["x"];
REQUIRE(x.is<T>()); REQUIRE(x.is<T>());
REQUIRE(x.as<T>() == 0xFFFFFFFF); REQUIRE(x.as<T>() == 0xFFFFFFFF);
@ -47,8 +47,8 @@ TEST_CASE("large_integer/unsigned53", "pass large unsigned 53bit value to and fr
REQUIRE(num == 0x1FFFFFFFFFFFFFull); REQUIRE(num == 0x1FFFFFFFFFFFFFull);
return num; return num;
}); });
lua.script("x = f(0x1FFFFFFFFFFFFF)"); lua.safe_script("x = f(0x1FFFFFFFFFFFFF)");
lua.script("assert(x == 0x1FFFFFFFFFFFFF)"); lua.safe_script("assert(x == 0x1FFFFFFFFFFFFF)");
sol::object x = lua["x"]; sol::object x = lua["x"];
REQUIRE(x.is<T>()); REQUIRE(x.is<T>());
REQUIRE(x.as<T>() == 0x1FFFFFFFFFFFFFull); REQUIRE(x.as<T>() == 0x1FFFFFFFFFFFFFull);
@ -83,10 +83,10 @@ TEST_CASE("large_integer/double", "pass negative and large positive values as si
}); });
//signed 32bit //signed 32bit
REQUIRE_NOTHROW([&lua]() { REQUIRE_NOTHROW([&lua]() {
lua.script("x = s32(-1)"); lua.safe_script("x = s32(-1)");
lua.script("assert(x == -1)"); lua.safe_script("assert(x == -1)");
lua.script("x = s32(0xFFFFFFFF)"); lua.safe_script("x = s32(0xFFFFFFFF)");
lua.script("assert(x == -1)"); lua.safe_script("assert(x == -1)");
sol::object x = lua["x"]; sol::object x = lua["x"];
REQUIRE(x.is<std::int32_t>()); REQUIRE(x.is<std::int32_t>());
REQUIRE(x.as<std::int32_t>() == -1); REQUIRE(x.as<std::int32_t>() == -1);
@ -95,10 +95,10 @@ TEST_CASE("large_integer/double", "pass negative and large positive values as si
}()); }());
//unsigned 32bit //unsigned 32bit
REQUIRE_NOTHROW([&lua]() { REQUIRE_NOTHROW([&lua]() {
lua.script("x = u32(0xFFFFFFFF)"); lua.safe_script("x = u32(0xFFFFFFFF)");
lua.script("assert(x == 0xFFFFFFFF)"); lua.safe_script("assert(x == 0xFFFFFFFF)");
lua.script("x = u32(-1)"); lua.safe_script("x = u32(-1)");
lua.script("assert(x == 0xFFFFFFFF)"); lua.safe_script("assert(x == 0xFFFFFFFF)");
sol::object x = lua["x"]; sol::object x = lua["x"];
REQUIRE(x.is<std::int32_t>()); REQUIRE(x.is<std::int32_t>());
REQUIRE(x.as<std::int32_t>() == -1); REQUIRE(x.as<std::int32_t>() == -1);
@ -107,8 +107,8 @@ TEST_CASE("large_integer/double", "pass negative and large positive values as si
}()); }());
//signed 64bit //signed 64bit
REQUIRE_NOTHROW([&lua]() { REQUIRE_NOTHROW([&lua]() {
lua.script("x = s64(-1)"); lua.safe_script("x = s64(-1)");
lua.script("assert(x == -1)"); lua.safe_script("assert(x == -1)");
sol::object x = lua["x"]; sol::object x = lua["x"];
REQUIRE(x.is<std::int64_t>()); REQUIRE(x.is<std::int64_t>());
REQUIRE(x.as<std::int64_t>() == -1); REQUIRE(x.as<std::int64_t>() == -1);

View File

@ -47,6 +47,43 @@ TEST_CASE("operators/default", "test that generic equality operators and all sor
lua["v2"] = &v2; lua["v2"] = &v2;
lua["v3"] = &v3; lua["v3"] = &v3;
SECTION("plain") {
// Can only compare identity here
REQUIRE_NOTHROW([&] {
lua.safe_script("assert(t1 == t1)");
lua.safe_script("assert(t2 == t2)");
lua.safe_script("assert(t3 == t3)");
}());
REQUIRE_NOTHROW([&] {
lua.safe_script("assert(t1 == t2)");
lua.safe_script("assert(not (t1 == t3))");
lua.safe_script("assert(not (t2 == t3))");
}());
// Object should compare equal to themselves
// (and not invoke operator==; pointer test should be sufficient)
REQUIRE_NOTHROW([&] {
lua.safe_script("assert(u1 == u1)");
lua.safe_script("assert(u2 == u2)");
lua.safe_script("assert(u3 == u3)");
}());
REQUIRE_NOTHROW([&] {
lua.safe_script("assert(not (u1 == u2))");
lua.safe_script("assert(u1 == u3)");
lua.safe_script("assert(not (u2 == u3))");
}());
// Object should compare equal to themselves
// (and not invoke operator==; pointer test should be sufficient)
REQUIRE_NOTHROW([&] {
lua.safe_script("assert(v1 == v1)");
lua.safe_script("assert(v2 == v2)");
lua.safe_script("assert(v3 == v3)");
}());
REQUIRE_NOTHROW([&] {
lua.safe_script("assert(not (v1 == v2))");
lua.safe_script("assert(v1 == v3)");
lua.safe_script("assert(not (v2 == v3))");
}());
}
SECTION("regular") { SECTION("regular") {
lua.new_usertype<T>("T"); lua.new_usertype<T>("T");
lua.new_usertype<U>("U"); lua.new_usertype<U>("U");
@ -54,38 +91,38 @@ TEST_CASE("operators/default", "test that generic equality operators and all sor
// Can only compare identity here // Can only compare identity here
REQUIRE_NOTHROW([&] { REQUIRE_NOTHROW([&] {
lua.script("assert(t1 == t1)"); lua.safe_script("assert(t1 == t1)");
lua.script("assert(t2 == t2)"); lua.safe_script("assert(t2 == t2)");
lua.script("assert(t3 == t3)"); lua.safe_script("assert(t3 == t3)");
}()); }());
REQUIRE_NOTHROW([&] { REQUIRE_NOTHROW([&] {
lua.script("assert(t1 == t2)"); lua.safe_script("assert(t1 == t2)");
lua.script("assert(not (t1 == t3))"); lua.safe_script("assert(not (t1 == t3))");
lua.script("assert(not (t2 == t3))"); lua.safe_script("assert(not (t2 == t3))");
}()); }());
// Object should compare equal to themselves // Object should compare equal to themselves
// (and not invoke operator==; pointer test should be sufficient) // (and not invoke operator==; pointer test should be sufficient)
REQUIRE_NOTHROW([&] { REQUIRE_NOTHROW([&] {
lua.script("assert(u1 == u1)"); lua.safe_script("assert(u1 == u1)");
lua.script("assert(u2 == u2)"); lua.safe_script("assert(u2 == u2)");
lua.script("assert(u3 == u3)"); lua.safe_script("assert(u3 == u3)");
}()); }());
REQUIRE_NOTHROW([&] { REQUIRE_NOTHROW([&] {
lua.script("assert(not (u1 == u2))"); lua.safe_script("assert(not (u1 == u2))");
lua.script("assert(u1 == u3)"); lua.safe_script("assert(u1 == u3)");
lua.script("assert(not (u2 == u3))"); lua.safe_script("assert(not (u2 == u3))");
}()); }());
// Object should compare equal to themselves // Object should compare equal to themselves
// (and not invoke operator==; pointer test should be sufficient) // (and not invoke operator==; pointer test should be sufficient)
REQUIRE_NOTHROW([&] { REQUIRE_NOTHROW([&] {
lua.script("assert(v1 == v1)"); lua.safe_script("assert(v1 == v1)");
lua.script("assert(v2 == v2)"); lua.safe_script("assert(v2 == v2)");
lua.script("assert(v3 == v3)"); lua.safe_script("assert(v3 == v3)");
}()); }());
REQUIRE_NOTHROW([&] { REQUIRE_NOTHROW([&] {
lua.script("assert(not (v1 == v2))"); lua.safe_script("assert(not (v1 == v2))");
lua.script("assert(v1 == v3)"); lua.safe_script("assert(v1 == v3)");
lua.script("assert(not (v2 == v3))"); lua.safe_script("assert(not (v2 == v3))");
}()); }());
} }
SECTION("simple") { SECTION("simple") {
@ -95,38 +132,38 @@ TEST_CASE("operators/default", "test that generic equality operators and all sor
// Can only compare identity here // Can only compare identity here
REQUIRE_NOTHROW([&] { REQUIRE_NOTHROW([&] {
lua.script("assert(t1 == t1)"); lua.safe_script("assert(t1 == t1)");
lua.script("assert(t2 == t2)"); lua.safe_script("assert(t2 == t2)");
lua.script("assert(t3 == t3)"); lua.safe_script("assert(t3 == t3)");
}()); }());
REQUIRE_NOTHROW([&] { REQUIRE_NOTHROW([&] {
lua.script("assert(t1 == t2)"); lua.safe_script("assert(t1 == t2)");
lua.script("assert(not (t1 == t3))"); lua.safe_script("assert(not (t1 == t3))");
lua.script("assert(not (t2 == t3))"); lua.safe_script("assert(not (t2 == t3))");
}()); }());
// Object should compare equal to themselves // Object should compare equal to themselves
// (and not invoke operator==; pointer test should be sufficient) // (and not invoke operator==; pointer test should be sufficient)
REQUIRE_NOTHROW([&] { REQUIRE_NOTHROW([&] {
lua.script("assert(u1 == u1)"); lua.safe_script("assert(u1 == u1)");
lua.script("assert(u2 == u2)"); lua.safe_script("assert(u2 == u2)");
lua.script("assert(u3 == u3)"); lua.safe_script("assert(u3 == u3)");
}()); }());
REQUIRE_NOTHROW([&] { REQUIRE_NOTHROW([&] {
lua.script("assert(not (u1 == u2))"); lua.safe_script("assert(not (u1 == u2))");
lua.script("assert(u1 == u3)"); lua.safe_script("assert(u1 == u3)");
lua.script("assert(not (u2 == u3))"); lua.safe_script("assert(not (u2 == u3))");
}()); }());
// Object should compare equal to themselves // Object should compare equal to themselves
// (and not invoke operator==; pointer test should be sufficient) // (and not invoke operator==; pointer test should be sufficient)
REQUIRE_NOTHROW([&] { REQUIRE_NOTHROW([&] {
lua.script("assert(v1 == v1)"); lua.safe_script("assert(v1 == v1)");
lua.script("assert(v2 == v2)"); lua.safe_script("assert(v2 == v2)");
lua.script("assert(v3 == v3)"); lua.safe_script("assert(v3 == v3)");
}()); }());
REQUIRE_NOTHROW([&] { REQUIRE_NOTHROW([&] {
lua.script("assert(not (v1 == v2))"); lua.safe_script("assert(not (v1 == v2))");
lua.script("assert(v1 == v3)"); lua.safe_script("assert(v1 == v3)");
lua.script("assert(not (v2 == v3))"); lua.safe_script("assert(not (v2 == v3))");
}()); }());
} }
} }
@ -134,13 +171,21 @@ TEST_CASE("operators/default", "test that generic equality operators and all sor
TEST_CASE("operators/call", "test call operator generation") { TEST_CASE("operators/call", "test call operator generation") {
struct callable { struct callable {
int operator ()(int a, std::string b) { int operator ()(int a, std::string b) {
return a + b.length(); return a + static_cast<int>(b.length());
} }
}; };
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
SECTION("plain") {
{
lua.set("obj", callable());
lua.safe_script("v = obj(2, 'bark woof')");
int v = lua["v"];
REQUIRE(v == 11);
}
}
SECTION("regular") { SECTION("regular") {
lua.new_usertype<callable>("callable"); lua.new_usertype<callable>("callable");
{ {
@ -168,13 +213,53 @@ const void* stringable::last_print_ptr = nullptr;
std::ostream& operator<< (std::ostream& ostr, const stringable& o) { std::ostream& operator<< (std::ostream& ostr, const stringable& o) {
stringable::last_print_ptr = static_cast<const void*>(&o); stringable::last_print_ptr = static_cast<const void*>(&o);
return ostr << " { stringable! }"; return ostr << "{ stringable, std::ostream! }";
} }
struct adl_stringable {
static const void* last_print_ptr;
};
const void* adl_stringable::last_print_ptr = nullptr;
std::string to_string(const adl_stringable& o) {
adl_stringable::last_print_ptr = static_cast<const void*>(&o);
return "{ adl_stringable, to_string! }";
}
namespace inside {
struct adl_stringable2 {
static const void* last_print_ptr;
};
const void* adl_stringable2::last_print_ptr = nullptr;
std::string to_string(const adl_stringable2& o) {
adl_stringable2::last_print_ptr = static_cast<const void*>(&o);
return "{ inside::adl_stringable2, inside::to_string! }";
}
}
struct member_stringable {
static const void* last_print_ptr;
std::string to_string() const {
member_stringable::last_print_ptr = static_cast<const void*>(this);
return "{ member_stringable, to_string! }";
}
};
const void* member_stringable::last_print_ptr = nullptr;
TEST_CASE("operators/stringable", "test std::ostream stringability") { TEST_CASE("operators/stringable", "test std::ostream stringability") {
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
SECTION("plain") {
{
lua["obj"] = stringable();
lua.safe_script("print(obj)");
stringable& obj = lua["obj"];
REQUIRE(stringable::last_print_ptr == &obj);
}
}
SECTION("regular") { SECTION("regular") {
lua.new_usertype<stringable>("stringable"); lua.new_usertype<stringable>("stringable");
{ {
@ -195,6 +280,102 @@ TEST_CASE("operators/stringable", "test std::ostream stringability") {
} }
} }
TEST_CASE("operators/adl_stringable", "test adl to_string stringability") {
sol::state lua;
lua.open_libraries(sol::lib::base);
SECTION("plain") {
{
lua["obj"] = adl_stringable();
lua.safe_script("print(obj)");
adl_stringable& obj = lua["obj"];
REQUIRE(adl_stringable::last_print_ptr == &obj);
}
}
SECTION("regular") {
lua.new_usertype<adl_stringable>("stringable");
{
lua["obj"] = adl_stringable();
lua.safe_script("print(obj)");
adl_stringable& obj = lua["obj"];
REQUIRE(adl_stringable::last_print_ptr == &obj);
}
}
SECTION("simple") {
lua.new_simple_usertype<adl_stringable>("stringable");
{
lua.safe_script("obj = stringable.new()");
lua.safe_script("print(obj)");
adl_stringable& obj = lua["obj"];
REQUIRE(adl_stringable::last_print_ptr == &obj);
}
}
}
TEST_CASE("operators/inside::adl_stringable2", "test adl to_string stringability from inside a namespace") {
sol::state lua;
lua.open_libraries(sol::lib::base);
SECTION("plain") {
{
lua["obj"] = inside::adl_stringable2();
lua.safe_script("print(obj)");
inside::adl_stringable2& obj = lua["obj"];
REQUIRE(inside::adl_stringable2::last_print_ptr == &obj);
}
}
SECTION("regular") {
lua.new_usertype<inside::adl_stringable2>("stringable");
{
lua.safe_script("obj = stringable.new()");
lua.safe_script("print(obj)");
inside::adl_stringable2& obj = lua["obj"];
REQUIRE(inside::adl_stringable2::last_print_ptr == &obj);
}
}
SECTION("simple") {
lua.new_simple_usertype<inside::adl_stringable2>("stringable");
{
lua.safe_script("obj = stringable.new()");
lua.safe_script("print(obj)");
inside::adl_stringable2& obj = lua["obj"];
REQUIRE(inside::adl_stringable2::last_print_ptr == &obj);
}
}
}
TEST_CASE("operators/member_stringable", "test member to_string stringability") {
sol::state lua;
lua.open_libraries(sol::lib::base);
SECTION("plain") {
{
lua["obj"] = member_stringable();
lua.safe_script("print(obj)");
member_stringable& obj = lua["obj"];
REQUIRE(member_stringable::last_print_ptr == &obj);
}
}
SECTION("regular") {
lua.new_usertype<member_stringable>("stringable");
{
lua.safe_script("obj = stringable.new()");
lua.safe_script("print(obj)");
member_stringable& obj = lua["obj"];
REQUIRE(member_stringable::last_print_ptr == &obj);
}
}
SECTION("simple") {
lua.new_simple_usertype<member_stringable>("stringable");
{
lua.safe_script("obj = stringable.new()");
lua.safe_script("print(obj)");
member_stringable& obj = lua["obj"];
REQUIRE(member_stringable::last_print_ptr == &obj);
}
}
}
TEST_CASE("operators/container-like", "test that generic begin/end and iterator are automatically bound") { TEST_CASE("operators/container-like", "test that generic begin/end and iterator are automatically bound") {
#if SOL_LUA_VERSION > 501 #if SOL_LUA_VERSION > 501
struct container { struct container {
@ -219,6 +400,14 @@ TEST_CASE("operators/container-like", "test that generic begin/end and iterator
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
SECTION("plain") {
{
lua["obj"] = container();
lua.safe_script("i = 0 for k, v in pairs(obj) do i = i + 1 assert(k == v) end");
std::size_t i = lua["i"];
REQUIRE(i == 10);
}
}
SECTION("regular") { SECTION("regular") {
lua.new_usertype<container>("container"); lua.new_usertype<container>("container");
{ {
@ -252,6 +441,14 @@ TEST_CASE("operators/length", "test that size is automatically bound to the leng
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
SECTION("plain") {
{
lua["obj"] = sizable();
lua.safe_script("s = #obj");
std::size_t s = lua["s"];
REQUIRE(s == 6);
}
}
SECTION("regular") { SECTION("regular") {
lua.new_usertype<sizable>("sizable"); lua.new_usertype<sizable>("sizable");
{ {

View File

@ -6,8 +6,8 @@
TEST_CASE("issues/stack overflow", "make sure various operations repeated don't trigger stack overflow") { TEST_CASE("issues/stack overflow", "make sure various operations repeated don't trigger stack overflow") {
sol::state lua; sol::state lua;
lua.script("t = {};t[0]=20"); lua.safe_script("t = {};t[0]=20");
lua.script("lua_function=function(i)return i;end"); lua.safe_script("lua_function=function(i)return i;end");
sol::function f = lua["lua_function"]; sol::function f = lua["lua_function"];
std::string teststring = "testtext"; std::string teststring = "testtext";

72
test_plain_types.cpp Normal file
View File

@ -0,0 +1,72 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <catch.hpp>
TEST_CASE("plain/alignment", "test that aligned classes in certain compilers don't trigger compiler errors") {
#ifdef _MSC_VER
__declspec(align(16)) class aligned_class {
int var;
};
class A {
aligned_class a;
};
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::math);
lua.new_usertype<A>("A");
A a;
lua["a"] = &a;
A& la = lua["a"];
REQUIRE(&a == &la);
#else
REQUIRE(true);
#endif // VC++ stuff
}
TEST_CASE("plain/indestructible", "test that we error for types that are innately indestructible") {
struct indestructible {
public:
int v = 20;
struct insider {
void operator()(indestructible* i) const {
i->~indestructible();
}
};
private:
~indestructible() {
}
};
SECTION("doomed") {
sol::state lua;
lua.open_libraries(sol::lib::base);
std::unique_ptr<indestructible, indestructible::insider> i = sol::detail::make_unique_deleter<indestructible, indestructible::insider>();
lua["i"] = *i;
lua.safe_script("i = nil");
auto result = lua.safe_script("collectgarbage()", sol::script_pass_on_error);
REQUIRE_FALSE(result.valid());
}
SECTION("saved") {
sol::state lua;
lua.open_libraries(sol::lib::base);
std::unique_ptr<indestructible, indestructible::insider> i = sol::detail::make_unique_deleter<indestructible, indestructible::insider>();
lua["i"] = *i;
lua.new_usertype<indestructible>("indestructible",
sol::default_constructor,
sol::meta_function::garbage_collect, sol::destructor([](indestructible& i) {
indestructible::insider del;
del(&i);
})
);
lua.safe_script("i = nil");
auto result = lua.safe_script("collectgarbage()", sol::script_pass_on_error);
REQUIRE(result.valid());
}
}

View File

@ -49,20 +49,20 @@ TEST_CASE("simple_usertype/usertypes", "Ensure that simple usertypes properly wo
"z", sol::overload(&bark::get, &bark::set) "z", sol::overload(&bark::get, &bark::set)
); );
lua.script("b = bark.new()"); lua.safe_script("b = bark.new()");
bark& b = lua["b"]; bark& b = lua["b"];
lua.script("b:fun()"); lua.safe_script("b:fun()");
int var = b.var; int var = b.var;
REQUIRE(var == 51); REQUIRE(var == 51);
lua.script("b:var(20)"); lua.safe_script("b:var(20)");
lua.script("v = b:var()"); lua.safe_script("v = b:var()");
int v = lua["v"]; int v = lua["v"];
REQUIRE(v == 20); REQUIRE(v == 20);
REQUIRE(b.var == 20); REQUIRE(b.var == 20);
lua.script("m = b:the_marker()"); lua.safe_script("m = b:the_marker()");
marker& m = lua["m"]; marker& m = lua["m"];
REQUIRE_FALSE(b.mark.value); REQUIRE_FALSE(b.mark.value);
REQUIRE_FALSE(m.value); REQUIRE_FALSE(m.value);
@ -73,16 +73,16 @@ TEST_CASE("simple_usertype/usertypes", "Ensure that simple usertypes properly wo
sol::table barktable = lua["bark"]; sol::table barktable = lua["bark"];
barktable["special"] = &bark::special; barktable["special"] = &bark::special;
lua.script("s = b:special()"); lua.safe_script("s = b:special()");
std::string s = lua["s"]; std::string s = lua["s"];
REQUIRE(s == "woof"); REQUIRE(s == "woof");
lua.script("b:y(24)"); lua.safe_script("b:y(24)");
lua.script("x = b:x()"); lua.safe_script("x = b:x()");
int x = lua["x"]; int x = lua["x"];
REQUIRE(x == 24); REQUIRE(x == 24);
lua.script("z = b:z(b:z() + 5)"); lua.safe_script("z = b:z(b:z() + 5)");
int z = lua["z"]; int z = lua["z"];
REQUIRE(z == 29); REQUIRE(z == 29);
} }
@ -132,23 +132,23 @@ TEST_CASE("simple_usertype/usertype constructors", "Ensure that calls with speci
"z", sol::overload(&bark::get, &bark::set) "z", sol::overload(&bark::get, &bark::set)
); );
lua.script("bx = bark.new(760)"); lua.safe_script("bx = bark.new(760)");
bark& bx = lua["bx"]; bark& bx = lua["bx"];
REQUIRE(bx.var == 760); REQUIRE(bx.var == 760);
lua.script("b = bark.new()"); lua.safe_script("b = bark.new()");
bark& b = lua["b"]; bark& b = lua["b"];
lua.script("b:fun()"); lua.safe_script("b:fun()");
int var = b.var; int var = b.var;
REQUIRE(var == 51); REQUIRE(var == 51);
lua.script("b:var(20)"); lua.safe_script("b:var(20)");
lua.script("v = b:var()"); lua.safe_script("v = b:var()");
int v = lua["v"]; int v = lua["v"];
REQUIRE(v == 20); REQUIRE(v == 20);
lua.script("m = b:the_marker()"); lua.safe_script("m = b:the_marker()");
marker& m = lua["m"]; marker& m = lua["m"];
REQUIRE_FALSE(b.mark.value); REQUIRE_FALSE(b.mark.value);
REQUIRE_FALSE(m.value); REQUIRE_FALSE(m.value);
@ -159,58 +159,20 @@ TEST_CASE("simple_usertype/usertype constructors", "Ensure that calls with speci
sol::table barktable = lua["bark"]; sol::table barktable = lua["bark"];
barktable["special"] = &bark::special; barktable["special"] = &bark::special;
lua.script("s = b:special()"); lua.safe_script("s = b:special()");
std::string s = lua["s"]; std::string s = lua["s"];
REQUIRE(s == "woof"); REQUIRE(s == "woof");
lua.script("b:y(24)"); lua.safe_script("b:y(24)");
lua.script("x = b:x()"); lua.safe_script("x = b:x()");
int x = lua["x"]; int x = lua["x"];
REQUIRE(x == 24); REQUIRE(x == 24);
lua.script("z = b:z(b:z() + 5)"); lua.safe_script("z = b:z(b:z() + 5)");
int z = lua["z"]; int z = lua["z"];
REQUIRE(z == 29); REQUIRE(z == 29);
} }
TEST_CASE("simple_usertype/shared_ptr regression", "simple usertype metatables should not screw over unique usertype metatables") {
static int created = 0;
static int destroyed = 0;
struct test {
test() {
++created;
}
~test() {
++destroyed;
}
};
{
std::list<std::shared_ptr<test>> tests;
sol::state lua;
lua.open_libraries();
lua.new_simple_usertype<test>("test",
"create", [&]() -> std::shared_ptr<test> {
tests.push_back(std::make_shared<test>());
return tests.back();
}
);
REQUIRE(created == 0);
REQUIRE(destroyed == 0);
lua.script("x = test.create()");
REQUIRE(created == 1);
REQUIRE(destroyed == 0);
REQUIRE_FALSE(tests.empty());
std::shared_ptr<test>& x = lua["x"];
std::size_t xuse = x.use_count();
std::size_t tuse = tests.back().use_count();
REQUIRE(xuse == tuse);
}
REQUIRE(created == 1);
REQUIRE(destroyed == 1);
}
TEST_CASE("simple_usertype/vars", "simple usertype vars can bind various values (no ref)") { TEST_CASE("simple_usertype/vars", "simple usertype vars can bind various values (no ref)") {
int muh_variable = 10; int muh_variable = 10;
int through_variable = 25; int through_variable = 25;
@ -228,7 +190,7 @@ TEST_CASE("simple_usertype/vars", "simple usertype vars can bind various values
through_variable = 20; through_variable = 20;
lua.script(R"( lua.safe_script(R"(
print(test.straight) print(test.straight)
s = test.straight s = test.straight
print(test.global) print(test.global)
@ -297,29 +259,29 @@ TEST_CASE("simple_usertype/variable-control", "test to see if usertypes respond
B b; B b;
lua.set("b", &b); lua.set("b", &b);
lua.script("b:a()"); lua.safe_script("b:a()");
sB sb; sB sb;
lua.set("sb", &sb); lua.set("sb", &sb);
lua.script("sb:a()"); lua.safe_script("sb:a()");
sV sv; sV sv;
lua.set("sv", &sv); lua.set("sv", &sv);
lua.script("print(sv.b)assert(sv.b == 20)"); lua.safe_script("print(sv.b)assert(sv.b == 20)");
sW sw; sW sw;
lua.set("sw", &sw); lua.set("sw", &sw);
lua.script("print(sw.a)assert(sw.a == 10)"); lua.safe_script("print(sw.a)assert(sw.a == 10)");
lua.script("print(sw.b)assert(sw.b == 20)"); lua.safe_script("print(sw.b)assert(sw.b == 20)");
lua.script("print(sw.pb)assert(sw.pb == 22)"); lua.safe_script("print(sw.pb)assert(sw.pb == 22)");
lua.script("sw.a = 11"); lua.safe_script("sw.a = 11");
lua.script("sw.b = 21"); lua.safe_script("sw.b = 21");
lua.script("print(sw.a)assert(sw.a == 11)"); lua.safe_script("print(sw.a)assert(sw.a == 11)");
lua.script("print(sw.b)assert(sw.b == 21)"); lua.safe_script("print(sw.b)assert(sw.b == 21)");
lua.script("print(sw.pb)assert(sw.pb == 23)"); lua.safe_script("print(sw.pb)assert(sw.pb == 23)");
lua.script("sw.pb = 25"); lua.safe_script("sw.pb = 25");
lua.script("print(sw.b)assert(sw.b == 25)"); lua.safe_script("print(sw.b)assert(sw.b == 25)");
lua.script("print(sw.pb)assert(sw.pb == 27)"); lua.safe_script("print(sw.pb)assert(sw.pb == 27)");
} }
TEST_CASE("simple_usertype/factory constructor overloads", "simple usertypes should invoke the proper factories") { TEST_CASE("simple_usertype/factory constructor overloads", "simple usertypes should invoke the proper factories") {
@ -340,21 +302,30 @@ TEST_CASE("simple_usertype/factory constructor overloads", "simple usertypes sho
sol::constructors<sol::types<>, sol::types<const B&>> c; sol::constructors<sol::types<>, sol::types<const B&>> c;
lua.new_simple_usertype<B>("B", lua.new_simple_usertype<B>("B",
sol::call_constructor, c, sol::call_constructor, c,
"new", sol::factories([]() { return B(); }), "new", sol::factories([]() {
"new2", sol::initializers([](B& mem) { new(&mem)B(); }, [](B& mem, int v) { new(&mem)B(); mem.bvar = v; }), return B();
}),
"new2", sol::initializers(
[](B& mem) {
new(&mem)B();
},
[](B& mem, int v) {
new(&mem)B(); mem.bvar = v;
}
),
"f", sol::as_function(&B::bvar), "f", sol::as_function(&B::bvar),
"g", sol::overload([](B&) { return 2; }, [](B&, int v) { return v; }) "g", sol::overload([](B&) { return 2; }, [](B&, int v) { return v; })
); );
lua.script("b = B()"); lua.safe_script("b = B()");
lua.script("b2 = B.new()"); lua.safe_script("b2 = B.new()");
lua.script("b3 = B.new2()"); lua.safe_script("b3 = B.new2()");
lua.script("b4 = B.new2(11)"); lua.safe_script("b4 = B.new2(11)");
lua.script("x = b:f()"); lua.safe_script("x = b:f()");
lua.script("x2 = b2:f()"); lua.safe_script("x2 = b2:f()");
lua.script("x3 = b3:f()"); lua.safe_script("x3 = b3:f()");
lua.script("x4 = b4:f()"); lua.safe_script("x4 = b4:f()");
int x = lua["x"]; int x = lua["x"];
int x2 = lua["x2"]; int x2 = lua["x2"];
int x3 = lua["x3"]; int x3 = lua["x3"];
@ -364,10 +335,10 @@ TEST_CASE("simple_usertype/factory constructor overloads", "simple usertypes sho
REQUIRE(x3 == 24); REQUIRE(x3 == 24);
REQUIRE(x4 == 11); REQUIRE(x4 == 11);
lua.script("y = b:g()"); lua.safe_script("y = b:g()");
lua.script("y2 = b2:g(3)"); lua.safe_script("y2 = b2:g(3)");
lua.script("y3 = b3:g()"); lua.safe_script("y3 = b3:g()");
lua.script("y4 = b4:g(3)"); lua.safe_script("y4 = b4:g(3)");
int y = lua["y"]; int y = lua["y"];
int y2 = lua["y2"]; int y2 = lua["y2"];
int y3 = lua["y3"]; int y3 = lua["y3"];
@ -391,53 +362,22 @@ TEST_CASE("simple_usertype/runtime append", "allow extra functions to be appende
lua.set("b", std::make_unique<B>()); lua.set("b", std::make_unique<B>());
lua["A"]["method"] = []() { return 200; }; lua["A"]["method"] = []() { return 200; };
lua["B"]["method2"] = [](B&) { return 100; }; lua["B"]["method2"] = [](B&) { return 100; };
lua.script("x = b.method()"); lua.safe_script("x = b.method()");
lua.script("y = b:method()"); lua.safe_script("y = b:method()");
int x = lua["x"]; int x = lua["x"];
int y = lua["y"]; int y = lua["y"];
REQUIRE(x == 200); REQUIRE(x == 200);
REQUIRE(y == 200); REQUIRE(y == 200);
lua.script("z = b.method2(b)"); lua.safe_script("z = b.method2(b)");
lua.script("w = b:method2()"); lua.safe_script("w = b:method2()");
int z = lua["z"]; int z = lua["z"];
int w = lua["w"]; int w = lua["w"];
REQUIRE(z == 100); REQUIRE(z == 100);
REQUIRE(w == 100); REQUIRE(w == 100);
} }
TEST_CASE("simple_usertype/destruction test", "make sure usertypes are properly destructed and don't double-delete memory or segfault") {
sol::state lua;
class CrashClass {
public:
CrashClass() {
}
~CrashClass() {
a = 10; // This will cause a crash.
}
private:
int a;
};
lua.new_simple_usertype<CrashClass>("CrashClass",
sol::call_constructor, sol::constructors<sol::types<>>()
);
lua.script(R"(
function testCrash()
local x = CrashClass()
end
)");
for (int i = 0; i < 1000; ++i) {
lua["testCrash"]();
}
}
TEST_CASE("simple_usertype/table append", "Ensure that appending to the meta table also affects the internal function table for pointers as well") { TEST_CASE("simple_usertype/table append", "Ensure that appending to the meta table also affects the internal function table for pointers as well") {
struct A { struct A {
int func() { int func() {
@ -456,9 +396,9 @@ TEST_CASE("simple_usertype/table append", "Ensure that appending to the meta tab
lua.set("pa", &a); lua.set("pa", &a);
lua.set("ua", std::make_unique<A>()); lua.set("ua", std::make_unique<A>());
REQUIRE_NOTHROW([&]{ REQUIRE_NOTHROW([&]{
lua.script("assert(a:func() == 5000)"); lua.safe_script("assert(a:func() == 5000)");
lua.script("assert(pa:func() == 5000)"); lua.safe_script("assert(pa:func() == 5000)");
lua.script("assert(ua:func() == 5000)"); lua.safe_script("assert(ua:func() == 5000)");
}()); }());
} }
@ -481,7 +421,7 @@ TEST_CASE("simple_usertype/class call propogation", "make sure methods and varia
"var", &B::var "var", &B::var
); );
lua.script(R"( lua.safe_script(R"(
b = B.new() b = B.new()
print(b.var) print(b.var)
b:thing() b:thing()
@ -526,10 +466,10 @@ TEST_CASE("simple_usertype/call constructor", "ensure that all kinds of call-bas
} }
); );
lua.script("a = f_test()"); lua.safe_script("a = f_test()");
lua.script("b = i_test()"); lua.safe_script("b = i_test()");
lua.script("c = r_test()"); lua.safe_script("c = r_test()");
lua.script("d = f_test.new()"); lua.safe_script("d = f_test.new()");
f_test& a = lua["a"]; f_test& a = lua["a"];
f_test& d = lua["d"]; f_test& d = lua["d"];
i_test& b = lua["b"]; i_test& b = lua["b"];
@ -555,13 +495,13 @@ TEST_CASE("simple_usertype/call constructor", "ensure that all kinds of call-bas
); );
lua.new_simple_usertype<thing>("thing"); lua.new_simple_usertype<thing>("thing");
lua.script("things = {thing.new(), thing.new()}"); lua.safe_script("things = {thing.new(), thing.new()}");
SECTION("new") { SECTION("new") {
REQUIRE_NOTHROW(lua.script("a = v_test.new(things)")); REQUIRE_NOTHROW(lua.safe_script("a = v_test.new(things)"));
} }
SECTION("call_constructor") { SECTION("call_constructor") {
REQUIRE_NOTHROW(lua.script("b = v_test(things)")); REQUIRE_NOTHROW(lua.safe_script("b = v_test(things)"));
} }
} }
@ -598,7 +538,7 @@ TEST_CASE("simple_usertype/missing key", "make sure a missing key returns nil")
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.new_simple_usertype<thing>("thing"); lua.new_simple_usertype<thing>("thing");
REQUIRE_NOTHROW(lua.script("print(thing.missingKey)")); REQUIRE_NOTHROW(lua.safe_script("print(thing.missingKey)"));
} }
TEST_CASE("simple_usertype/runtime extensibility", "Check if usertypes are runtime extensible") { TEST_CASE("simple_usertype/runtime extensibility", "Check if usertypes are runtime extensible") {
@ -616,7 +556,7 @@ TEST_CASE("simple_usertype/runtime extensibility", "Check if usertypes are runti
"func", &thing::func "func", &thing::func
); );
lua.script(R"( lua.safe_script(R"(
t = thing.new() t = thing.new()
)"); )");
@ -638,19 +578,19 @@ end
REQUIRE_FALSE(result.valid()); REQUIRE_FALSE(result.valid());
} }
lua.script("val = t:func(2)"); lua.safe_script("val = t:func(2)");
val = lua["val"]; val = lua["val"];
REQUIRE(val == 2); REQUIRE(val == 2);
REQUIRE_NOTHROW([&lua]() { REQUIRE_NOTHROW([&lua]() {
lua.script(R"( lua.safe_script(R"(
function thing:runtime_func(a) function thing:runtime_func(a)
return a + 1 return a + 1
end end
)"); )");
}()); }());
lua.script("val = t:runtime_func(2)"); lua.safe_script("val = t:runtime_func(2)");
val = lua["val"]; val = lua["val"];
REQUIRE(val == 3); REQUIRE(val == 3);
} }
@ -663,7 +603,7 @@ end
"v", &thing::v "v", &thing::v
); );
lua.script(R"( lua.safe_script(R"(
t = thing.new() t = thing.new()
)"); )");
@ -685,19 +625,19 @@ end
REQUIRE_FALSE(result.valid()); REQUIRE_FALSE(result.valid());
}()); }());
lua.script("val = t:func(2)"); lua.safe_script("val = t:func(2)");
val = lua["val"]; val = lua["val"];
REQUIRE(val == 2); REQUIRE(val == 2);
REQUIRE_NOTHROW([&lua]() { REQUIRE_NOTHROW([&lua]() {
lua.script(R"( lua.safe_script(R"(
function thing:runtime_func(a) function thing:runtime_func(a)
return a + 1 return a + 1
end end
)"); )");
}()); }());
lua.script("val = t:runtime_func(2)"); lua.safe_script("val = t:runtime_func(2)");
val = lua["val"]; val = lua["val"];
REQUIRE(val == 3); REQUIRE(val == 3);
} }
@ -715,13 +655,13 @@ TEST_CASE("simple_usertype/runtime replacement", "ensure that functions can be p
lua.new_simple_usertype<heart_t>("a"); lua.new_simple_usertype<heart_t>("a");
REQUIRE_NOTHROW([&lua]() { REQUIRE_NOTHROW([&lua]() {
lua.script("obj = a.new()"); lua.safe_script("obj = a.new()");
lua.script("function a:heartbeat () print('arf') return 1 end"); lua.safe_script("function a:heartbeat () print('arf') return 1 end");
lua.script("v1 = obj:heartbeat()"); lua.safe_script("v1 = obj:heartbeat()");
lua.script("function a:heartbeat () print('bark') return 2 end"); lua.safe_script("function a:heartbeat () print('bark') return 2 end");
lua.script("v2 = obj:heartbeat()"); lua.safe_script("v2 = obj:heartbeat()");
lua.script("a.heartbeat = function(self) print('woof') return 3 end"); lua.safe_script("a.heartbeat = function(self) print('woof') return 3 end");
lua.script("v3 = obj:heartbeat()"); lua.safe_script("v3 = obj:heartbeat()");
}()); }());
int v1 = lua["v1"]; int v1 = lua["v1"];
int v2 = lua["v2"]; int v2 = lua["v2"];
@ -739,13 +679,13 @@ TEST_CASE("simple_usertype/runtime replacement", "ensure that functions can be p
); );
REQUIRE_NOTHROW([&lua]() { REQUIRE_NOTHROW([&lua]() {
lua.script("obj = a.new()"); lua.safe_script("obj = a.new()");
lua.script("function a:heartbeat () print('arf') return 1 end"); lua.safe_script("function a:heartbeat () print('arf') return 1 end");
lua.script("v1 = obj:heartbeat()"); lua.safe_script("v1 = obj:heartbeat()");
lua.script("function a:heartbeat () print('bark') return 2 end"); lua.safe_script("function a:heartbeat () print('bark') return 2 end");
lua.script("v2 = obj:heartbeat()"); lua.safe_script("v2 = obj:heartbeat()");
lua.script("a.heartbeat = function(self) print('woof') return 3 end"); lua.safe_script("a.heartbeat = function(self) print('woof') return 3 end");
lua.script("v3 = obj:heartbeat()"); lua.safe_script("v3 = obj:heartbeat()");
}()); }());
int v1 = lua["v1"]; int v1 = lua["v1"];
int v2 = lua["v2"]; int v2 = lua["v2"];
@ -764,13 +704,13 @@ TEST_CASE("simple_usertype/runtime replacement", "ensure that functions can be p
); );
REQUIRE_NOTHROW([&lua]() { REQUIRE_NOTHROW([&lua]() {
lua.script("obj = a.new()"); lua.safe_script("obj = a.new()");
lua.script("function a:heartbeat () print('arf') return 1 end"); lua.safe_script("function a:heartbeat () print('arf') return 1 end");
lua.script("v1 = obj:heartbeat()"); lua.safe_script("v1 = obj:heartbeat()");
lua.script("function a:heartbeat () print('bark') return 2 end"); lua.safe_script("function a:heartbeat () print('bark') return 2 end");
lua.script("v2 = obj:heartbeat()"); lua.safe_script("v2 = obj:heartbeat()");
lua.script("a.heartbeat = function(self) print('woof') return 3 end"); lua.safe_script("a.heartbeat = function(self) print('woof') return 3 end");
lua.script("v3 = obj:heartbeat()"); lua.safe_script("v3 = obj:heartbeat()");
}()); }());
int v1 = lua["v1"]; int v1 = lua["v1"];
int v2 = lua["v2"]; int v2 = lua["v2"];
@ -801,11 +741,11 @@ TEST_CASE("simple_usertype/meta key retrievals", "allow for special meta keys (_
lua["var"] = s; lua["var"] = s;
lua.script("var = sample.new()"); lua.safe_script("var = sample.new()");
lua.script("var.key = 2"); lua.safe_script("var.key = 2");
lua.script("var.__newindex = 4"); lua.safe_script("var.__newindex = 4");
lua.script("var.__index = 3"); lua.safe_script("var.__index = 3");
lua.script("var.__call = 1"); lua.safe_script("var.__call = 1");
REQUIRE(values[0] == 2); REQUIRE(values[0] == 2);
REQUIRE(values[1] == 4); REQUIRE(values[1] == 4);
REQUIRE(values[2] == 3); REQUIRE(values[2] == 3);
@ -831,11 +771,11 @@ TEST_CASE("simple_usertype/meta key retrievals", "allow for special meta keys (_
sol::state lua; sol::state lua;
lua.new_simple_usertype<sample>("sample", sol::meta_function::new_index, &sample::foo); lua.new_simple_usertype<sample>("sample", sol::meta_function::new_index, &sample::foo);
lua.script("var = sample.new()"); lua.safe_script("var = sample.new()");
lua.script("var.key = 2"); lua.safe_script("var.key = 2");
lua.script("var.__newindex = 4"); lua.safe_script("var.__newindex = 4");
lua.script("var.__index = 3"); lua.safe_script("var.__index = 3");
lua.script("var.__call = 1"); lua.safe_script("var.__call = 1");
REQUIRE(values[0] == 2); REQUIRE(values[0] == 2);
REQUIRE(values[1] == 4); REQUIRE(values[1] == 4);
REQUIRE(values[2] == 3); REQUIRE(values[2] == 3);
@ -871,10 +811,10 @@ TEST_CASE("simple_usertype/static properties", "allow for static functions to ge
"g", sol::property(&test_t::s_func, &test_t::g_func) "g", sol::property(&test_t::s_func, &test_t::g_func)
); );
lua.script("v1 = test.f()"); lua.safe_script("v1 = test.f()");
lua.script("v2 = test.g"); lua.safe_script("v2 = test.g");
lua.script("test.g = 60"); lua.safe_script("test.g = 60");
lua.script("v2a = test.g"); lua.safe_script("v2a = test.g");
int v1 = lua["v1"]; int v1 = lua["v1"];
REQUIRE(v1 == 24); REQUIRE(v1 == 24);
double v2 = lua["v2"]; double v2 = lua["v2"];
@ -914,7 +854,7 @@ TEST_CASE("simple_usertype/indexing", "make sure simple usertypes can be indexed
sol::meta_function::new_index, &indexing_test::setter sol::meta_function::new_index, &indexing_test::setter
); );
lua.script(R"( lua.safe_script(R"(
local t = test.new() local t = test.new()
v = t.a v = t.a
print(v) print(v)
@ -934,7 +874,7 @@ TEST_CASE("simple_usertype/indexing", "make sure simple usertypes can be indexed
lua["test"]["hi"] = [](indexing_test& _self) -> int { return _self.hi(); }; lua["test"]["hi"] = [](indexing_test& _self) -> int { return _self.hi(); };
lua.script(R"( lua.safe_script(R"(
local t = test.new() local t = test.new()
v = t.a; v = t.a;
print(v) print(v)

View File

@ -164,12 +164,12 @@ TEST_CASE("state/multi require", "make sure that requires transfers across hand-
TEST_CASE("state/require-safety", "make sure unrelated modules aren't harmed in using requires") { TEST_CASE("state/require-safety", "make sure unrelated modules aren't harmed in using requires") {
sol::state lua; sol::state lua;
lua.open_libraries(); lua.open_libraries();
std::string t1 = lua.script(R"(require 'io' std::string t1 = lua.safe_script(R"(require 'io'
return 'test1')"); return 'test1')");
sol::object ot2 = lua.require_script("test2", R"(require 'io' sol::object ot2 = lua.require_script("test2", R"(require 'io'
return 'test2')"); return 'test2')");
std::string t2 = ot2.as<std::string>(); std::string t2 = ot2.as<std::string>();
std::string t3 = lua.script(R"(require 'io' std::string t3 = lua.safe_script(R"(require 'io'
return 'test3')"); return 'test3')");
REQUIRE(t1 == "test1"); REQUIRE(t1 == "test1");
REQUIRE(t2 == "test2"); REQUIRE(t2 == "test2");
@ -179,7 +179,7 @@ return 'test3')");
TEST_CASE("state/leak check", "make sure there are no humongous memory leaks in iteration") { TEST_CASE("state/leak check", "make sure there are no humongous memory leaks in iteration") {
#if 0 #if 0
sol::state lua; sol::state lua;
lua.script(R"( lua.safe_script(R"(
record = {} record = {}
for i=1,256 do for i=1,256 do
record[i] = i record[i] = i
@ -244,7 +244,7 @@ return example;
auto bar = [&script](sol::this_state l) { auto bar = [&script](sol::this_state l) {
sol::state_view lua = l; sol::state_view lua = l;
sol::table data = lua.script(script); sol::table data = lua.safe_script(script);
std::string str = data["str"]; std::string str = data["str"];
int num = data["num"]; int num = data["num"];
@ -256,7 +256,7 @@ return example;
auto foo = [&script](int, sol::this_state l) { auto foo = [&script](int, sol::this_state l) {
sol::state_view lua = l; sol::state_view lua = l;
sol::table data = lua.script(script); sol::table data = lua.safe_script(script);
std::string str = data["str"]; std::string str = data["str"];
int num = data["num"]; int num = data["num"];
@ -299,7 +299,7 @@ return example;
lua.set_function("bar", bar); lua.set_function("bar", bar);
lua.set_function("bar2", bar2); lua.set_function("bar2", bar2);
lua.script("bar() bar2() foo(1) foo2(1)"); lua.safe_script("bar() bar2() foo(1) foo2(1)");
} }
TEST_CASE("state/copy and move", "ensure state can be properly copied and moved") { TEST_CASE("state/copy and move", "ensure state can be properly copied and moved") {
@ -318,9 +318,9 @@ TEST_CASE("state/requires-reload", "ensure that reloading semantics do not cause
sol::state lua; sol::state lua;
sol::stack_guard sg(lua); sol::stack_guard sg(lua);
lua.open_libraries(); lua.open_libraries();
lua.script("require 'io'\nreturn 'test1'"); lua.safe_script("require 'io'\nreturn 'test1'");
lua.require_script("test2", "require 'io'\nreturn 'test2'"); lua.require_script("test2", "require 'io'\nreturn 'test2'");
lua.script("require 'io'\nreturn 'test3'"); lua.safe_script("require 'io'\nreturn 'test3'");
} }
TEST_CASE("state/script, do, and load", "test success and failure cases for loading and running scripts") { TEST_CASE("state/script, do, and load", "test success and failure cases for loading and running scripts") {
@ -348,7 +348,7 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
SECTION("script") { SECTION("script") {
sol::state lua; sol::state lua;
sol::stack_guard sg(lua); sol::stack_guard sg(lua);
int ar = lua.script(good); int ar = lua.safe_script(good);
int a = lua["a"]; int a = lua["a"];
REQUIRE(a == 21); REQUIRE(a == 21);
REQUIRE(ar == 21); REQUIRE(ar == 21);
@ -366,13 +366,13 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
SECTION("script-handler") { SECTION("script-handler") {
sol::state lua; sol::state lua;
sol::stack_guard sg(lua); sol::stack_guard sg(lua);
auto errbs = lua.script(bad_syntax, sol::script_pass_on_error); auto errbs = lua.safe_script(bad_syntax, sol::script_pass_on_error);
REQUIRE(!errbs.valid()); REQUIRE(!errbs.valid());
auto errbr = lua.script(bad_runtime, sol::script_pass_on_error); auto errbr = lua.safe_script(bad_runtime, sol::script_pass_on_error);
REQUIRE(!errbr.valid()); REQUIRE(!errbr.valid());
auto result = lua.script(good, sol::script_pass_on_error); auto result = lua.safe_script(good, sol::script_pass_on_error);
int a = lua["a"]; int a = lua["a"];
int ar = result; int ar = result;
REQUIRE(result.valid()); REQUIRE(result.valid());
@ -423,7 +423,7 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
SECTION("script_file") { SECTION("script_file") {
sol::state lua; sol::state lua;
sol::stack_guard sg(lua); sol::stack_guard sg(lua);
int ar = lua.script_file(file_good); int ar = lua.safe_script_file(file_good);
int a = lua["a"]; int a = lua["a"];
REQUIRE(a == 21); REQUIRE(a == 21);
REQUIRE(ar == 21); REQUIRE(ar == 21);
@ -441,13 +441,13 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
SECTION("script_file-handler") { SECTION("script_file-handler") {
sol::state lua; sol::state lua;
sol::stack_guard sg(lua); sol::stack_guard sg(lua);
auto errbs = lua.script_file(file_bad_syntax, sol::script_pass_on_error); auto errbs = lua.safe_script_file(file_bad_syntax, sol::script_pass_on_error);
REQUIRE(!errbs.valid()); REQUIRE(!errbs.valid());
auto errbr = lua.script_file(file_bad_runtime, sol::script_pass_on_error); auto errbr = lua.safe_script_file(file_bad_runtime, sol::script_pass_on_error);
REQUIRE(!errbr.valid()); REQUIRE(!errbr.valid());
auto result = lua.script_file(file_good, sol::script_pass_on_error); auto result = lua.safe_script_file(file_good, sol::script_pass_on_error);
int a = lua["a"]; int a = lua["a"];
int ar = result; int ar = result;
REQUIRE(result.valid()); REQUIRE(result.valid());

View File

@ -97,7 +97,7 @@ TEST_CASE("tables/nested cleanup", "make sure tables leave the stack balanced")
sol::state lua; sol::state lua;
lua.open_libraries(); lua.open_libraries();
lua.script("A={}"); lua.safe_script("A={}");
auto f = [] { return 5; }; auto f = [] { return 5; };
for (int i = 0; i < 30; i++) { for (int i = 0; i < 30; i++) {
std::string name = std::string("init") + std::to_string(i); std::string name = std::string("init") + std::to_string(i);
@ -143,7 +143,7 @@ TEST_CASE("tables/for_each", "Testing the use of for_each to get values from a l
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.script("arr = {\n" lua.safe_script("arr = {\n"
"[0] = \"Hi\",\n" "[0] = \"Hi\",\n"
"[1] = 123.45,\n" "[1] = 123.45,\n"
"[2] = \"String value\",\n" "[2] = \"String value\",\n"
@ -200,7 +200,7 @@ TEST_CASE("tables/for_each empty", "empty tables should not crash") {
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.script("arr = {}"); lua.safe_script("arr = {}");
sol::table tbl = lua["arr"]; sol::table tbl = lua["arr"];
REQUIRE(tbl.empty()); REQUIRE(tbl.empty());
std::size_t tablesize = 0; std::size_t tablesize = 0;
@ -257,7 +257,7 @@ TEST_CASE("tables/iterators", "Testing the use of iteratrs to get values from a
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.script("arr = {\n" lua.safe_script("arr = {\n"
"[0] = \"Hi\",\n" "[0] = \"Hi\",\n"
"[1] = 123.45,\n" "[1] = 123.45,\n"
"[2] = \"String value\",\n" "[2] = \"String value\",\n"
@ -316,7 +316,7 @@ TEST_CASE("tables/variables", "Check if tables and variables work as intended")
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::os); lua.open_libraries(sol::lib::base, sol::lib::os);
lua.get<sol::table>("os").set("name", "windows"); lua.get<sol::table>("os").set("name", "windows");
REQUIRE_NOTHROW(lua.script("assert(os.name == \"windows\")")); REQUIRE_NOTHROW(lua.safe_script("assert(os.name == \"windows\")"));
} }
TEST_CASE("tables/create", "Check if creating a table is kosher") { TEST_CASE("tables/create", "Check if creating a table is kosher") {
@ -368,7 +368,7 @@ TEST_CASE("tables/function variables", "Check if tables and function calls work
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::os); lua.open_libraries(sol::lib::base, sol::lib::os);
auto run_script = [](sol::state& lua) -> void { auto run_script = [](sol::state& lua) -> void {
lua.script("assert(os.fun() == \"test\")"); lua.safe_script("assert(os.fun() == \"test\")");
}; };
lua.get<sol::table>("os").set_function("fun", lua.get<sol::table>("os").set_function("fun",
@ -419,7 +419,7 @@ TEST_CASE("tables/operator[]", "Check if operator[] retrieval and setting works
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.script("foo = 20\nbar = \"hello world\""); lua.safe_script("foo = 20\nbar = \"hello world\"");
// basic retrieval // basic retrieval
std::string bar = lua["bar"]; std::string bar = lua["bar"];
int foo = lua["foo"]; int foo = lua["foo"];
@ -439,7 +439,7 @@ TEST_CASE("tables/operator[]", "Check if operator[] retrieval and setting works
// function setting // function setting
lua["test"] = plop_xyz; lua["test"] = plop_xyz;
REQUIRE_NOTHROW(lua.script("assert(test(10, 11, \"hello\") == 11)")); REQUIRE_NOTHROW(lua.safe_script("assert(test(10, 11, \"hello\") == 11)"));
// function retrieval // function retrieval
sol::function test = lua["test"]; sol::function test = lua["test"];
@ -450,7 +450,7 @@ TEST_CASE("tables/operator[]", "Check if operator[] retrieval and setting works
return x * 2; return x * 2;
}; };
REQUIRE_NOTHROW(lua.script("assert(lamb(220) == 440)")); REQUIRE_NOTHROW(lua.safe_script("assert(lamb(220) == 440)"));
// function retrieval of a lambda // function retrieval of a lambda
sol::function lamb = lua["lamb"]; sol::function lamb = lua["lamb"];
@ -552,7 +552,7 @@ TEST_CASE("tables/boolean keys", "make sure boolean keys don't get caught up in
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.script(R"( lua.safe_script(R"(
tbl = {} tbl = {}
tbl[true] = 10 tbl[true] = 10
tbl[1] = 20 tbl[1] = 20

View File

@ -271,7 +271,7 @@ TEST_CASE("usertype/usertype", "Show that we can create classes from usertype an
sol::usertype<fuser> lc{ "add", &fuser::add, "add2", &fuser::add2 }; sol::usertype<fuser> lc{ "add", &fuser::add, "add2", &fuser::add2 };
lua.set_usertype(lc); lua.set_usertype(lc);
lua.script("a = fuser:new()\n" lua.safe_script("a = fuser:new()\n"
"b = a:add(1)\n" "b = a:add(1)\n"
"c = a:add2(1)\n"); "c = a:add2(1)\n");
@ -299,7 +299,7 @@ TEST_CASE("usertype/usertype-constructors", "Show that we can create classes fro
sol::usertype<crapola::fuser> lc(con, "add", &crapola::fuser::add, "add2", &crapola::fuser::add2); sol::usertype<crapola::fuser> lc(con, "add", &crapola::fuser::add, "add2", &crapola::fuser::add2);
lua.set_usertype(lc); lua.set_usertype(lc);
lua.script( lua.safe_script(
"a = fuser.new(2)\n" "a = fuser.new(2)\n"
"u = a:add(1)\n" "u = a:add(1)\n"
"v = a:add2(1)\n" "v = a:add2(1)\n"
@ -339,7 +339,7 @@ TEST_CASE("usertype/usertype-utility", "Show internal management of classes regi
lua.new_usertype<fuser>("fuser", "add", &fuser::add, "add2", &fuser::add2); lua.new_usertype<fuser>("fuser", "add", &fuser::add, "add2", &fuser::add2);
lua.script("a = fuser.new()\n" lua.safe_script("a = fuser.new()\n"
"b = a:add(1)\n" "b = a:add(1)\n"
"c = a:add2(1)\n"); "c = a:add2(1)\n");
@ -367,8 +367,8 @@ TEST_CASE("usertype/usertype-utility-derived", "usertype classes must play nice
lua.set_usertype(baseusertype); lua.set_usertype(baseusertype);
lua.script("base = Base.new(5)"); lua.safe_script("base = Base.new(5)");
REQUIRE_NOTHROW(lua.script("print(base:get_num())")); REQUIRE_NOTHROW(lua.safe_script("print(base:get_num())"));
sol::constructors<sol::types<int>> derivedctor; sol::constructors<sol::types<int>> derivedctor;
sol::usertype<Derived> derivedusertype(derivedctor, sol::usertype<Derived> derivedusertype(derivedctor,
@ -378,10 +378,10 @@ TEST_CASE("usertype/usertype-utility-derived", "usertype classes must play nice
lua.set_usertype(derivedusertype); lua.set_usertype(derivedusertype);
lua.script("derived = Derived.new(7)"); lua.safe_script("derived = Derived.new(7)");
lua.script("dgn = derived:get_num()\n" lua.safe_script("dgn = derived:get_num()\n"
"print(dgn)"); "print(dgn)");
lua.script("dgn10 = derived:get_num_10()\n" lua.safe_script("dgn10 = derived:get_num_10()\n"
"print(dgn10)"); "print(dgn10)");
REQUIRE((lua.get<int>("dgn10") == 70)); REQUIRE((lua.get<int>("dgn10") == 70));
@ -394,7 +394,7 @@ TEST_CASE("usertype/self-referential usertype", "usertype classes must play nice
lua.new_usertype<self_test>("test", "g", &self_test::g, "f", &self_test::f); lua.new_usertype<self_test>("test", "g", &self_test::g, "f", &self_test::f);
lua.script( lua.safe_script(
"local a = test.new()\n" "local a = test.new()\n"
"a:g(\"woof\")\n" "a:g(\"woof\")\n"
"a:f(a)\n" "a:f(a)\n"
@ -429,16 +429,16 @@ TEST_CASE("usertype/issue-number-twenty-five", "Using pointers and references fr
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.new_usertype<test>("test", "set", &test::set, "get", &test::get, "pointer_get", &test::pget, "fun", &test::fun, "create_get", &test::create_get); lua.new_usertype<test>("test", "set", &test::set, "get", &test::get, "pointer_get", &test::pget, "fun", &test::fun, "create_get", &test::create_get);
REQUIRE_NOTHROW(lua.script("x = test.new()")); REQUIRE_NOTHROW(lua.safe_script("x = test.new()"));
REQUIRE_NOTHROW(lua.script("assert(x:set():get() == 10)")); REQUIRE_NOTHROW(lua.safe_script("assert(x:set():get() == 10)"));
REQUIRE_NOTHROW(lua.script("y = x:pointer_get()")); REQUIRE_NOTHROW(lua.safe_script("y = x:pointer_get()"));
REQUIRE_NOTHROW(lua.script("y:set():get()")); REQUIRE_NOTHROW(lua.safe_script("y:set():get()"));
REQUIRE_NOTHROW(lua.script("y:fun(10)")); REQUIRE_NOTHROW(lua.safe_script("y:fun(10)"));
REQUIRE_NOTHROW(lua.script("x:fun(10)")); REQUIRE_NOTHROW(lua.safe_script("x:fun(10)"));
REQUIRE_NOTHROW(lua.script("assert(y:fun(10) == x:fun(10), '...')")); REQUIRE_NOTHROW(lua.safe_script("assert(y:fun(10) == x:fun(10), '...')"));
REQUIRE_NOTHROW(lua.script("assert(y:fun(10) == 100, '...')")); REQUIRE_NOTHROW(lua.safe_script("assert(y:fun(10) == 100, '...')"));
REQUIRE_NOTHROW(lua.script("assert(y:set():get() == y:set():get(), '...')")); REQUIRE_NOTHROW(lua.safe_script("assert(y:set():get() == y:set():get(), '...')"));
REQUIRE_NOTHROW(lua.script("assert(y:set():get() == 10, '...')")); REQUIRE_NOTHROW(lua.safe_script("assert(y:set():get() == 10, '...')"));
} }
TEST_CASE("usertype/issue-number-thirty-five", "using value types created from lua-called C++ code, fixing user-defined types with constructors") { TEST_CASE("usertype/issue-number-thirty-five", "using value types created from lua-called C++ code, fixing user-defined types with constructors") {
@ -449,9 +449,9 @@ TEST_CASE("usertype/issue-number-thirty-five", "using value types created from l
sol::usertype<Vec> udata(ctor, "normalized", &Vec::normalized, "length", &Vec::length); sol::usertype<Vec> udata(ctor, "normalized", &Vec::normalized, "length", &Vec::length);
lua.set_usertype(udata); lua.set_usertype(udata);
REQUIRE_NOTHROW(lua.script("v = Vec.new(1, 2, 3)\n" REQUIRE_NOTHROW(lua.safe_script("v = Vec.new(1, 2, 3)\n"
"print(v:length())")); "print(v:length())"));
REQUIRE_NOTHROW(lua.script("v = Vec.new(1, 2, 3)\n" REQUIRE_NOTHROW(lua.safe_script("v = Vec.new(1, 2, 3)\n"
"print(v:normalized():length())")); "print(v:normalized():length())"));
} }
@ -469,11 +469,11 @@ TEST_CASE("usertype/lua-stored-usertype", "ensure usertype values can be stored
// usertype dies, but still usable in lua! // usertype dies, but still usable in lua!
} }
REQUIRE_NOTHROW(lua.script("collectgarbage()\n" REQUIRE_NOTHROW(lua.safe_script("collectgarbage()\n"
"v = Vec.new(1, 2, 3)\n" "v = Vec.new(1, 2, 3)\n"
"print(v:length())")); "print(v:length())"));
REQUIRE_NOTHROW(lua.script("v = Vec.new(1, 2, 3)\n" REQUIRE_NOTHROW(lua.safe_script("v = Vec.new(1, 2, 3)\n"
"print(v:normalized():length())")); "print(v:normalized():length())"));
} }
@ -489,20 +489,20 @@ TEST_CASE("usertype/member-variables", "allow table-like accessors to behave as
"length", &Vec::length); "length", &Vec::length);
lua.set_usertype(udata); lua.set_usertype(udata);
REQUIRE_NOTHROW(lua.script("v = Vec.new(1, 2, 3)\n" REQUIRE_NOTHROW(lua.safe_script("v = Vec.new(1, 2, 3)\n"
"v2 = Vec.new(0, 1, 0)\n" "v2 = Vec.new(0, 1, 0)\n"
"print(v:length())\n" "print(v:length())\n"
)); ));
REQUIRE_NOTHROW(lua.script("v.x = 2\n" REQUIRE_NOTHROW(lua.safe_script("v.x = 2\n"
"v2.y = 2\n" "v2.y = 2\n"
"print(v.x, v.y, v.z)\n" "print(v.x, v.y, v.z)\n"
"print(v2.x, v2.y, v2.z)\n" "print(v2.x, v2.y, v2.z)\n"
)); ));
REQUIRE_NOTHROW(lua.script("assert(v.x == 2)\n" REQUIRE_NOTHROW(lua.safe_script("assert(v.x == 2)\n"
"assert(v2.x == 0)\n" "assert(v2.x == 0)\n"
"assert(v2.y == 2)\n" "assert(v2.y == 2)\n"
)); ));
REQUIRE_NOTHROW(lua.script("v.x = 3\n" REQUIRE_NOTHROW(lua.safe_script("v.x = 3\n"
"local x = v.x\n" "local x = v.x\n"
"assert(x == 3)\n" "assert(x == 3)\n"
)); ));
@ -518,8 +518,8 @@ TEST_CASE("usertype/member-variables", "allow table-like accessors to behave as
); );
breaks& b = lua["b"]; breaks& b = lua["b"];
REQUIRE_NOTHROW(lua.script("b.f = function () print('BARK!') end")); REQUIRE_NOTHROW(lua.safe_script("b.f = function () print('BARK!') end"));
REQUIRE_NOTHROW(lua.script("b.f()")); REQUIRE_NOTHROW(lua.safe_script("b.f()"));
REQUIRE_NOTHROW(b.f()); REQUIRE_NOTHROW(b.f());
} }
@ -535,8 +535,8 @@ TEST_CASE("usertype/nonmember-functions", "let users set non-member functions th
} }
).get<sol::table>("giver").set_function("stuff", giver::stuff); ).get<sol::table>("giver").set_function("stuff", giver::stuff);
REQUIRE_NOTHROW(lua.script("giver.stuff()")); REQUIRE_NOTHROW(lua.safe_script("giver.stuff()"));
REQUIRE_NOTHROW(lua.script("t = giver.new()\n" REQUIRE_NOTHROW(lua.safe_script("t = giver.new()\n"
"print(tostring(t))\n" "print(tostring(t))\n"
"t:gief()\n" "t:gief()\n"
"t:gief_stuff(20)\n")); "t:gief_stuff(20)\n"));
@ -575,7 +575,7 @@ TEST_CASE("regressions/one", "issue number 48") {
sol::state lua; sol::state lua;
lua.new_usertype<vars>("vars", lua.new_usertype<vars>("vars",
"boop", &vars::boop); "boop", &vars::boop);
REQUIRE_NOTHROW(lua.script("beep = vars.new()\n" REQUIRE_NOTHROW(lua.safe_script("beep = vars.new()\n"
"beep.boop = 1")); "beep.boop = 1"));
// test for segfault // test for segfault
auto my_var = lua.get<vars>("beep"); auto my_var = lua.get<vars>("beep");
@ -612,37 +612,6 @@ TEST_CASE("usertype/get-set-references", "properly get and set with std::ref sem
REQUIRE(rvar.boop == ref_var.boop); REQUIRE(rvar.boop == ref_var.boop);
} }
TEST_CASE("usertype/destructor-tests", "Show that proper copies / destruction happens") {
static int created = 0;
static int destroyed = 0;
static void* last_call = nullptr;
struct x {
x() { ++created; }
x(const x&) { ++created; }
x(x&&) { ++created; }
x& operator=(const x&) { return *this; }
x& operator=(x&&) { return *this; }
~x() { ++destroyed; }
};
{
sol::state lua;
lua.new_usertype<x>("x");
x x1;
x x2;
lua.set("x1copy", x1, "x2copy", x2, "x1ref", std::ref(x1));
x& x1copyref = lua["x1copy"];
x& x2copyref = lua["x2copy"];
x& x1ref = lua["x1ref"];
REQUIRE(created == 4);
REQUIRE(destroyed == 0);
REQUIRE(std::addressof(x1) == std::addressof(x1ref));
REQUIRE(std::addressof(x1copyref) != std::addressof(x1));
REQUIRE(std::addressof(x2copyref) != std::addressof(x2));
}
REQUIRE(created == 4);
REQUIRE(destroyed == 4);
}
TEST_CASE("usertype/private-constructible", "Check to make sure special snowflake types from Enterprise thingamahjongs work properly.") { TEST_CASE("usertype/private-constructible", "Check to make sure special snowflake types from Enterprise thingamahjongs work properly.") {
int numsaved = factory_test::num_saved; int numsaved = factory_test::num_saved;
int numkilled = factory_test::num_killed; int numkilled = factory_test::num_killed;
@ -658,9 +627,9 @@ TEST_CASE("usertype/private-constructible", "Check to make sure special snowflak
std::unique_ptr<factory_test, factory_test::deleter> f = factory_test::make(); std::unique_ptr<factory_test, factory_test::deleter> f = factory_test::make();
lua.set("true_a", factory_test::true_a, "f", f.get()); lua.set("true_a", factory_test::true_a, "f", f.get());
REQUIRE_NOTHROW(lua.script("assert(f.a == true_a)")); REQUIRE_NOTHROW(lua.safe_script("assert(f.a == true_a)"));
REQUIRE_NOTHROW(lua.script( REQUIRE_NOTHROW(lua.safe_script(
"local fresh_f = factory_test:new()\n" "local fresh_f = factory_test:new()\n"
"assert(fresh_f.a == true_a)\n")); "assert(fresh_f.a == true_a)\n"));
} }
@ -682,7 +651,7 @@ TEST_CASE("usertype/const-pointer", "Make sure const pointers can be taken") {
); );
lua.set("a", A_x()); lua.set("a", A_x());
lua.set("b", B_foo()); lua.set("b", B_foo());
lua.script("x = b:foo(a)"); lua.safe_script("x = b:foo(a)");
int x = lua["x"]; int x = lua["x"];
REQUIRE(x == 201); REQUIRE(x == 201);
} }
@ -713,7 +682,7 @@ TEST_CASE("usertype/overloading", "Check if overloading works properly for usert
const std::string bark_58 = "bark 58"; const std::string bark_58 = "bark 58";
REQUIRE_NOTHROW(lua.script( REQUIRE_NOTHROW(lua.safe_script(
"r = woof:new()\n" "r = woof:new()\n"
"a = r:func(1)\n" "a = r:func(1)\n"
"b = r:func(1, 2)\n" "b = r:func(1, 2)\n"
@ -782,7 +751,7 @@ TEST_CASE("usertype/reference-and-constness", "Make sure constness compiles prop
lua.set("n", nested()); lua.set("n", nested());
lua.set("o", outer()); lua.set("o", outer());
lua.set("f", sol::c_call<decltype(&nested::f), &nested::f>); lua.set("f", sol::c_call<decltype(&nested::f), &nested::f>);
lua.script(R"( lua.safe_script(R"(
x = w.b x = w.b
x.var = 20 x.var = 20
val = w.b.var == x.var val = w.b.var == x.var
@ -839,8 +808,8 @@ TEST_CASE("usertype/readonly-and-static-functions", "Check if static functions c
sol::meta_function::call_function, &bark::operator() sol::meta_function::call_function, &bark::operator()
); );
REQUIRE_NOTHROW(lua.script("assert(bark.oh_boy('woo') == 3)")); REQUIRE_NOTHROW(lua.safe_script("assert(bark.oh_boy('woo') == 3)"));
REQUIRE_NOTHROW(lua.script("bark.oh_boy()")); REQUIRE_NOTHROW(lua.safe_script("bark.oh_boy()"));
bark b; bark b;
lua.set("b", &b); lua.set("b", &b);
@ -865,7 +834,7 @@ TEST_CASE("usertype/readonly-and-static-functions", "Check if static functions c
REQUIRE(z); REQUIRE(z);
REQUIRE(w == 5); REQUIRE(w == 5);
lua.script(R"( lua.safe_script(R"(
lx = b(1) lx = b(1)
ly = getmetatable(b).__call(b, 1) ly = getmetatable(b).__call(b, 1)
lz = b.something() lz = b.something()
@ -926,11 +895,11 @@ TEST_CASE("usertype/properties", "Check if member properties/variables work") {
bark b; bark b;
lua.set("b", &b); lua.set("b", &b);
lua.script("b.a = 59"); lua.safe_script("b.a = 59");
lua.script("var2_0 = b.a"); lua.safe_script("var2_0 = b.a");
lua.script("var2_1 = b.b"); lua.safe_script("var2_1 = b.b");
lua.script("b.d = 1568"); lua.safe_script("b.d = 1568");
lua.script("var2_2 = b.c"); lua.safe_script("var2_2 = b.c");
int var2_0 = lua["var2_0"]; int var2_0 = lua["var2_0"];
int var2_1 = lua["var2_1"]; int var2_1 = lua["var2_1"];
@ -987,7 +956,7 @@ TEST_CASE("usertype/call_constructor", "make sure lua types can be constructed w
, sol::call_constructor, sol::constructors<sol::types<>, sol::types<int>>() , sol::call_constructor, sol::constructors<sol::types<>, sol::types<int>>()
); );
lua.script(R"( lua.safe_script(R"(
t = thing(256) t = thing(256)
)"); )");
@ -1004,13 +973,13 @@ TEST_CASE("usertype/call_constructor-factories", "make sure tables can be passed
sol::call_constructor, sol::factories(&matrix_xf::from_lua_table) sol::call_constructor, sol::factories(&matrix_xf::from_lua_table)
); );
lua.script("m = mat{ {1.1, 2.2} }"); lua.safe_script("m = mat{ {1.1, 2.2} }");
lua.new_usertype<matrix_xi>("mati", lua.new_usertype<matrix_xi>("mati",
sol::call_constructor, sol::factories(&matrix_xi::from_lua_table) sol::call_constructor, sol::factories(&matrix_xi::from_lua_table)
); );
lua.script("mi = mati{ {1, 2} }"); lua.safe_script("mi = mati{ {1, 2} }");
matrix_xf& m = lua["m"]; matrix_xf& m = lua["m"];
REQUIRE(m.a == 1.1f); REQUIRE(m.a == 1.1f);
@ -1044,7 +1013,7 @@ TEST_CASE("usertype/call_constructor_2", "prevent metatable regression") {
sol::call_constructor, sol::constructors<sol::types<>, sol::types<const class02&>, sol::types<const class01&>>() sol::call_constructor, sol::constructors<sol::types<>, sol::types<const class02&>, sol::types<const class01&>>()
); );
REQUIRE_NOTHROW(lua.script(R"( REQUIRE_NOTHROW(lua.safe_script(R"(
x = class01() x = class01()
y = class02(x) y = class02(x)
)")); )"));
@ -1138,7 +1107,7 @@ TEST_CASE("usertype/coverage", "try all the things") {
INFO("usertype created"); INFO("usertype created");
lua.script(R"( lua.safe_script(R"(
e = ext_getset() e = ext_getset()
w = e:x(e:x(), e:x(e:x())) w = e:x(e:x(), e:x(e:x()))
print(w) print(w)
@ -1149,7 +1118,7 @@ print(w)
INFO("REQUIRE(w) successful"); INFO("REQUIRE(w) successful");
lua.script(R"( lua.safe_script(R"(
e:set(500) e:set(500)
e.sset(24) e.sset(24)
x = e:get() x = e:get()
@ -1163,7 +1132,7 @@ y = e.sget(20)
INFO("REQUIRE(x, y) successful"); INFO("REQUIRE(x, y) successful");
lua.script(R"( lua.safe_script(R"(
e.bark = 5001 e.bark = 5001
a = e:get() a = e:get()
print(e.bark) print(e.bark)
@ -1182,7 +1151,7 @@ print(b)
INFO("REQUIRE(a, b) successful"); INFO("REQUIRE(a, b) successful");
lua.script(R"( lua.safe_script(R"(
c = e.readonlybark c = e.readonlybark
d = e.meow d = e.meow
print(e.readonlybark) print(e.readonlybark)
@ -1198,7 +1167,7 @@ print(d)
INFO("REQUIRE(c, d) successful"); INFO("REQUIRE(c, d) successful");
lua.script(R"( lua.safe_script(R"(
e.writeonlypropbark = 500 e.writeonlypropbark = 500
z = e.readonlypropbark z = e.readonlypropbark
print(e.readonlybark) print(e.readonlybark)
@ -1239,7 +1208,7 @@ TEST_CASE("usertype/copyability", "make sure user can write to a class variable
lua.new_usertype<NoCopy>("NoCopy", "val", sol::property(&NoCopy::get, &NoCopy::set)); lua.new_usertype<NoCopy>("NoCopy", "val", sol::property(&NoCopy::get, &NoCopy::set));
REQUIRE_NOTHROW( REQUIRE_NOTHROW(
lua.script(R"__( lua.safe_script(R"__(
nocopy = NoCopy.new() nocopy = NoCopy.new()
nocopy.val = 5 nocopy.val = 5
)__") )__")
@ -1260,7 +1229,7 @@ TEST_CASE("usertype/protect", "users should be allowed to manually protect a fun
); );
REQUIRE_NOTHROW( REQUIRE_NOTHROW(
lua.script(R"__( lua.safe_script(R"__(
pm = protect_me.new() pm = protect_me.new()
value = pcall(pm.gen,pm) value = pcall(pm.gen,pm)
)__") )__")
@ -1269,59 +1238,6 @@ value = pcall(pm.gen,pm)
REQUIRE_FALSE(value); REQUIRE_FALSE(value);
} }
TEST_CASE("usertype/shared-ptr-regression", "usertype metatables should not screw over unique usertype metatables") {
static int created = 0;
static int destroyed = 0;
struct test {
test() {
++created;
}
~test() {
++destroyed;
}
};
{
std::list<std::shared_ptr<test>> tests;
sol::state lua;
lua.open_libraries();
lua.new_usertype<test>("test",
"create", [&]() -> std::shared_ptr<test> {
tests.push_back(std::make_shared<test>());
return tests.back();
}
);
REQUIRE(created == 0);
REQUIRE(destroyed == 0);
lua.script("x = test.create()");
REQUIRE(created == 1);
REQUIRE(destroyed == 0);
REQUIRE_FALSE(tests.empty());
std::shared_ptr<test>& x = lua["x"];
std::size_t xuse = x.use_count();
std::size_t tuse = tests.back().use_count();
REQUIRE(xuse == tuse);
}
REQUIRE(created == 1);
REQUIRE(destroyed == 1);
}
TEST_CASE("usertype/double-deleter-guards", "usertype metatables internally must not rely on C++ state") {
struct c_a { int x; };
struct c_b { int y; };
auto routine = []() {
sol::state lua;
lua.new_usertype<c_a>("c_a", "x", &c_a::x);
lua.new_usertype<c_b>("c_b", "y", &c_b::y);
lua = sol::state();
lua.new_usertype<c_a>("c_a", "x", &c_a::x);
lua.new_usertype<c_b>("c_b", "y", &c_b::y);
lua = sol::state();
};
REQUIRE_NOTHROW(routine());
}
TEST_CASE("usertype/vars", "usertype vars can bind various class items") { TEST_CASE("usertype/vars", "usertype vars can bind various class items") {
static int muh_variable = 25; static int muh_variable = 25;
static int through_variable = 10; static int through_variable = 10;
@ -1349,7 +1265,7 @@ TEST_CASE("usertype/vars", "usertype vars can bind various class items") {
REQUIRE(pretg2 == 10); REQUIRE(pretg2 == 10);
REQUIRE(pretrg2 == 10); REQUIRE(pretrg2 == 10);
lua.script(R"( lua.safe_script(R"(
print(test.straight) print(test.straight)
test.straight = 50 test.straight = 50
print(test.straight) print(test.straight)
@ -1357,7 +1273,7 @@ print(test.straight)
int s = lua["test"]["straight"]; int s = lua["test"]["straight"];
REQUIRE(s == 50); REQUIRE(s == 50);
lua.script(R"( lua.safe_script(R"(
t = test.new() t = test.new()
print(t.global) print(t.global)
t.global = 50 t.global = 50
@ -1368,7 +1284,7 @@ print(t.global)
REQUIRE(muh_variable == 25); REQUIRE(muh_variable == 25);
lua.script(R"( lua.safe_script(R"(
print(t.ref_global) print(t.ref_global)
t.ref_global = 50 t.ref_global = 50
print(t.ref_global) print(t.ref_global)
@ -1378,7 +1294,7 @@ print(t.ref_global)
REQUIRE(muh_variable == 50); REQUIRE(muh_variable == 50);
REQUIRE(through_variable == 10); REQUIRE(through_variable == 10);
lua.script(R"( lua.safe_script(R"(
print(test.global2) print(test.global2)
test.global2 = 35 test.global2 = 35
print(test.global2) print(test.global2)
@ -1387,7 +1303,7 @@ print(test.global2)
REQUIRE(through_variable == 10); REQUIRE(through_variable == 10);
REQUIRE(tv == 35); REQUIRE(tv == 35);
lua.script(R"( lua.safe_script(R"(
print(test.ref_global2) print(test.ref_global2)
test.ref_global2 = 35 test.ref_global2 = 35
print(test.ref_global2) print(test.ref_global2)
@ -1421,10 +1337,10 @@ TEST_CASE("usertype/static-properties", "allow for static functions to get and s
"g", sol::property(&test_t::s_func, &test_t::g_func) "g", sol::property(&test_t::s_func, &test_t::g_func)
); );
lua.script("v1 = test.f()"); lua.safe_script("v1 = test.f()");
lua.script("v2 = test.g"); lua.safe_script("v2 = test.g");
lua.script("test.g = 60"); lua.safe_script("test.g = 60");
lua.script("v2a = test.g"); lua.safe_script("v2a = test.g");
int v1 = lua["v1"]; int v1 = lua["v1"];
REQUIRE(v1 == 24); REQUIRE(v1 == 24);
double v2 = lua["v2"]; double v2 = lua["v2"];
@ -1455,7 +1371,7 @@ TEST_CASE("usertype/var-and-property", "make sure const vars are readonly and pr
"global", sol::var(std::ref(arf)) "global", sol::var(std::ref(arf))
); );
lua.script(R"( lua.safe_script(R"(
t = test.new() t = test.new()
print(t.prop) print(t.prop)
t.prop = 50 t.prop = 50
@ -1465,7 +1381,7 @@ print(t.prop)
test& t = lua["t"]; test& t = lua["t"];
REQUIRE(t.value == 50); REQUIRE(t.value == 50);
lua.script(R"( lua.safe_script(R"(
t = test.new() t = test.new()
print(t.global) print(t.global)
)"); )");
@ -1473,7 +1389,7 @@ print(t.global)
auto result = lua.safe_script("t.global = 20", sol::script_pass_on_error); auto result = lua.safe_script("t.global = 20", sol::script_pass_on_error);
REQUIRE_FALSE(result.valid()); REQUIRE_FALSE(result.valid());
} }
lua.script("print(t.global)"); lua.safe_script("print(t.global)");
} }
TEST_CASE("usertype/unique_usertype-check", "make sure unique usertypes don't get pushed as references with function calls and the like") { TEST_CASE("usertype/unique_usertype-check", "make sure unique usertypes don't get pushed as references with function calls and the like") {
@ -1492,7 +1408,7 @@ TEST_CASE("usertype/unique_usertype-check", "make sure unique usertypes don't ge
"get_name", &Entity::GetName "get_name", &Entity::GetName
); );
lua.script(R"( lua.safe_script(R"(
function my_func(entity) function my_func(entity)
print("INSIDE LUA") print("INSIDE LUA")
print(entity:get_name()) print(entity:get_name())
@ -1514,7 +1430,7 @@ TEST_CASE("usertype/abstract-base-class", "Ensure that abstract base classes and
lua.new_usertype<abstract_A>("A", "a", &abstract_A::a); lua.new_usertype<abstract_A>("A", "a", &abstract_A::a);
lua.new_usertype<abstract_B>("B", sol::base_classes, sol::bases<abstract_A>()); lua.new_usertype<abstract_B>("B", sol::base_classes, sol::bases<abstract_A>());
REQUIRE_NOTHROW([&]() { REQUIRE_NOTHROW([&]() {
lua.script(R"( lua.safe_script(R"(
local b = B.new() local b = B.new()
b:a() b:a()
)"); )");
@ -1533,45 +1449,14 @@ TEST_CASE("usertype/as_function", "Ensure that variables can be turned into func
B b; B b;
lua.set("b", &b); lua.set("b", &b);
lua.script("x = b:f()"); lua.safe_script("x = b:f()");
lua.script("y = b.b"); lua.safe_script("y = b.b");
int x = lua["x"]; int x = lua["x"];
int y = lua["y"]; int y = lua["y"];
REQUIRE(x == 24); REQUIRE(x == 24);
REQUIRE(y == 24); REQUIRE(y == 24);
} }
TEST_CASE("usertype/destruction-test", "make sure usertypes are properly destructed and don't double-delete memory or segfault") {
sol::state lua;
class CrashClass {
public:
CrashClass() {
}
~CrashClass() {
a = 10; // This will cause a crash.
}
private:
int a;
};
lua.new_usertype<CrashClass>("CrashClass",
sol::call_constructor, sol::constructors<sol::types<>>()
);
lua.script(R"(
function testCrash()
local x = CrashClass()
end
)");
for (int i = 0; i < 1000; ++i) {
lua["testCrash"]();
}
}
TEST_CASE("usertype/call-initializers", "Ensure call constructors with initializers work well") { TEST_CASE("usertype/call-initializers", "Ensure call constructors with initializers work well") {
struct A { struct A {
double f = 25.5; double f = 25.5;
@ -1588,7 +1473,7 @@ TEST_CASE("usertype/call-initializers", "Ensure call constructors with initializ
sol::call_constructor, sol::initializers(&A::init) sol::call_constructor, sol::initializers(&A::init)
); );
lua.script(R"( lua.safe_script(R"(
a = A(24.3) a = A(24.3)
)"); )");
A& a = lua["a"]; A& a = lua["a"];
@ -1602,7 +1487,7 @@ TEST_CASE("usertype/missing-key", "make sure a missing key returns nil") {
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.new_usertype<thing>("thing"); lua.new_usertype<thing>("thing");
REQUIRE_NOTHROW(lua.script("v = thing.missingKey\nprint(v)")); REQUIRE_NOTHROW(lua.safe_script("v = thing.missingKey\nprint(v)"));
sol::object o = lua["v"]; sol::object o = lua["v"];
bool isnil = o.is<sol::lua_nil_t>(); bool isnil = o.is<sol::lua_nil_t>();
REQUIRE(isnil); REQUIRE(isnil);
@ -1623,7 +1508,7 @@ TEST_CASE("usertype/runtime-extensibility", "Check if usertypes are runtime exte
"func", &thing::func "func", &thing::func
); );
lua.script(R"( lua.safe_script(R"(
t = thing.new() t = thing.new()
)"); )");
@ -1645,19 +1530,19 @@ end
REQUIRE_FALSE(result.valid()); REQUIRE_FALSE(result.valid());
}; };
lua.script("val = t:func(2)"); lua.safe_script("val = t:func(2)");
val = lua["val"]; val = lua["val"];
REQUIRE(val == 2); REQUIRE(val == 2);
REQUIRE_NOTHROW([&lua]() { REQUIRE_NOTHROW([&lua]() {
lua.script(R"( lua.safe_script(R"(
function thing:runtime_func(a) function thing:runtime_func(a)
return a + 1 return a + 1
end end
)"); )");
}()); }());
lua.script("val = t:runtime_func(2)"); lua.safe_script("val = t:runtime_func(2)");
val = lua["val"]; val = lua["val"];
REQUIRE(val == 3); REQUIRE(val == 3);
} }
@ -1670,7 +1555,7 @@ end
"v", &thing::v "v", &thing::v
); );
lua.script(R"( lua.safe_script(R"(
t = thing.new() t = thing.new()
)"); )");
@ -1692,19 +1577,19 @@ end
REQUIRE_FALSE(result.valid()); REQUIRE_FALSE(result.valid());
}; };
lua.script("val = t:func(2)"); lua.safe_script("val = t:func(2)");
val = lua["val"]; val = lua["val"];
REQUIRE(val == 2); REQUIRE(val == 2);
REQUIRE_NOTHROW([&lua]() { REQUIRE_NOTHROW([&lua]() {
lua.script(R"( lua.safe_script(R"(
function thing:runtime_func(a) function thing:runtime_func(a)
return a + 1 return a + 1
end end
)"); )");
}()); }());
lua.script("val = t:runtime_func(2)"); lua.safe_script("val = t:runtime_func(2)");
val = lua["val"]; val = lua["val"];
REQUIRE(val == 3); REQUIRE(val == 3);
} }
@ -1722,13 +1607,13 @@ TEST_CASE("usertype/runtime-replacement", "ensure that functions can be properly
lua.new_usertype<heart_t>("a"); lua.new_usertype<heart_t>("a");
REQUIRE_NOTHROW([&lua]() { REQUIRE_NOTHROW([&lua]() {
lua.script("obj = a.new()"); lua.safe_script("obj = a.new()");
lua.script("function a:heartbeat () print('arf') return 1 end"); lua.safe_script("function a:heartbeat () print('arf') return 1 end");
lua.script("v1 = obj:heartbeat()"); lua.safe_script("v1 = obj:heartbeat()");
lua.script("function a:heartbeat () print('bark') return 2 end"); lua.safe_script("function a:heartbeat () print('bark') return 2 end");
lua.script("v2 = obj:heartbeat()"); lua.safe_script("v2 = obj:heartbeat()");
lua.script("a.heartbeat = function(self) print('woof') return 3 end"); lua.safe_script("a.heartbeat = function(self) print('woof') return 3 end");
lua.script("v3 = obj:heartbeat()"); lua.safe_script("v3 = obj:heartbeat()");
}()); }());
int v1 = lua["v1"]; int v1 = lua["v1"];
int v2 = lua["v2"]; int v2 = lua["v2"];
@ -1746,13 +1631,13 @@ TEST_CASE("usertype/runtime-replacement", "ensure that functions can be properly
); );
REQUIRE_NOTHROW([&lua]() { REQUIRE_NOTHROW([&lua]() {
lua.script("obj = a.new()"); lua.safe_script("obj = a.new()");
lua.script("function a:heartbeat () print('arf') return 1 end"); lua.safe_script("function a:heartbeat () print('arf') return 1 end");
lua.script("v1 = obj:heartbeat()"); lua.safe_script("v1 = obj:heartbeat()");
lua.script("function a:heartbeat () print('bark') return 2 end"); lua.safe_script("function a:heartbeat () print('bark') return 2 end");
lua.script("v2 = obj:heartbeat()"); lua.safe_script("v2 = obj:heartbeat()");
lua.script("a.heartbeat = function(self) print('woof') return 3 end"); lua.safe_script("a.heartbeat = function(self) print('woof') return 3 end");
lua.script("v3 = obj:heartbeat()"); lua.safe_script("v3 = obj:heartbeat()");
}()); }());
int v1 = lua["v1"]; int v1 = lua["v1"];
int v2 = lua["v2"]; int v2 = lua["v2"];
@ -1771,13 +1656,13 @@ TEST_CASE("usertype/runtime-replacement", "ensure that functions can be properly
); );
REQUIRE_NOTHROW([&lua]() { REQUIRE_NOTHROW([&lua]() {
lua.script("obj = a.new()"); lua.safe_script("obj = a.new()");
lua.script("function a:heartbeat () print('arf') return 1 end"); lua.safe_script("function a:heartbeat () print('arf') return 1 end");
lua.script("v1 = obj:heartbeat()"); lua.safe_script("v1 = obj:heartbeat()");
lua.script("function a:heartbeat () print('bark') return 2 end"); lua.safe_script("function a:heartbeat () print('bark') return 2 end");
lua.script("v2 = obj:heartbeat()"); lua.safe_script("v2 = obj:heartbeat()");
lua.script("a.heartbeat = function(self) print('woof') return 3 end"); lua.safe_script("a.heartbeat = function(self) print('woof') return 3 end");
lua.script("v3 = obj:heartbeat()"); lua.safe_script("v3 = obj:heartbeat()");
}()); }());
int v1 = lua["v1"]; int v1 = lua["v1"];
int v2 = lua["v2"]; int v2 = lua["v2"];
@ -1808,11 +1693,11 @@ TEST_CASE("usertype/meta-key-retrievals", "allow for special meta keys (__index,
lua["var"] = s; lua["var"] = s;
lua.script("var = sample.new()"); lua.safe_script("var = sample.new()");
lua.script("var.key = 2"); lua.safe_script("var.key = 2");
lua.script("var.__newindex = 4"); lua.safe_script("var.__newindex = 4");
lua.script("var.__index = 3"); lua.safe_script("var.__index = 3");
lua.script("var.__call = 1"); lua.safe_script("var.__call = 1");
REQUIRE(values[0] == 2); REQUIRE(values[0] == 2);
REQUIRE(values[1] == 4); REQUIRE(values[1] == 4);
REQUIRE(values[2] == 3); REQUIRE(values[2] == 3);
@ -1838,11 +1723,11 @@ TEST_CASE("usertype/meta-key-retrievals", "allow for special meta keys (__index,
sol::state lua; sol::state lua;
lua.new_usertype<sample>("sample", sol::meta_function::new_index, &sample::foo); lua.new_usertype<sample>("sample", sol::meta_function::new_index, &sample::foo);
lua.script("var = sample.new()"); lua.safe_script("var = sample.new()");
lua.script("var.key = 2"); lua.safe_script("var.key = 2");
lua.script("var.__newindex = 4"); lua.safe_script("var.__newindex = 4");
lua.script("var.__index = 3"); lua.safe_script("var.__index = 3");
lua.script("var.__call = 1"); lua.safe_script("var.__call = 1");
REQUIRE(values[0] == 2); REQUIRE(values[0] == 2);
REQUIRE(values[1] == 4); REQUIRE(values[1] == 4);
REQUIRE(values[2] == 3); REQUIRE(values[2] == 3);
@ -1871,9 +1756,9 @@ TEST_CASE("usertype/noexcept-methods", "make sure noexcept functinos and methods
"nm", &T::noexcept_method "nm", &T::noexcept_method
); );
lua.script("t = T.new()"); lua.safe_script("t = T.new()");
lua.script("v1 = t.nf()"); lua.safe_script("v1 = t.nf()");
lua.script("v2 = t:nm()"); lua.safe_script("v2 = t:nm()");
int v1 = lua["v1"]; int v1 = lua["v1"];
int v2 = lua["v2"]; int v2 = lua["v2"];
REQUIRE(v1 == 0x61); REQUIRE(v1 == 0x61);

View File

@ -52,8 +52,8 @@ TEST_CASE("utility/variant", "test that variant can be round-tripped") {
}); });
lua["v"] = std::variant<float, int, std::string>(2); lua["v"] = std::variant<float, int, std::string>(2);
REQUIRE_NOTHROW([&]() { REQUIRE_NOTHROW([&]() {
lua.script("assert(f(v))"); lua.safe_script("assert(f(v))");
lua.script("assert(g(v))"); lua.safe_script("assert(g(v))");
}()); }());
} }
SECTION("throws") { SECTION("throws") {
@ -93,7 +93,7 @@ TEST_CASE("utility/string_view", "test that string_view can be taken as an argum
lua["v"] = "bark!"; lua["v"] = "bark!";
REQUIRE_NOTHROW([&]() { REQUIRE_NOTHROW([&]() {
lua.script("assert(f(v))"); lua.safe_script("assert(f(v))");
}()); }());
#else #else
REQUIRE(true); REQUIRE(true);
@ -148,9 +148,9 @@ TEST_CASE("utility/this_state", "Ensure this_state argument can be gotten anywhe
int a = fx(25, 25); int a = fx(25, 25);
INFO("finished setting fx"); INFO("finished setting fx");
INFO("calling a script"); INFO("calling a script");
lua.script("a = with_state_2(25, 25)"); lua.safe_script("a = with_state_2(25, 25)");
INFO("calling c script"); INFO("calling c script");
lua.script("c = b:with_state(25, 25)"); lua.safe_script("c = b:with_state(25, 25)");
INFO("getting a"); INFO("getting a");
int la = lua["a"]; int la = lua["a"];
INFO("getting b"); INFO("getting b");

View File

@ -25,9 +25,9 @@ TEST_CASE("variadics/variadic_args", "Check to see we can receive multiple argum
return{ r, r > 200 }; return{ r, r > 200 };
}); });
lua.script("x = v(25, 25)"); lua.safe_script("x = v(25, 25)");
lua.script("x2 = v(25, 25, 100, 50, 250, 150)"); lua.safe_script("x2 = v(25, 25, 100, 50, 250, 150)");
lua.script("x3 = v(1, 2, 3, 4, 5, 6)"); lua.safe_script("x3 = v(1, 2, 3, 4, 5, 6)");
structure& lx = lua["x"]; structure& lx = lua["x"];
structure& lx2 = lua["x2"]; structure& lx2 = lua["x2"];
@ -46,8 +46,8 @@ TEST_CASE("variadics/required with variadic_args", "Check if a certain number of
[](sol::this_state, sol::variadic_args, int, int) { [](sol::this_state, sol::variadic_args, int, int) {
} }
); );
REQUIRE_NOTHROW(lua.script("v(20, 25, 30)")); REQUIRE_NOTHROW(lua.safe_script("v(20, 25, 30)"));
REQUIRE_NOTHROW(lua.script("v(20, 25)")); REQUIRE_NOTHROW(lua.safe_script("v(20, 25)"));
auto result = lua.safe_script("v(20)", sol::script_pass_on_error); auto result = lua.safe_script("v(20)", sol::script_pass_on_error);
REQUIRE_FALSE(result.valid()); REQUIRE_FALSE(result.valid());
} }
@ -72,8 +72,8 @@ TEST_CASE("variadics/variadic_args get type", "Make sure we can inspect types pr
REQUIRE(working); REQUIRE(working);
}); });
lua.script("f(1, 'bark', true)"); lua.safe_script("f(1, 'bark', true)");
lua.script("f(2, 'wuf', false)"); lua.safe_script("f(2, 'wuf', false)");
} }
TEST_CASE("variadics/variadic_results", "returning a variable amount of arguments from C++") { TEST_CASE("variadics/variadic_results", "returning a variable amount of arguments from C++") {
@ -90,7 +90,7 @@ TEST_CASE("variadics/variadic_results", "returning a variable amount of argument
}); });
REQUIRE_NOTHROW([&]() { REQUIRE_NOTHROW([&]() {
lua.script(R"( lua.safe_script(R"(
v1, v2, v3 = f() v1, v2, v3 = f()
v4, v5 = g() v4, v5 = g()
)"); )");
@ -116,7 +116,7 @@ TEST_CASE("variadics/variadic_results", "returning a variable amount of argument
}); });
REQUIRE_NOTHROW([&]() { REQUIRE_NOTHROW([&]() {
lua.script(R"( lua.safe_script(R"(
v1, v2, v3 = f(1, 'bark', true) v1, v2, v3 = f(1, 'bark', true)
v4, v5 = f(25, 82) v4, v5 = f(25, 82)
)"); )");
@ -156,7 +156,7 @@ TEST_CASE("variadics/variadic_results", "returning a variable amount of argument
}); });
REQUIRE_NOTHROW([&]() { REQUIRE_NOTHROW([&]() {
lua.script(R"( lua.safe_script(R"(
v1, v2, v3 = f(true) v1, v2, v3 = f(true)
v4, v5, v6, v7 = f(false) v4, v5, v6, v7 = f(false)
)"); )");
@ -208,10 +208,10 @@ TEST_CASE("variadics/fallback_constructor", "ensure constructor matching behaves
); );
REQUIRE_NOTHROW([&]() { REQUIRE_NOTHROW([&]() {
lua.script("v0 = vec2();"); lua.safe_script("v0 = vec2();");
lua.script("v1 = vec2(1);"); lua.safe_script("v1 = vec2(1);");
lua.script("v2 = vec2(1, 2);"); lua.safe_script("v2 = vec2(1, 2);");
lua.script("v3 = vec2(v2)"); lua.safe_script("v3 = vec2(v2)");
}()); }());
vec2& v0 = lua["v0"]; vec2& v0 = lua["v0"];

View File

@ -77,40 +77,40 @@ TEST_CASE("simple/set", "Check if the set works properly.") {
test_stack_guard g(lua.lua_state(), begintop, endtop); test_stack_guard g(lua.lua_state(), begintop, endtop);
lua.set("a", 9); lua.set("a", 9);
} REQUIRE(begintop == endtop); } REQUIRE(begintop == endtop);
REQUIRE_NOTHROW(lua.script("if a ~= 9 then error('wrong value') end")); REQUIRE_NOTHROW(lua.safe_script("if a ~= 9 then error('wrong value') end"));
{ {
test_stack_guard g(lua.lua_state(), begintop, endtop); test_stack_guard g(lua.lua_state(), begintop, endtop);
lua.set("d", "hello"); lua.set("d", "hello");
} REQUIRE(begintop == endtop); } REQUIRE(begintop == endtop);
REQUIRE_NOTHROW(lua.script("if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end")); REQUIRE_NOTHROW(lua.safe_script("if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end"));
{ {
test_stack_guard g(lua.lua_state(), begintop, endtop); test_stack_guard g(lua.lua_state(), begintop, endtop);
lua.set("e", std::string("hello"), "f", true); lua.set("e", std::string("hello"), "f", true);
} REQUIRE(begintop == endtop); } REQUIRE(begintop == endtop);
REQUIRE_NOTHROW(lua.script("if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end")); REQUIRE_NOTHROW(lua.safe_script("if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end"));
REQUIRE_NOTHROW(lua.script("if f ~= true then error('wrong value') end")); REQUIRE_NOTHROW(lua.safe_script("if f ~= true then error('wrong value') end"));
} }
TEST_CASE("simple/get", "Tests if the get function works properly.") { TEST_CASE("simple/get", "Tests if the get function works properly.") {
sol::state lua; sol::state lua;
int begintop = 0, endtop = 0; int begintop = 0, endtop = 0;
lua.script("a = 9"); lua.safe_script("a = 9");
{ {
test_stack_guard g(lua.lua_state(), begintop, endtop); test_stack_guard g(lua.lua_state(), begintop, endtop);
auto a = lua.get<int>("a"); auto a = lua.get<int>("a");
REQUIRE(a == 9.0); REQUIRE(a == 9.0);
} REQUIRE(begintop == endtop); } REQUIRE(begintop == endtop);
lua.script("b = nil"); lua.safe_script("b = nil");
{ {
test_stack_guard g(lua.lua_state(), begintop, endtop); test_stack_guard g(lua.lua_state(), begintop, endtop);
REQUIRE_NOTHROW(lua.get<sol::nil_t>("b")); REQUIRE_NOTHROW(lua.get<sol::nil_t>("b"));
} REQUIRE(begintop == endtop); } REQUIRE(begintop == endtop);
lua.script("d = 'hello'"); lua.safe_script("d = 'hello'");
lua.script("e = true"); lua.safe_script("e = true");
{ {
test_stack_guard g(lua.lua_state(), begintop, endtop); test_stack_guard g(lua.lua_state(), begintop, endtop);
std::string d; std::string d;
@ -124,7 +124,7 @@ TEST_CASE("simple/get", "Tests if the get function works properly.") {
TEST_CASE("simple/set and get global integer", "Tests if the get function works properly with global integers") { TEST_CASE("simple/set and get global integer", "Tests if the get function works properly with global integers") {
sol::state lua; sol::state lua;
lua[1] = 25.4; lua[1] = 25.4;
lua.script("b = 1"); lua.safe_script("b = 1");
double a = lua.get<double>(1); double a = lua.get<double>(1);
double b = lua.get<double>("b"); double b = lua.get<double>("b");
REQUIRE(a == 25.4); REQUIRE(a == 25.4);
@ -169,7 +169,7 @@ TEST_CASE("simple/addition", "check if addition works and can be gotten through
sol::state lua; sol::state lua;
lua.set("b", 0.2); lua.set("b", 0.2);
lua.script("c = 9 + b"); lua.safe_script("c = 9 + b");
auto c = lua.get<double>("c"); auto c = lua.get<double>("c");
REQUIRE(c == 9.2); REQUIRE(c == 9.2);
@ -179,7 +179,7 @@ TEST_CASE("simple/if", "check if if statements work through lua") {
sol::state lua; sol::state lua;
std::string program = "if true then f = 0.1 else f = 'test' end"; std::string program = "if true then f = 0.1 else f = 'test' end";
lua.script(program); lua.safe_script(program);
auto f = lua.get<double>("f"); auto f = lua.get<double>("f");
REQUIRE(f == 0.1); REQUIRE(f == 0.1);
@ -223,7 +223,7 @@ TEST_CASE("interop/null-to-nil-and-back", "nil should be the given type when a p
lua.set_function("rofl", [](int* x) { lua.set_function("rofl", [](int* x) {
INFO(x); INFO(x);
}); });
REQUIRE_NOTHROW(lua.script("x = lol()\n" REQUIRE_NOTHROW(lua.safe_script("x = lol()\n"
"rofl(x)\n" "rofl(x)\n"
"assert(x == nil)")); "assert(x == nil)"));
} }
@ -234,7 +234,7 @@ TEST_CASE("object/conversions", "make sure all basic reference types can be made
struct d {}; struct d {};
lua.script("function f () print('bark') end"); lua.safe_script("function f () print('bark') end");
lua["d"] = d{}; lua["d"] = d{};
lua["l"] = static_cast<void*>(nullptr); lua["l"] = static_cast<void*>(nullptr);
@ -317,7 +317,7 @@ TEST_CASE("feature/indexing overrides", "make sure index functions can be overri
, "props", sol::property(&DynamicObject::get_dynamic_props) , "props", sol::property(&DynamicObject::get_dynamic_props)
); );
lua.script(R"__( lua.safe_script(R"__(
obj = DynamicObject:new() obj = DynamicObject:new()
obj.props.name = 'test name' obj.props.name = 'test name'
print('name = ' .. obj.props.name) print('name = ' .. obj.props.name)
@ -356,7 +356,7 @@ TEST_CASE("features/indexing numbers", "make sure indexing functions can be over
lua.new_usertype<vector>("vector", sol::constructors<sol::types<>>(), lua.new_usertype<vector>("vector", sol::constructors<sol::types<>>(),
sol::meta_function::index, &vector::my_index, sol::meta_function::index, &vector::my_index,
sol::meta_function::new_index, &vector::my_new_index); sol::meta_function::new_index, &vector::my_new_index);
lua.script("v = vector.new()\n" lua.safe_script("v = vector.new()\n"
"print(v[1])\n" "print(v[1])\n"
"v[2] = 3\n" "v[2] = 3\n"
"print(v[2])\n" "print(v[2])\n"
@ -403,7 +403,7 @@ TEST_CASE("features/multiple inheritance", "Ensure that multiple inheritance wor
"a2", &complex::a2, "a2", &complex::a2,
sol::base_classes, sol::bases<base1, base2>() sol::base_classes, sol::bases<base1, base2>()
); );
lua.script("c = complex.new()\n" lua.safe_script("c = complex.new()\n"
"s = simple.new()\n" "s = simple.new()\n"
"b1 = base1.new()\n" "b1 = base1.new()\n"
"b2 = base1.new()\n" "b2 = base1.new()\n"
@ -455,7 +455,7 @@ TEST_CASE("optional/left out args", "Make sure arguments can be left out of opti
// sol::optional needs an argument no matter what? // sol::optional needs an argument no matter what?
lua.set_function("func_opt_ret_bool", func_opt_ret_bool); lua.set_function("func_opt_ret_bool", func_opt_ret_bool);
REQUIRE_NOTHROW([&]{ REQUIRE_NOTHROW([&]{
lua.script(R"( lua.safe_script(R"(
func_opt_ret_bool(42) func_opt_ret_bool(42)
func_opt_ret_bool() func_opt_ret_bool()
print('ok') print('ok')
@ -496,7 +496,7 @@ TEST_CASE("proxy/proper-pushing", "allow proxies to reference other proxies and
T t; T t;
lua["t1"] = &t; lua["t1"] = &t;
lua["t2"] = lua["t1"]; lua["t2"] = lua["t1"];
lua.script("b = t1 == t2"); lua.safe_script("b = t1 == t2");
bool b = lua["b"]; bool b = lua["b"];
REQUIRE(b); REQUIRE(b);
} }
@ -563,7 +563,7 @@ TEST_CASE("object/is", "test whether or not the is abstraction works properly fo
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.set_function("is_thing", [](sol::stack_object obj) { return obj.is<thing>(); } ); lua.set_function("is_thing", [](sol::stack_object obj) { return obj.is<thing>(); } );
lua["a"] = thing{}; lua["a"] = thing{};
REQUIRE_NOTHROW(lua.script("assert(is_thing(a))")); REQUIRE_NOTHROW(lua.safe_script("assert(is_thing(a))"));
} }
SECTION("object") SECTION("object")
@ -572,6 +572,6 @@ TEST_CASE("object/is", "test whether or not the is abstraction works properly fo
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.set_function("is_thing", [](sol::object obj) { return obj.is<thing>(); }); lua.set_function("is_thing", [](sol::object obj) { return obj.is<thing>(); });
lua["a"] = thing{}; lua["a"] = thing{};
REQUIRE_NOTHROW(lua.script("assert(is_thing(a))")); REQUIRE_NOTHROW(lua.safe_script("assert(is_thing(a))"));
} }
} }