From 0c9d567d0a0739183eecf9ea1855b7128bbe949e Mon Sep 17 00:00:00 2001 From: ThePhD Date: Mon, 21 Aug 2017 15:25:43 -0400 Subject: [PATCH] "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 --- docs/source/api/state.rst | 1 + docs/source/safety.rst | 9 +- single/sol/sol.hpp | 1596 ++++++++++++++++---------- sol/call.hpp | 225 ++-- sol/container_usertype_metatable.hpp | 2 +- sol/demangle.hpp | 4 +- sol/filters.hpp | 86 ++ sol/forward.hpp | 5 +- sol/forward_detail.hpp | 54 + sol/function_types.hpp | 24 +- sol/proxy.hpp | 13 + sol/raii.hpp | 3 +- sol/reference.hpp | 12 +- sol/simple_usertype_metatable.hpp | 76 +- sol/stack.hpp | 23 +- sol/stack_check.hpp | 47 +- sol/stack_check_get.hpp | 2 +- sol/stack_core.hpp | 31 +- sol/stack_get.hpp | 2 +- sol/stack_push.hpp | 53 +- sol/state.hpp | 5 +- sol/state_view.hpp | 6 +- sol/table_core.hpp | 2 +- sol/traits.hpp | 53 +- sol/types.hpp | 53 + sol/unsafe_function.hpp | 2 +- sol/userdata.hpp | 4 +- sol/usertype.hpp | 14 +- sol/usertype_core.hpp | 235 ++++ sol/usertype_metatable.hpp | 149 +-- test_container_semantics.cpp | 186 +-- test_containers.cpp | 126 +- test_coroutines.cpp | 4 +- test_customizations.cpp | 2 +- test_environments.cpp | 33 +- test_filters.cpp | 236 ++++ test_functions.cpp | 328 ++---- test_gc.cpp | 504 ++++++++ test_inheritance.cpp | 26 +- test_large_integer.cpp | 32 +- test_operators.cpp | 273 ++++- test_overflow.cpp | 4 +- test_plain_types.cpp | 72 ++ test_simple_usertypes.cpp | 296 ++--- test_state.cpp | 32 +- test_tables.cpp | 20 +- test_usertypes.cpp | 347 ++---- test_utility.cpp | 10 +- test_variadics.cpp | 28 +- tests.cpp | 40 +- 50 files changed, 3534 insertions(+), 1856 deletions(-) create mode 100644 sol/filters.hpp create mode 100644 sol/forward_detail.hpp create mode 100644 sol/usertype_core.hpp create mode 100644 test_filters.cpp create mode 100644 test_gc.cpp create mode 100644 test_plain_types.cpp diff --git a/docs/source/api/state.rst b/docs/source/api/state.rst index eafac326..be50cc5f 100644 --- a/docs/source/api/state.rst +++ b/docs/source/api/state.rst @@ -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(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); 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`, creating a new state, or other Lua sandboxing techniques. diff --git a/docs/source/safety.rst b/docs/source/safety.rst index 56bdfb06..83073c16 100644 --- a/docs/source/safety.rst +++ b/docs/source/safety.rst @@ -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: * 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::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 diff --git a/single/sol/sol.hpp b/single/sol/sol.hpp index 26a769ac..15b6a5f5 100644 --- a/single/sol/sol.hpp +++ b/single/sol/sol.hpp @@ -20,8 +20,8 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // This file was generated with a script. -// Generated 2017-08-14 13:59:52.716584 UTC -// This header was generated with sol v2.18.0 (revision 9b1c70c) +// Generated 2017-08-21 19:22:41.597215 UTC +// This header was generated with sol v2.18.0 (revision 488edd9) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -235,7 +235,10 @@ namespace sol { struct user; template struct as_args_t; - + template + struct protect_t; + template + struct filter_wrapper; } // sol // end of sol/forward.hpp @@ -1094,7 +1097,7 @@ namespace sol { using no = struct { char s[2]; }; struct F { void operator()(); }; - struct Derived : T, F {}; + struct Derived : T, F { ~Derived() = delete; }; template struct Check; template @@ -1215,6 +1218,35 @@ namespace sol { static const bool value = sizeof(test(0)) == sizeof(char); }; + template + struct has_to_string_test { + private: + typedef std::array one; + typedef std::array two; + + template static one test(decltype(std::declval().to_string())*); + template static two test(...); + + public: + static const bool value = sizeof(test(0)) == sizeof(char); + }; +#if defined(_MSC_VER) && _MSC_VER <= 1910 + template () < std::declval())> + std::true_type supports_op_less_test(std::reference_wrapper, std::reference_wrapper); + std::false_type supports_op_less_test(...); + template () == std::declval())> + std::true_type supports_op_equal_test(std::reference_wrapper, std::reference_wrapper); + std::false_type supports_op_equal_test(...); + template () <= std::declval())> + std::true_type supports_op_less_equal_test(std::reference_wrapper, std::reference_wrapper); + std::false_type supports_op_less_equal_test(...); + template () << std::declval())> + std::true_type supports_ostream_op(std::reference_wrapper, std::reference_wrapper); + std::false_type supports_ostream_op(...); + template ()))> + std::true_type supports_adl_to_string(std::reference_wrapper); + std::false_type supports_adl_to_string(...); +#else template () < std::declval())> std::true_type supports_op_less_test(const T&, const U&); std::false_type supports_op_less_test(...); @@ -1227,9 +1259,24 @@ namespace sol { template () << std::declval())> std::true_type supports_ostream_op(const T&, const OS&); std::false_type supports_ostream_op(...); - + template ()))> + std::true_type supports_adl_to_string(const T&); + std::false_type supports_adl_to_string(...); +#endif } // meta_detail +#if defined(_MSC_VER) && _MSC_VER <= 1910 + template + using supports_op_less = decltype(meta_detail::supports_op_less_test(std::ref(std::declval()), std::ref(std::declval()))); + template + using supports_op_equal = decltype(meta_detail::supports_op_equal_test(std::ref(std::declval()), std::ref(std::declval()))); + template + using supports_op_less_equal = decltype(meta_detail::supports_op_less_equal_test(std::ref(std::declval()), std::ref(std::declval()))); + template + using supports_ostream_op = decltype(meta_detail::supports_ostream_op(std::ref(std::declval()), std::ref(std::declval()))); + template + using supports_adl_to_string = decltype(meta_detail::supports_adl_to_string(std::ref(std::declval()))); +#else template using supports_op_less = decltype(meta_detail::supports_op_less_test(std::declval(), std::declval())); template @@ -1238,6 +1285,11 @@ namespace sol { using supports_op_less_equal = decltype(meta_detail::supports_op_less_equal_test(std::declval(), std::declval())); template using supports_ostream_op = decltype(meta_detail::supports_ostream_op(std::declval(), std::declval())); + template + using supports_adl_to_string = decltype(meta_detail::supports_adl_to_string(std::declval())); +#endif + template + using supports_to_string_member = meta::boolean::value>; template struct is_callable : boolean::value> {}; @@ -3582,6 +3634,35 @@ namespace sol { // end of sol/optional.hpp +// beginning of sol/forward_detail.hpp + +namespace sol { + namespace meta { + namespace meta_detail { + + } // meta_detail + } // meta + + namespace stack { + namespace stack_detail { + template + struct undefined_metatable; + } // stack_detail + } // stack + + namespace usertype_detail { + template + void insert_default_registrations(Regs& l, int& index, Fx&& fx); + + template >, std::is_destructible> = meta::enabler> + void make_destructor(Regs& l, int& index); + template >, std::is_destructible> = meta::enabler> + void make_destructor(Regs& l, int& index); + } // usertype_detail +} // sol + +// end of sol/forward_detail.hpp + // beginning of sol/string_shim.hpp #ifdef SOL_CXX17_FEATURES @@ -3667,7 +3748,178 @@ namespace sol { // end of sol/string_shim.hpp +// beginning of sol/raii.hpp + +namespace sol { + namespace detail { + struct default_construct { + template + static void construct(T&& obj, Args&&... args) { + std::allocator> alloc{}; + alloc.construct(obj, std::forward(args)...); + } + + template + void operator()(T&& obj, Args&&... args) const { + construct(std::forward(obj), std::forward(args)...); + } + }; + + struct default_destruct { + template + static void destroy(T&& obj) { + std::allocator> alloc{}; + alloc.destroy(obj); + } + + template + void operator()(T&& obj) const { + destroy(std::forward(obj)); + } + }; + + struct deleter { + template + void operator()(T* p) const { + delete p; + } + }; + + template + inline std::unique_ptr make_unique_deleter(Args&&... args) { + return std::unique_ptr(new T(std::forward(args)...)); + } + + template + struct tagged { + T value; + template , tagged>> = meta::enabler> + tagged(Arg&& arg, Args&&... args) : value(std::forward(arg), std::forward(args)...) {} + }; + } // detail + + template + struct constructor_list {}; + + template + using constructors = constructor_list; + + const auto default_constructor = constructors>{}; + + struct no_construction {}; + const auto no_constructor = no_construction{}; + + struct call_construction {}; + const auto call_constructor = call_construction{}; + + template + struct constructor_wrapper { + std::tuple functions; + template , constructor_wrapper>> = meta::enabler> + constructor_wrapper(Arg&& arg, Args&&... args) : functions(std::forward(arg), std::forward(args)...) {} + }; + + template + inline auto initializers(Functions&&... functions) { + return constructor_wrapper...>(std::forward(functions)...); + } + + template + struct factory_wrapper { + std::tuple functions; + template , factory_wrapper>> = meta::enabler> + factory_wrapper(Arg&& arg, Args&&... args) : functions(std::forward(arg), std::forward(args)...) {} + }; + + template + inline auto factories(Functions&&... functions) { + return factory_wrapper...>(std::forward(functions)...); + } + + template + struct destructor_wrapper { + Function fx; + destructor_wrapper(Function f) : fx(std::move(f)) {} + }; + + template <> + struct destructor_wrapper {}; + + const destructor_wrapper default_destructor{}; + + template + inline auto destructor(Fx&& fx) { + return destructor_wrapper>(std::forward(fx)); + } + +} // sol + +// end of sol/raii.hpp + +// beginning of sol/filters.hpp + #include + +namespace sol { + namespace detail { + struct filter_base_tag {}; + } // detail + + template + struct static_stack_dependencies : detail::filter_base_tag {}; + typedef static_stack_dependencies<-1, 1> self_dependency; + template + 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 stack_indices; + std::size_t len; + + template + 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(std::forward(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 + struct filter_wrapper { + typedef std::make_integer_sequence indices; + + F value; + std::tuple filters; + + template , filter_wrapper>>> = meta::enabler> + filter_wrapper(Fx&& fx, Args&&... args) : value(std::forward(fx)), filters(std::forward(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 + auto filters(F&& f, Args&&... args) { + return filter_wrapper, std::decay_t...>( std::forward(f), std::forward(args)... ); + } +} // sol + +// end of sol/filters.hpp + #ifdef SOL_CXX17_FEATURES #include #endif // C++17 @@ -4677,6 +4929,13 @@ namespace sol { template <> struct is_lua_index : std::true_type {}; + template + struct is_stack_based : std::is_base_of {}; + template <> + struct is_stack_based : std::true_type {}; + template <> + struct is_stack_based : std::true_type {}; + template struct lua_bind_traits : meta::bind_traits { private: @@ -4718,6 +4977,48 @@ namespace sol { inline type type_of() { return lua_type_of>::value; } + + namespace detail { + template + struct is_non_factory_constructor : std::false_type {}; + + template + struct is_non_factory_constructor> : std::true_type {}; + + template + struct is_non_factory_constructor> : std::true_type {}; + + template <> + struct is_non_factory_constructor : std::true_type {}; + + template + struct is_constructor : is_non_factory_constructor {}; + + template + struct is_constructor> : std::true_type {}; + + template + struct is_constructor> : is_constructor> {}; + + template + struct is_constructor> : is_constructor> {}; + + template + using has_constructor = meta::any>...>; + + template + struct is_destructor : std::false_type {}; + + template + struct is_destructor> : std::true_type {}; + + template + using has_destructor = meta::any>...>; + + struct add_destructor_tag {}; + struct check_destructor_tag {}; + struct verified_tag {} const verified{}; + } // detail } // sol // end of sol/types.hpp @@ -4860,17 +5161,23 @@ namespace sol { struct push_popper_n { push_popper_n(lua_State*, int) { } }; - template + template struct push_popper { T t; push_popper(T x) : t(x) { t.push(); } ~push_popper() { t.pop(); } }; - template - struct push_popper { + template + struct push_popper { push_popper(T) {} ~push_popper() {} }; + template + struct push_popper>::value>> { + push_popper(T) {} + ~push_popper() {} + }; + template push_popper push_pop(T&& x) { return push_popper(std::forward(x)); @@ -5155,8 +5462,152 @@ namespace sol { // end of sol/stack_guard.hpp +// beginning of sol/demangle.hpp + +#include +#if defined(__GNUC__) && defined(__MINGW32__) && (__GNUC__ < 6) +extern "C" { +#include +} +#endif // MinGW is on some stuff +#include + +namespace sol { + namespace detail { +#if defined(__GNUC__) || defined(__clang__) + template + inline std::string ctti_get_type_name() { + // cardinal sins from MINGW + using namespace std; + const static std::array removals = { { "{anonymous}", "(anonymous namespace)" } }; + std::string name = __PRETTY_FUNCTION__; + std::size_t start = name.find_first_of('['); + start = name.find_first_of('=', start); + std::size_t end = name.find_last_of(']'); + if (end == std::string::npos) + end = name.size(); + if (start == std::string::npos) + start = 0; + if (start < name.size() - 1) + start += 1; + name = name.substr(start, end - start); + start = name.rfind("seperator_mark"); + if (start != std::string::npos) { + name.erase(start - 2, name.length()); + } + while (!name.empty() && isblank(name.front())) name.erase(name.begin()); + while (!name.empty() && isblank(name.back())) name.pop_back(); + + for (std::size_t r = 0; r < removals.size(); ++r) { + auto found = name.find(removals[r]); + while (found != std::string::npos) { + name.erase(found, removals[r].size()); + found = name.find(removals[r]); + } + } + + return name; + } +#elif defined(_MSC_VER) + template + inline std::string ctti_get_type_name() { + const static std::array removals = { { "public:", "private:", "protected:", "struct ", "class ", "`anonymous-namespace'", "`anonymous namespace'" } }; + std::string name = __FUNCSIG__; + std::size_t start = name.find("get_type_name"); + if (start == std::string::npos) + start = 0; + else + start += 13; + if (start < name.size() - 1) + start += 1; + std::size_t end = name.find_last_of('>'); + if (end == std::string::npos) + end = name.size(); + name = name.substr(start, end - start); + if (name.find("struct", 0) == 0) + name.replace(0, 6, "", 0); + if (name.find("class", 0) == 0) + name.replace(0, 5, "", 0); + while (!name.empty() && isblank(name.front())) name.erase(name.begin()); + while (!name.empty() && isblank(name.back())) name.pop_back(); + + for (std::size_t r = 0; r < removals.size(); ++r) { + auto found = name.find(removals[r]); + while (found != std::string::npos) { + name.erase(found, removals[r].size()); + found = name.find(removals[r]); + } + } + + return name; + } +#else +#error Compiler not supported for demangling +#endif // compilers + + template + inline std::string demangle_once() { + std::string realname = ctti_get_type_name(); + return realname; + } + + template + inline std::string short_demangle_once() { + std::string realname = ctti_get_type_name(); + // This isn't the most complete but it'll do for now...? + static const std::array ops = { { "operator<", "operator<<", "operator<<=", "operator<=", "operator>", "operator>>", "operator>>=", "operator>=", "operator->", "operator->*" } }; + int level = 0; + std::ptrdiff_t idx = 0; + for (idx = static_cast(realname.empty() ? 0 : realname.size() - 1); idx > 0; --idx) { + if (level == 0 && realname[idx] == ':') { + break; + } + bool isleft = realname[idx] == '<'; + bool isright = realname[idx] == '>'; + if (!isleft && !isright) + continue; + bool earlybreak = false; + for (const auto& op : ops) { + std::size_t nisop = realname.rfind(op, idx); + if (nisop == std::string::npos) + continue; + std::size_t nisopidx = idx - op.size() + 1; + if (nisop == nisopidx) { + idx = static_cast(nisopidx); + earlybreak = true; + } + break; + } + if (earlybreak) { + continue; + } + level += isleft ? -1 : 1; + } + if (idx > 0) { + realname.erase(0, realname.length() < static_cast(idx) ? realname.length() : idx + 1); + } + return realname; + } + + template + inline const std::string& demangle() { + static const std::string d = demangle_once(); + return d; + } + + template + inline const std::string& short_demangle() { + static const std::string d = short_demangle_once(); + return d; + } + } // detail +} // sol + +// end of sol/demangle.hpp + #include #include +#include namespace sol { namespace detail { @@ -5177,17 +5628,8 @@ namespace sol { return 0; } - template - inline void usertype_unique_alloc_destroy(void* memory) { - T** pointerpointer = static_cast(memory); - unique_destructor* dx = static_cast(static_cast(pointerpointer + 1)); - Real* target = static_cast(static_cast(dx + 1)); - std::allocator alloc; - alloc.destroy(target); - } - template - inline int user_alloc_destroy(lua_State* L) { + inline int user_alloc_destruct(lua_State* L) { void* rawdata = lua_touserdata(L, 1); T* data = static_cast(rawdata); std::allocator alloc; @@ -5196,7 +5638,7 @@ namespace sol { } template - inline int usertype_alloc_destroy(lua_State* L) { + inline int usertype_alloc_destruct(lua_State* L) { void* rawdata = lua_touserdata(L, 1); T** pdata = static_cast(rawdata); T* data = *pdata; @@ -5205,6 +5647,20 @@ namespace sol { return 0; } + template + 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().data()); + } + + template + inline void usertype_unique_alloc_destroy(void* memory) { + T** pointerpointer = static_cast(memory); + unique_destructor* dx = static_cast(static_cast(pointerpointer + 1)); + Real* target = static_cast(static_cast(dx + 1)); + std::allocator alloc; + alloc.destroy(target); + } + template void reserve(T&, std::size_t) {} @@ -5571,149 +6027,6 @@ namespace sol { // beginning of sol/usertype_traits.hpp -// beginning of sol/demangle.hpp - -#include -#if defined(__GNUC__) && defined(__MINGW32__) && (__GNUC__ < 6) -extern "C" { -#include -} -#endif // MinGW is on some stuff -#include - -namespace sol { - namespace detail { -#if defined(__GNUC__) || defined(__clang__) - template - inline std::string ctti_get_type_name() { - // cardinal sins from MINGW - using namespace std; - const static std::array removals = { { "{anonymous}", "(anonymous namespace)" } }; - std::string name = __PRETTY_FUNCTION__; - std::size_t start = name.find_first_of('['); - start = name.find_first_of('=', start); - std::size_t end = name.find_last_of(']'); - if (end == std::string::npos) - end = name.size(); - if (start == std::string::npos) - start = 0; - if (start < name.size() - 1) - start += 1; - name = name.substr(start, end - start); - start = name.rfind("seperator_mark"); - if (start != std::string::npos) { - name.erase(start - 2, name.length()); - } - while (!name.empty() && isblank(name.front())) name.erase(name.begin()); - while (!name.empty() && isblank(name.back())) name.pop_back(); - - for (std::size_t r = 0; r < removals.size(); ++r) { - auto found = name.find(removals[r]); - while (found != std::string::npos) { - name.erase(found, removals[r].size()); - found = name.find(removals[r]); - } - } - - return name; - } -#elif defined(_MSC_VER) - template - inline std::string ctti_get_type_name() { - const static std::array removals = { { "public:", "private:", "protected:", "struct ", "class ", "`anonymous-namespace'", "`anonymous namespace'" } }; - std::string name = __FUNCSIG__; - std::size_t start = name.find("get_type_name"); - if (start == std::string::npos) - start = 0; - else - start += 13; - if (start < name.size() - 1) - start += 1; - std::size_t end = name.find_last_of('>'); - if (end == std::string::npos) - end = name.size(); - name = name.substr(start, end - start); - if (name.find("struct", 0) == 0) - name.replace(0, 6, "", 0); - if (name.find("class", 0) == 0) - name.replace(0, 5, "", 0); - while (!name.empty() && std::isblank(name.front())) name.erase(name.begin()); - while (!name.empty() && std::isblank(name.back())) name.pop_back(); - - for (std::size_t r = 0; r < removals.size(); ++r) { - auto found = name.find(removals[r]); - while (found != std::string::npos) { - name.erase(found, removals[r].size()); - found = name.find(removals[r]); - } - } - - return name; - } -#else -#error Compiler not supported for demangling -#endif // compilers - - template - inline std::string demangle_once() { - std::string realname = ctti_get_type_name(); - return realname; - } - - template - inline std::string short_demangle_once() { - std::string realname = ctti_get_type_name(); - // This isn't the most complete but it'll do for now...? - static const std::array ops = { { "operator<", "operator<<", "operator<<=", "operator<=", "operator>", "operator>>", "operator>>=", "operator>=", "operator->", "operator->*" } }; - int level = 0; - std::ptrdiff_t idx = 0; - for (idx = static_cast(realname.empty() ? 0 : realname.size() - 1); idx > 0; --idx) { - if (level == 0 && realname[idx] == ':') { - break; - } - bool isleft = realname[idx] == '<'; - bool isright = realname[idx] == '>'; - if (!isleft && !isright) - continue; - bool earlybreak = false; - for (const auto& op : ops) { - std::size_t nisop = realname.rfind(op, idx); - if (nisop == std::string::npos) - continue; - std::size_t nisopidx = idx - op.size() + 1; - if (nisop == nisopidx) { - idx = static_cast(nisopidx); - earlybreak = true; - } - break; - } - if (earlybreak) { - continue; - } - level += isleft ? -1 : 1; - } - if (idx > 0) { - realname.erase(0, realname.length() < static_cast(idx) ? realname.length() : idx + 1); - } - return realname; - } - - template - inline const std::string& demangle() { - static const std::string d = demangle_once(); - return d; - } - - template - inline const std::string& short_demangle() { - static const std::string d = short_demangle_once(); - return d; - } - } // detail -} // sol - -// end of sol/demangle.hpp - namespace sol { template @@ -5901,18 +6214,45 @@ namespace sol { static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); #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; } -#endif - int isnum = 0; - const lua_Number v = lua_tonumberx(L, index, &isnum); - const bool success = isnum != 0 && static_cast(std::llround(v)) == v; + const bool success = false; +#endif // If numbers are enabled, use the imprecise check if (!success) { // expected type, actual type handler(L, index, type::number, type_of(L, index)); } 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(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 } }; @@ -5921,12 +6261,22 @@ namespace sol { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 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; if (!success) { // expected type, actual type handler(L, index, type::number, type_of(L, index)); } return success; +#endif } }; @@ -6408,7 +6758,7 @@ namespace sol { return static_cast(lua_tointeger(L, index)); } #endif - return static_cast(std::llround(lua_tonumber(L, index))); + return static_cast(llround(lua_tonumber(L, index))); } }; @@ -7167,7 +7517,7 @@ namespace sol { const lua_Number value = lua_tonumberx(L, index, &isnum); if (isnum != 0) { #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(integer_value) == value) { tracking.use(1); return static_cast(integer_value); @@ -7273,114 +7623,6 @@ namespace sol { // beginning of sol/stack_push.hpp -// beginning of sol/raii.hpp - -namespace sol { - namespace detail { - struct default_construct { - template - static void construct(T&& obj, Args&&... args) { - std::allocator> alloc{}; - alloc.construct(obj, std::forward(args)...); - } - - template - void operator()(T&& obj, Args&&... args) const { - construct(std::forward(obj), std::forward(args)...); - } - }; - - struct default_destruct { - template - static void destroy(T&& obj) { - std::allocator> alloc{}; - alloc.destroy(obj); - } - - template - void operator()(T&& obj) const { - destroy(std::forward(obj)); - } - }; - - struct deleter { - template - void operator()(T* p) const { - delete p; - } - }; - - template - inline std::unique_ptr make_unique_deleter(Args&&... args) { - return std::unique_ptr(new T(std::forward(args)...)); - } - - template - struct tagged { - T value; - template , tagged>> = meta::enabler> - tagged(Arg&& arg, Args&&... args) : value(std::forward(arg), std::forward(args)...) {} - }; - } // detail - - template - struct constructor_list {}; - - template - using constructors = constructor_list; - - const auto default_constructor = constructors>{}; - - struct no_construction {}; - const auto no_constructor = no_construction{}; - - struct call_construction {}; - const auto call_constructor = call_construction{}; - - template - struct constructor_wrapper { - std::tuple functions; - template , constructor_wrapper>> = meta::enabler> - constructor_wrapper(Arg&& arg, Args&&... args) : functions(std::forward(arg), std::forward(args)...) {} - }; - - template - inline auto initializers(Functions&&... functions) { - return constructor_wrapper...>(std::forward(functions)...); - } - - template - struct factory_wrapper { - std::tuple functions; - template , factory_wrapper>> = meta::enabler> - factory_wrapper(Arg&& arg, Args&&... args) : functions(std::forward(arg), std::forward(args)...) {} - }; - - template - inline auto factories(Functions&&... functions) { - return factory_wrapper...>(std::forward(functions)...); - } - - template - struct destructor_wrapper { - Function fx; - destructor_wrapper(Function f) : fx(std::move(f)) {} - }; - - template <> - struct destructor_wrapper {}; - - const destructor_wrapper default_destructor{}; - - template - inline auto destructor(Fx&& fx) { - return destructor_wrapper>(std::forward(fx)); - } - -} // sol - -// end of sol/raii.hpp - #include #include #ifdef SOL_CODECVT_SUPPORT @@ -7432,10 +7674,8 @@ namespace sol { template static int push_keyed(lua_State* L, K&& k, Args&&... args) { - return push_fx(L, [&L, &k]() { - luaL_newmetatable(L, &k[0]); - lua_setmetatable(L, -2); - }, std::forward(args)...); + stack_detail::undefined_metatable fx(L, &k[0]); + return push_fx(L, fx, std::forward(args)...); } template @@ -7446,6 +7686,8 @@ namespace sol { template struct pusher> { + typedef meta::unqualified_t U; + template static int push_fx(lua_State* L, F&& f, T* obj) { if (obj == nullptr) @@ -7458,14 +7700,12 @@ namespace sol { template static int push_keyed(lua_State* L, K&& k, T* obj) { - return push_fx(L, [&L, &k]() { - luaL_newmetatable(L, &k[0]); - lua_setmetatable(L, -2); - }, obj); + stack_detail::undefined_metatable fx(L, &k[0]); + return push_fx(L, fx, obj); } static int push(lua_State* L, T* obj) { - return push_keyed(L, usertype_traits*>::metatable(), obj); + return push_keyed(L, usertype_traits::metatable(), obj); } }; @@ -7520,7 +7760,12 @@ namespace sol { detail::default_construct::construct(mem, std::forward(args)...); *pref = unique_usertype_traits::get(*mem); if (luaL_newmetatable(L, &usertype_traits>::metatable()[0]) == 1) { - set_field(L, "__gc", detail::unique_destruct

); + luaL_Reg l[32]{}; + int index = 0; + auto prop_fx = [](meta_function) { return true; }; + usertype_detail::insert_default_registrations

(l, index, prop_fx); + usertype_detail::make_destructor(l, index); + luaL_setfuncs(L, l, 0); } lua_setmetatable(L, -2); return 1; @@ -7562,7 +7807,7 @@ namespace sol { } #endif #if defined(SOL_CHECK_ARGUMENTS) && !defined(SOL_NO_CHECK_NUMBER_PRECISION) - if (static_cast(std::llround(static_cast(value))) != value) { + if (static_cast(llround(static_cast(value))) != value) { #ifndef SOL_NO_EXCEPTIONS throw sol::error("The integer will be misrepresented in lua."); #else @@ -7786,7 +8031,7 @@ namespace sol { std::allocator alloc; alloc.construct(data, std::forward(args)...); if (with_meta) { - lua_CFunction cdel = detail::user_alloc_destroy; + lua_CFunction cdel = detail::user_alloc_destruct; // Make sure we have a plain GC set for this data if (luaL_newmetatable(L, name) != 0) { lua_pushcclosure(L, cdel, 0); @@ -7910,6 +8155,30 @@ namespace sol { } }; + template <> + struct pusher { + static int push(lua_State* L, absolute_index ai) { + lua_pushvalue(L, ai); + return 1; + } + }; + + template <> + struct pusher { + static int push(lua_State* L, raw_index ri) { + lua_pushvalue(L, ri); + return 1; + } + }; + + template <> + struct pusher { + static int push(lua_State* L, ref_index ri) { + lua_rawgeti(L, LUA_REGISTRYINDEX, ri); + return 1; + } + }; + #ifdef SOL_CODECVT_SUPPORT template<> struct pusher { @@ -8658,34 +8927,41 @@ namespace sol { template ::value>> inline decltype(auto) call_from_top(types tr, types ta, lua_State* L, Fx&& fx, FxArgs&&... args) { - return call(tr, ta, L, static_cast(lua_gettop(L) - sizeof...(Args)), std::forward(fx), std::forward(args)...); + typedef meta::count_for_pack expected_count; + return call(tr, ta, L, (std::max)(static_cast(lua_gettop(L) - expected_count::value), static_cast(0)), std::forward(fx), std::forward(args)...); } template inline void call_from_top(types tr, types ta, lua_State* L, Fx&& fx, FxArgs&&... args) { - call(tr, ta, L, static_cast(lua_gettop(L) - sizeof...(Args)), std::forward(fx), std::forward(args)...); + typedef meta::count_for_pack expected_count; + call(tr, ta, L, (std::max)(static_cast(lua_gettop(L) - expected_count::value), static_cast(0)), std::forward(fx), std::forward(args)...); } - template + template inline int call_into_lua(types tr, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { call(tr, ta, L, start, std::forward(fx), std::forward(fxargs)...); - lua_settop(L, 0); + if (clean_stack) { + lua_settop(L, 0); + } return 0; } - template>::value>> + template>::value>> inline int call_into_lua(types, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { decltype(auto) r = call(types>(), ta, L, start, std::forward(fx), std::forward(fxargs)...); - lua_settop(L, 0); + typedef is_stack_based> is_stack; + if (clean_stack && !is_stack::value) { + lua_settop(L, 0); + } return push_reference(L, std::forward(r)); } - template + template inline int call_lua(lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { typedef lua_bind_traits> traits_type; typedef typename traits_type::args_list args_list; typedef typename traits_type::returns_list returns_list; - return call_into_lua(returns_list(), args_list(), L, start, std::forward(fx), std::forward(fxargs)...); + return call_into_lua(returns_list(), args_list(), L, start, std::forward(fx), std::forward(fxargs)...); } inline call_syntax get_call_syntax(lua_State* L, const std::string& key, int index) { @@ -9302,11 +9578,62 @@ namespace sol { // end of sol/property.hpp namespace sol { + namespace usertype_detail { + + } // usertype_detail + + namespace filter_detail { + template + inline void handle_filter(static_stack_dependencies, 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(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 + inline void handle_filter(returns_self_with, 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(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 >> = meta::enabler> + inline void handle_filter(P&& p, lua_State* L, int& pushed) { + pushed = std::forward

(p)(L, pushed); + } + } // filter_detail + namespace function_detail { inline int no_construction_error(lua_State* L) { return luaL_error(L, "sol: cannot call this constructor (tagged as non-constructible)"); } - } + } // function_detail namespace call_detail { @@ -9328,7 +9655,7 @@ namespace sol { static void call(Args...) {} }; - template + template struct constructor_match { T* obj; @@ -9337,7 +9664,7 @@ namespace sol { template int operator()(types, index_value, types r, types a, lua_State* L, int, int start) const { detail::default_construct func{}; - return stack::call_into_lua(r, a, L, start, func, obj); + return stack::call_into_lua(r, a, L, start, func, obj); } }; @@ -9423,7 +9750,7 @@ namespace sol { return overload_match_arity::call)...>(std::forward(matchfx), L, fxarity, start, std::forward(args)...); } - template + template inline int construct(lua_State* L) { static const auto& meta = usertype_traits::metatable(); int argcount = lua_gettop(L); @@ -9437,7 +9764,7 @@ namespace sol { reference userdataref(L, -1); userdataref.pop(); - construct_match(constructor_match(obj), L, argcount, 1 + static_cast(syntax)); + construct_match(constructor_match(obj), L, argcount, 1 + static_cast(syntax)); userdataref.push(); luaL_getmetatable(L, &meta[0]); @@ -9450,7 +9777,7 @@ namespace sol { return 1; } - template + template struct agnostic_lua_call_wrapper { template static int call(lua_State* L, Fx&& f, Args&&... args) { @@ -9458,23 +9785,30 @@ namespace sol { typedef typename wrap::returns_list returns_list; typedef typename wrap::free_args_list args_list; typedef typename wrap::caller caller; - return stack::call_into_lua(returns_list(), args_list(), L, boost + 1, caller(), std::forward(f), std::forward(args)...); + return stack::call_into_lua(returns_list(), args_list(), L, boost + 1, caller(), std::forward(f), std::forward(args)...); } }; - template - struct agnostic_lua_call_wrapper, true, is_variable, checked, boost, C> { + template + struct agnostic_lua_call_wrapper, true, is_variable, checked, boost, clean_stack, C> { template static int call(lua_State* L, F&& f) { + typedef is_stack_based> is_stack; + if (clean_stack && !is_stack::value) { + lua_settop(L, 0); + } return stack::push_reference(L, detail::unwrap(f.value)); } }; - template - struct agnostic_lua_call_wrapper, false, is_variable, checked, boost, C> { + template + struct agnostic_lua_call_wrapper, false, is_variable, checked, boost, clean_stack, C> { template static int call_assign(std::true_type, lua_State* L, V&& f) { detail::unwrap(f.value) = stack::get>(L, boost + (is_variable ? 3 : 1)); + if (clean_stack) { + lua_settop(L, 0); + } return 0; } @@ -9500,63 +9834,63 @@ namespace sol { } }; - template - struct agnostic_lua_call_wrapper { + template + struct agnostic_lua_call_wrapper { static int call(lua_State* L, lua_r_CFunction f) { return f(L); } }; - template - struct agnostic_lua_call_wrapper { + template + struct agnostic_lua_call_wrapper { static int call(lua_State* L, lua_CFunction f) { return f(L); } }; #ifdef SOL_NOEXCEPT_FUNCTION_TYPE - template - struct agnostic_lua_call_wrapper { + template + struct agnostic_lua_call_wrapper { static int call(lua_State* L, detail::lua_CFunction_noexcept f) { return f(L); } }; #endif // noexcept function types - template - struct agnostic_lua_call_wrapper { + template + struct agnostic_lua_call_wrapper { 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"); } }; - template - struct agnostic_lua_call_wrapper { + template + struct agnostic_lua_call_wrapper { static int call(lua_State* L, const no_construction&) { return function_detail::no_construction_error(L); } }; - template - struct agnostic_lua_call_wrapper, is_index, is_variable, checked, boost, C> { + template + struct agnostic_lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { static int call(lua_State*, const bases&) { // Uh. How did you even call this, lul return 0; } }; - template - struct agnostic_lua_call_wrapper, is_index, is_variable, checked, boost, C> { + template + struct agnostic_lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { static int call(lua_State* L, std::reference_wrapper f) { - return agnostic_lua_call_wrapper{}.call(L, f.get()); + return agnostic_lua_call_wrapper{}.call(L, f.get()); } }; - template - struct lua_call_wrapper : agnostic_lua_call_wrapper {}; + template + struct lua_call_wrapper : agnostic_lua_call_wrapper {}; - template - struct lua_call_wrapper::value>> { + template + struct lua_call_wrapper::value>> { typedef wrapper> wrap; typedef typename wrap::object_type object_type; @@ -9565,7 +9899,7 @@ namespace sol { typedef typename wrap::returns_list returns_list; typedef typename wrap::args_list args_list; typedef typename wrap::caller caller; - return stack::call_into_lua(returns_list(), args_list(), L, boost + ( is_variable ? 3 : 2 ), caller(), std::forward(f), o); + return stack::call_into_lua(returns_list(), args_list(), L, boost + ( is_variable ? 3 : 2 ), caller(), std::forward(f), o); } template @@ -9585,8 +9919,8 @@ namespace sol { } }; - template - struct lua_call_wrapper::value>> { + template + struct lua_call_wrapper::value>> { typedef lua_bind_traits traits_type; typedef wrapper> wrap; typedef typename wrap::object_type object_type; @@ -9595,7 +9929,7 @@ namespace sol { static int call_assign(std::true_type, lua_State* L, V&& f, object_type& o) { typedef typename wrap::args_list args_list; typedef typename wrap::caller caller; - return stack::call_into_lua(types(), args_list(), L, boost + ( is_variable ? 3 : 2 ), caller(), f, o); + return stack::call_into_lua(types(), args_list(), L, boost + ( is_variable ? 3 : 2 ), caller(), f, o); } template @@ -9644,8 +9978,8 @@ namespace sol { } }; - template - struct lua_call_wrapper::value>> { + template + struct lua_call_wrapper::value>> { typedef lua_bind_traits traits_type; typedef wrapper> wrap; typedef typename wrap::object_type object_type; @@ -9655,7 +9989,7 @@ namespace sol { typedef typename wrap::returns_list returns_list; typedef typename wrap::caller caller; F f(std::forward(v)); - return stack::call_into_lua(returns_list(), types<>(), L, boost + ( is_variable ? 3 : 2 ), caller(), f, o); + return stack::call_into_lua(returns_list(), types<>(), L, boost + ( is_variable ? 3 : 2 ), caller(), f, o); } template @@ -9678,8 +10012,8 @@ namespace sol { } }; - template - struct lua_call_wrapper, false, is_variable, checked, boost, C> { + template + struct lua_call_wrapper, false, is_variable, checked, boost, clean_stack, C> { typedef lua_bind_traits traits_type; typedef wrapper> wrap; typedef typename wrap::object_type object_type; @@ -9695,13 +10029,13 @@ namespace sol { } }; - template - struct lua_call_wrapper, true, is_variable, checked, boost, C> : lua_call_wrapper { + template + struct lua_call_wrapper, true, is_variable, checked, boost, clean_stack, C> : lua_call_wrapper { }; - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, C> { + template + struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { typedef constructor_list F; static int call(lua_State* L, F&) { @@ -9716,7 +10050,7 @@ namespace sol { T* obj = reinterpret_cast(pointerpointer + 1); referencepointer = obj; - construct_match(constructor_match(obj), L, argcount, boost + 1 + static_cast(syntax)); + construct_match(constructor_match(obj), L, argcount, boost + 1 + static_cast(syntax)); userdataref.push(); luaL_getmetatable(L, &metakey[0]); @@ -9730,8 +10064,8 @@ namespace sol { } }; - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, C> { + template + struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { typedef constructor_wrapper F; struct onmatch { @@ -9745,7 +10079,7 @@ namespace sol { referencepointer = obj; auto& func = std::get(f.functions); - stack::call_into_lua(r, a, L, boost + start, func, detail::implicit_wrapper(obj)); + stack::call_into_lua(r, a, L, boost + start, func, detail::implicit_wrapper(obj)); userdataref.push(); luaL_getmetatable(L, &metakey[0]); @@ -9770,17 +10104,17 @@ namespace sol { }; - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, std::enable_if_t::value>> { + template + struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, std::enable_if_t::value>> { typedef destructor_wrapper F; static int call(lua_State* L, const F&) { - return detail::usertype_alloc_destroy(L); + return detail::usertype_alloc_destruct(L); } }; - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, std::enable_if_t::value>> { + template + struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, std::enable_if_t::value>> { typedef destructor_wrapper F; static int call(lua_State* L, const F& f) { @@ -9790,8 +10124,8 @@ namespace sol { } }; - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, C> { + template + struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { typedef overload_set F; struct on_match { @@ -9807,15 +10141,15 @@ namespace sol { } }; - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, C> { + template + struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { typedef factory_wrapper F; struct on_match { template int operator()(types, index_value, types, types, lua_State* L, int, int, F& fx) { auto& f = std::get(fx.functions); - return lua_call_wrapper{}.call(L, f); + return lua_call_wrapper{}.call(L, f); } }; @@ -9824,8 +10158,8 @@ namespace sol { } }; - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, C> { + template + struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { typedef std::conditional_t P; typedef meta::unqualified_t

U; typedef wrapper wrap; @@ -9838,7 +10172,7 @@ namespace sol { typedef typename traits_type::free_args_list args_list; typedef typename wrap::returns_list returns_list; typedef typename wrap::caller caller; - return stack::call_into_lua(returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), f); + return stack::call_into_lua(returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), f); } template @@ -9859,7 +10193,7 @@ namespace sol { #endif // Safety typedef typename wrap::returns_list returns_list; typedef typename wrap::caller caller; - return stack::call_into_lua(returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), f, *o); + return stack::call_into_lua(returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), f, *o); } template @@ -9870,7 +10204,7 @@ namespace sol { template static int defer_call(std::true_type, lua_State* L, F&& f, Args&&... args) { auto& p = pick(meta::boolean(), std::forward(f)); - return lua_call_wrapper, is_index, is_variable, checked, boost>{}.call(L, p, std::forward(args)...); + return lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack>{}.call(L, p, std::forward(args)...); } template @@ -9887,33 +10221,50 @@ namespace sol { } }; - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, C> { + template + struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { typedef protect_t F; template static int call(lua_State* L, F& fx, Args&&... args) { - return lua_call_wrapper{}.call(L, fx.value, std::forward(args)...); + return lua_call_wrapper{}.call(L, fx.value, std::forward(args)...); } }; - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, C> { + template + struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { + typedef filter_wrapper P; + + template + static int call(std::index_sequence, lua_State* L, P& fx) { + int pushed = lua_call_wrapper{}.call(L, fx.value); + (void)detail::swallow{ int(), (filter_detail::handle_filter(std::get(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 + struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { template static int call(lua_State* L, F&& f) { - return lua_call_wrapper, is_index, is_variable, stack::stack_detail::default_check_arguments, boost>{}.call(L, std::get<0>(f.arguments)); + return lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack>{}.call(L, std::get<0>(f.arguments)); } }; - template + template inline int call_wrapped(lua_State* L, Fx&& fx, Args&&... args) { - return lua_call_wrapper, is_index, is_variable, stack::stack_detail::default_check_arguments, boost>{}.call(L, std::forward(fx), std::forward(args)...); + return lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack>{}.call(L, std::forward(fx), std::forward(args)...); } - template + template inline int call_user(lua_State* L) { auto& fx = stack::get>(L, upvalue_index(start)); - return call_wrapped(L, fx); + return call_wrapped(L, fx); } template @@ -9932,7 +10283,10 @@ namespace sol { struct is_var_bind> : std::true_type {}; template - struct is_var_bind> : is_var_bind {}; + struct is_var_bind> : is_var_bind> {}; + + template + struct is_var_bind> : is_var_bind> {}; } // call_detail template @@ -10886,7 +11240,7 @@ namespace sol { template struct pusher>> { static int push(lua_State* L, detail::tagged>) { - lua_CFunction cf = call_detail::construct; + lua_CFunction cf = call_detail::construct; return stack::push(L, cf); } }; @@ -10906,7 +11260,7 @@ namespace sol { template struct pusher>> { static int push(lua_State* L, destructor_wrapper) { - lua_CFunction cf = detail::usertype_alloc_destroy; + lua_CFunction cf = detail::usertype_alloc_destruct; return stack::push(L, cf); } }; @@ -10922,6 +11276,26 @@ namespace sol { } }; + template + struct pusher> { + typedef filter_wrapper P; + + static int push(lua_State* L, const P& p) { + lua_CFunction cf = call_detail::call_user; + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push>(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; + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push>(L, std::move(p)); + return stack::push(L, c_closure(cf, upvalues)); + } + }; } // stack } // sol @@ -10980,7 +11354,7 @@ namespace sol { basic_function& operator=(basic_function&&) = default; 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()) {} - template >>, meta::neg>> = meta::enabler> + template >>> = meta::enabler> 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) { #ifdef SOL_CHECK_ARGUMENTS @@ -11136,8 +11510,6 @@ namespace sol { // end of sol/protected_function_result.hpp -#include - namespace sol { namespace detail { inline const char (&default_handler_name())[11] { @@ -11474,6 +11846,19 @@ namespace sol { tbl.traverse_set(std::get(key)..., std::forward(value)); } + auto setup_table(std::true_type) { + auto p = stack::probe_get_field, 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, global_table>::value>(lua_state(), key, lua_gettop(lua_state())); + lua_pop(lua_state(), p.levels); + return p; + } + public: Table tbl; key_type key; @@ -11734,7 +12119,7 @@ namespace sol { basic_userdata& operator=(basic_userdata&&) = default; 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()) {} - template >>, meta::neg, ref_index>>> = meta::enabler> + template >>> = meta::enabler> 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) { #ifdef SOL_CHECK_ARGUMENTS @@ -11771,7 +12156,7 @@ namespace sol { basic_lightuserdata& operator=(basic_lightuserdata&&) = default; 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()) {} - template >>, meta::neg, ref_index>>> = meta::enabler> + template >> = meta::enabler> 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) { #ifdef SOL_CHECK_ARGUMENTS @@ -13697,7 +14082,7 @@ namespace sol { { "add", &meta_cumt::add_call }, { "find", &meta_cumt::find_call }, { "erase", &meta_cumt::erase_call }, - std::is_pointer::value ? luaL_Reg{ nullptr, nullptr } : luaL_Reg{ "__gc", &detail::usertype_alloc_destroy }, + std::is_pointer::value ? luaL_Reg{ nullptr, nullptr } : luaL_Reg{ "__gc", &detail::usertype_alloc_destruct }, { nullptr, nullptr } } }; @@ -13803,9 +14188,211 @@ namespace sol { // end of sol/container_usertype_metatable.hpp -#include +// beginning of sol/usertype_core.hpp + #include +namespace sol { + namespace usertype_detail { + struct no_comp { + template + bool operator()(A&&, B&&) const { + return false; + } + }; + + template + inline int member_default_to_string(std::true_type, lua_State* L) { + std::string ts = stack::get(L, 1).to_string(); + return stack::push(L, std::move(ts)); + } + + template + 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().data()); + } + + template + inline int adl_default_to_string(std::true_type, lua_State* L) { + using std::to_string; + std::string ts = to_string(stack::get(L, 1)); + return stack::push(L, std::move(ts)); + } + + template + inline int adl_default_to_string(std::false_type, lua_State* L) { + return member_default_to_string(meta::supports_to_string_member(), L); + } + + template + inline int oss_default_to_string(std::true_type, lua_State* L) { + std::ostringstream oss; + oss << stack::get(L, 1); + return stack::push(L, oss.str()); + } + + template + inline int oss_default_to_string(std::false_type, lua_State* L) { + return adl_default_to_string(meta::supports_adl_to_string(), L); + } + + template + inline int default_to_string(lua_State* L) { + return oss_default_to_string(meta::supports_ostream_op(), L); + } + + template + int comparsion_operator_wrap(lua_State* L) { + auto maybel = stack::check_get(L, 1); + if (maybel) { + auto mayber = stack::check_get(L, 2); + if (mayber) { + auto& l = *maybel; + auto& r = *mayber; + if (std::is_same::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 = meta::enabler> + inline void make_reg_op(Regs& l, int& index, const char* name) { + lua_CFunction f = &comparsion_operator_wrap; + l[index] = luaL_Reg{ name, f }; + ++index; + } + + template = meta::enabler> + inline void make_reg_op(Regs&, int&, const char*) { + // Do nothing if there's no support + } + + template = 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>; + l[index] = luaL_Reg{ name, f }; + ++index; + } + + template = meta::enabler> + inline void make_to_string_op(Regs&, int&) { + // Do nothing if there's no support + } + + template > = 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; + l[index] = luaL_Reg{ name, f }; + ++index; + } + + template > = meta::enabler> + inline void make_call_op(Regs&, int&) { + // Do nothing if there's no support + } + + template > = 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 }; + ++index; + } + + template > = meta::enabler> + inline void make_length_op(Regs&, int&) { + // Do nothing if there's no support + } + + template >, std::is_destructible>> + 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::value ? &detail::unique_destruct : &detail::usertype_alloc_destruct }; + ++index; + } + + template >, std::is_destructible>> + void make_destructor(Regs& l, int& index) { + if (!std::is_destructible::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 }; + ++index; + } + } + + template + 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, meta::supports_op_less>(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, meta::supports_op_less_equal>(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::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>::pairs_call }; + ++index; + } + if (fx(meta_function::length)) { + usertype_detail::make_length_op(l, index); + } + if (fx(meta_function::to_string)) { + usertype_detail::make_to_string_op, meta::supports_adl_to_string, meta::supports_ostream_op>>(l, index); + } + if (fx(meta_function::call_function)) { + usertype_detail::make_call_op(l, index); + } + } + } // usertype_detail + + namespace stack { + namespace stack_detail { + template + struct undefined_metatable { + typedef meta::all>, std::is_destructible> is_destructible; + typedef std::remove_pointer_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

(l, index, fx); + usertype_detail::make_destructor(l, index); + luaL_setfuncs(L, l, 0); + } + lua_setmetatable(L, -2); + } + }; + } // stack_detail + } // stack +} // sol + +// end of sol/usertype_core.hpp + +#include + namespace sol { namespace usertype_detail { const int metatable_index = 2; @@ -13870,13 +14457,6 @@ namespace sol { index(std::move(i)), newindex(std::move(ni)), indexbaseclasspropogation(index), newindexbaseclasspropogation(newindex) {} }; - - template - inline int default_to_string(lua_State* L) { - std::ostringstream oss; - oss << stack::get(L, 1); - return stack::push(L, oss.str()); - } } // usertype_detail struct usertype_metatable_core { @@ -13902,47 +14482,6 @@ namespace sol { namespace usertype_detail { const lua_Integer toplevel_magic = static_cast(0xCCC2CCC1); - struct add_destructor_tag {}; - struct check_destructor_tag {}; - struct verified_tag {} const verified{}; - - template - struct is_non_factory_constructor : std::false_type {}; - - template - struct is_non_factory_constructor> : std::true_type {}; - - template - struct is_non_factory_constructor> : std::true_type {}; - - template <> - struct is_non_factory_constructor : std::true_type {}; - - template - struct is_constructor : is_non_factory_constructor {}; - - template - struct is_constructor> : std::true_type {}; - - template - using has_constructor = meta::any>...>; - - template - struct is_destructor : std::false_type {}; - - template - struct is_destructor> : std::true_type {}; - - template - using has_destructor = meta::any>...>; - - struct no_comp { - template - bool operator()(A&&, B&&) const { - return false; - } - }; - inline int is_indexer(string_detail::string_shim s) { if (s == to_string(meta_function::index)) { return 1; @@ -14177,76 +14716,6 @@ namespace sol { (void)accessor; (void)detail::swallow{ 0, (walk_single_base(L, found, ret, accessor), 0)... }; } - - template - int operator_wrap(lua_State* L) { - auto maybel = stack::check_get(L, 1); - if (maybel) { - auto mayber = stack::check_get(L, 2); - if (mayber) { - auto& l = *maybel; - auto& r = *mayber; - if (std::is_same::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 = meta::enabler> - inline void make_reg_op(Regs& l, int& index, const char* name) { - lua_CFunction f = &operator_wrap; - l[index] = luaL_Reg{ name, f }; - ++index; - } - - template = meta::enabler> - inline void make_reg_op(Regs&, int&, const char*) { - // Do nothing if there's no support - } - - template = 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>; - l[index] = luaL_Reg{ name, f }; - ++index; - } - - template = meta::enabler> - inline void make_to_string_op(Regs&, int&) { - // Do nothing if there's no support - } - - template > = 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; - l[index] = luaL_Reg{ name, f }; - ++index; - } - - template > = meta::enabler> - inline void make_call_op(Regs&, int&) { - // Do nothing if there's no support - } - - template > = 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 }; - ++index; - } - - template > = meta::enabler> - inline void make_length_op(Regs&, int&) { - // Do nothing if there's no support - } } // usertype_detail template @@ -14304,32 +14773,8 @@ namespace sol { } int finish_regs(regs_t& l, int& index) { - if (!properties[static_cast(meta_function::less_than)]) { - const char* name = to_string(meta_function::less_than).c_str(); - usertype_detail::make_reg_op, meta::supports_op_less>(l, index, name); - } - if (!properties[static_cast(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, meta::supports_op_less_equal>(l, index, name); - } - if (!properties[static_cast(meta_function::equal_to)]) { - const char* name = to_string(meta_function::equal_to).c_str(); - usertype_detail::make_reg_op::value, std::equal_to<>, usertype_detail::no_comp>, std::true_type>(l, index, name); - } - if (!properties[static_cast(meta_function::pairs)]) { - const char* name = to_string(meta_function::pairs).c_str(); - l[index] = luaL_Reg{ name, container_usertype_metatable>::pairs_call }; - ++index; - } - if (!properties[static_cast(meta_function::length)]) { - usertype_detail::make_length_op(l, index); - } - if (!properties[static_cast(meta_function::to_string)]) { - usertype_detail::make_to_string_op>(l, index); - } - if (!properties[static_cast(meta_function::call)]) { - usertype_detail::make_call_op(l, index); - } + auto prop_fx = [&](meta_function mf) { return !properties[static_cast(mf)]; }; + usertype_detail::insert_default_registrations(l, index, prop_fx); if (destructfunc != nullptr) { l[index] = luaL_Reg{ to_string(meta_function::garbage_collect).c_str(), destructfunc }; ++index; @@ -14500,7 +14945,7 @@ namespace sol { typedef meta::unqualified_tuple_element_t K; typedef meta::unqualified_tuple_element_t F; static const int boost = - !usertype_detail::is_non_factory_constructor::value + !detail::is_non_factory_constructor::value && std::is_same::value ? 1 : 0; auto& f = std::get(um.functions); @@ -14978,7 +15423,7 @@ namespace sol { private: template - simple_usertype_metatable(usertype_detail::verified_tag, std::index_sequence, lua_State* L, Tuple&& args) + simple_usertype_metatable(detail::verified_tag, std::index_sequence, lua_State* L, Tuple&& args) : callconstructfunc(lua_nil), indexfunc(lua_nil), newindexfunc(lua_nil), indexbase(&usertype_detail::simple_core_indexing_call), newindexbase(&usertype_detail::simple_core_indexing_call), @@ -14993,33 +15438,33 @@ namespace sol { } template - simple_usertype_metatable(lua_State* L, usertype_detail::verified_tag v, Args&&... args) : simple_usertype_metatable(v, std::make_index_sequence(), L, std::forward_as_tuple(std::forward(args)...)) {} + simple_usertype_metatable(lua_State* L, detail::verified_tag v, Args&&... args) : simple_usertype_metatable(v, std::make_index_sequence(), L, std::forward_as_tuple(std::forward(args)...)) {} template - simple_usertype_metatable(lua_State* L, usertype_detail::add_destructor_tag, Args&&... args) : simple_usertype_metatable(L, usertype_detail::verified, std::forward(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)..., "__gc", default_destructor) {} template - simple_usertype_metatable(lua_State* L, usertype_detail::check_destructor_tag, Args&&... args) : simple_usertype_metatable(L, meta::condition, meta::neg>>, usertype_detail::add_destructor_tag, usertype_detail::verified_tag>(), std::forward(args)...) {} + simple_usertype_metatable(lua_State* L, detail::check_destructor_tag, Args&&... args) : simple_usertype_metatable(L, meta::condition, meta::neg>>, detail::add_destructor_tag, detail::verified_tag>(), std::forward(args)...) {} public: - simple_usertype_metatable(lua_State* L) : simple_usertype_metatable(L, meta::condition>, decltype(default_constructor), usertype_detail::check_destructor_tag>()) {} + simple_usertype_metatable(lua_State* L) : simple_usertype_metatable(L, meta::condition>, decltype(default_constructor), detail::check_destructor_tag>()) {} template, - usertype_detail::verified_tag, - usertype_detail::add_destructor_tag, - usertype_detail::check_destructor_tag + detail::verified_tag, + detail::add_destructor_tag, + detail::check_destructor_tag >, meta::is_specialization_of>, meta::is_specialization_of> > = meta::enabler> - simple_usertype_metatable(lua_State* L, Arg&& arg, Args&&... args) : simple_usertype_metatable(L, meta::condition, meta::neg>>, decltype(default_constructor), usertype_detail::check_destructor_tag>(), std::forward(arg), std::forward(args)...) {} + simple_usertype_metatable(lua_State* L, Arg&& arg, Args&&... args) : simple_usertype_metatable(L, meta::condition, meta::neg>>, decltype(default_constructor), detail::check_destructor_tag>(), std::forward(arg), std::forward(args)...) {} template - simple_usertype_metatable(lua_State* L, constructors constructorlist, Args&&... args) : simple_usertype_metatable(L, usertype_detail::check_destructor_tag(), std::forward(args)..., "new", constructorlist) {} + simple_usertype_metatable(lua_State* L, constructors constructorlist, Args&&... args) : simple_usertype_metatable(L, detail::check_destructor_tag(), std::forward(args)..., "new", constructorlist) {} template - simple_usertype_metatable(lua_State* L, constructor_wrapper constructorlist, Args&&... args) : simple_usertype_metatable(L, usertype_detail::check_destructor_tag(), std::forward(args)..., "new", constructorlist) {} + simple_usertype_metatable(lua_State* L, constructor_wrapper constructorlist, Args&&... args) : simple_usertype_metatable(L, detail::check_destructor_tag(), std::forward(args)..., "new", constructorlist) {} simple_usertype_metatable(const simple_usertype_metatable&) = default; simple_usertype_metatable(simple_usertype_metatable&&) = default; @@ -15076,18 +15521,18 @@ namespace sol { for (std::size_t i = 1; i < properties.size(); ++i) { mf = static_cast(i); const std::string& mfname = to_string(mf); - if (mfname == first) { - properties[i] = true; - switch (mf) { - case meta_function::index: - umx.indexfunc = second; - break; - case meta_function::new_index: - umx.newindexfunc = second; - break; - default: - break; - } + if (mfname != first) + continue; + properties[i] = true; + switch (mf) { + case meta_function::index: + umx.indexfunc = second; + break; + case meta_function::new_index: + umx.newindexfunc = second; + break; + default: + break; } break; } @@ -15130,34 +15575,10 @@ namespace sol { auto& second = std::get<1>(kvp); register_kvp(i, t, first, second); } - luaL_Reg opregs[29]{}; + luaL_Reg opregs[32]{}; int opregsindex = 0; - if (!properties[static_cast(meta_function::less_than)]) { - const char* name = to_string(meta_function::less_than).c_str(); - usertype_detail::make_reg_op, meta::supports_op_less>(opregs, opregsindex, name); - } - if (!properties[static_cast(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, meta::supports_op_less_equal>(opregs, opregsindex, name); - } - if (!properties[static_cast(meta_function::equal_to)]) { - const char* name = to_string(meta_function::equal_to).c_str(); - usertype_detail::make_reg_op::value, std::equal_to<>, usertype_detail::no_comp>, std::true_type>(opregs, opregsindex, name); - } - if (!properties[static_cast(meta_function::pairs)]) { - const char* name = to_string(meta_function::pairs).c_str(); - opregs[opregsindex] = { name, container_usertype_metatable>::pairs_call }; - ++opregsindex; - } - if (!properties[static_cast(meta_function::length)]) { - usertype_detail::make_length_op(opregs, opregsindex); - } - if (!properties[static_cast(meta_function::to_string)]) { - usertype_detail::make_to_string_op>(opregs, opregsindex); - } - if (!properties[static_cast(meta_function::call)]) { - usertype_detail::make_call_op(opregs, opregsindex); - } + auto prop_fx = [&](meta_function mf) { return !properties[static_cast(mf)]; }; + usertype_detail::insert_default_registrations(opregs, opregsindex, prop_fx); t.push(); luaL_setfuncs(L, opregs, 0); t.pop(); @@ -15268,24 +15689,26 @@ namespace sol { std::unique_ptr metatableregister; template - usertype(usertype_detail::verified_tag, Args&&... args) : metatableregister(detail::make_unique_deleter, Args...>, detail::deleter>(std::forward(args)...)) {} + usertype(detail::verified_tag, Args&&... args) : metatableregister(detail::make_unique_deleter, Args...>, detail::deleter>(std::forward(args)...)) { + static_assert(detail::has_destructor::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 - usertype(usertype_detail::add_destructor_tag, Args&&... args) : usertype(usertype_detail::verified, std::forward(args)..., "__gc", default_destructor) {} + usertype(detail::add_destructor_tag, Args&&... args) : usertype(detail::verified, std::forward(args)..., "__gc", default_destructor) {} template - usertype(usertype_detail::check_destructor_tag, Args&&... args) : usertype(meta::condition, meta::neg>>, usertype_detail::add_destructor_tag, usertype_detail::verified_tag>(), std::forward(args)...) {} + usertype(detail::check_destructor_tag, Args&&... args) : usertype(meta::condition, meta::neg>>, detail::add_destructor_tag, detail::verified_tag>(), std::forward(args)...) {} public: template - usertype(Args&&... args) : usertype(meta::condition, meta::neg>>, decltype(default_constructor), usertype_detail::check_destructor_tag>(), std::forward(args)...) {} + usertype(Args&&... args) : usertype(meta::condition, meta::neg>>, decltype(default_constructor), detail::check_destructor_tag>(), std::forward(args)...) {} template - usertype(constructors constructorlist, Args&&... args) : usertype(usertype_detail::check_destructor_tag(), std::forward(args)..., "new", constructorlist) {} + usertype(constructors constructorlist, Args&&... args) : usertype(detail::check_destructor_tag(), std::forward(args)..., "new", constructorlist) {} template - usertype(constructor_wrapper constructorlist, Args&&... args) : usertype(usertype_detail::check_destructor_tag(), std::forward(args)..., "new", constructorlist) {} + usertype(constructor_wrapper constructorlist, Args&&... args) : usertype(detail::check_destructor_tag(), std::forward(args)..., "new", constructorlist) {} template usertype(simple_tag, lua_State* L, Args&&... args) : metatableregister(detail::make_unique_deleter, detail::deleter>(L, std::forward(args)...)) {} @@ -15572,7 +15995,7 @@ namespace sol { 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(stack_reference&& r) : basic_table_core(r.lua_state(), r.stack_index()) {} - template >>, meta::neg, ref_index>>> = meta::enabler> + template >>> = 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, new_table nt) : base_t(L, (lua_createtable(L, nt.sequence_hint, nt.map_hint), -1)) { if (!std::is_base_of::value) { @@ -16604,6 +17027,10 @@ namespace sol { 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_status x = static_cast(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str())); return load_result(L, absolute_index(L, -1), 1, 1, x); @@ -16611,7 +17038,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) { 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 load_status x = static_cast(lua_load(L, reader, data, chunknametarget, to_string(mode).c_str())); #else @@ -16849,9 +17276,10 @@ namespace sol { (void)L; return -1; #else - const char* message = lua_tostring(L, -1); + size_t messagesize; + const char* message = lua_tolstring(L, -1, &messagesize); if (message) { - std::string err = message; + std::string err(message, messagesize); lua_settop(L, 0); throw error(err); } diff --git a/sol/call.hpp b/sol/call.hpp index b0dfa07e..a2a51b93 100644 --- a/sol/call.hpp +++ b/sol/call.hpp @@ -25,14 +25,66 @@ #include "protect.hpp" #include "wrapper.hpp" #include "property.hpp" +#include "filters.hpp" #include "stack.hpp" namespace sol { + namespace usertype_detail { + + } // usertype_detail + + namespace filter_detail { + template + inline void handle_filter(static_stack_dependencies, 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(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 + inline void handle_filter(returns_self_with, 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(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 >> = meta::enabler> + inline void handle_filter(P&& p, lua_State* L, int& pushed) { + pushed = std::forward

(p)(L, pushed); + } + } // filter_detail + namespace function_detail { inline int no_construction_error(lua_State* L) { return luaL_error(L, "sol: cannot call this constructor (tagged as non-constructible)"); } - } + } // function_detail namespace call_detail { @@ -54,7 +106,7 @@ namespace sol { static void call(Args...) {} }; - template + template struct constructor_match { T* obj; @@ -63,7 +115,7 @@ namespace sol { template int operator()(types, index_value, types r, types a, lua_State* L, int, int start) const { detail::default_construct func{}; - return stack::call_into_lua(r, a, L, start, func, obj); + return stack::call_into_lua(r, a, L, start, func, obj); } }; @@ -149,7 +201,7 @@ namespace sol { return overload_match_arity::call)...>(std::forward(matchfx), L, fxarity, start, std::forward(args)...); } - template + template inline int construct(lua_State* L) { static const auto& meta = usertype_traits::metatable(); int argcount = lua_gettop(L); @@ -163,7 +215,7 @@ namespace sol { reference userdataref(L, -1); userdataref.pop(); - construct_match(constructor_match(obj), L, argcount, 1 + static_cast(syntax)); + construct_match(constructor_match(obj), L, argcount, 1 + static_cast(syntax)); userdataref.push(); luaL_getmetatable(L, &meta[0]); @@ -176,7 +228,7 @@ namespace sol { return 1; } - template + template struct agnostic_lua_call_wrapper { template 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::free_args_list args_list; typedef typename wrap::caller caller; - return stack::call_into_lua(returns_list(), args_list(), L, boost + 1, caller(), std::forward(f), std::forward(args)...); + return stack::call_into_lua(returns_list(), args_list(), L, boost + 1, caller(), std::forward(f), std::forward(args)...); } }; - template - struct agnostic_lua_call_wrapper, true, is_variable, checked, boost, C> { + template + struct agnostic_lua_call_wrapper, true, is_variable, checked, boost, clean_stack, C> { template static int call(lua_State* L, F&& f) { + typedef is_stack_based> is_stack; + if (clean_stack && !is_stack::value) { + lua_settop(L, 0); + } return stack::push_reference(L, detail::unwrap(f.value)); } }; - template - struct agnostic_lua_call_wrapper, false, is_variable, checked, boost, C> { + template + struct agnostic_lua_call_wrapper, false, is_variable, checked, boost, clean_stack, C> { template static int call_assign(std::true_type, lua_State* L, V&& f) { detail::unwrap(f.value) = stack::get>(L, boost + (is_variable ? 3 : 1)); + if (clean_stack) { + lua_settop(L, 0); + } return 0; } @@ -226,63 +285,63 @@ namespace sol { } }; - template - struct agnostic_lua_call_wrapper { + template + struct agnostic_lua_call_wrapper { static int call(lua_State* L, lua_r_CFunction f) { return f(L); } }; - template - struct agnostic_lua_call_wrapper { + template + struct agnostic_lua_call_wrapper { static int call(lua_State* L, lua_CFunction f) { return f(L); } }; #ifdef SOL_NOEXCEPT_FUNCTION_TYPE - template - struct agnostic_lua_call_wrapper { + template + struct agnostic_lua_call_wrapper { static int call(lua_State* L, detail::lua_CFunction_noexcept f) { return f(L); } }; #endif // noexcept function types - template - struct agnostic_lua_call_wrapper { + template + struct agnostic_lua_call_wrapper { 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"); } }; - template - struct agnostic_lua_call_wrapper { + template + struct agnostic_lua_call_wrapper { static int call(lua_State* L, const no_construction&) { return function_detail::no_construction_error(L); } }; - template - struct agnostic_lua_call_wrapper, is_index, is_variable, checked, boost, C> { + template + struct agnostic_lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { static int call(lua_State*, const bases&) { // Uh. How did you even call this, lul return 0; } }; - template - struct agnostic_lua_call_wrapper, is_index, is_variable, checked, boost, C> { + template + struct agnostic_lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { static int call(lua_State* L, std::reference_wrapper f) { - return agnostic_lua_call_wrapper{}.call(L, f.get()); + return agnostic_lua_call_wrapper{}.call(L, f.get()); } }; - template - struct lua_call_wrapper : agnostic_lua_call_wrapper {}; + template + struct lua_call_wrapper : agnostic_lua_call_wrapper {}; - template - struct lua_call_wrapper::value>> { + template + struct lua_call_wrapper::value>> { typedef wrapper> wrap; typedef typename wrap::object_type object_type; @@ -291,7 +350,7 @@ namespace sol { typedef typename wrap::returns_list returns_list; typedef typename wrap::args_list args_list; typedef typename wrap::caller caller; - return stack::call_into_lua(returns_list(), args_list(), L, boost + ( is_variable ? 3 : 2 ), caller(), std::forward(f), o); + return stack::call_into_lua(returns_list(), args_list(), L, boost + ( is_variable ? 3 : 2 ), caller(), std::forward(f), o); } template @@ -311,8 +370,8 @@ namespace sol { } }; - template - struct lua_call_wrapper::value>> { + template + struct lua_call_wrapper::value>> { typedef lua_bind_traits traits_type; typedef wrapper> wrap; 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) { typedef typename wrap::args_list args_list; typedef typename wrap::caller caller; - return stack::call_into_lua(types(), args_list(), L, boost + ( is_variable ? 3 : 2 ), caller(), f, o); + return stack::call_into_lua(types(), args_list(), L, boost + ( is_variable ? 3 : 2 ), caller(), f, o); } template @@ -370,8 +429,8 @@ namespace sol { } }; - template - struct lua_call_wrapper::value>> { + template + struct lua_call_wrapper::value>> { typedef lua_bind_traits traits_type; typedef wrapper> wrap; typedef typename wrap::object_type object_type; @@ -381,7 +440,7 @@ namespace sol { typedef typename wrap::returns_list returns_list; typedef typename wrap::caller caller; F f(std::forward(v)); - return stack::call_into_lua(returns_list(), types<>(), L, boost + ( is_variable ? 3 : 2 ), caller(), f, o); + return stack::call_into_lua(returns_list(), types<>(), L, boost + ( is_variable ? 3 : 2 ), caller(), f, o); } template @@ -404,8 +463,8 @@ namespace sol { } }; - template - struct lua_call_wrapper, false, is_variable, checked, boost, C> { + template + struct lua_call_wrapper, false, is_variable, checked, boost, clean_stack, C> { typedef lua_bind_traits traits_type; typedef wrapper> wrap; typedef typename wrap::object_type object_type; @@ -421,13 +480,13 @@ namespace sol { } }; - template - struct lua_call_wrapper, true, is_variable, checked, boost, C> : lua_call_wrapper { + template + struct lua_call_wrapper, true, is_variable, checked, boost, clean_stack, C> : lua_call_wrapper { }; - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, C> { + template + struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { typedef constructor_list F; static int call(lua_State* L, F&) { @@ -442,7 +501,7 @@ namespace sol { T* obj = reinterpret_cast(pointerpointer + 1); referencepointer = obj; - construct_match(constructor_match(obj), L, argcount, boost + 1 + static_cast(syntax)); + construct_match(constructor_match(obj), L, argcount, boost + 1 + static_cast(syntax)); userdataref.push(); luaL_getmetatable(L, &metakey[0]); @@ -456,8 +515,8 @@ namespace sol { } }; - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, C> { + template + struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { typedef constructor_wrapper F; struct onmatch { @@ -471,7 +530,7 @@ namespace sol { referencepointer = obj; auto& func = std::get(f.functions); - stack::call_into_lua(r, a, L, boost + start, func, detail::implicit_wrapper(obj)); + stack::call_into_lua(r, a, L, boost + start, func, detail::implicit_wrapper(obj)); userdataref.push(); luaL_getmetatable(L, &metakey[0]); @@ -496,17 +555,17 @@ namespace sol { }; - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, std::enable_if_t::value>> { + template + struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, std::enable_if_t::value>> { typedef destructor_wrapper F; static int call(lua_State* L, const F&) { - return detail::usertype_alloc_destroy(L); + return detail::usertype_alloc_destruct(L); } }; - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, std::enable_if_t::value>> { + template + struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, std::enable_if_t::value>> { typedef destructor_wrapper F; static int call(lua_State* L, const F& f) { @@ -516,8 +575,8 @@ namespace sol { } }; - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, C> { + template + struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { typedef overload_set F; struct on_match { @@ -533,15 +592,15 @@ namespace sol { } }; - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, C> { + template + struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { typedef factory_wrapper F; struct on_match { template int operator()(types, index_value, types, types, lua_State* L, int, int, F& fx) { auto& f = std::get(fx.functions); - return lua_call_wrapper{}.call(L, f); + return lua_call_wrapper{}.call(L, f); } }; @@ -550,8 +609,8 @@ namespace sol { } }; - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, C> { + template + struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { typedef std::conditional_t P; typedef meta::unqualified_t

U; typedef wrapper wrap; @@ -564,7 +623,7 @@ namespace sol { typedef typename traits_type::free_args_list args_list; typedef typename wrap::returns_list returns_list; typedef typename wrap::caller caller; - return stack::call_into_lua(returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), f); + return stack::call_into_lua(returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), f); } template @@ -585,7 +644,7 @@ namespace sol { #endif // Safety typedef typename wrap::returns_list returns_list; typedef typename wrap::caller caller; - return stack::call_into_lua(returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), f, *o); + return stack::call_into_lua(returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), f, *o); } template @@ -596,7 +655,7 @@ namespace sol { template static int defer_call(std::true_type, lua_State* L, F&& f, Args&&... args) { auto& p = pick(meta::boolean(), std::forward(f)); - return lua_call_wrapper, is_index, is_variable, checked, boost>{}.call(L, p, std::forward(args)...); + return lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack>{}.call(L, p, std::forward(args)...); } template @@ -613,33 +672,50 @@ namespace sol { } }; - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, C> { + template + struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { typedef protect_t F; template static int call(lua_State* L, F& fx, Args&&... args) { - return lua_call_wrapper{}.call(L, fx.value, std::forward(args)...); + return lua_call_wrapper{}.call(L, fx.value, std::forward(args)...); } }; - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, C> { + template + struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { + typedef filter_wrapper P; + + template + static int call(std::index_sequence, lua_State* L, P& fx) { + int pushed = lua_call_wrapper{}.call(L, fx.value); + (void)detail::swallow{ int(), (filter_detail::handle_filter(std::get(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 + struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { template static int call(lua_State* L, F&& f) { - return lua_call_wrapper, is_index, is_variable, stack::stack_detail::default_check_arguments, boost>{}.call(L, std::get<0>(f.arguments)); + return lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack>{}.call(L, std::get<0>(f.arguments)); } }; - template + template inline int call_wrapped(lua_State* L, Fx&& fx, Args&&... args) { - return lua_call_wrapper, is_index, is_variable, stack::stack_detail::default_check_arguments, boost>{}.call(L, std::forward(fx), std::forward(args)...); + return lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack>{}.call(L, std::forward(fx), std::forward(args)...); } - template + template inline int call_user(lua_State* L) { auto& fx = stack::get>(L, upvalue_index(start)); - return call_wrapped(L, fx); + return call_wrapped(L, fx); } template @@ -658,7 +734,10 @@ namespace sol { struct is_var_bind> : std::true_type {}; template - struct is_var_bind> : is_var_bind {}; + struct is_var_bind> : is_var_bind> {}; + + template + struct is_var_bind> : is_var_bind> {}; } // call_detail template diff --git a/sol/container_usertype_metatable.hpp b/sol/container_usertype_metatable.hpp index f7ee7a67..1fcc20d8 100644 --- a/sol/container_usertype_metatable.hpp +++ b/sol/container_usertype_metatable.hpp @@ -276,7 +276,7 @@ namespace sol { { "add", &meta_cumt::add_call }, { "find", &meta_cumt::find_call }, { "erase", &meta_cumt::erase_call }, - std::is_pointer::value ? luaL_Reg{ nullptr, nullptr } : luaL_Reg{ "__gc", &detail::usertype_alloc_destroy }, + std::is_pointer::value ? luaL_Reg{ nullptr, nullptr } : luaL_Reg{ "__gc", &detail::usertype_alloc_destruct }, { nullptr, nullptr } } }; diff --git a/sol/demangle.hpp b/sol/demangle.hpp index 5379e3c2..fe7be195 100644 --- a/sol/demangle.hpp +++ b/sol/demangle.hpp @@ -88,8 +88,8 @@ namespace sol { name.replace(0, 6, "", 0); if (name.find("class", 0) == 0) name.replace(0, 5, "", 0); - while (!name.empty() && std::isblank(name.front())) name.erase(name.begin()); - while (!name.empty() && std::isblank(name.back())) name.pop_back(); + while (!name.empty() && isblank(name.front())) name.erase(name.begin()); + while (!name.empty() && isblank(name.back())) name.pop_back(); for (std::size_t r = 0; r < removals.size(); ++r) { auto found = name.find(removals[r]); diff --git a/sol/filters.hpp b/sol/filters.hpp new file mode 100644 index 00000000..824320f1 --- /dev/null +++ b/sol/filters.hpp @@ -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 + +namespace sol { + namespace detail { + struct filter_base_tag {}; + } // detail + + template + struct static_stack_dependencies : detail::filter_base_tag {}; + typedef static_stack_dependencies<-1, 1> self_dependency; + template + 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 stack_indices; + std::size_t len; + + template + 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(std::forward(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 + struct filter_wrapper { + typedef std::make_integer_sequence indices; + + F value; + std::tuple filters; + + template , filter_wrapper>>> = meta::enabler> + filter_wrapper(Fx&& fx, Args&&... args) : value(std::forward(fx)), filters(std::forward(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 + auto filters(F&& f, Args&&... args) { + return filter_wrapper, std::decay_t...>( std::forward(f), std::forward(args)... ); + } +} // sol + +#endif // SOL_FILTERS_HPP diff --git a/sol/forward.hpp b/sol/forward.hpp index 0a22c845..679bcd61 100644 --- a/sol/forward.hpp +++ b/sol/forward.hpp @@ -110,7 +110,10 @@ namespace sol { struct user; template struct as_args_t; - + template + struct protect_t; + template + struct filter_wrapper; } // sol #endif // SOL_FORWARD_HPP diff --git a/sol/forward_detail.hpp b/sol/forward_detail.hpp new file mode 100644 index 00000000..bcc41c61 --- /dev/null +++ b/sol/forward_detail.hpp @@ -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 + struct undefined_metatable; + } // stack_detail + } // stack + + namespace usertype_detail { + template + void insert_default_registrations(Regs& l, int& index, Fx&& fx); + + template >, std::is_destructible> = meta::enabler> + void make_destructor(Regs& l, int& index); + template >, std::is_destructible> = meta::enabler> + void make_destructor(Regs& l, int& index); + } // usertype_detail +} // sol + +#endif // SOL_FORWARD_DETAIL_HPP diff --git a/sol/function_types.hpp b/sol/function_types.hpp index 9a3c368d..9930941a 100644 --- a/sol/function_types.hpp +++ b/sol/function_types.hpp @@ -391,7 +391,7 @@ namespace sol { template struct pusher>> { static int push(lua_State* L, detail::tagged>) { - lua_CFunction cf = call_detail::construct; + lua_CFunction cf = call_detail::construct; return stack::push(L, cf); } }; @@ -411,7 +411,7 @@ namespace sol { template struct pusher>> { static int push(lua_State* L, destructor_wrapper) { - lua_CFunction cf = detail::usertype_alloc_destroy; + lua_CFunction cf = detail::usertype_alloc_destruct; return stack::push(L, cf); } }; @@ -427,6 +427,26 @@ namespace sol { } }; + template + struct pusher> { + typedef filter_wrapper P; + + static int push(lua_State* L, const P& p) { + lua_CFunction cf = call_detail::call_user; + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push>(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; + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push>(L, std::move(p)); + return stack::push(L, c_closure(cf, upvalues)); + } + }; } // stack } // sol diff --git a/sol/proxy.hpp b/sol/proxy.hpp index 95bc9488..cfc289d3 100644 --- a/sol/proxy.hpp +++ b/sol/proxy.hpp @@ -43,6 +43,19 @@ namespace sol { tbl.traverse_set(std::get(key)..., std::forward(value)); } + auto setup_table(std::true_type) { + auto p = stack::probe_get_field, 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, global_table>::value>(lua_state(), key, lua_gettop(lua_state())); + lua_pop(lua_state(), p.levels); + return p; + } + public: Table tbl; key_type key; diff --git a/sol/raii.hpp b/sol/raii.hpp index 1176ef93..4a8fae05 100644 --- a/sol/raii.hpp +++ b/sol/raii.hpp @@ -22,9 +22,10 @@ #ifndef SOL_RAII_HPP #define SOL_RAII_HPP -#include #include "traits.hpp" +#include + namespace sol { namespace detail { struct default_construct { diff --git a/sol/reference.hpp b/sol/reference.hpp index 25a809be..6cab3ee8 100644 --- a/sol/reference.hpp +++ b/sol/reference.hpp @@ -69,17 +69,23 @@ namespace sol { struct push_popper_n { push_popper_n(lua_State*, int) { } }; - template + template struct push_popper { T t; push_popper(T x) : t(x) { t.push(); } ~push_popper() { t.pop(); } }; - template - struct push_popper { + template + struct push_popper { push_popper(T) {} ~push_popper() {} }; + template + struct push_popper>::value>> { + push_popper(T) {} + ~push_popper() {} + }; + template push_popper push_pop(T&& x) { return push_popper(std::forward(x)); diff --git a/sol/simple_usertype_metatable.hpp b/sol/simple_usertype_metatable.hpp index d0df409d..71ca36b1 100644 --- a/sol/simple_usertype_metatable.hpp +++ b/sol/simple_usertype_metatable.hpp @@ -322,7 +322,7 @@ namespace sol { private: template - simple_usertype_metatable(usertype_detail::verified_tag, std::index_sequence, lua_State* L, Tuple&& args) + simple_usertype_metatable(detail::verified_tag, std::index_sequence, lua_State* L, Tuple&& args) : callconstructfunc(lua_nil), indexfunc(lua_nil), newindexfunc(lua_nil), indexbase(&usertype_detail::simple_core_indexing_call), newindexbase(&usertype_detail::simple_core_indexing_call), @@ -337,33 +337,33 @@ namespace sol { } template - simple_usertype_metatable(lua_State* L, usertype_detail::verified_tag v, Args&&... args) : simple_usertype_metatable(v, std::make_index_sequence(), L, std::forward_as_tuple(std::forward(args)...)) {} + simple_usertype_metatable(lua_State* L, detail::verified_tag v, Args&&... args) : simple_usertype_metatable(v, std::make_index_sequence(), L, std::forward_as_tuple(std::forward(args)...)) {} template - simple_usertype_metatable(lua_State* L, usertype_detail::add_destructor_tag, Args&&... args) : simple_usertype_metatable(L, usertype_detail::verified, std::forward(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)..., "__gc", default_destructor) {} template - simple_usertype_metatable(lua_State* L, usertype_detail::check_destructor_tag, Args&&... args) : simple_usertype_metatable(L, meta::condition, meta::neg>>, usertype_detail::add_destructor_tag, usertype_detail::verified_tag>(), std::forward(args)...) {} + simple_usertype_metatable(lua_State* L, detail::check_destructor_tag, Args&&... args) : simple_usertype_metatable(L, meta::condition, meta::neg>>, detail::add_destructor_tag, detail::verified_tag>(), std::forward(args)...) {} public: - simple_usertype_metatable(lua_State* L) : simple_usertype_metatable(L, meta::condition>, decltype(default_constructor), usertype_detail::check_destructor_tag>()) {} + simple_usertype_metatable(lua_State* L) : simple_usertype_metatable(L, meta::condition>, decltype(default_constructor), detail::check_destructor_tag>()) {} template, - usertype_detail::verified_tag, - usertype_detail::add_destructor_tag, - usertype_detail::check_destructor_tag + detail::verified_tag, + detail::add_destructor_tag, + detail::check_destructor_tag >, meta::is_specialization_of>, meta::is_specialization_of> > = meta::enabler> - simple_usertype_metatable(lua_State* L, Arg&& arg, Args&&... args) : simple_usertype_metatable(L, meta::condition, meta::neg>>, decltype(default_constructor), usertype_detail::check_destructor_tag>(), std::forward(arg), std::forward(args)...) {} + simple_usertype_metatable(lua_State* L, Arg&& arg, Args&&... args) : simple_usertype_metatable(L, meta::condition, meta::neg>>, decltype(default_constructor), detail::check_destructor_tag>(), std::forward(arg), std::forward(args)...) {} template - simple_usertype_metatable(lua_State* L, constructors constructorlist, Args&&... args) : simple_usertype_metatable(L, usertype_detail::check_destructor_tag(), std::forward(args)..., "new", constructorlist) {} + simple_usertype_metatable(lua_State* L, constructors constructorlist, Args&&... args) : simple_usertype_metatable(L, detail::check_destructor_tag(), std::forward(args)..., "new", constructorlist) {} template - simple_usertype_metatable(lua_State* L, constructor_wrapper constructorlist, Args&&... args) : simple_usertype_metatable(L, usertype_detail::check_destructor_tag(), std::forward(args)..., "new", constructorlist) {} + simple_usertype_metatable(lua_State* L, constructor_wrapper constructorlist, Args&&... args) : simple_usertype_metatable(L, detail::check_destructor_tag(), std::forward(args)..., "new", constructorlist) {} simple_usertype_metatable(const simple_usertype_metatable&) = default; simple_usertype_metatable(simple_usertype_metatable&&) = default; @@ -420,18 +420,18 @@ namespace sol { for (std::size_t i = 1; i < properties.size(); ++i) { mf = static_cast(i); const std::string& mfname = to_string(mf); - if (mfname == first) { - properties[i] = true; - switch (mf) { - case meta_function::index: - umx.indexfunc = second; - break; - case meta_function::new_index: - umx.newindexfunc = second; - break; - default: - break; - } + if (mfname != first) + continue; + properties[i] = true; + switch (mf) { + case meta_function::index: + umx.indexfunc = second; + break; + case meta_function::new_index: + umx.newindexfunc = second; + break; + default: + break; } break; } @@ -474,34 +474,10 @@ namespace sol { auto& second = std::get<1>(kvp); register_kvp(i, t, first, second); } - luaL_Reg opregs[29]{}; + luaL_Reg opregs[32]{}; int opregsindex = 0; - if (!properties[static_cast(meta_function::less_than)]) { - const char* name = to_string(meta_function::less_than).c_str(); - usertype_detail::make_reg_op, meta::supports_op_less>(opregs, opregsindex, name); - } - if (!properties[static_cast(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, meta::supports_op_less_equal>(opregs, opregsindex, name); - } - if (!properties[static_cast(meta_function::equal_to)]) { - const char* name = to_string(meta_function::equal_to).c_str(); - usertype_detail::make_reg_op::value, std::equal_to<>, usertype_detail::no_comp>, std::true_type>(opregs, opregsindex, name); - } - if (!properties[static_cast(meta_function::pairs)]) { - const char* name = to_string(meta_function::pairs).c_str(); - opregs[opregsindex] = { name, container_usertype_metatable>::pairs_call }; - ++opregsindex; - } - if (!properties[static_cast(meta_function::length)]) { - usertype_detail::make_length_op(opregs, opregsindex); - } - if (!properties[static_cast(meta_function::to_string)]) { - usertype_detail::make_to_string_op>(opregs, opregsindex); - } - if (!properties[static_cast(meta_function::call)]) { - usertype_detail::make_call_op(opregs, opregsindex); - } + auto prop_fx = [&](meta_function mf) { return !properties[static_cast(mf)]; }; + usertype_detail::insert_default_registrations(opregs, opregsindex, prop_fx); t.push(); luaL_setfuncs(L, opregs, 0); t.pop(); diff --git a/sol/stack.hpp b/sol/stack.hpp index af688e5d..93110e34 100644 --- a/sol/stack.hpp +++ b/sol/stack.hpp @@ -159,34 +159,41 @@ namespace sol { template ::value>> inline decltype(auto) call_from_top(types tr, types ta, lua_State* L, Fx&& fx, FxArgs&&... args) { - return call(tr, ta, L, static_cast(lua_gettop(L) - sizeof...(Args)), std::forward(fx), std::forward(args)...); + typedef meta::count_for_pack expected_count; + return call(tr, ta, L, (std::max)(static_cast(lua_gettop(L) - expected_count::value), static_cast(0)), std::forward(fx), std::forward(args)...); } template inline void call_from_top(types tr, types ta, lua_State* L, Fx&& fx, FxArgs&&... args) { - call(tr, ta, L, static_cast(lua_gettop(L) - sizeof...(Args)), std::forward(fx), std::forward(args)...); + typedef meta::count_for_pack expected_count; + call(tr, ta, L, (std::max)(static_cast(lua_gettop(L) - expected_count::value), static_cast(0)), std::forward(fx), std::forward(args)...); } - template + template inline int call_into_lua(types tr, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { call(tr, ta, L, start, std::forward(fx), std::forward(fxargs)...); - lua_settop(L, 0); + if (clean_stack) { + lua_settop(L, 0); + } return 0; } - template>::value>> + template>::value>> inline int call_into_lua(types, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { decltype(auto) r = call(types>(), ta, L, start, std::forward(fx), std::forward(fxargs)...); - lua_settop(L, 0); + typedef is_stack_based> is_stack; + if (clean_stack && !is_stack::value) { + lua_settop(L, 0); + } return push_reference(L, std::forward(r)); } - template + template inline int call_lua(lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { typedef lua_bind_traits> traits_type; typedef typename traits_type::args_list args_list; typedef typename traits_type::returns_list returns_list; - return call_into_lua(returns_list(), args_list(), L, start, std::forward(fx), std::forward(fxargs)...); + return call_into_lua(returns_list(), args_list(), L, start, std::forward(fx), std::forward(fxargs)...); } inline call_syntax get_call_syntax(lua_State* L, const std::string& key, int index) { diff --git a/sol/stack_check.hpp b/sol/stack_check.hpp index 676eb2e2..ee0c8ce8 100644 --- a/sol/stack_check.hpp +++ b/sol/stack_check.hpp @@ -87,18 +87,45 @@ namespace sol { static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); #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; } -#endif - int isnum = 0; - const lua_Number v = lua_tonumberx(L, index, &isnum); - const bool success = isnum != 0 && static_cast(std::llround(v)) == v; + const bool success = false; +#endif // If numbers are enabled, use the imprecise check if (!success) { // expected type, actual type handler(L, index, type::number, type_of(L, index)); } 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(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 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 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; if (!success) { // expected type, actual type handler(L, index, type::number, type_of(L, index)); } return success; +#endif } }; diff --git a/sol/stack_check_get.hpp b/sol/stack_check_get.hpp index 001393d1..8f6aa7bc 100644 --- a/sol/stack_check_get.hpp +++ b/sol/stack_check_get.hpp @@ -67,7 +67,7 @@ namespace sol { const lua_Number value = lua_tonumberx(L, index, &isnum); if (isnum != 0) { #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(integer_value) == value) { tracking.use(1); return static_cast(integer_value); diff --git a/sol/stack_core.hpp b/sol/stack_core.hpp index a9628f1c..f87cde83 100644 --- a/sol/stack_core.hpp +++ b/sol/stack_core.hpp @@ -29,9 +29,13 @@ #include "traits.hpp" #include "tie.hpp" #include "stack_guard.hpp" +#include "demangle.hpp" +#include "forward_detail.hpp" + #include #include #include +#include namespace sol { namespace detail { @@ -52,17 +56,8 @@ namespace sol { return 0; } - template - inline void usertype_unique_alloc_destroy(void* memory) { - T** pointerpointer = static_cast(memory); - unique_destructor* dx = static_cast(static_cast(pointerpointer + 1)); - Real* target = static_cast(static_cast(dx + 1)); - std::allocator alloc; - alloc.destroy(target); - } - template - inline int user_alloc_destroy(lua_State* L) { + inline int user_alloc_destruct(lua_State* L) { void* rawdata = lua_touserdata(L, 1); T* data = static_cast(rawdata); std::allocator alloc; @@ -71,7 +66,7 @@ namespace sol { } template - inline int usertype_alloc_destroy(lua_State* L) { + inline int usertype_alloc_destruct(lua_State* L) { void* rawdata = lua_touserdata(L, 1); T** pdata = static_cast(rawdata); T* data = *pdata; @@ -80,6 +75,20 @@ namespace sol { return 0; } + template + 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().data()); + } + + template + inline void usertype_unique_alloc_destroy(void* memory) { + T** pointerpointer = static_cast(memory); + unique_destructor* dx = static_cast(static_cast(pointerpointer + 1)); + Real* target = static_cast(static_cast(dx + 1)); + std::allocator alloc; + alloc.destroy(target); + } + template void reserve(T&, std::size_t) {} diff --git a/sol/stack_get.hpp b/sol/stack_get.hpp index 3861c323..e99b0e9b 100644 --- a/sol/stack_get.hpp +++ b/sol/stack_get.hpp @@ -68,7 +68,7 @@ namespace sol { return static_cast(lua_tointeger(L, index)); } #endif - return static_cast(std::llround(lua_tonumber(L, index))); + return static_cast(llround(lua_tonumber(L, index))); } }; diff --git a/sol/stack_push.hpp b/sol/stack_push.hpp index acec6498..6b280f6f 100644 --- a/sol/stack_push.hpp +++ b/sol/stack_push.hpp @@ -26,6 +26,8 @@ #include "raii.hpp" #include "optional.hpp" #include "usertype_traits.hpp" +#include "filters.hpp" + #include #include #include @@ -83,10 +85,8 @@ namespace sol { template static int push_keyed(lua_State* L, K&& k, Args&&... args) { - return push_fx(L, [&L, &k]() { - luaL_newmetatable(L, &k[0]); - lua_setmetatable(L, -2); - }, std::forward(args)...); + stack_detail::undefined_metatable fx(L, &k[0]); + return push_fx(L, fx, std::forward(args)...); } template @@ -97,6 +97,8 @@ namespace sol { template struct pusher> { + typedef meta::unqualified_t U; + template static int push_fx(lua_State* L, F&& f, T* obj) { if (obj == nullptr) @@ -109,14 +111,12 @@ namespace sol { template static int push_keyed(lua_State* L, K&& k, T* obj) { - return push_fx(L, [&L, &k]() { - luaL_newmetatable(L, &k[0]); - lua_setmetatable(L, -2); - }, obj); + stack_detail::undefined_metatable fx(L, &k[0]); + return push_fx(L, fx, obj); } static int push(lua_State* L, T* obj) { - return push_keyed(L, usertype_traits*>::metatable(), obj); + return push_keyed(L, usertype_traits::metatable(), obj); } }; @@ -171,7 +171,12 @@ namespace sol { detail::default_construct::construct(mem, std::forward(args)...); *pref = unique_usertype_traits::get(*mem); if (luaL_newmetatable(L, &usertype_traits>::metatable()[0]) == 1) { - set_field(L, "__gc", detail::unique_destruct

); + luaL_Reg l[32]{}; + int index = 0; + auto prop_fx = [](meta_function) { return true; }; + usertype_detail::insert_default_registrations

(l, index, prop_fx); + usertype_detail::make_destructor(l, index); + luaL_setfuncs(L, l, 0); } lua_setmetatable(L, -2); return 1; @@ -213,7 +218,7 @@ namespace sol { } #endif #if defined(SOL_CHECK_ARGUMENTS) && !defined(SOL_NO_CHECK_NUMBER_PRECISION) - if (static_cast(std::llround(static_cast(value))) != value) { + if (static_cast(llround(static_cast(value))) != value) { #ifndef SOL_NO_EXCEPTIONS throw sol::error("The integer will be misrepresented in lua."); #else @@ -437,7 +442,7 @@ namespace sol { std::allocator alloc; alloc.construct(data, std::forward(args)...); if (with_meta) { - lua_CFunction cdel = detail::user_alloc_destroy; + lua_CFunction cdel = detail::user_alloc_destruct; // Make sure we have a plain GC set for this data if (luaL_newmetatable(L, name) != 0) { lua_pushcclosure(L, cdel, 0); @@ -561,6 +566,30 @@ namespace sol { } }; + template <> + struct pusher { + static int push(lua_State* L, absolute_index ai) { + lua_pushvalue(L, ai); + return 1; + } + }; + + template <> + struct pusher { + static int push(lua_State* L, raw_index ri) { + lua_pushvalue(L, ri); + return 1; + } + }; + + template <> + struct pusher { + static int push(lua_State* L, ref_index ri) { + lua_rawgeti(L, LUA_REGISTRYINDEX, ri); + return 1; + } + }; + #ifdef SOL_CODECVT_SUPPORT template<> struct pusher { diff --git a/sol/state.hpp b/sol/state.hpp index 7b716bf8..33e3cd80 100644 --- a/sol/state.hpp +++ b/sol/state.hpp @@ -32,9 +32,10 @@ namespace sol { (void)L; return -1; #else - const char* message = lua_tostring(L, -1); + size_t messagesize; + const char* message = lua_tolstring(L, -1, &messagesize); if (message) { - std::string err = message; + std::string err(message, messagesize); lua_settop(L, 0); throw error(err); } diff --git a/sol/state_view.hpp b/sol/state_view.hpp index e61cc579..4f69568b 100644 --- a/sol/state_view.hpp +++ b/sol/state_view.hpp @@ -450,6 +450,10 @@ namespace sol { 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_status x = static_cast(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str())); 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) { 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 load_status x = static_cast(lua_load(L, reader, data, chunknametarget, to_string(mode).c_str())); #else diff --git a/sol/table_core.hpp b/sol/table_core.hpp index 508ec3bf..f9cbc552 100644 --- a/sol/table_core.hpp +++ b/sol/table_core.hpp @@ -176,7 +176,7 @@ namespace sol { 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(stack_reference&& r) : basic_table_core(r.lua_state(), r.stack_index()) {} - template >>, meta::neg, ref_index>>> = meta::enabler> + template >>> = 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, new_table nt) : base_t(L, (lua_createtable(L, nt.sequence_hint, nt.map_hint), -1)) { if (!std::is_base_of::value) { diff --git a/sol/traits.hpp b/sol/traits.hpp index ae4f8863..09cc5f75 100644 --- a/sol/traits.hpp +++ b/sol/traits.hpp @@ -261,7 +261,7 @@ namespace sol { using no = struct { char s[2]; }; struct F { void operator()(); }; - struct Derived : T, F {}; + struct Derived : T, F { ~Derived() = delete; }; template struct Check; template @@ -382,6 +382,35 @@ namespace sol { static const bool value = sizeof(test(0)) == sizeof(char); }; + template + struct has_to_string_test { + private: + typedef std::array one; + typedef std::array two; + + template static one test(decltype(std::declval().to_string())*); + template static two test(...); + + public: + static const bool value = sizeof(test(0)) == sizeof(char); + }; +#if defined(_MSC_VER) && _MSC_VER <= 1910 + template () < std::declval())> + std::true_type supports_op_less_test(std::reference_wrapper, std::reference_wrapper); + std::false_type supports_op_less_test(...); + template () == std::declval())> + std::true_type supports_op_equal_test(std::reference_wrapper, std::reference_wrapper); + std::false_type supports_op_equal_test(...); + template () <= std::declval())> + std::true_type supports_op_less_equal_test(std::reference_wrapper, std::reference_wrapper); + std::false_type supports_op_less_equal_test(...); + template () << std::declval())> + std::true_type supports_ostream_op(std::reference_wrapper, std::reference_wrapper); + std::false_type supports_ostream_op(...); + template ()))> + std::true_type supports_adl_to_string(std::reference_wrapper); + std::false_type supports_adl_to_string(...); +#else template () < std::declval())> std::true_type supports_op_less_test(const T&, const U&); std::false_type supports_op_less_test(...); @@ -394,9 +423,24 @@ namespace sol { template () << std::declval())> std::true_type supports_ostream_op(const T&, const OS&); std::false_type supports_ostream_op(...); - + template ()))> + std::true_type supports_adl_to_string(const T&); + std::false_type supports_adl_to_string(...); +#endif } // meta_detail +#if defined(_MSC_VER) && _MSC_VER <= 1910 + template + using supports_op_less = decltype(meta_detail::supports_op_less_test(std::ref(std::declval()), std::ref(std::declval()))); + template + using supports_op_equal = decltype(meta_detail::supports_op_equal_test(std::ref(std::declval()), std::ref(std::declval()))); + template + using supports_op_less_equal = decltype(meta_detail::supports_op_less_equal_test(std::ref(std::declval()), std::ref(std::declval()))); + template + using supports_ostream_op = decltype(meta_detail::supports_ostream_op(std::ref(std::declval()), std::ref(std::declval()))); + template + using supports_adl_to_string = decltype(meta_detail::supports_adl_to_string(std::ref(std::declval()))); +#else template using supports_op_less = decltype(meta_detail::supports_op_less_test(std::declval(), std::declval())); template @@ -405,6 +449,11 @@ namespace sol { using supports_op_less_equal = decltype(meta_detail::supports_op_less_equal_test(std::declval(), std::declval())); template using supports_ostream_op = decltype(meta_detail::supports_ostream_op(std::declval(), std::declval())); + template + using supports_adl_to_string = decltype(meta_detail::supports_adl_to_string(std::declval())); +#endif + template + using supports_to_string_member = meta::boolean::value>; template struct is_callable : boolean::value> {}; diff --git a/sol/types.hpp b/sol/types.hpp index 57f6b98f..3805e8d9 100644 --- a/sol/types.hpp +++ b/sol/types.hpp @@ -26,8 +26,12 @@ #include "optional.hpp" #include "compatibility.hpp" #include "forward.hpp" +#include "forward_detail.hpp" #include "traits.hpp" #include "string_shim.hpp" +#include "raii.hpp" +#include "filters.hpp" + #include #include #ifdef SOL_CXX17_FEATURES @@ -1042,6 +1046,13 @@ namespace sol { template <> struct is_lua_index : std::true_type {}; + template + struct is_stack_based : std::is_base_of {}; + template <> + struct is_stack_based : std::true_type {}; + template <> + struct is_stack_based : std::true_type {}; + template struct lua_bind_traits : meta::bind_traits { private: @@ -1083,6 +1094,48 @@ namespace sol { inline type type_of() { return lua_type_of>::value; } + + namespace detail { + template + struct is_non_factory_constructor : std::false_type {}; + + template + struct is_non_factory_constructor> : std::true_type {}; + + template + struct is_non_factory_constructor> : std::true_type {}; + + template <> + struct is_non_factory_constructor : std::true_type {}; + + template + struct is_constructor : is_non_factory_constructor {}; + + template + struct is_constructor> : std::true_type {}; + + template + struct is_constructor> : is_constructor> {}; + + template + struct is_constructor> : is_constructor> {}; + + template + using has_constructor = meta::any>...>; + + template + struct is_destructor : std::false_type {}; + + template + struct is_destructor> : std::true_type {}; + + template + using has_destructor = meta::any>...>; + + struct add_destructor_tag {}; + struct check_destructor_tag {}; + struct verified_tag {} const verified{}; + } // detail } // sol #endif // SOL_TYPES_HPP diff --git a/sol/unsafe_function.hpp b/sol/unsafe_function.hpp index 3a125ac4..c87658d9 100644 --- a/sol/unsafe_function.hpp +++ b/sol/unsafe_function.hpp @@ -81,7 +81,7 @@ namespace sol { basic_function& operator=(basic_function&&) = default; 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()) {} - template >>, meta::neg>> = meta::enabler> + template >>> = meta::enabler> 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) { #ifdef SOL_CHECK_ARGUMENTS diff --git a/sol/userdata.hpp b/sol/userdata.hpp index a665cfdc..6251fa35 100644 --- a/sol/userdata.hpp +++ b/sol/userdata.hpp @@ -48,7 +48,7 @@ namespace sol { basic_userdata& operator=(basic_userdata&&) = default; 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()) {} - template >>, meta::neg, ref_index>>> = meta::enabler> + template >>> = meta::enabler> 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) { #ifdef SOL_CHECK_ARGUMENTS @@ -85,7 +85,7 @@ namespace sol { basic_lightuserdata& operator=(basic_lightuserdata&&) = default; 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()) {} - template >>, meta::neg, ref_index>>> = meta::enabler> + template >> = meta::enabler> 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) { #ifdef SOL_CHECK_ARGUMENTS diff --git a/sol/usertype.hpp b/sol/usertype.hpp index b7c37df5..0e288bf7 100644 --- a/sol/usertype.hpp +++ b/sol/usertype.hpp @@ -36,24 +36,26 @@ namespace sol { std::unique_ptr metatableregister; template - usertype(usertype_detail::verified_tag, Args&&... args) : metatableregister(detail::make_unique_deleter, Args...>, detail::deleter>(std::forward(args)...)) {} + usertype(detail::verified_tag, Args&&... args) : metatableregister(detail::make_unique_deleter, Args...>, detail::deleter>(std::forward(args)...)) { + static_assert(detail::has_destructor::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 - usertype(usertype_detail::add_destructor_tag, Args&&... args) : usertype(usertype_detail::verified, std::forward(args)..., "__gc", default_destructor) {} + usertype(detail::add_destructor_tag, Args&&... args) : usertype(detail::verified, std::forward(args)..., "__gc", default_destructor) {} template - usertype(usertype_detail::check_destructor_tag, Args&&... args) : usertype(meta::condition, meta::neg>>, usertype_detail::add_destructor_tag, usertype_detail::verified_tag>(), std::forward(args)...) {} + usertype(detail::check_destructor_tag, Args&&... args) : usertype(meta::condition, meta::neg>>, detail::add_destructor_tag, detail::verified_tag>(), std::forward(args)...) {} public: template - usertype(Args&&... args) : usertype(meta::condition, meta::neg>>, decltype(default_constructor), usertype_detail::check_destructor_tag>(), std::forward(args)...) {} + usertype(Args&&... args) : usertype(meta::condition, meta::neg>>, decltype(default_constructor), detail::check_destructor_tag>(), std::forward(args)...) {} template - usertype(constructors constructorlist, Args&&... args) : usertype(usertype_detail::check_destructor_tag(), std::forward(args)..., "new", constructorlist) {} + usertype(constructors constructorlist, Args&&... args) : usertype(detail::check_destructor_tag(), std::forward(args)..., "new", constructorlist) {} template - usertype(constructor_wrapper constructorlist, Args&&... args) : usertype(usertype_detail::check_destructor_tag(), std::forward(args)..., "new", constructorlist) {} + usertype(constructor_wrapper constructorlist, Args&&... args) : usertype(detail::check_destructor_tag(), std::forward(args)..., "new", constructorlist) {} template usertype(simple_tag, lua_State* L, Args&&... args) : metatableregister(detail::make_unique_deleter, detail::deleter>(L, std::forward(args)...)) {} diff --git a/sol/usertype_core.hpp b/sol/usertype_core.hpp new file mode 100644 index 00000000..d8387c1f --- /dev/null +++ b/sol/usertype_core.hpp @@ -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 + +namespace sol { + namespace usertype_detail { + struct no_comp { + template + bool operator()(A&&, B&&) const { + return false; + } + }; + + template + inline int member_default_to_string(std::true_type, lua_State* L) { + std::string ts = stack::get(L, 1).to_string(); + return stack::push(L, std::move(ts)); + } + + template + 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().data()); + } + + template + inline int adl_default_to_string(std::true_type, lua_State* L) { + using std::to_string; + std::string ts = to_string(stack::get(L, 1)); + return stack::push(L, std::move(ts)); + } + + template + inline int adl_default_to_string(std::false_type, lua_State* L) { + return member_default_to_string(meta::supports_to_string_member(), L); + } + + template + inline int oss_default_to_string(std::true_type, lua_State* L) { + std::ostringstream oss; + oss << stack::get(L, 1); + return stack::push(L, oss.str()); + } + + template + inline int oss_default_to_string(std::false_type, lua_State* L) { + return adl_default_to_string(meta::supports_adl_to_string(), L); + } + + template + inline int default_to_string(lua_State* L) { + return oss_default_to_string(meta::supports_ostream_op(), L); + } + + template + int comparsion_operator_wrap(lua_State* L) { + auto maybel = stack::check_get(L, 1); + if (maybel) { + auto mayber = stack::check_get(L, 2); + if (mayber) { + auto& l = *maybel; + auto& r = *mayber; + if (std::is_same::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 = meta::enabler> + inline void make_reg_op(Regs& l, int& index, const char* name) { + lua_CFunction f = &comparsion_operator_wrap; + l[index] = luaL_Reg{ name, f }; + ++index; + } + + template = meta::enabler> + inline void make_reg_op(Regs&, int&, const char*) { + // Do nothing if there's no support + } + + template = 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>; + l[index] = luaL_Reg{ name, f }; + ++index; + } + + template = meta::enabler> + inline void make_to_string_op(Regs&, int&) { + // Do nothing if there's no support + } + + template > = 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; + l[index] = luaL_Reg{ name, f }; + ++index; + } + + template > = meta::enabler> + inline void make_call_op(Regs&, int&) { + // Do nothing if there's no support + } + + template > = 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 }; + ++index; + } + + template > = meta::enabler> + inline void make_length_op(Regs&, int&) { + // Do nothing if there's no support + } + + template >, std::is_destructible>> + 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::value ? &detail::unique_destruct : &detail::usertype_alloc_destruct }; + ++index; + } + + template >, std::is_destructible>> + void make_destructor(Regs& l, int& index) { + if (!std::is_destructible::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 }; + ++index; + } + } + + template + 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, meta::supports_op_less>(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, meta::supports_op_less_equal>(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::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>::pairs_call }; + ++index; + } + if (fx(meta_function::length)) { + usertype_detail::make_length_op(l, index); + } + if (fx(meta_function::to_string)) { + usertype_detail::make_to_string_op, meta::supports_adl_to_string, meta::supports_ostream_op>>(l, index); + } + if (fx(meta_function::call_function)) { + usertype_detail::make_call_op(l, index); + } + } + } // usertype_detail + + namespace stack { + namespace stack_detail { + template + struct undefined_metatable { + typedef meta::all>, std::is_destructible> is_destructible; + typedef std::remove_pointer_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

(l, index, fx); + usertype_detail::make_destructor(l, index); + luaL_setfuncs(L, l, 0); + } + lua_setmetatable(L, -2); + } + }; + } // stack_detail + } // stack +} // sol + +#endif // SOL_USERTYPE_CORE_HPP diff --git a/sol/usertype_metatable.hpp b/sol/usertype_metatable.hpp index d99c3a17..e40cf01e 100644 --- a/sol/usertype_metatable.hpp +++ b/sol/usertype_metatable.hpp @@ -33,6 +33,7 @@ #include "deprecate.hpp" #include "object.hpp" #include "container_usertype_metatable.hpp" +#include "usertype_core.hpp" #include #include #include @@ -102,13 +103,6 @@ namespace sol { index(std::move(i)), newindex(std::move(ni)), indexbaseclasspropogation(index), newindexbaseclasspropogation(newindex) {} }; - - template - inline int default_to_string(lua_State* L) { - std::ostringstream oss; - oss << stack::get(L, 1); - return stack::push(L, oss.str()); - } } // usertype_detail struct usertype_metatable_core { @@ -134,47 +128,6 @@ namespace sol { namespace usertype_detail { const lua_Integer toplevel_magic = static_cast(0xCCC2CCC1); - struct add_destructor_tag {}; - struct check_destructor_tag {}; - struct verified_tag {} const verified{}; - - template - struct is_non_factory_constructor : std::false_type {}; - - template - struct is_non_factory_constructor> : std::true_type {}; - - template - struct is_non_factory_constructor> : std::true_type {}; - - template <> - struct is_non_factory_constructor : std::true_type {}; - - template - struct is_constructor : is_non_factory_constructor {}; - - template - struct is_constructor> : std::true_type {}; - - template - using has_constructor = meta::any>...>; - - template - struct is_destructor : std::false_type {}; - - template - struct is_destructor> : std::true_type {}; - - template - using has_destructor = meta::any>...>; - - struct no_comp { - template - bool operator()(A&&, B&&) const { - return false; - } - }; - inline int is_indexer(string_detail::string_shim s) { if (s == to_string(meta_function::index)) { return 1; @@ -409,76 +362,6 @@ namespace sol { (void)accessor; (void)detail::swallow{ 0, (walk_single_base(L, found, ret, accessor), 0)... }; } - - template - int operator_wrap(lua_State* L) { - auto maybel = stack::check_get(L, 1); - if (maybel) { - auto mayber = stack::check_get(L, 2); - if (mayber) { - auto& l = *maybel; - auto& r = *mayber; - if (std::is_same::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 = meta::enabler> - inline void make_reg_op(Regs& l, int& index, const char* name) { - lua_CFunction f = &operator_wrap; - l[index] = luaL_Reg{ name, f }; - ++index; - } - - template = meta::enabler> - inline void make_reg_op(Regs&, int&, const char*) { - // Do nothing if there's no support - } - - template = 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>; - l[index] = luaL_Reg{ name, f }; - ++index; - } - - template = meta::enabler> - inline void make_to_string_op(Regs&, int&) { - // Do nothing if there's no support - } - - template > = 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; - l[index] = luaL_Reg{ name, f }; - ++index; - } - - template > = meta::enabler> - inline void make_call_op(Regs&, int&) { - // Do nothing if there's no support - } - - template > = 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 }; - ++index; - } - - template > = meta::enabler> - inline void make_length_op(Regs&, int&) { - // Do nothing if there's no support - } } // usertype_detail template @@ -536,32 +419,8 @@ namespace sol { } int finish_regs(regs_t& l, int& index) { - if (!properties[static_cast(meta_function::less_than)]) { - const char* name = to_string(meta_function::less_than).c_str(); - usertype_detail::make_reg_op, meta::supports_op_less>(l, index, name); - } - if (!properties[static_cast(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, meta::supports_op_less_equal>(l, index, name); - } - if (!properties[static_cast(meta_function::equal_to)]) { - const char* name = to_string(meta_function::equal_to).c_str(); - usertype_detail::make_reg_op::value, std::equal_to<>, usertype_detail::no_comp>, std::true_type>(l, index, name); - } - if (!properties[static_cast(meta_function::pairs)]) { - const char* name = to_string(meta_function::pairs).c_str(); - l[index] = luaL_Reg{ name, container_usertype_metatable>::pairs_call }; - ++index; - } - if (!properties[static_cast(meta_function::length)]) { - usertype_detail::make_length_op(l, index); - } - if (!properties[static_cast(meta_function::to_string)]) { - usertype_detail::make_to_string_op>(l, index); - } - if (!properties[static_cast(meta_function::call)]) { - usertype_detail::make_call_op(l, index); - } + auto prop_fx = [&](meta_function mf) { return !properties[static_cast(mf)]; }; + usertype_detail::insert_default_registrations(l, index, prop_fx); if (destructfunc != nullptr) { l[index] = luaL_Reg{ to_string(meta_function::garbage_collect).c_str(), destructfunc }; ++index; @@ -732,7 +591,7 @@ namespace sol { typedef meta::unqualified_tuple_element_t K; typedef meta::unqualified_tuple_element_t F; static const int boost = - !usertype_detail::is_non_factory_constructor::value + !detail::is_non_factory_constructor::value && std::is_same::value ? 1 : 0; auto& f = std::get(um.functions); diff --git a/test_container_semantics.cpp b/test_container_semantics.cpp index c2480bc0..79e170ca 100644 --- a/test_container_semantics.cpp +++ b/test_container_semantics.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include @@ -94,7 +94,7 @@ namespace sol { template 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 v = c[i] assert(v == (i + 10)) @@ -104,45 +104,45 @@ end } { 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()); - 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()); }; 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()); - 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()); }; 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()); - 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()); }; 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()); - 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()); - 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()); - 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()); - 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()); }; 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()); }; 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()); }; 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_NOTHROW(ffind()); @@ -203,7 +203,7 @@ end template 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 v = c[(i + 10)] assert(v == (i + 10)) @@ -213,45 +213,45 @@ end } { 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()); - 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()); }; 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()); - 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()); }; 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()); - 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()); }; 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()); - 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()); - 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()); - 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()); - 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()); }; 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()); }; 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()); }; 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_NOTHROW(ffind()); @@ -313,45 +313,45 @@ template void unordered_container_check(sol::state& lua, T& items) { { 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()); - 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()); }; 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()); - 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()); }; 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()); - 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()); }; 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()); - 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()); - 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()); - 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()); - 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()); }; 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()); }; 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()); }; 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_NOTHROW(ffind()); @@ -398,7 +398,7 @@ void unordered_container_check(sol::state& lua, T& items) { template 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 v = c[(i + 10)] assert(v == (i + 20)) @@ -408,47 +408,47 @@ end } { 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()); - 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()); }; 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()); - 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()); }; 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()); - 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()); - 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()); }; 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()); - 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()); - 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()); - 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()); - 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()); }; 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()); }; 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()); }; 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_NOTHROW(ffind()); @@ -518,47 +518,47 @@ template void associative_unordered_container_check(sol::state& lua, T& items) { { 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()); - 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()); }; 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()); - 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()); }; 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()); - 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()); - 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()); }; 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()); - 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()); - 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()); - 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()); - 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()); }; 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()); }; 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()); }; 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_NOTHROW(ffind()); @@ -612,7 +612,7 @@ void associative_unordered_container_check(sol::state& lua, T& items) { template 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 v = c[i] assert(v == (i + 10)) @@ -622,45 +622,45 @@ end } { 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()); - 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()); }; 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()); - 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()); }; 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()); - 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()); }; 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()); - 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()); - 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()); - 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()); - 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()); }; 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()); }; 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()); }; 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_NOTHROW(ffind()); @@ -892,7 +892,7 @@ TEST_CASE("containers/auxiliary functions test", "make sure the manipulation fun sol::state lua; lua.open_libraries(); - lua.script(R"( + lua.safe_script(R"( function g (x) x:add(20) end @@ -962,7 +962,7 @@ end REQUIRE(set.empty()); REQUIRE_NOTHROW([&]() { - lua.script(R"( + lua.safe_script(R"( c_arr[1] = 7 c_arr[2] = 7 c_arr[3] = 7 diff --git a/test_containers.cpp b/test_containers.cpp index 891843e4..ae1d1688 100644 --- a/test_containers.cpp +++ b/test_containers.cpp @@ -36,7 +36,7 @@ TEST_CASE("containers/returns", "make sure that even references to vectors are b lua.set_function("f", [&]() -> std::vector& { return v; }); - lua.script("x = f()"); + lua.safe_script("x = f()"); sol::object x = lua["x"]; sol::type xt = x.get_type(); 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{"bark", "woof"}); }); - lua.script("v1 = bark()"); - lua.script("v2 = woof()"); + lua.safe_script("v1 = bark()"); + lua.safe_script("v2 = woof()"); sol::as_table_t> as_table_strings = lua["v1"]; sol::nested> 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& { return v; }); - lua.script("x = f()"); + lua.safe_script("x = f()"); std::vector x = lua["x"]; bool areequal = x == v; REQUIRE(areequal); @@ -91,7 +91,7 @@ TEST_CASE("containers/deque roundtrip", "make sure deques can be round-tripped") lua.set_function("f", [&]() -> std::deque& { return v; }); - lua.script("x = f()"); + lua.safe_script("x = f()"); std::deque x = lua["x"]; bool areequal = x == v; REQUIRE(areequal); @@ -103,7 +103,7 @@ TEST_CASE("containers/array roundtrip", "make sure arrays can be round-tripped") lua.set_function("f", [&]() -> std::array& { return v; }); - lua.script("x = f()"); + lua.safe_script("x = f()"); std::array x = lua["x"]; bool areequal = x == v; REQUIRE(areequal); @@ -115,7 +115,7 @@ TEST_CASE("containers/list roundtrip", "make sure lists can be round-tripped") { lua.set_function("f", [&]() -> std::list& { return v; }); - lua.script("x = f()"); + lua.safe_script("x = f()"); std::list x = lua["x"]; bool areequal = x == v; 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& { return v; }); - lua.script("x = f()"); + lua.safe_script("x = f()"); std::forward_list x = lua["x"]; bool areequal = x == v; REQUIRE(areequal); @@ -139,7 +139,7 @@ TEST_CASE("containers/map roundtrip", "make sure maps can be round-tripped") { lua.set_function("f", [&]() -> std::map& { return v; }); - lua.script("x = f()"); + lua.safe_script("x = f()"); std::map x = lua["x"]; bool areequal = x == v; 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& { return v; }); - lua.script("x = f()"); + lua.safe_script("x = f()"); std::unordered_map x = lua["x"]; bool areequal = x == v; 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& { return v; }); - lua.script("x = f()"); + lua.safe_script("x = f()"); std::unordered_set x = lua["x"]; bool areequal = x == v; REQUIRE(areequal); @@ -175,7 +175,7 @@ TEST_CASE("containers/set roundtrip", "make sure sets can be round-tripped") { lua.set_function("f", [&]() -> std::set& { return v; }); - lua.script("x = f()"); + lua.safe_script("x = f()"); std::set x = lua["x"]; bool areequal = x == v; REQUIRE(areequal); @@ -187,7 +187,7 @@ TEST_CASE("containers/vector table roundtrip", "make sure vectors can be round-t lua.set_function("f", [&]() { return sol::as_table(v); }); - lua.script("x = f()"); + lua.safe_script("x = f()"); sol::as_table_t> x = lua["x"]; bool areequal = x.source == v; REQUIRE(areequal); @@ -199,7 +199,7 @@ TEST_CASE("containers/deque table roundtrip", "make sure deques can be round-tri lua.set_function("f", [&]() { return sol::as_table(v); }); - lua.script("x = f()"); + lua.safe_script("x = f()"); sol::as_table_t> x = lua["x"]; bool areequal = x.source == v; REQUIRE(areequal); @@ -211,7 +211,7 @@ TEST_CASE("containers/array table roundtrip", "make sure arrays can be round-tri lua.set_function("f", [&]() { return sol::as_table(v); }); - lua.script("x = f()"); + lua.safe_script("x = f()"); sol::as_table_t> x = lua["x"]; bool areequal = x.source == v; REQUIRE(areequal); @@ -223,7 +223,7 @@ TEST_CASE("containers/list table roundtrip", "make sure lists can be round-tripp lua.set_function("f", [&]() { return sol::as_table(v); }); - lua.script("x = f()"); + lua.safe_script("x = f()"); sol::as_table_t> x = lua["x"]; bool areequal = x.source == v; REQUIRE(areequal); @@ -235,7 +235,7 @@ TEST_CASE("containers/forward_list table roundtrip", "make sure forward_lists ca lua.set_function("f", [&]() { return sol::as_table(v); }); - lua.script("x = f()"); + lua.safe_script("x = f()"); sol::as_table_t> x = lua["x"]; bool areequal = x.source == v; REQUIRE(areequal); @@ -247,7 +247,7 @@ TEST_CASE("containers/map table roundtrip", "make sure maps can be round-tripped lua.set_function("f", [&]() { return sol::as_table(v); }); - lua.script("x = f()"); + lua.safe_script("x = f()"); sol::as_table_t> x = lua["x"]; bool areequal = x.source == v; REQUIRE(areequal); @@ -259,7 +259,7 @@ TEST_CASE("containers/unordered_map table roundtrip", "make sure unordered_maps lua.set_function("f", [&]() { return sol::as_table(v); }); - lua.script("x = f()"); + lua.safe_script("x = f()"); sol::as_table_t> x = lua["x"]; bool areequal = x.source == v; REQUIRE(areequal); @@ -271,7 +271,7 @@ TEST_CASE("containers/unordered_set table roundtrip", "make sure unordered_sets lua.set_function("f", [&]() { return sol::as_table(v); }); - lua.script("x = f()"); + lua.safe_script("x = f()"); sol::as_table_t> x = lua["x"]; bool areequal = x.source == v; REQUIRE(areequal); @@ -283,7 +283,7 @@ TEST_CASE("containers/set table roundtrip", "make sure sets can be round-tripped lua.set_function("f", [&]() { return sol::as_table(v); }); - lua.script("x = f()"); + lua.safe_script("x = f()"); sol::as_table_t> x = lua["x"]; bool areequal = x.source == v; REQUIRE(areequal); @@ -304,11 +304,11 @@ TEST_CASE("containers/custom usertype", "make sure container usertype metatables ); bark obj{ { 24, 50 } }; lua.set("a", &obj); - REQUIRE_NOTHROW(lua.script("assert(a:at(24) == 50)")); - REQUIRE_NOTHROW(lua.script("a:something()")); + REQUIRE_NOTHROW(lua.safe_script("assert(a:at(24) == 50)")); + REQUIRE_NOTHROW(lua.safe_script("a:something()")); lua.set("a", obj); - REQUIRE_NOTHROW(lua.script("assert(a:at(24) == 50)")); - REQUIRE_NOTHROW(lua.script("a:something()")); + REQUIRE_NOTHROW(lua.safe_script("assert(a:at(24) == 50)")); + REQUIRE_NOTHROW(lua.safe_script("a:something()")); } 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(); bark obj{ { 24, 50 } }; 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); 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") { @@ -330,20 +330,20 @@ TEST_CASE("containers/basic serialization", "make sure containers are turned int 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 }); 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 }; lua.set("b", w); 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); 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)); 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.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( - 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); REQUIRE_FALSE(result.valid()); @@ -367,20 +367,20 @@ TEST_CASE("containers/table serialization", "ensure types can be serialized as t 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 })); 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 }; lua.set("b", sol::as_table(w)); 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)); 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))); 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 bar; bar.push_back(&vec); - lua.script(R"( + lua.safe_script(R"( func = function(vecs) for i = 1, #vecs do 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_four", test_table_return_four); - REQUIRE_NOTHROW(lua.script("a = test_one()")); - REQUIRE_NOTHROW(lua.script("b = test_two()")); - REQUIRE_NOTHROW(lua.script("c = test_three()")); - REQUIRE_NOTHROW(lua.script("d = test_four()")); + REQUIRE_NOTHROW(lua.safe_script("a = test_one()")); + REQUIRE_NOTHROW(lua.safe_script("b = test_two()")); + REQUIRE_NOTHROW(lua.safe_script("c = test_three()")); + REQUIRE_NOTHROW(lua.safe_script("d = test_four()")); - REQUIRE_NOTHROW(lua.script("assert(#a == 10, 'error')")); - REQUIRE_NOTHROW(lua.script("assert(a[3] == 3, 'error')")); - REQUIRE_NOTHROW(lua.script("assert(b.one == 1, 'error')")); - REQUIRE_NOTHROW(lua.script("assert(b.three == 3, 'error')")); - REQUIRE_NOTHROW(lua.script("assert(c.name == 'Rapptz', 'error')")); - REQUIRE_NOTHROW(lua.script("assert(c.project == 'sol', 'error')")); - REQUIRE_NOTHROW(lua.script("assert(d.one == 1, 'error')")); - REQUIRE_NOTHROW(lua.script("assert(d.three == 3, 'error')")); - REQUIRE_NOTHROW(lua.script("assert(d.four == 4, 'error')")); + REQUIRE_NOTHROW(lua.safe_script("assert(#a == 10, 'error')")); + REQUIRE_NOTHROW(lua.safe_script("assert(a[3] == 3, 'error')")); + REQUIRE_NOTHROW(lua.safe_script("assert(b.one == 1, 'error')")); + REQUIRE_NOTHROW(lua.safe_script("assert(b.three == 3, 'error')")); + REQUIRE_NOTHROW(lua.safe_script("assert(c.name == 'Rapptz', 'error')")); + REQUIRE_NOTHROW(lua.safe_script("assert(c.project == 'sol', 'error')")); + REQUIRE_NOTHROW(lua.safe_script("assert(d.one == 1, 'error')")); + REQUIRE_NOTHROW(lua.safe_script("assert(d.three == 3, 'error')")); + REQUIRE_NOTHROW(lua.safe_script("assert(d.four == 4, 'error')")); sol::table a = lua.get("a"); sol::table b = lua.get("b"); @@ -483,7 +483,7 @@ TEST_CASE("containers/usertype transparency", "Make sure containers pass their a "a_list", &B::a_list ); - lua.script(R"( + lua.safe_script(R"( b = B.new() 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; lua["machine"] = &m; - lua.script(R"( + lua.safe_script(R"( machine:opt():output_help() )"); @@ -577,7 +577,7 @@ TEST_CASE("containers/readonly", "make sure readonly members are stored appropri ); lua["value"] = std::list{ {},{},{} }; - lua.script(R"( + lua.safe_script(R"( a = foo.new() x = a.seq a.seq = value @@ -597,7 +597,7 @@ TEST_CASE("containers/to_args", "Test that the to_args abstractions works") { sol::state lua; 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"]; int a, b, c, d; @@ -637,11 +637,11 @@ TEST_CASE("containers/ipairs test", "ensure that abstractions roundtrip properly return std::vector(5, &t); }); - lua.script(R"( + lua.safe_script(R"( c = f() )"); - lua.script(R"( + lua.safe_script(R"( check = {} local i = 1 while c[i] do @@ -660,7 +660,7 @@ end TEST_CASE("containers/append idiom", "ensure the append-idiom works as intended") { sol::state lua; lua.open_libraries(sol::lib::base); - lua.script( + lua.safe_script( R"( function f_fill(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; lua["c"] = &c; #if SOL_LUA_VERSION > 502 - lua.script(R"lua( + lua.safe_script(R"lua( for k, v in pairs(c) do assert((k - 1) == v:val()) end )lua"); #endif - lua.script(R"lua( + lua.safe_script(R"lua( for k=1,#c do v = c[k] 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["d"] = &d; - lua.script("av1, av2 = a:get(1)"); - lua.script("bv1, bv2 = b:get(1)"); - lua.script("cv1, cv2 = c:get(1)"); - lua.script("dv1, dv2 = d:get(1)"); + lua.safe_script("av1, av2 = a:get(1)"); + lua.safe_script("bv1, bv2 = b:get(1)"); + lua.safe_script("cv1, cv2 = c:get(1)"); + lua.safe_script("dv1, dv2 = d:get(1)"); std::vector>& la = lua["a"]; std::array, 5>& lb = lua["b"]; diff --git a/test_coroutines.cpp b/test_coroutines.cpp index a3276bcd..317e76cc 100644 --- a/test_coroutines.cpp +++ b/test_coroutines.cpp @@ -18,7 +18,7 @@ end sol::state lua; lua.open_libraries(sol::lib::base, sol::lib::coroutine); - lua.script(script); + lua.safe_script(script); sol::coroutine cr = lua["loop"]; int counter; @@ -47,7 +47,7 @@ end sol::state lua; 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::state_view runnerstate = runner.state(); sol::coroutine cr = runnerstate["loop"]; diff --git a/test_customizations.cpp b/test_customizations.cpp index 9f398e54..be086a06 100644 --- a/test_customizations.cpp +++ b/test_customizations.cpp @@ -68,7 +68,7 @@ TEST_CASE("customization/split struct", "using the newly documented customizatio sol::state lua; // 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) { return std::make_tuple(a + c, b, d + 2.5); }); diff --git a/test_environments.cpp b/test_environments.cpp index 30be5f61..39a01cd3 100644 --- a/test_environments.cpp +++ b/test_environments.cpp @@ -1,7 +1,8 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 + +#include #include -#include #include #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); 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::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(); REQUIRE(result == 31); - lua.script("g = function() test = 5 end"); + lua.safe_script("g = function() test = 5 end"); sol::function g = lua["g"]; sol::environment env_g(lua, sol::create); 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"]; REQUIRE(!global_test.valid()); - lua.script("h = function() end"); + lua.safe_script("h = function() end"); lua.set_function("check_f_env", [&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]() { - lua.script("check_f_env(f)"); - lua.script("check_g_env(g)"); - lua.script("check_h_env(h)"); + lua.safe_script("check_f_env(f)"); + lua.safe_script("check_g_env(g)"); + lua.safe_script("check_h_env(h)"); }()); } @@ -80,7 +81,7 @@ TEST_CASE("environments/shadowing", "Environments can properly shadow and fallba SECTION("no fallback") { sol::environment plain_env(lua, sol::create); - lua.script("a = 24", plain_env); + lua.safe_script("a = 24", plain_env); sol::optional maybe_env_a = plain_env["a"]; sol::optional maybe_global_a = lua["a"]; sol::optional maybe_env_b = plain_env["b"]; @@ -96,7 +97,7 @@ TEST_CASE("environments/shadowing", "Environments can properly shadow and fallba } SECTION("fallback") { 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 maybe_env_a = env_with_fallback["a"]; sol::optional maybe_global_a = lua["a"]; sol::optional 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()); lua["env"] = env_with_fallback; 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 maybe_env_a = env["a"]; sol::optional maybe_global_a = lua["a"]; sol::optional maybe_env_b = env["b"]; @@ -133,7 +134,7 @@ TEST_CASE("environments/shadowing", "Environments can properly shadow and fallba SECTION("name with newtable") { lua["blank_env"] = sol::new_table(0, 1); sol::environment plain_env = lua["blank_env"]; - lua.script("a = 24", plain_env); + lua.safe_script("a = 24", plain_env); sol::optional maybe_env_a = plain_env["a"]; sol::optional maybe_global_a = lua["a"]; sol::optional maybe_env_b = plain_env["b"]; @@ -154,7 +155,7 @@ TEST_CASE("environments/functions", "see if environments on functions are workin SECTION("basic") { sol::state lua; - lua.script("a = function() return 5 end"); + lua.safe_script("a = function() return 5 end"); sol::function a = lua["a"]; @@ -170,7 +171,7 @@ TEST_CASE("environments/functions", "see if environments on functions are workin SECTION("return environment value") { sol::state lua; - lua.script("a = function() return test end"); + lua.safe_script("a = function() return test end"); sol::function a = lua["a"]; 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") { sol::state lua; - lua.script("a = function() test = 5 end"); + lua.safe_script("a = function() test = 5 end"); sol::function a = lua["a"]; sol::environment env(lua, sol::create); @@ -220,7 +221,7 @@ TEST_CASE("environments/this_environment", "test various situations of pulling o lua["x"] = 5; e["x"] = 20; SECTION("from Lua script") { - int value = lua.script(code, e); + int value = lua.safe_script(code, e); REQUIRE(value == 30); } SECTION("from C++") { diff --git a/test_filters.cpp b/test_filters.cpp new file mode 100644 index 00000000..a44c8ef5 --- /dev/null +++ b/test_filters.cpp @@ -0,0 +1,236 @@ +#define SOL_CHECK_ARGUMENTS 1 + +#include +#include + +#include +#include + +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::lowest(); + y = std::numeric_limits::lowest(); + } + }; + + sol::state lua; + lua.open_libraries(sol::lib::base); + + lua.new_usertype("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 deps_destroyed; + static std::vector gc_tests_destroyed; + + struct dep { + int value = 20; + ~dep() { + std::cout << "\t" << "[C++] ~dep" << std::endl; + value = std::numeric_limits::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", + "value", &dep::value, + sol::meta_function::to_string, [](dep& d) { + return "{ " + std::to_string(d.value) + " }"; + } + ); + lua.new_usertype("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_relateds_destroyed; + static std::vector holders_destroyed; + static std::vector 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::max(); + holders_destroyed.push_back(this); + } + }; + + struct depends_on_reference { + + std::reference_wrapper 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", + "value", &holder::value + ); + lua.new_usertype("depends_on_reference", + "new", sol::filters(sol::constructors(), 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); +} diff --git a/test_functions.cpp b/test_functions.cpp index 6761600e..23a78e5b 100644 --- a/test_functions.cpp +++ b/test_functions.cpp @@ -1,7 +1,9 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 + +#include #include -#include + #include #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") { sol::state lua; - lua.script("function f() return '3', 4 end"); + lua.safe_script("function f() return '3', 4 end"); std::tuple result = lua["f"](); 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.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 // deductions to make this work lua.set_function("overloaded", overloaded); - REQUIRE_NOTHROW(lua.script("print(overloaded(1))")); + REQUIRE_NOTHROW(lua.safe_script("print(overloaded(1))")); lua.set_function("overloaded", overloaded); - REQUIRE_NOTHROW(lua.script("print(overloaded(1, 2))")); + REQUIRE_NOTHROW(lua.safe_script("print(overloaded(1, 2))")); lua.set_function("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(overloaded)); - REQUIRE_NOTHROW(lua.script("print(overloaded(1))")); + REQUIRE_NOTHROW(lua.safe_script("print(overloaded(1))")); lua.set_function("overloaded", sol::resolve(overloaded)); - REQUIRE_NOTHROW(lua.script("print(overloaded(1, 2))")); + REQUIRE_NOTHROW(lua.safe_script("print(overloaded(1, 2))")); lua.set_function("overloaded", sol::resolve(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") { @@ -154,7 +156,7 @@ TEST_CASE("functions/return order and multi get", "Check if return order is in t lua.set_function("h", []() { 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("f").call(); auto tlua = lua.get("g").call(); auto tcpp2 = lua.get("h").call(); @@ -180,7 +182,7 @@ TEST_CASE("functions/deducing return order and multi get", "Check if return orde lua.set_function("f", [] { 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 tcpp = lua.get("f")(); std::tuple tlua = lua.get("g")(); std::tuple tluaget = lua.get("x", "y", "z"); @@ -197,7 +199,7 @@ TEST_CASE("functions/optional values", "check if optionals can be passed in to b int v; }; sol::state lua; - lua.script(R"( function f (a) + lua.safe_script(R"( function f (a) return a end )"); @@ -217,7 +219,7 @@ TEST_CASE("functions/pair and tuple and proxy tests", "Check if sol::reference a sol::state lua; lua.new_usertype("A", "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() end 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("testFunc2", test_free_func2); - lua.script( + lua.safe_script( "testFunc(function() print(\"hello std::function\") end)" ); - REQUIRE_NOTHROW(lua.script( + REQUIRE_NOTHROW(lua.safe_script( "function m(a)\n" " print(\"hello std::function with arg \", 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("takefn", takefn); - lua.script("afx = makefn()\n" + lua.safe_script("afx = makefn()\n" "print(afx())\n" "takefn(afx)\n"); } @@ -308,7 +310,7 @@ TEST_CASE("functions/function_result and protected_function_result", "Function r return handlederrormessage; }; lua.set_function("cpphandler", cpphandlerfx); - lua.script( + lua.safe_script( std::string("function luahandler ( message )") + " print('lua handler called with: ' .. message)" + " 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(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(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") { 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("n", sol::c_call); - lua.script(R"( + lua.safe_script(R"( o1 = test_1.new() o2 = test_2.new() )"); - lua.script(R"( + lua.safe_script(R"( ob = o1:bark() A = a() @@ -551,32 +474,32 @@ I = i(o1) )"); - lua.script(R"( + lua.safe_script(R"( J0 = j() j(24) J1 = j() )"); - lua.script(R"( + lua.safe_script(R"( K0 = k(o2) k(o2, 1024) K1 = k(o2) )"); - lua.script(R"( + lua.safe_script(R"( L0 = l(o1) l(o1, 678) L1 = l(o1) )"); - lua.script(R"( + lua.safe_script(R"( M0 = m() m(256) M1 = m() )"); - lua.script(R"( + lua.safe_script(R"( 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; @@ -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++") { 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("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("my_nothing"); REQUIRE_NOTHROW([&]() { fvoid(1, 2, 3); @@ -699,7 +622,7 @@ TEST_CASE("simple/call c++ function", "C++ function is called from lua") { sol::state lua; 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("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.script("foo()"); + lua.safe_script("foo()"); REQUIRE(a == 1); } @@ -795,7 +718,7 @@ TEST_CASE("advanced/call lambdas", "A C++ lambda is exposed to lua and called") return 0; }); - lua.script("set_x(9)"); + lua.safe_script("set_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.script("set_x(9)"); - lua.script("set_y(9)"); + lua.safe_script("set_x(9)"); + lua.safe_script("set_y(9)"); REQUIRE(x == 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") { sol::state lua; - lua.script(R"(function f () + lua.safe_script(R"(function f () return 1, 2, 3 end)"); 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"; - REQUIRE_NOTHROW(lua.script( + REQUIRE_NOTHROW(lua.safe_script( "a = func(1)\n" "b = func('bark')\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); lua.set("obj", fer()); - lua.script("r1 = f(1)"); - lua.script("r2 = f(1, 2)"); - lua.script("r3 = f(obj, 1, 2)"); - lua.script("r4 = g(1)"); - lua.script("r5 = h(1, 2)"); + lua.safe_script("r1 = f(1)"); + lua.safe_script("r2 = f(1, 2)"); + lua.safe_script("r3 = f(obj, 1, 2)"); + lua.safe_script("r4 = g(1)"); + lua.safe_script("r5 = h(1, 2)"); int r1 = lua["r1"]; 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; lua.open_libraries(sol::lib::base, sol::lib::string); - lua.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 ErrorHandler(msg) print('Lua created error msg : ' .. msg) return msg 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 { @@ -941,48 +864,9 @@ TEST_CASE("functions/stack atomic", "make sure functions don't impede on the sta 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 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(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") { 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); @@ -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") { 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); @@ -1030,8 +914,8 @@ TEST_CASE("functions/function_result as arguments", "ensure that function_result sol::state lua; lua.open_libraries(); - lua.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 f () return 1, 2, 3, 4, 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); @@ -1059,8 +943,8 @@ TEST_CASE("functions/protected_function_result as arguments", "ensure that prote sol::state lua; lua.open_libraries(); - lua.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 f () return 1, 2, 3, 4, 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); @@ -1091,9 +975,9 @@ TEST_CASE("functions/overloaded variadic", "make sure variadics work to some deg sol::table ssl = lua.create_named_table("ssl"); ssl.set_function("test", sol::overload(&va_func, &va_func)); - lua.script("a = ssl.test(1, 2, 3)"); - lua.script("b = ssl.test(1, 2)"); - lua.script("c = ssl.test(2.2)"); + lua.safe_script("a = ssl.test(1, 2, 3)"); + lua.safe_script("b = ssl.test(1, 2)"); + lua.safe_script("c = ssl.test(2.2)"); int a = lua["a"]; int b = lua["b"]; @@ -1117,20 +1001,20 @@ TEST_CASE("functions/sectioning variadic", "make sure variadics can bite off chu return r; }); - lua.script("x = f(1, 2, 3, 4)"); - lua.script("x2 = f(8, 200, 3, 4)"); - lua.script("x3 = f(1, 2, 3, 4, 5, 6)"); + lua.safe_script("x = f(1, 2, 3, 4)"); + lua.safe_script("x2 = f(8, 200, 3, 4)"); + lua.safe_script("x3 = f(1, 2, 3, 4, 5, 6)"); - lua.script("print(x) assert(x == 7)"); - lua.script("print(x2) assert(x2 == 7)"); - lua.script("print(x3) assert(x3 == 18)"); + lua.safe_script("print(x) assert(x == 7)"); + lua.safe_script("print(x2) assert(x2 == 7)"); + 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") { SECTION("test different types") { sol::state lua; 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; std::function 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("test3", sfn); - REQUIRE_NOTHROW(lua.script("assert(type(test) == 'function')")); - REQUIRE_NOTHROW(lua.script("assert(test() ~= nil)")); - REQUIRE_NOTHROW(lua.script("assert(test() == 5)")); + REQUIRE_NOTHROW(lua.safe_script("assert(type(test) == 'function')")); + REQUIRE_NOTHROW(lua.safe_script("assert(test() ~= nil)")); + REQUIRE_NOTHROW(lua.safe_script("assert(test() == 5)")); - REQUIRE_NOTHROW(lua.script("assert(type(test2) == 'function')")); - REQUIRE_NOTHROW(lua.script("assert(test2() ~= nil)")); - REQUIRE_NOTHROW(lua.script("assert(test2() == 5)")); + REQUIRE_NOTHROW(lua.safe_script("assert(type(test2) == 'function')")); + REQUIRE_NOTHROW(lua.safe_script("assert(test2() ~= nil)")); + REQUIRE_NOTHROW(lua.safe_script("assert(test2() == 5)")); - REQUIRE_NOTHROW(lua.script("assert(type(test3) == 'function')")); - REQUIRE_NOTHROW(lua.script("assert(test3() ~= nil)")); - REQUIRE_NOTHROW(lua.script("assert(test3() == 5)")); + REQUIRE_NOTHROW(lua.safe_script("assert(type(test3) == 'function')")); + REQUIRE_NOTHROW(lua.safe_script("assert(test3() ~= nil)")); + REQUIRE_NOTHROW(lua.safe_script("assert(test3() == 5)")); } SECTION("getting the value from C++") { sol::state lua; 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(); REQUIRE(result == 5); @@ -1163,13 +1047,13 @@ TEST_CASE("functions/set_function already wrapped", "setting a function returned SECTION("setting the function directly") { sol::state lua; 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); - REQUIRE_NOTHROW(lua.script("assert(type(test) == 'function')")); - REQUIRE_NOTHROW(lua.script("assert(test() ~= nil)")); - REQUIRE_NOTHROW(lua.script("assert(test() == 5)")); + REQUIRE_NOTHROW(lua.safe_script("assert(type(test) == 'function')")); + REQUIRE_NOTHROW(lua.safe_script("assert(test() ~= nil)")); + 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; 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); - REQUIRE_NOTHROW(lua.script("assert(type(test) == 'function')")); - REQUIRE_NOTHROW(lua.script("test()")); + REQUIRE_NOTHROW(lua.safe_script("assert(type(test) == 'function')")); + REQUIRE_NOTHROW(lua.safe_script("test()")); } SECTION("setting the function indirectly, with the return value cast explicitly") { sol::state lua; 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(); }); - REQUIRE_NOTHROW(lua.script("assert(type(test) == 'function')")); - REQUIRE_NOTHROW(lua.script("assert(test() ~= nil)")); - REQUIRE_NOTHROW(lua.script("assert(test() == 5)")); + REQUIRE_NOTHROW(lua.safe_script("assert(type(test) == 'function')")); + REQUIRE_NOTHROW(lua.safe_script("assert(test() ~= nil)")); + 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; REQUIRE_NOTHROW([&]() { - lua.script("f(v1)"); - lua.script("f(v2)"); - lua.script("f(v3)"); - lua.script("f(v4)"); + lua.safe_script("f(v1)"); + lua.safe_script("f(v2)"); + lua.safe_script("f(v3)"); + lua.safe_script("f(v4)"); - lua.script("assert(v1 == nil)"); - lua.script("assert(v2 == nil)"); - lua.script("assert(v3 == nil)"); - lua.script("assert(v4 == nil)"); + lua.safe_script("assert(v1 == nil)"); + lua.safe_script("assert(v2 == nil)"); + lua.safe_script("assert(v3 == nil)"); + lua.safe_script("assert(v4 == nil)"); }()); } SECTION("throw unique argument") { @@ -1405,16 +1289,16 @@ TEST_CASE("functions/unique_usertype overloading", "make sure overloading can wo lua["v4"] = ut.get(); REQUIRE_NOTHROW([&]() { - lua.script("f(v1)"); - lua.script("g(v1)"); - lua.script("g(v2)"); - lua.script("g(v3)"); - lua.script("g(v4)"); - lua.script("h(v1)"); - lua.script("h(v2)"); - lua.script("h(v3)"); - lua.script("h(v4)"); - lua.script("i(20, v1)"); + lua.safe_script("f(v1)"); + lua.safe_script("g(v1)"); + lua.safe_script("g(v2)"); + lua.safe_script("g(v3)"); + lua.safe_script("g(v4)"); + lua.safe_script("h(v1)"); + lua.safe_script("h(v2)"); + lua.safe_script("h(v3)"); + lua.safe_script("h(v4)"); + lua.safe_script("i(20, v1)"); }()); }; // 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["t"] = T(); - lua.script("v1 = f()"); - lua.script("v2 = g(t)"); - lua.script("v3 = h()"); - lua.script("v4 = i()"); - lua.script("v5 = j()"); - lua.script("v6 = k()"); - lua.script("v7 = l()"); - lua.script("v8 = m()"); + lua.safe_script("v1 = f()"); + lua.safe_script("v2 = g(t)"); + lua.safe_script("v3 = h()"); + lua.safe_script("v4 = i()"); + lua.safe_script("v5 = j()"); + lua.safe_script("v6 = k()"); + lua.safe_script("v7 = l()"); + lua.safe_script("v8 = m()"); int v1 = lua["v1"]; int v2 = lua["v2"]; int v3 = lua["v3"]; diff --git a/test_gc.cpp b/test_gc.cpp new file mode 100644 index 00000000..be9a24b9 --- /dev/null +++ b/test_gc.cpp @@ -0,0 +1,504 @@ +#define SOL_CHECK_ARGUMENTS 1 + +#include +#include + +#include +#include +#include +#include +#include + +TEST_CASE("gc/destructors", "test if destructors are fired properly through gc of unbound usertypes") { + struct test; + static std::vector 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 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("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("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(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(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 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(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 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 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("CrashClass", + sol::call_constructor, sol::constructors>() + ); + + 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("CrashClass", + sol::call_constructor, sol::constructors>() + ); + + 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> tests; + sol::state lua; + lua.open_libraries(); + + lua.new_usertype("test", + "create", [&]() -> std::shared_ptr { + tests.push_back(std::make_shared()); + 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& 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> tests; + sol::state lua; + lua.open_libraries(); + + lua.new_simple_usertype("test", + "create", [&]() -> std::shared_ptr { + tests.push_back(std::make_shared()); + 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& 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", "x", &c_a::xv); + lua.new_usertype("c_b", "y", &c_b::yv); + lua = sol::state(); + lua.new_usertype("c_a", "x", &c_a::xv); + lua.new_usertype("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("c_a", "x", &sc_a::xv); + lua.new_simple_usertype("c_b", "y", &sc_b::yv); + lua = sol::state(); + lua.new_simple_usertype("c_a", "x", &sc_a::xv); + lua.new_simple_usertype("c_b", "y", &sc_b::yv); + lua = sol::state(); + }; + REQUIRE_NOTHROW(routine()); + } +} diff --git a/test_inheritance.cpp b/test_inheritance.cpp index 3071dac8..2b2d74e0 100644 --- a/test_inheritance.cpp +++ b/test_inheritance.cpp @@ -42,14 +42,14 @@ TEST_CASE("inheritance/basic", "test that metatables are properly inherited") { sol::base_classes, sol::bases() ); - lua.script("obj = D.new()"); - lua.script("d = obj:d()"); + lua.safe_script("obj = D.new()"); + lua.safe_script("d = obj:d()"); bool d = lua["d"]; - lua.script("c = obj.c"); + lua.safe_script("c = obj.c"); double c = lua["c"]; - lua.script("b = obj:b()"); + lua.safe_script("b = obj:b()"); int b = lua["b"]; - lua.script("a = obj.a"); + lua.safe_script("a = obj.a"); int a = lua["a"]; 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.script(R"( + lua.safe_script(R"( tc0 = TestClass00() )"); - lua.script(R"( + lua.safe_script(R"( tc2 = TestClass02(tc0) )"); - lua.script(R"( + lua.safe_script(R"( tc1 = TestClass01() )"); - lua.script(R"( + lua.safe_script(R"( 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.script(R"( + lua.safe_script(R"( tc0 = TestClass00() )"); - lua.script(R"( + lua.safe_script(R"( tc2 = TestClass02(tc0) )"); - lua.script(R"( + lua.safe_script(R"( tc1 = TestClass01() )"); - lua.script(R"( + lua.safe_script(R"( tc3 = TestClass03(tc1) )"); diff --git a/test_large_integer.cpp b/test_large_integer.cpp index e2b79c66..d0e09303 100644 --- a/test_large_integer.cpp +++ b/test_large_integer.cpp @@ -12,8 +12,8 @@ TEST_CASE("large_integer/bool", "pass bool integral value to and from lua") { REQUIRE(num == true); return num; }); - lua.script("x = f(true)"); - lua.script("assert(x == true)"); + lua.safe_script("x = f(true)"); + lua.safe_script("assert(x == true)"); sol::object x = lua["x"]; REQUIRE(x.is()); REQUIRE(x.as() == true); @@ -32,8 +32,8 @@ TEST_CASE("large_integers/unsigned32", "pass large unsigned 32bit values to and REQUIRE(num == 0xFFFFFFFF); return num; }); - lua.script("x = f(0xFFFFFFFF)"); - lua.script("assert(x == 0xFFFFFFFF)"); + lua.safe_script("x = f(0xFFFFFFFF)"); + lua.safe_script("assert(x == 0xFFFFFFFF)"); sol::object x = lua["x"]; REQUIRE(x.is()); REQUIRE(x.as() == 0xFFFFFFFF); @@ -47,8 +47,8 @@ TEST_CASE("large_integer/unsigned53", "pass large unsigned 53bit value to and fr REQUIRE(num == 0x1FFFFFFFFFFFFFull); return num; }); - lua.script("x = f(0x1FFFFFFFFFFFFF)"); - lua.script("assert(x == 0x1FFFFFFFFFFFFF)"); + lua.safe_script("x = f(0x1FFFFFFFFFFFFF)"); + lua.safe_script("assert(x == 0x1FFFFFFFFFFFFF)"); sol::object x = lua["x"]; REQUIRE(x.is()); REQUIRE(x.as() == 0x1FFFFFFFFFFFFFull); @@ -83,10 +83,10 @@ TEST_CASE("large_integer/double", "pass negative and large positive values as si }); //signed 32bit REQUIRE_NOTHROW([&lua]() { - lua.script("x = s32(-1)"); - lua.script("assert(x == -1)"); - lua.script("x = s32(0xFFFFFFFF)"); - lua.script("assert(x == -1)"); + lua.safe_script("x = s32(-1)"); + lua.safe_script("assert(x == -1)"); + lua.safe_script("x = s32(0xFFFFFFFF)"); + lua.safe_script("assert(x == -1)"); sol::object x = lua["x"]; REQUIRE(x.is()); REQUIRE(x.as() == -1); @@ -95,10 +95,10 @@ TEST_CASE("large_integer/double", "pass negative and large positive values as si }()); //unsigned 32bit REQUIRE_NOTHROW([&lua]() { - lua.script("x = u32(0xFFFFFFFF)"); - lua.script("assert(x == 0xFFFFFFFF)"); - lua.script("x = u32(-1)"); - lua.script("assert(x == 0xFFFFFFFF)"); + lua.safe_script("x = u32(0xFFFFFFFF)"); + lua.safe_script("assert(x == 0xFFFFFFFF)"); + lua.safe_script("x = u32(-1)"); + lua.safe_script("assert(x == 0xFFFFFFFF)"); sol::object x = lua["x"]; REQUIRE(x.is()); REQUIRE(x.as() == -1); @@ -107,8 +107,8 @@ TEST_CASE("large_integer/double", "pass negative and large positive values as si }()); //signed 64bit REQUIRE_NOTHROW([&lua]() { - lua.script("x = s64(-1)"); - lua.script("assert(x == -1)"); + lua.safe_script("x = s64(-1)"); + lua.safe_script("assert(x == -1)"); sol::object x = lua["x"]; REQUIRE(x.is()); REQUIRE(x.as() == -1); diff --git a/test_operators.cpp b/test_operators.cpp index 508b4347..210ed77f 100644 --- a/test_operators.cpp +++ b/test_operators.cpp @@ -47,6 +47,43 @@ TEST_CASE("operators/default", "test that generic equality operators and all sor lua["v2"] = &v2; 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") { lua.new_usertype("T"); lua.new_usertype("U"); @@ -54,38 +91,38 @@ TEST_CASE("operators/default", "test that generic equality operators and all sor // Can only compare identity here REQUIRE_NOTHROW([&] { - lua.script("assert(t1 == t1)"); - lua.script("assert(t2 == t2)"); - lua.script("assert(t3 == t3)"); + lua.safe_script("assert(t1 == t1)"); + lua.safe_script("assert(t2 == t2)"); + lua.safe_script("assert(t3 == t3)"); }()); REQUIRE_NOTHROW([&] { - lua.script("assert(t1 == t2)"); - lua.script("assert(not (t1 == t3))"); - lua.script("assert(not (t2 == t3))"); + 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.script("assert(u1 == u1)"); - lua.script("assert(u2 == u2)"); - lua.script("assert(u3 == u3)"); + lua.safe_script("assert(u1 == u1)"); + lua.safe_script("assert(u2 == u2)"); + lua.safe_script("assert(u3 == u3)"); }()); REQUIRE_NOTHROW([&] { - lua.script("assert(not (u1 == u2))"); - lua.script("assert(u1 == u3)"); - lua.script("assert(not (u2 == u3))"); + 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.script("assert(v1 == v1)"); - lua.script("assert(v2 == v2)"); - lua.script("assert(v3 == v3)"); + lua.safe_script("assert(v1 == v1)"); + lua.safe_script("assert(v2 == v2)"); + lua.safe_script("assert(v3 == v3)"); }()); REQUIRE_NOTHROW([&] { - lua.script("assert(not (v1 == v2))"); - lua.script("assert(v1 == v3)"); - lua.script("assert(not (v2 == v3))"); + lua.safe_script("assert(not (v1 == v2))"); + lua.safe_script("assert(v1 == v3)"); + lua.safe_script("assert(not (v2 == v3))"); }()); } SECTION("simple") { @@ -95,38 +132,38 @@ TEST_CASE("operators/default", "test that generic equality operators and all sor // Can only compare identity here REQUIRE_NOTHROW([&] { - lua.script("assert(t1 == t1)"); - lua.script("assert(t2 == t2)"); - lua.script("assert(t3 == t3)"); + lua.safe_script("assert(t1 == t1)"); + lua.safe_script("assert(t2 == t2)"); + lua.safe_script("assert(t3 == t3)"); }()); REQUIRE_NOTHROW([&] { - lua.script("assert(t1 == t2)"); - lua.script("assert(not (t1 == t3))"); - lua.script("assert(not (t2 == t3))"); + 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.script("assert(u1 == u1)"); - lua.script("assert(u2 == u2)"); - lua.script("assert(u3 == u3)"); + lua.safe_script("assert(u1 == u1)"); + lua.safe_script("assert(u2 == u2)"); + lua.safe_script("assert(u3 == u3)"); }()); REQUIRE_NOTHROW([&] { - lua.script("assert(not (u1 == u2))"); - lua.script("assert(u1 == u3)"); - lua.script("assert(not (u2 == u3))"); + 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.script("assert(v1 == v1)"); - lua.script("assert(v2 == v2)"); - lua.script("assert(v3 == v3)"); + lua.safe_script("assert(v1 == v1)"); + lua.safe_script("assert(v2 == v2)"); + lua.safe_script("assert(v3 == v3)"); }()); REQUIRE_NOTHROW([&] { - lua.script("assert(not (v1 == v2))"); - lua.script("assert(v1 == v3)"); - lua.script("assert(not (v2 == v3))"); + lua.safe_script("assert(not (v1 == v2))"); + lua.safe_script("assert(v1 == 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") { struct callable { int operator ()(int a, std::string b) { - return a + b.length(); + return a + static_cast(b.length()); } }; sol::state lua; 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") { lua.new_usertype("callable"); { @@ -168,13 +213,53 @@ const void* stringable::last_print_ptr = nullptr; std::ostream& operator<< (std::ostream& ostr, const stringable& o) { stringable::last_print_ptr = static_cast(&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(&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(&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(this); + return "{ member_stringable, to_string! }"; + } +}; +const void* member_stringable::last_print_ptr = nullptr; + TEST_CASE("operators/stringable", "test std::ostream stringability") { sol::state lua; 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") { lua.new_usertype("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("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("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("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("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("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("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") { #if SOL_LUA_VERSION > 501 struct container { @@ -219,6 +400,14 @@ TEST_CASE("operators/container-like", "test that generic begin/end and iterator sol::state lua; 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") { lua.new_usertype("container"); { @@ -252,6 +441,14 @@ TEST_CASE("operators/length", "test that size is automatically bound to the leng sol::state lua; 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") { lua.new_usertype("sizable"); { diff --git a/test_overflow.cpp b/test_overflow.cpp index ef7b2e4c..98d56d06 100644 --- a/test_overflow.cpp +++ b/test_overflow.cpp @@ -6,8 +6,8 @@ TEST_CASE("issues/stack overflow", "make sure various operations repeated don't trigger stack overflow") { sol::state lua; - lua.script("t = {};t[0]=20"); - lua.script("lua_function=function(i)return i;end"); + lua.safe_script("t = {};t[0]=20"); + lua.safe_script("lua_function=function(i)return i;end"); sol::function f = lua["lua_function"]; std::string teststring = "testtext"; diff --git a/test_plain_types.cpp b/test_plain_types.cpp new file mode 100644 index 00000000..a425d4ab --- /dev/null +++ b/test_plain_types.cpp @@ -0,0 +1,72 @@ +#define SOL_CHECK_ARGUMENTS 1 + +#include +#include + +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; + 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 i = sol::detail::make_unique_deleter(); + 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 i = sol::detail::make_unique_deleter(); + lua["i"] = *i; + lua.new_usertype("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()); + } +} \ No newline at end of file diff --git a/test_simple_usertypes.cpp b/test_simple_usertypes.cpp index 33cf779a..4ddb49b4 100644 --- a/test_simple_usertypes.cpp +++ b/test_simple_usertypes.cpp @@ -49,20 +49,20 @@ TEST_CASE("simple_usertype/usertypes", "Ensure that simple usertypes properly wo "z", sol::overload(&bark::get, &bark::set) ); - lua.script("b = bark.new()"); + lua.safe_script("b = bark.new()"); bark& b = lua["b"]; - lua.script("b:fun()"); + lua.safe_script("b:fun()"); int var = b.var; REQUIRE(var == 51); - lua.script("b:var(20)"); - lua.script("v = b:var()"); + lua.safe_script("b:var(20)"); + lua.safe_script("v = b:var()"); int v = lua["v"]; REQUIRE(v == 20); REQUIRE(b.var == 20); - lua.script("m = b:the_marker()"); + lua.safe_script("m = b:the_marker()"); marker& m = lua["m"]; REQUIRE_FALSE(b.mark.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"]; barktable["special"] = &bark::special; - lua.script("s = b:special()"); + lua.safe_script("s = b:special()"); std::string s = lua["s"]; REQUIRE(s == "woof"); - lua.script("b:y(24)"); - lua.script("x = b:x()"); + lua.safe_script("b:y(24)"); + lua.safe_script("x = b:x()"); int x = lua["x"]; REQUIRE(x == 24); - lua.script("z = b:z(b:z() + 5)"); + lua.safe_script("z = b:z(b:z() + 5)"); int z = lua["z"]; 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) ); - lua.script("bx = bark.new(760)"); + lua.safe_script("bx = bark.new(760)"); bark& bx = lua["bx"]; REQUIRE(bx.var == 760); - lua.script("b = bark.new()"); + lua.safe_script("b = bark.new()"); bark& b = lua["b"]; - lua.script("b:fun()"); + lua.safe_script("b:fun()"); int var = b.var; REQUIRE(var == 51); - lua.script("b:var(20)"); - lua.script("v = b:var()"); + lua.safe_script("b:var(20)"); + lua.safe_script("v = b:var()"); int v = lua["v"]; REQUIRE(v == 20); - lua.script("m = b:the_marker()"); + lua.safe_script("m = b:the_marker()"); marker& m = lua["m"]; REQUIRE_FALSE(b.mark.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"]; barktable["special"] = &bark::special; - lua.script("s = b:special()"); + lua.safe_script("s = b:special()"); std::string s = lua["s"]; REQUIRE(s == "woof"); - lua.script("b:y(24)"); - lua.script("x = b:x()"); + lua.safe_script("b:y(24)"); + lua.safe_script("x = b:x()"); int x = lua["x"]; REQUIRE(x == 24); - lua.script("z = b:z(b:z() + 5)"); + lua.safe_script("z = b:z(b:z() + 5)"); int z = lua["z"]; 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> tests; - sol::state lua; - lua.open_libraries(); - - lua.new_simple_usertype("test", - "create", [&]() -> std::shared_ptr { - tests.push_back(std::make_shared()); - 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& 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)") { int muh_variable = 10; int through_variable = 25; @@ -228,7 +190,7 @@ TEST_CASE("simple_usertype/vars", "simple usertype vars can bind various values through_variable = 20; - lua.script(R"( + lua.safe_script(R"( print(test.straight) s = test.straight print(test.global) @@ -297,29 +259,29 @@ TEST_CASE("simple_usertype/variable-control", "test to see if usertypes respond B b; lua.set("b", &b); - lua.script("b:a()"); + lua.safe_script("b:a()"); sB sb; lua.set("sb", &sb); - lua.script("sb:a()"); + lua.safe_script("sb:a()"); 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; lua.set("sw", &sw); - lua.script("print(sw.a)assert(sw.a == 10)"); - lua.script("print(sw.b)assert(sw.b == 20)"); - lua.script("print(sw.pb)assert(sw.pb == 22)"); - lua.script("sw.a = 11"); - lua.script("sw.b = 21"); - lua.script("print(sw.a)assert(sw.a == 11)"); - lua.script("print(sw.b)assert(sw.b == 21)"); - lua.script("print(sw.pb)assert(sw.pb == 23)"); - lua.script("sw.pb = 25"); - lua.script("print(sw.b)assert(sw.b == 25)"); - lua.script("print(sw.pb)assert(sw.pb == 27)"); + lua.safe_script("print(sw.a)assert(sw.a == 10)"); + lua.safe_script("print(sw.b)assert(sw.b == 20)"); + lua.safe_script("print(sw.pb)assert(sw.pb == 22)"); + lua.safe_script("sw.a = 11"); + lua.safe_script("sw.b = 21"); + lua.safe_script("print(sw.a)assert(sw.a == 11)"); + lua.safe_script("print(sw.b)assert(sw.b == 21)"); + lua.safe_script("print(sw.pb)assert(sw.pb == 23)"); + lua.safe_script("sw.pb = 25"); + lua.safe_script("print(sw.b)assert(sw.b == 25)"); + lua.safe_script("print(sw.pb)assert(sw.pb == 27)"); } 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> c; lua.new_simple_usertype("B", sol::call_constructor, c, - "new", sol::factories([]() { return B(); }), - "new2", sol::initializers([](B& mem) { new(&mem)B(); }, [](B& mem, int v) { new(&mem)B(); mem.bvar = v; }), + "new", sol::factories([]() { + 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), "g", sol::overload([](B&) { return 2; }, [](B&, int v) { return v; }) ); - lua.script("b = B()"); - lua.script("b2 = B.new()"); - lua.script("b3 = B.new2()"); - lua.script("b4 = B.new2(11)"); + lua.safe_script("b = B()"); + lua.safe_script("b2 = B.new()"); + lua.safe_script("b3 = B.new2()"); + lua.safe_script("b4 = B.new2(11)"); - lua.script("x = b:f()"); - lua.script("x2 = b2:f()"); - lua.script("x3 = b3:f()"); - lua.script("x4 = b4:f()"); + lua.safe_script("x = b:f()"); + lua.safe_script("x2 = b2:f()"); + lua.safe_script("x3 = b3:f()"); + lua.safe_script("x4 = b4:f()"); int x = lua["x"]; int x2 = lua["x2"]; int x3 = lua["x3"]; @@ -364,10 +335,10 @@ TEST_CASE("simple_usertype/factory constructor overloads", "simple usertypes sho REQUIRE(x3 == 24); REQUIRE(x4 == 11); - lua.script("y = b:g()"); - lua.script("y2 = b2:g(3)"); - lua.script("y3 = b3:g()"); - lua.script("y4 = b4:g(3)"); + lua.safe_script("y = b:g()"); + lua.safe_script("y2 = b2:g(3)"); + lua.safe_script("y3 = b3:g()"); + lua.safe_script("y4 = b4:g(3)"); int y = lua["y"]; int y2 = lua["y2"]; 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()); lua["A"]["method"] = []() { return 200; }; lua["B"]["method2"] = [](B&) { return 100; }; - lua.script("x = b.method()"); - lua.script("y = b:method()"); + lua.safe_script("x = b.method()"); + lua.safe_script("y = b:method()"); int x = lua["x"]; int y = lua["y"]; REQUIRE(x == 200); REQUIRE(y == 200); - lua.script("z = b.method2(b)"); - lua.script("w = b:method2()"); + lua.safe_script("z = b.method2(b)"); + lua.safe_script("w = b:method2()"); int z = lua["z"]; int w = lua["w"]; REQUIRE(z == 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", - sol::call_constructor, sol::constructors>() - ); - - 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") { struct A { 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("ua", std::make_unique()); REQUIRE_NOTHROW([&]{ - lua.script("assert(a:func() == 5000)"); - lua.script("assert(pa:func() == 5000)"); - lua.script("assert(ua:func() == 5000)"); + lua.safe_script("assert(a:func() == 5000)"); + lua.safe_script("assert(pa: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 ); - lua.script(R"( + lua.safe_script(R"( b = B.new() print(b.var) 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.script("b = i_test()"); - lua.script("c = r_test()"); - lua.script("d = f_test.new()"); + lua.safe_script("a = f_test()"); + lua.safe_script("b = i_test()"); + lua.safe_script("c = r_test()"); + lua.safe_script("d = f_test.new()"); f_test& a = lua["a"]; f_test& d = lua["d"]; 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"); - lua.script("things = {thing.new(), thing.new()}"); + lua.safe_script("things = {thing.new(), thing.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") { - 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.new_simple_usertype("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") { @@ -616,7 +556,7 @@ TEST_CASE("simple_usertype/runtime extensibility", "Check if usertypes are runti "func", &thing::func ); - lua.script(R"( + lua.safe_script(R"( t = thing.new() )"); @@ -638,19 +578,19 @@ end REQUIRE_FALSE(result.valid()); } - lua.script("val = t:func(2)"); + lua.safe_script("val = t:func(2)"); val = lua["val"]; REQUIRE(val == 2); REQUIRE_NOTHROW([&lua]() { - lua.script(R"( + lua.safe_script(R"( function thing:runtime_func(a) return a + 1 end )"); }()); - lua.script("val = t:runtime_func(2)"); + lua.safe_script("val = t:runtime_func(2)"); val = lua["val"]; REQUIRE(val == 3); } @@ -663,7 +603,7 @@ end "v", &thing::v ); - lua.script(R"( + lua.safe_script(R"( t = thing.new() )"); @@ -685,19 +625,19 @@ end REQUIRE_FALSE(result.valid()); }()); - lua.script("val = t:func(2)"); + lua.safe_script("val = t:func(2)"); val = lua["val"]; REQUIRE(val == 2); REQUIRE_NOTHROW([&lua]() { - lua.script(R"( + lua.safe_script(R"( function thing:runtime_func(a) return a + 1 end )"); }()); - lua.script("val = t:runtime_func(2)"); + lua.safe_script("val = t:runtime_func(2)"); val = lua["val"]; REQUIRE(val == 3); } @@ -715,13 +655,13 @@ TEST_CASE("simple_usertype/runtime replacement", "ensure that functions can be p lua.new_simple_usertype("a"); REQUIRE_NOTHROW([&lua]() { - lua.script("obj = a.new()"); - lua.script("function a:heartbeat () print('arf') return 1 end"); - lua.script("v1 = obj:heartbeat()"); - lua.script("function a:heartbeat () print('bark') return 2 end"); - lua.script("v2 = obj:heartbeat()"); - lua.script("a.heartbeat = function(self) print('woof') return 3 end"); - lua.script("v3 = obj:heartbeat()"); + lua.safe_script("obj = a.new()"); + lua.safe_script("function a:heartbeat () print('arf') return 1 end"); + lua.safe_script("v1 = obj:heartbeat()"); + lua.safe_script("function a:heartbeat () print('bark') return 2 end"); + lua.safe_script("v2 = obj:heartbeat()"); + lua.safe_script("a.heartbeat = function(self) print('woof') return 3 end"); + lua.safe_script("v3 = obj:heartbeat()"); }()); int v1 = lua["v1"]; int v2 = lua["v2"]; @@ -739,13 +679,13 @@ TEST_CASE("simple_usertype/runtime replacement", "ensure that functions can be p ); REQUIRE_NOTHROW([&lua]() { - lua.script("obj = a.new()"); - lua.script("function a:heartbeat () print('arf') return 1 end"); - lua.script("v1 = obj:heartbeat()"); - lua.script("function a:heartbeat () print('bark') return 2 end"); - lua.script("v2 = obj:heartbeat()"); - lua.script("a.heartbeat = function(self) print('woof') return 3 end"); - lua.script("v3 = obj:heartbeat()"); + lua.safe_script("obj = a.new()"); + lua.safe_script("function a:heartbeat () print('arf') return 1 end"); + lua.safe_script("v1 = obj:heartbeat()"); + lua.safe_script("function a:heartbeat () print('bark') return 2 end"); + lua.safe_script("v2 = obj:heartbeat()"); + lua.safe_script("a.heartbeat = function(self) print('woof') return 3 end"); + lua.safe_script("v3 = obj:heartbeat()"); }()); int v1 = lua["v1"]; int v2 = lua["v2"]; @@ -764,13 +704,13 @@ TEST_CASE("simple_usertype/runtime replacement", "ensure that functions can be p ); REQUIRE_NOTHROW([&lua]() { - lua.script("obj = a.new()"); - lua.script("function a:heartbeat () print('arf') return 1 end"); - lua.script("v1 = obj:heartbeat()"); - lua.script("function a:heartbeat () print('bark') return 2 end"); - lua.script("v2 = obj:heartbeat()"); - lua.script("a.heartbeat = function(self) print('woof') return 3 end"); - lua.script("v3 = obj:heartbeat()"); + lua.safe_script("obj = a.new()"); + lua.safe_script("function a:heartbeat () print('arf') return 1 end"); + lua.safe_script("v1 = obj:heartbeat()"); + lua.safe_script("function a:heartbeat () print('bark') return 2 end"); + lua.safe_script("v2 = obj:heartbeat()"); + lua.safe_script("a.heartbeat = function(self) print('woof') return 3 end"); + lua.safe_script("v3 = obj:heartbeat()"); }()); int v1 = lua["v1"]; int v2 = lua["v2"]; @@ -801,11 +741,11 @@ TEST_CASE("simple_usertype/meta key retrievals", "allow for special meta keys (_ lua["var"] = s; - lua.script("var = sample.new()"); - lua.script("var.key = 2"); - lua.script("var.__newindex = 4"); - lua.script("var.__index = 3"); - lua.script("var.__call = 1"); + lua.safe_script("var = sample.new()"); + lua.safe_script("var.key = 2"); + lua.safe_script("var.__newindex = 4"); + lua.safe_script("var.__index = 3"); + lua.safe_script("var.__call = 1"); REQUIRE(values[0] == 2); REQUIRE(values[1] == 4); REQUIRE(values[2] == 3); @@ -831,11 +771,11 @@ TEST_CASE("simple_usertype/meta key retrievals", "allow for special meta keys (_ sol::state lua; lua.new_simple_usertype("sample", sol::meta_function::new_index, &sample::foo); - lua.script("var = sample.new()"); - lua.script("var.key = 2"); - lua.script("var.__newindex = 4"); - lua.script("var.__index = 3"); - lua.script("var.__call = 1"); + lua.safe_script("var = sample.new()"); + lua.safe_script("var.key = 2"); + lua.safe_script("var.__newindex = 4"); + lua.safe_script("var.__index = 3"); + lua.safe_script("var.__call = 1"); REQUIRE(values[0] == 2); REQUIRE(values[1] == 4); 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) ); - lua.script("v1 = test.f()"); - lua.script("v2 = test.g"); - lua.script("test.g = 60"); - lua.script("v2a = test.g"); + lua.safe_script("v1 = test.f()"); + lua.safe_script("v2 = test.g"); + lua.safe_script("test.g = 60"); + lua.safe_script("v2a = test.g"); int v1 = lua["v1"]; REQUIRE(v1 == 24); 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 ); - lua.script(R"( + lua.safe_script(R"( local t = test.new() v = t.a 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.script(R"( + lua.safe_script(R"( local t = test.new() v = t.a; print(v) diff --git a/test_state.cpp b/test_state.cpp index e2250a14..2b5e121e 100644 --- a/test_state.cpp +++ b/test_state.cpp @@ -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") { sol::state lua; lua.open_libraries(); - std::string t1 = lua.script(R"(require 'io' + std::string t1 = lua.safe_script(R"(require 'io' return 'test1')"); sol::object ot2 = lua.require_script("test2", R"(require 'io' return 'test2')"); std::string t2 = ot2.as(); - std::string t3 = lua.script(R"(require 'io' + std::string t3 = lua.safe_script(R"(require 'io' return 'test3')"); REQUIRE(t1 == "test1"); REQUIRE(t2 == "test2"); @@ -179,7 +179,7 @@ return 'test3')"); TEST_CASE("state/leak check", "make sure there are no humongous memory leaks in iteration") { #if 0 sol::state lua; - lua.script(R"( + lua.safe_script(R"( record = {} for i=1,256 do record[i] = i @@ -244,7 +244,7 @@ return example; auto bar = [&script](sol::this_state l) { sol::state_view lua = l; - sol::table data = lua.script(script); + sol::table data = lua.safe_script(script); std::string str = data["str"]; int num = data["num"]; @@ -256,7 +256,7 @@ return example; auto foo = [&script](int, sol::this_state l) { sol::state_view lua = l; - sol::table data = lua.script(script); + sol::table data = lua.safe_script(script); std::string str = data["str"]; int num = data["num"]; @@ -299,7 +299,7 @@ return example; lua.set_function("bar", bar); 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") { @@ -318,9 +318,9 @@ TEST_CASE("state/requires-reload", "ensure that reloading semantics do not cause sol::state lua; sol::stack_guard sg(lua); 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.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") { @@ -348,7 +348,7 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load SECTION("script") { sol::state lua; sol::stack_guard sg(lua); - int ar = lua.script(good); + int ar = lua.safe_script(good); int a = lua["a"]; REQUIRE(a == 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") { sol::state 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()); - 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()); - 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 ar = result; REQUIRE(result.valid()); @@ -423,7 +423,7 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load SECTION("script_file") { sol::state 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"]; REQUIRE(a == 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") { sol::state 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()); - 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()); - 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 ar = result; REQUIRE(result.valid()); diff --git a/test_tables.cpp b/test_tables.cpp index c5d4e4b0..c11baae5 100644 --- a/test_tables.cpp +++ b/test_tables.cpp @@ -97,7 +97,7 @@ TEST_CASE("tables/nested cleanup", "make sure tables leave the stack balanced") sol::state lua; lua.open_libraries(); - lua.script("A={}"); + lua.safe_script("A={}"); auto f = [] { return 5; }; for (int i = 0; i < 30; 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; lua.open_libraries(sol::lib::base); - lua.script("arr = {\n" + lua.safe_script("arr = {\n" "[0] = \"Hi\",\n" "[1] = 123.45,\n" "[2] = \"String value\",\n" @@ -200,7 +200,7 @@ TEST_CASE("tables/for_each empty", "empty tables should not crash") { sol::state lua; lua.open_libraries(sol::lib::base); - lua.script("arr = {}"); + lua.safe_script("arr = {}"); sol::table tbl = lua["arr"]; REQUIRE(tbl.empty()); 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; lua.open_libraries(sol::lib::base); - lua.script("arr = {\n" + lua.safe_script("arr = {\n" "[0] = \"Hi\",\n" "[1] = 123.45,\n" "[2] = \"String value\",\n" @@ -316,7 +316,7 @@ TEST_CASE("tables/variables", "Check if tables and variables work as intended") sol::state lua; lua.open_libraries(sol::lib::base, sol::lib::os); lua.get("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") { @@ -368,7 +368,7 @@ TEST_CASE("tables/function variables", "Check if tables and function calls work sol::state lua; lua.open_libraries(sol::lib::base, sol::lib::os); auto run_script = [](sol::state& lua) -> void { - lua.script("assert(os.fun() == \"test\")"); + lua.safe_script("assert(os.fun() == \"test\")"); }; lua.get("os").set_function("fun", @@ -419,7 +419,7 @@ TEST_CASE("tables/operator[]", "Check if operator[] retrieval and setting works sol::state lua; lua.open_libraries(sol::lib::base); - lua.script("foo = 20\nbar = \"hello world\""); + lua.safe_script("foo = 20\nbar = \"hello world\""); // basic retrieval std::string bar = lua["bar"]; int foo = lua["foo"]; @@ -439,7 +439,7 @@ TEST_CASE("tables/operator[]", "Check if operator[] retrieval and setting works // function setting 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 sol::function test = lua["test"]; @@ -450,7 +450,7 @@ TEST_CASE("tables/operator[]", "Check if operator[] retrieval and setting works 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 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; lua.open_libraries(sol::lib::base); - lua.script(R"( + lua.safe_script(R"( tbl = {} tbl[true] = 10 tbl[1] = 20 diff --git a/test_usertypes.cpp b/test_usertypes.cpp index a45d810d..a08f1f90 100644 --- a/test_usertypes.cpp +++ b/test_usertypes.cpp @@ -271,7 +271,7 @@ TEST_CASE("usertype/usertype", "Show that we can create classes from usertype an sol::usertype lc{ "add", &fuser::add, "add2", &fuser::add2 }; lua.set_usertype(lc); - lua.script("a = fuser:new()\n" + lua.safe_script("a = fuser:new()\n" "b = a:add(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 lc(con, "add", &crapola::fuser::add, "add2", &crapola::fuser::add2); lua.set_usertype(lc); - lua.script( + lua.safe_script( "a = fuser.new(2)\n" "u = a:add(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", "add", &fuser::add, "add2", &fuser::add2); - lua.script("a = fuser.new()\n" + lua.safe_script("a = fuser.new()\n" "b = a:add(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.script("base = Base.new(5)"); - REQUIRE_NOTHROW(lua.script("print(base:get_num())")); + lua.safe_script("base = Base.new(5)"); + REQUIRE_NOTHROW(lua.safe_script("print(base:get_num())")); sol::constructors> derivedctor; sol::usertype derivedusertype(derivedctor, @@ -378,10 +378,10 @@ TEST_CASE("usertype/usertype-utility-derived", "usertype classes must play nice lua.set_usertype(derivedusertype); - lua.script("derived = Derived.new(7)"); - lua.script("dgn = derived:get_num()\n" + lua.safe_script("derived = Derived.new(7)"); + lua.safe_script("dgn = derived:get_num()\n" "print(dgn)"); - lua.script("dgn10 = derived:get_num_10()\n" + lua.safe_script("dgn10 = derived:get_num_10()\n" "print(dgn10)"); REQUIRE((lua.get("dgn10") == 70)); @@ -394,7 +394,7 @@ TEST_CASE("usertype/self-referential usertype", "usertype classes must play nice lua.new_usertype("test", "g", &self_test::g, "f", &self_test::f); - lua.script( + lua.safe_script( "local a = test.new()\n" "a:g(\"woof\")\n" "a:f(a)\n" @@ -429,16 +429,16 @@ TEST_CASE("usertype/issue-number-twenty-five", "Using pointers and references fr sol::state lua; lua.open_libraries(sol::lib::base); lua.new_usertype("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.script("assert(x:set():get() == 10)")); - REQUIRE_NOTHROW(lua.script("y = x:pointer_get()")); - REQUIRE_NOTHROW(lua.script("y:set():get()")); - REQUIRE_NOTHROW(lua.script("y:fun(10)")); - REQUIRE_NOTHROW(lua.script("x:fun(10)")); - REQUIRE_NOTHROW(lua.script("assert(y:fun(10) == x:fun(10), '...')")); - REQUIRE_NOTHROW(lua.script("assert(y:fun(10) == 100, '...')")); - REQUIRE_NOTHROW(lua.script("assert(y:set():get() == y:set():get(), '...')")); - REQUIRE_NOTHROW(lua.script("assert(y:set():get() == 10, '...')")); + REQUIRE_NOTHROW(lua.safe_script("x = test.new()")); + REQUIRE_NOTHROW(lua.safe_script("assert(x:set():get() == 10)")); + REQUIRE_NOTHROW(lua.safe_script("y = x:pointer_get()")); + REQUIRE_NOTHROW(lua.safe_script("y:set():get()")); + REQUIRE_NOTHROW(lua.safe_script("y:fun(10)")); + REQUIRE_NOTHROW(lua.safe_script("x:fun(10)")); + REQUIRE_NOTHROW(lua.safe_script("assert(y:fun(10) == x:fun(10), '...')")); + REQUIRE_NOTHROW(lua.safe_script("assert(y:fun(10) == 100, '...')")); + REQUIRE_NOTHROW(lua.safe_script("assert(y:set():get() == y:set():get(), '...')")); + 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") { @@ -449,9 +449,9 @@ TEST_CASE("usertype/issue-number-thirty-five", "using value types created from l sol::usertype udata(ctor, "normalized", &Vec::normalized, "length", &Vec::length); 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())")); - 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())")); } @@ -469,11 +469,11 @@ TEST_CASE("usertype/lua-stored-usertype", "ensure usertype values can be stored // 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" "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())")); } @@ -489,20 +489,20 @@ TEST_CASE("usertype/member-variables", "allow table-like accessors to behave as "length", &Vec::length); 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" "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" "print(v.x, v.y, v.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.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" "assert(x == 3)\n" )); @@ -518,8 +518,8 @@ TEST_CASE("usertype/member-variables", "allow table-like accessors to behave as ); breaks& b = lua["b"]; - REQUIRE_NOTHROW(lua.script("b.f = function () print('BARK!') end")); - REQUIRE_NOTHROW(lua.script("b.f()")); + REQUIRE_NOTHROW(lua.safe_script("b.f = function () print('BARK!') end")); + REQUIRE_NOTHROW(lua.safe_script("b.f()")); REQUIRE_NOTHROW(b.f()); } @@ -535,8 +535,8 @@ TEST_CASE("usertype/nonmember-functions", "let users set non-member functions th } ).get("giver").set_function("stuff", giver::stuff); - REQUIRE_NOTHROW(lua.script("giver.stuff()")); - REQUIRE_NOTHROW(lua.script("t = giver.new()\n" + REQUIRE_NOTHROW(lua.safe_script("giver.stuff()")); + REQUIRE_NOTHROW(lua.safe_script("t = giver.new()\n" "print(tostring(t))\n" "t:gief()\n" "t:gief_stuff(20)\n")); @@ -575,7 +575,7 @@ TEST_CASE("regressions/one", "issue number 48") { sol::state lua; lua.new_usertype("vars", "boop", &vars::boop); - REQUIRE_NOTHROW(lua.script("beep = vars.new()\n" + REQUIRE_NOTHROW(lua.safe_script("beep = vars.new()\n" "beep.boop = 1")); // test for segfault auto my_var = lua.get("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); } -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 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.") { int numsaved = factory_test::num_saved; int numkilled = factory_test::num_killed; @@ -658,9 +627,9 @@ TEST_CASE("usertype/private-constructible", "Check to make sure special snowflak std::unique_ptr f = factory_test::make(); 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" "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("b", B_foo()); - lua.script("x = b:foo(a)"); + lua.safe_script("x = b:foo(a)"); int x = lua["x"]; 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"; - REQUIRE_NOTHROW(lua.script( + REQUIRE_NOTHROW(lua.safe_script( "r = woof:new()\n" "a = r:func(1)\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("o", outer()); lua.set("f", sol::c_call); - lua.script(R"( + lua.safe_script(R"( x = w.b x.var = 20 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() ); - REQUIRE_NOTHROW(lua.script("assert(bark.oh_boy('woo') == 3)")); - REQUIRE_NOTHROW(lua.script("bark.oh_boy()")); + REQUIRE_NOTHROW(lua.safe_script("assert(bark.oh_boy('woo') == 3)")); + REQUIRE_NOTHROW(lua.safe_script("bark.oh_boy()")); bark b; lua.set("b", &b); @@ -865,7 +834,7 @@ TEST_CASE("usertype/readonly-and-static-functions", "Check if static functions c REQUIRE(z); REQUIRE(w == 5); - lua.script(R"( + lua.safe_script(R"( lx = b(1) ly = getmetatable(b).__call(b, 1) lz = b.something() @@ -926,11 +895,11 @@ TEST_CASE("usertype/properties", "Check if member properties/variables work") { bark b; lua.set("b", &b); - lua.script("b.a = 59"); - lua.script("var2_0 = b.a"); - lua.script("var2_1 = b.b"); - lua.script("b.d = 1568"); - lua.script("var2_2 = b.c"); + lua.safe_script("b.a = 59"); + lua.safe_script("var2_0 = b.a"); + lua.safe_script("var2_1 = b.b"); + lua.safe_script("b.d = 1568"); + lua.safe_script("var2_2 = b.c"); int var2_0 = lua["var2_0"]; 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>() ); - lua.script(R"( + lua.safe_script(R"( 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) ); - lua.script("m = mat{ {1.1, 2.2} }"); + lua.safe_script("m = mat{ {1.1, 2.2} }"); lua.new_usertype("mati", 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"]; 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>() ); - REQUIRE_NOTHROW(lua.script(R"( + REQUIRE_NOTHROW(lua.safe_script(R"( x = class01() y = class02(x) )")); @@ -1138,7 +1107,7 @@ TEST_CASE("usertype/coverage", "try all the things") { INFO("usertype created"); - lua.script(R"( + lua.safe_script(R"( e = ext_getset() w = e:x(e:x(), e:x(e:x())) print(w) @@ -1149,7 +1118,7 @@ print(w) INFO("REQUIRE(w) successful"); - lua.script(R"( + lua.safe_script(R"( e:set(500) e.sset(24) x = e:get() @@ -1163,7 +1132,7 @@ y = e.sget(20) INFO("REQUIRE(x, y) successful"); - lua.script(R"( + lua.safe_script(R"( e.bark = 5001 a = e:get() print(e.bark) @@ -1182,7 +1151,7 @@ print(b) INFO("REQUIRE(a, b) successful"); - lua.script(R"( + lua.safe_script(R"( c = e.readonlybark d = e.meow print(e.readonlybark) @@ -1198,7 +1167,7 @@ print(d) INFO("REQUIRE(c, d) successful"); - lua.script(R"( + lua.safe_script(R"( e.writeonlypropbark = 500 z = e.readonlypropbark print(e.readonlybark) @@ -1239,7 +1208,7 @@ TEST_CASE("usertype/copyability", "make sure user can write to a class variable lua.new_usertype("NoCopy", "val", sol::property(&NoCopy::get, &NoCopy::set)); REQUIRE_NOTHROW( - lua.script(R"__( + lua.safe_script(R"__( nocopy = NoCopy.new() nocopy.val = 5 )__") @@ -1260,7 +1229,7 @@ TEST_CASE("usertype/protect", "users should be allowed to manually protect a fun ); REQUIRE_NOTHROW( - lua.script(R"__( + lua.safe_script(R"__( pm = protect_me.new() value = pcall(pm.gen,pm) )__") @@ -1269,59 +1238,6 @@ value = pcall(pm.gen,pm) 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> tests; - sol::state lua; - lua.open_libraries(); - - lua.new_usertype("test", - "create", [&]() -> std::shared_ptr { - tests.push_back(std::make_shared()); - 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& 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", "x", &c_a::x); - lua.new_usertype("c_b", "y", &c_b::y); - lua = sol::state(); - lua.new_usertype("c_a", "x", &c_a::x); - lua.new_usertype("c_b", "y", &c_b::y); - lua = sol::state(); - }; - REQUIRE_NOTHROW(routine()); -} - TEST_CASE("usertype/vars", "usertype vars can bind various class items") { static int muh_variable = 25; static int through_variable = 10; @@ -1349,7 +1265,7 @@ TEST_CASE("usertype/vars", "usertype vars can bind various class items") { REQUIRE(pretg2 == 10); REQUIRE(pretrg2 == 10); - lua.script(R"( + lua.safe_script(R"( print(test.straight) test.straight = 50 print(test.straight) @@ -1357,7 +1273,7 @@ print(test.straight) int s = lua["test"]["straight"]; REQUIRE(s == 50); - lua.script(R"( + lua.safe_script(R"( t = test.new() print(t.global) t.global = 50 @@ -1368,7 +1284,7 @@ print(t.global) REQUIRE(muh_variable == 25); - lua.script(R"( + lua.safe_script(R"( print(t.ref_global) t.ref_global = 50 print(t.ref_global) @@ -1378,7 +1294,7 @@ print(t.ref_global) REQUIRE(muh_variable == 50); REQUIRE(through_variable == 10); - lua.script(R"( + lua.safe_script(R"( print(test.global2) test.global2 = 35 print(test.global2) @@ -1387,7 +1303,7 @@ print(test.global2) REQUIRE(through_variable == 10); REQUIRE(tv == 35); - lua.script(R"( + lua.safe_script(R"( print(test.ref_global2) test.ref_global2 = 35 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) ); - lua.script("v1 = test.f()"); - lua.script("v2 = test.g"); - lua.script("test.g = 60"); - lua.script("v2a = test.g"); + lua.safe_script("v1 = test.f()"); + lua.safe_script("v2 = test.g"); + lua.safe_script("test.g = 60"); + lua.safe_script("v2a = test.g"); int v1 = lua["v1"]; REQUIRE(v1 == 24); 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)) ); - lua.script(R"( + lua.safe_script(R"( t = test.new() print(t.prop) t.prop = 50 @@ -1465,7 +1381,7 @@ print(t.prop) test& t = lua["t"]; REQUIRE(t.value == 50); - lua.script(R"( + lua.safe_script(R"( t = test.new() print(t.global) )"); @@ -1473,7 +1389,7 @@ print(t.global) auto result = lua.safe_script("t.global = 20", sol::script_pass_on_error); 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") { @@ -1492,7 +1408,7 @@ TEST_CASE("usertype/unique_usertype-check", "make sure unique usertypes don't ge "get_name", &Entity::GetName ); - lua.script(R"( + lua.safe_script(R"( function my_func(entity) print("INSIDE LUA") print(entity:get_name()) @@ -1514,7 +1430,7 @@ TEST_CASE("usertype/abstract-base-class", "Ensure that abstract base classes and lua.new_usertype("A", "a", &abstract_A::a); lua.new_usertype("B", sol::base_classes, sol::bases()); REQUIRE_NOTHROW([&]() { - lua.script(R"( + lua.safe_script(R"( local b = B.new() b:a() )"); @@ -1533,45 +1449,14 @@ TEST_CASE("usertype/as_function", "Ensure that variables can be turned into func B b; lua.set("b", &b); - lua.script("x = b:f()"); - lua.script("y = b.b"); + lua.safe_script("x = b:f()"); + lua.safe_script("y = b.b"); int x = lua["x"]; int y = lua["y"]; REQUIRE(x == 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", - sol::call_constructor, sol::constructors>() - ); - - 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") { struct A { 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) ); - lua.script(R"( + lua.safe_script(R"( a = A(24.3) )"); 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.new_usertype("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"]; bool isnil = o.is(); REQUIRE(isnil); @@ -1623,7 +1508,7 @@ TEST_CASE("usertype/runtime-extensibility", "Check if usertypes are runtime exte "func", &thing::func ); - lua.script(R"( + lua.safe_script(R"( t = thing.new() )"); @@ -1645,19 +1530,19 @@ end REQUIRE_FALSE(result.valid()); }; - lua.script("val = t:func(2)"); + lua.safe_script("val = t:func(2)"); val = lua["val"]; REQUIRE(val == 2); REQUIRE_NOTHROW([&lua]() { - lua.script(R"( + lua.safe_script(R"( function thing:runtime_func(a) return a + 1 end )"); }()); - lua.script("val = t:runtime_func(2)"); + lua.safe_script("val = t:runtime_func(2)"); val = lua["val"]; REQUIRE(val == 3); } @@ -1670,7 +1555,7 @@ end "v", &thing::v ); - lua.script(R"( + lua.safe_script(R"( t = thing.new() )"); @@ -1692,19 +1577,19 @@ end REQUIRE_FALSE(result.valid()); }; - lua.script("val = t:func(2)"); + lua.safe_script("val = t:func(2)"); val = lua["val"]; REQUIRE(val == 2); REQUIRE_NOTHROW([&lua]() { - lua.script(R"( + lua.safe_script(R"( function thing:runtime_func(a) return a + 1 end )"); }()); - lua.script("val = t:runtime_func(2)"); + lua.safe_script("val = t:runtime_func(2)"); val = lua["val"]; REQUIRE(val == 3); } @@ -1722,13 +1607,13 @@ TEST_CASE("usertype/runtime-replacement", "ensure that functions can be properly lua.new_usertype("a"); REQUIRE_NOTHROW([&lua]() { - lua.script("obj = a.new()"); - lua.script("function a:heartbeat () print('arf') return 1 end"); - lua.script("v1 = obj:heartbeat()"); - lua.script("function a:heartbeat () print('bark') return 2 end"); - lua.script("v2 = obj:heartbeat()"); - lua.script("a.heartbeat = function(self) print('woof') return 3 end"); - lua.script("v3 = obj:heartbeat()"); + lua.safe_script("obj = a.new()"); + lua.safe_script("function a:heartbeat () print('arf') return 1 end"); + lua.safe_script("v1 = obj:heartbeat()"); + lua.safe_script("function a:heartbeat () print('bark') return 2 end"); + lua.safe_script("v2 = obj:heartbeat()"); + lua.safe_script("a.heartbeat = function(self) print('woof') return 3 end"); + lua.safe_script("v3 = obj:heartbeat()"); }()); int v1 = lua["v1"]; int v2 = lua["v2"]; @@ -1746,13 +1631,13 @@ TEST_CASE("usertype/runtime-replacement", "ensure that functions can be properly ); REQUIRE_NOTHROW([&lua]() { - lua.script("obj = a.new()"); - lua.script("function a:heartbeat () print('arf') return 1 end"); - lua.script("v1 = obj:heartbeat()"); - lua.script("function a:heartbeat () print('bark') return 2 end"); - lua.script("v2 = obj:heartbeat()"); - lua.script("a.heartbeat = function(self) print('woof') return 3 end"); - lua.script("v3 = obj:heartbeat()"); + lua.safe_script("obj = a.new()"); + lua.safe_script("function a:heartbeat () print('arf') return 1 end"); + lua.safe_script("v1 = obj:heartbeat()"); + lua.safe_script("function a:heartbeat () print('bark') return 2 end"); + lua.safe_script("v2 = obj:heartbeat()"); + lua.safe_script("a.heartbeat = function(self) print('woof') return 3 end"); + lua.safe_script("v3 = obj:heartbeat()"); }()); int v1 = lua["v1"]; int v2 = lua["v2"]; @@ -1771,13 +1656,13 @@ TEST_CASE("usertype/runtime-replacement", "ensure that functions can be properly ); REQUIRE_NOTHROW([&lua]() { - lua.script("obj = a.new()"); - lua.script("function a:heartbeat () print('arf') return 1 end"); - lua.script("v1 = obj:heartbeat()"); - lua.script("function a:heartbeat () print('bark') return 2 end"); - lua.script("v2 = obj:heartbeat()"); - lua.script("a.heartbeat = function(self) print('woof') return 3 end"); - lua.script("v3 = obj:heartbeat()"); + lua.safe_script("obj = a.new()"); + lua.safe_script("function a:heartbeat () print('arf') return 1 end"); + lua.safe_script("v1 = obj:heartbeat()"); + lua.safe_script("function a:heartbeat () print('bark') return 2 end"); + lua.safe_script("v2 = obj:heartbeat()"); + lua.safe_script("a.heartbeat = function(self) print('woof') return 3 end"); + lua.safe_script("v3 = obj:heartbeat()"); }()); int v1 = lua["v1"]; int v2 = lua["v2"]; @@ -1808,11 +1693,11 @@ TEST_CASE("usertype/meta-key-retrievals", "allow for special meta keys (__index, lua["var"] = s; - lua.script("var = sample.new()"); - lua.script("var.key = 2"); - lua.script("var.__newindex = 4"); - lua.script("var.__index = 3"); - lua.script("var.__call = 1"); + lua.safe_script("var = sample.new()"); + lua.safe_script("var.key = 2"); + lua.safe_script("var.__newindex = 4"); + lua.safe_script("var.__index = 3"); + lua.safe_script("var.__call = 1"); REQUIRE(values[0] == 2); REQUIRE(values[1] == 4); REQUIRE(values[2] == 3); @@ -1838,11 +1723,11 @@ TEST_CASE("usertype/meta-key-retrievals", "allow for special meta keys (__index, sol::state lua; lua.new_usertype("sample", sol::meta_function::new_index, &sample::foo); - lua.script("var = sample.new()"); - lua.script("var.key = 2"); - lua.script("var.__newindex = 4"); - lua.script("var.__index = 3"); - lua.script("var.__call = 1"); + lua.safe_script("var = sample.new()"); + lua.safe_script("var.key = 2"); + lua.safe_script("var.__newindex = 4"); + lua.safe_script("var.__index = 3"); + lua.safe_script("var.__call = 1"); REQUIRE(values[0] == 2); REQUIRE(values[1] == 4); REQUIRE(values[2] == 3); @@ -1871,9 +1756,9 @@ TEST_CASE("usertype/noexcept-methods", "make sure noexcept functinos and methods "nm", &T::noexcept_method ); - lua.script("t = T.new()"); - lua.script("v1 = t.nf()"); - lua.script("v2 = t:nm()"); + lua.safe_script("t = T.new()"); + lua.safe_script("v1 = t.nf()"); + lua.safe_script("v2 = t:nm()"); int v1 = lua["v1"]; int v2 = lua["v2"]; REQUIRE(v1 == 0x61); diff --git a/test_utility.cpp b/test_utility.cpp index da2edd99..a0992361 100644 --- a/test_utility.cpp +++ b/test_utility.cpp @@ -52,8 +52,8 @@ TEST_CASE("utility/variant", "test that variant can be round-tripped") { }); lua["v"] = std::variant(2); REQUIRE_NOTHROW([&]() { - lua.script("assert(f(v))"); - lua.script("assert(g(v))"); + lua.safe_script("assert(f(v))"); + lua.safe_script("assert(g(v))"); }()); } SECTION("throws") { @@ -93,7 +93,7 @@ TEST_CASE("utility/string_view", "test that string_view can be taken as an argum lua["v"] = "bark!"; REQUIRE_NOTHROW([&]() { - lua.script("assert(f(v))"); + lua.safe_script("assert(f(v))"); }()); #else REQUIRE(true); @@ -148,9 +148,9 @@ TEST_CASE("utility/this_state", "Ensure this_state argument can be gotten anywhe int a = fx(25, 25); INFO("finished setting fx"); 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"); - lua.script("c = b:with_state(25, 25)"); + lua.safe_script("c = b:with_state(25, 25)"); INFO("getting a"); int la = lua["a"]; INFO("getting b"); diff --git a/test_variadics.cpp b/test_variadics.cpp index 4485c3ef..a5b92c72 100644 --- a/test_variadics.cpp +++ b/test_variadics.cpp @@ -25,9 +25,9 @@ TEST_CASE("variadics/variadic_args", "Check to see we can receive multiple argum return{ r, r > 200 }; }); - lua.script("x = v(25, 25)"); - lua.script("x2 = v(25, 25, 100, 50, 250, 150)"); - lua.script("x3 = v(1, 2, 3, 4, 5, 6)"); + lua.safe_script("x = v(25, 25)"); + lua.safe_script("x2 = v(25, 25, 100, 50, 250, 150)"); + lua.safe_script("x3 = v(1, 2, 3, 4, 5, 6)"); structure& lx = lua["x"]; 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) { } ); - REQUIRE_NOTHROW(lua.script("v(20, 25, 30)")); - REQUIRE_NOTHROW(lua.script("v(20, 25)")); + REQUIRE_NOTHROW(lua.safe_script("v(20, 25, 30)")); + REQUIRE_NOTHROW(lua.safe_script("v(20, 25)")); auto result = lua.safe_script("v(20)", sol::script_pass_on_error); REQUIRE_FALSE(result.valid()); } @@ -72,8 +72,8 @@ TEST_CASE("variadics/variadic_args get type", "Make sure we can inspect types pr REQUIRE(working); }); - lua.script("f(1, 'bark', true)"); - lua.script("f(2, 'wuf', false)"); + lua.safe_script("f(1, 'bark', true)"); + lua.safe_script("f(2, 'wuf', false)"); } 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([&]() { - lua.script(R"( + lua.safe_script(R"( v1, v2, v3 = f() v4, v5 = g() )"); @@ -116,7 +116,7 @@ TEST_CASE("variadics/variadic_results", "returning a variable amount of argument }); REQUIRE_NOTHROW([&]() { - lua.script(R"( + lua.safe_script(R"( v1, v2, v3 = f(1, 'bark', true) v4, v5 = f(25, 82) )"); @@ -156,7 +156,7 @@ TEST_CASE("variadics/variadic_results", "returning a variable amount of argument }); REQUIRE_NOTHROW([&]() { - lua.script(R"( + lua.safe_script(R"( v1, v2, v3 = f(true) v4, v5, v6, v7 = f(false) )"); @@ -208,10 +208,10 @@ TEST_CASE("variadics/fallback_constructor", "ensure constructor matching behaves ); REQUIRE_NOTHROW([&]() { - lua.script("v0 = vec2();"); - lua.script("v1 = vec2(1);"); - lua.script("v2 = vec2(1, 2);"); - lua.script("v3 = vec2(v2)"); + lua.safe_script("v0 = vec2();"); + lua.safe_script("v1 = vec2(1);"); + lua.safe_script("v2 = vec2(1, 2);"); + lua.safe_script("v3 = vec2(v2)"); }()); vec2& v0 = lua["v0"]; diff --git a/tests.cpp b/tests.cpp index 17f7dfc5..508ed628 100644 --- a/tests.cpp +++ b/tests.cpp @@ -77,40 +77,40 @@ TEST_CASE("simple/set", "Check if the set works properly.") { test_stack_guard g(lua.lua_state(), begintop, endtop); lua.set("a", 9); } 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); lua.set("d", "hello"); } 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); lua.set("e", std::string("hello"), "f", true); } REQUIRE(begintop == endtop); - REQUIRE_NOTHROW(lua.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 d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) 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.") { sol::state lua; int begintop = 0, endtop = 0; - lua.script("a = 9"); + lua.safe_script("a = 9"); { test_stack_guard g(lua.lua_state(), begintop, endtop); auto a = lua.get("a"); REQUIRE(a == 9.0); } REQUIRE(begintop == endtop); - lua.script("b = nil"); + lua.safe_script("b = nil"); { test_stack_guard g(lua.lua_state(), begintop, endtop); REQUIRE_NOTHROW(lua.get("b")); } REQUIRE(begintop == endtop); - lua.script("d = 'hello'"); - lua.script("e = true"); + lua.safe_script("d = 'hello'"); + lua.safe_script("e = true"); { test_stack_guard g(lua.lua_state(), begintop, endtop); 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") { sol::state lua; lua[1] = 25.4; - lua.script("b = 1"); + lua.safe_script("b = 1"); double a = lua.get(1); double b = lua.get("b"); REQUIRE(a == 25.4); @@ -169,7 +169,7 @@ TEST_CASE("simple/addition", "check if addition works and can be gotten through sol::state lua; lua.set("b", 0.2); - lua.script("c = 9 + b"); + lua.safe_script("c = 9 + b"); auto c = lua.get("c"); REQUIRE(c == 9.2); @@ -179,7 +179,7 @@ TEST_CASE("simple/if", "check if if statements work through lua") { sol::state lua; std::string program = "if true then f = 0.1 else f = 'test' end"; - lua.script(program); + lua.safe_script(program); auto f = lua.get("f"); 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) { INFO(x); }); - REQUIRE_NOTHROW(lua.script("x = lol()\n" + REQUIRE_NOTHROW(lua.safe_script("x = lol()\n" "rofl(x)\n" "assert(x == nil)")); } @@ -234,7 +234,7 @@ TEST_CASE("object/conversions", "make sure all basic reference types can be made struct d {}; - lua.script("function f () print('bark') end"); + lua.safe_script("function f () print('bark') end"); lua["d"] = d{}; lua["l"] = static_cast(nullptr); @@ -317,7 +317,7 @@ TEST_CASE("feature/indexing overrides", "make sure index functions can be overri , "props", sol::property(&DynamicObject::get_dynamic_props) ); - lua.script(R"__( + lua.safe_script(R"__( obj = DynamicObject:new() obj.props.name = 'test 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", sol::constructors>(), sol::meta_function::index, &vector::my_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" "v[2] = 3\n" "print(v[2])\n" @@ -403,7 +403,7 @@ TEST_CASE("features/multiple inheritance", "Ensure that multiple inheritance wor "a2", &complex::a2, sol::base_classes, sol::bases() ); - lua.script("c = complex.new()\n" + lua.safe_script("c = complex.new()\n" "s = simple.new()\n" "b1 = 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? lua.set_function("func_opt_ret_bool", func_opt_ret_bool); REQUIRE_NOTHROW([&]{ - lua.script(R"( + lua.safe_script(R"( func_opt_ret_bool(42) func_opt_ret_bool() print('ok') @@ -496,7 +496,7 @@ TEST_CASE("proxy/proper-pushing", "allow proxies to reference other proxies and T t; lua["t1"] = &t; lua["t2"] = lua["t1"]; - lua.script("b = t1 == t2"); + lua.safe_script("b = t1 == t2"); bool b = lua["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.set_function("is_thing", [](sol::stack_object obj) { return obj.is(); } ); lua["a"] = thing{}; - REQUIRE_NOTHROW(lua.script("assert(is_thing(a))")); + REQUIRE_NOTHROW(lua.safe_script("assert(is_thing(a))")); } 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.set_function("is_thing", [](sol::object obj) { return obj.is(); }); lua["a"] = thing{}; - REQUIRE_NOTHROW(lua.script("assert(is_thing(a))")); + REQUIRE_NOTHROW(lua.safe_script("assert(is_thing(a))")); } }