diff --git a/single/sol/sol.hpp b/single/sol/sol.hpp index 13e18fc8..42846135 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-04-19 00:25:59.958025 UTC -// This header was generated with sol v2.17.1 (revision 2acc8be) +// Generated 2017-04-19 16:59:23.068202 UTC +// This header was generated with sol v2.17.1 (revision de7d7e8) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -3683,14 +3683,14 @@ namespace sol { template struct lua_type_of> : std::integral_constant { }; - template - struct lua_type_of> : std::integral_constant { }; - template <> struct lua_type_of : std::integral_constant { }; + template + struct lua_type_of> : std::integral_constant { }; + template <> - struct lua_type_of : std::integral_constant { }; + struct lua_type_of : std::integral_constant { }; template <> struct lua_type_of : std::integral_constant { }; @@ -3920,6 +3920,9 @@ namespace sol { template struct is_userdata> : std::true_type {}; + template + struct is_environment : std::integral_constant::value || is_table::value> {}; + template struct is_container : detail::is_container{}; @@ -4032,11 +4035,11 @@ namespace sol { namespace sol { namespace stack { - inline void remove(lua_State* L, int index, int count) { + inline void remove(lua_State* L, int rawindex, int count) { if (count < 1) return; int top = lua_gettop(L); - if (index == -count || top == index) { + if (rawindex == -count || top == rawindex) { // Slice them right off the top lua_pop(L, static_cast(count)); return; @@ -4045,6 +4048,7 @@ namespace sol { // Remove each item one at a time using stack operations // Probably slower, maybe, haven't benchmarked, // but necessary + int index = lua_absindex(L, rawindex); if (index < 0) { index = lua_gettop(L) + (index + 1); } @@ -4102,6 +4106,7 @@ namespace sol { namespace detail { struct global_tag { } const global_{}; + struct no_safety_tag {} const no_safety; } // detail class reference { @@ -5188,6 +5193,14 @@ namespace sol { } }; + template + struct checker, type::userdata, C> { + template + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + return stack::check(L, index, std::forward(handler), tracking); + } + }; + template struct checker, type::userdata, C> : checker, type::lightuserdata, C> {}; @@ -5258,6 +5271,28 @@ namespace sol { template struct checker { + template + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + tracking.use(1); + if (lua_getmetatable(L, index) == 0) { + return true; + } + type t = type_of(L, -1); + if (t == type::table || t == type::none || t == type::nil) { + lua_pop(L, 1); + return true; + } + if (t != type::userdata) { + lua_pop(L, 1); + handler(L, index, expected, t); + return false; + } + return true; + } + }; + + template + struct checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -5278,8 +5313,8 @@ namespace sol { } }; - template - struct checker { + template + struct checker, type::poly, C> { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -7500,21 +7535,21 @@ namespace sol { basic_userdata(stack_reference&& r) : basic_userdata(r.lua_state(), r.stack_index()) {} template >>, meta::neg, ref_index>>> = 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(L, index) { + basic_userdata(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) { #ifdef SOL_CHECK_ARGUMENTS - type_assert(L, index, type::userdata); + stack::check(L, index, type_panic); #endif // Safety } - basic_userdata(lua_State* L, ref_index index) : base_t(L, index) { + basic_userdata(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) { #ifdef SOL_CHECK_ARGUMENTS auto pp = stack::push_pop(*this); - type_assert(L, -1, type::userdata); + stack::check(L, index, type_panic); #endif // Safety } }; template - class basic_lightuserdata : public basic_object_base< base_type > { + class basic_lightuserdata : public basic_object_base { typedef basic_object_base base_t; public: basic_lightuserdata() noexcept = default; @@ -7537,13 +7572,13 @@ namespace sol { 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 - type_assert(L, index, type::lightuserdata); + stack::check(L, index, type_panic); #endif // Safety } basic_lightuserdata(lua_State* L, ref_index index) : base_t(L, index) { #ifdef SOL_CHECK_ARGUMENTS auto pp = stack::push_pop(*this); - type_assert(L, -1, type::lightuserdata); + stack::check(L, index, type_panic); #endif // Safety } }; @@ -10594,7 +10629,7 @@ namespace sol { return stack::push(L, runtime[runtimetarget]); } - template + template inline int indexing_fail(lua_State* L) { if (is_index) { #if 0//def SOL_SAFE_USERTYPE @@ -10602,6 +10637,15 @@ namespace sol { string_detail::string_shim accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)")); return luaL_error(L, "sol: attempt to index (get) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.c_str()); #else + int isnum = 0; + lua_Integer magic = lua_tointegerx(L, upvalue_index(4), &isnum); + if (isnum != 0 && magic == toplevel_magic) { + if (lua_getmetatable(L, 1) == 1) { + int metatarget = lua_gettop(L); + stack::get_field(L, stack_reference(L, raw_index(2)), metatarget); + return 1; + } + } // With runtime extensibility, we can't hard-error things. They have to return nil, like regular table types, unfortunately... return stack::push(L, lua_nil); #endif @@ -10641,34 +10685,40 @@ namespace sol { } }; non_simple(); - for (std::size_t i = 0; i < 4; lua_pop(L, 1), ++i) { + for (std::size_t i = 0; i < 4; lua_settop(L, 3), ++i) { const char* metakey = nullptr; switch (i) { case 0: metakey = &usertype_traits::metatable()[0]; + luaL_getmetatable(L, metakey); break; case 1: metakey = &usertype_traits>::metatable()[0]; + luaL_getmetatable(L, metakey); break; case 2: - metakey = &usertype_traits::user_metatable()[0]; + metakey = &usertype_traits::metatable()[0]; + luaL_getmetatable(L, metakey); break; case 3: default: - metakey = &usertype_traits::metatable()[0]; + metakey = &usertype_traits::user_metatable()[0]; + { + luaL_getmetatable(L, metakey); + lua_getmetatable(L, -1); + } break; } - luaL_getmetatable(L, metakey); int tableindex = lua_gettop(L); if (type_of(L, tableindex) == type::lua_nil) { continue; } - stack::set_field(L, stack_reference(L, 2), stack_reference(L, 3), tableindex); + stack::set_field(L, stack_reference(L, raw_index(2)), stack_reference(L, raw_index(3)), tableindex); } lua_settop(L, 0); return 0; } - return indexing_fail(L); + return indexing_fail(L); } template @@ -10877,7 +10927,7 @@ namespace sol { } template > - usertype_metatable(Args&&... args) : usertype_metatable_core(&usertype_detail::indexing_fail, &usertype_detail::metatable_newindex), usertype_detail::registrar(), + usertype_metatable(Args&&... args) : usertype_metatable_core(&usertype_detail::indexing_fail, &usertype_detail::metatable_newindex), usertype_detail::registrar(), functions(std::forward(args)...), destructfunc(nullptr), callconstructfunc(nullptr), indexbase(&core_indexing_call), newindexbase(&core_indexing_call), @@ -11408,7 +11458,7 @@ namespace sol { template simple_usertype_metatable(usertype_detail::verified_tag, std::index_sequence, lua_State* L, Tuple&& args) : callconstructfunc(lua_nil), - indexfunc(&usertype_detail::indexing_fail), newindexfunc(&usertype_detail::metatable_newindex), + indexfunc(&usertype_detail::indexing_fail), newindexfunc(&usertype_detail::metatable_newindex), indexbase(&usertype_detail::simple_core_indexing_call), newindexbase(&usertype_detail::simple_core_indexing_call), indexbaseclasspropogation(usertype_detail::walk_all_bases), newindexbaseclasspropogation(&usertype_detail::walk_all_bases), baseclasscheck(nullptr), baseclasscast(nullptr), @@ -12449,6 +12499,12 @@ namespace sol { } basic_table_core(lua_State* L, detail::global_tag t) noexcept : base_t(L, t) { } + + protected: + basic_table_core(detail::no_safety_tag, lua_State* L, int index) : base_t(L, index) {} + basic_table_core(detail::no_safety_tag, lua_State* L, ref_index index) : base_t(L, index) {} + template , basic_table_core>>, meta::neg>, std::is_base_of>> = meta::enabler> + basic_table_core(detail::no_safety_tag, T&& r) noexcept : base_t(std::forward(r)) {} public: typedef basic_table_iterator iterator; @@ -12468,19 +12524,19 @@ namespace sol { lua_pop(L, 1); } } - basic_table_core(lua_State* L, int index = -1) : base_t(L, index) { + basic_table_core(lua_State* L, int index = -1) : basic_table_core(detail::no_safety, L, index) { #ifdef SOL_CHECK_ARGUMENTS stack::check(L, index, type_panic); #endif // Safety } - basic_table_core(lua_State* L, ref_index index) : base_t(L, index) { + basic_table_core(lua_State* L, ref_index index) : basic_table_core(detail::no_safety, L, index) { #ifdef SOL_CHECK_ARGUMENTS auto pp = stack::push_pop(*this); stack::check(L, -1, type_panic); #endif // Safety } template , basic_table_core>>, meta::neg>, std::is_base_of>> = meta::enabler> - basic_table_core(T&& r) noexcept : base_t(std::forward(r)) { + basic_table_core(T&& r) noexcept : basic_table_core(detail::no_safety, std::forward(r)) { #ifdef SOL_CHECK_ARGUMENTS if (!is_table>::value) { auto pp = stack::push_pop(*this); @@ -12800,35 +12856,57 @@ namespace sol { template struct basic_environment : basic_table { private: - typedef basic_table table_t; + typedef basic_table base_t; + public: basic_environment() noexcept = default; basic_environment(const basic_environment&) = default; basic_environment(basic_environment&&) = default; basic_environment& operator=(const basic_environment&) = default; basic_environment& operator=(basic_environment&&) = default; - - basic_environment(env_t, const stack_reference& extraction_target) : table_t(extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { - lua_pop(this->lua_state(), 2); - } - basic_environment(env_t, const reference& extraction_target) : table_t(extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { - lua_pop(this->lua_state(), 2); - } + basic_environment(const stack_reference& r) : basic_environment(r.lua_state(), r.stack_index()) {} + basic_environment(stack_reference&& r) : basic_environment(r.lua_state(), r.stack_index()) {} - basic_environment(lua_State* L, new_table t, const reference& fallback) : table_t(L, std::move(t)) { + basic_environment(lua_State* L, new_table nt) : base_t(L, std::move(nt)) {} + basic_environment(lua_State* L, new_table t, const reference& fallback) : basic_environment(L, std::move(t)) { sol::stack_table mt(L, sol::new_table(0, 1)); mt.set(sol::meta_function::index, fallback); this->set(metatable_key, mt); mt.pop(); } - - template , basic_environment>>, - meta::boolean...>::value)>, - meta::boolean>::value)>, - meta::boolean>::value)> - > = meta::enabler> - basic_environment(T&& arg, Args&&... args) : table_t(std::forward(arg), std::forward(args)...) { } + + basic_environment(env_t, const stack_reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { +#ifdef SOL_CHECK_ARGUMENTS + stack::check(this->lua_state(), -1, type_panic); +#endif // Safety + lua_pop(this->lua_state(), 2); + } + basic_environment(env_t, const reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { +#ifdef SOL_CHECK_ARGUMENTS + stack::check(this->lua_state(), -1, type_panic); +#endif // Safety + lua_pop(this->lua_state(), 2); + } + basic_environment(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) { +#ifdef SOL_CHECK_ARGUMENTS + stack::check(L, index, type_panic); +#endif // Safety + } + basic_environment(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) { +#ifdef SOL_CHECK_ARGUMENTS + auto pp = stack::push_pop(*this); + stack::check(L, -1, type_panic); +#endif // Safety + } + template , basic_environment>>, meta::neg>, std::is_base_of>> = meta::enabler> + basic_environment(T&& r) noexcept : base_t(detail::no_safety, std::forward(r)) { +#ifdef SOL_CHECK_ARGUMENTS + if (!is_environment>::value) { + auto pp = stack::push_pop(*this); + stack::check(base_t::lua_state(), -1, type_panic); + } +#endif // Safety + } template void set_on(const T& target) const { diff --git a/sol/environment.hpp b/sol/environment.hpp index 73b261e8..83cb5ae7 100644 --- a/sol/environment.hpp +++ b/sol/environment.hpp @@ -29,35 +29,57 @@ namespace sol { template struct basic_environment : basic_table { private: - typedef basic_table table_t; + typedef basic_table base_t; + public: basic_environment() noexcept = default; basic_environment(const basic_environment&) = default; basic_environment(basic_environment&&) = default; basic_environment& operator=(const basic_environment&) = default; basic_environment& operator=(basic_environment&&) = default; - - basic_environment(env_t, const stack_reference& extraction_target) : table_t(extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { - lua_pop(this->lua_state(), 2); - } - basic_environment(env_t, const reference& extraction_target) : table_t(extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { - lua_pop(this->lua_state(), 2); - } + basic_environment(const stack_reference& r) : basic_environment(r.lua_state(), r.stack_index()) {} + basic_environment(stack_reference&& r) : basic_environment(r.lua_state(), r.stack_index()) {} - basic_environment(lua_State* L, new_table t, const reference& fallback) : table_t(L, std::move(t)) { + basic_environment(lua_State* L, new_table nt) : base_t(L, std::move(nt)) {} + basic_environment(lua_State* L, new_table t, const reference& fallback) : basic_environment(L, std::move(t)) { sol::stack_table mt(L, sol::new_table(0, 1)); mt.set(sol::meta_function::index, fallback); this->set(metatable_key, mt); mt.pop(); } - - template , basic_environment>>, - meta::boolean...>::value)>, - meta::boolean>::value)>, - meta::boolean>::value)> - > = meta::enabler> - basic_environment(T&& arg, Args&&... args) : table_t(std::forward(arg), std::forward(args)...) { } + + basic_environment(env_t, const stack_reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { +#ifdef SOL_CHECK_ARGUMENTS + stack::check(this->lua_state(), -1, type_panic); +#endif // Safety + lua_pop(this->lua_state(), 2); + } + basic_environment(env_t, const reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { +#ifdef SOL_CHECK_ARGUMENTS + stack::check(this->lua_state(), -1, type_panic); +#endif // Safety + lua_pop(this->lua_state(), 2); + } + basic_environment(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) { +#ifdef SOL_CHECK_ARGUMENTS + stack::check(L, index, type_panic); +#endif // Safety + } + basic_environment(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) { +#ifdef SOL_CHECK_ARGUMENTS + auto pp = stack::push_pop(*this); + stack::check(L, -1, type_panic); +#endif // Safety + } + template , basic_environment>>, meta::neg>, std::is_base_of>> = meta::enabler> + basic_environment(T&& r) noexcept : base_t(detail::no_safety, std::forward(r)) { +#ifdef SOL_CHECK_ARGUMENTS + if (!is_environment>::value) { + auto pp = stack::push_pop(*this); + stack::check(base_t::lua_state(), -1, type_panic); + } +#endif // Safety + } template void set_on(const T& target) const { diff --git a/sol/reference.hpp b/sol/reference.hpp index 9fbc008a..203ad491 100644 --- a/sol/reference.hpp +++ b/sol/reference.hpp @@ -27,11 +27,11 @@ namespace sol { namespace stack { - inline void remove(lua_State* L, int index, int count) { + inline void remove(lua_State* L, int rawindex, int count) { if (count < 1) return; int top = lua_gettop(L); - if (index == -count || top == index) { + if (rawindex == -count || top == rawindex) { // Slice them right off the top lua_pop(L, static_cast(count)); return; @@ -40,6 +40,7 @@ namespace sol { // Remove each item one at a time using stack operations // Probably slower, maybe, haven't benchmarked, // but necessary + int index = lua_absindex(L, rawindex); if (index < 0) { index = lua_gettop(L) + (index + 1); } @@ -97,6 +98,7 @@ namespace sol { namespace detail { struct global_tag { } const global_{}; + struct no_safety_tag {} const no_safety; } // detail class reference { diff --git a/sol/simple_usertype_metatable.hpp b/sol/simple_usertype_metatable.hpp index 15bfdaaa..d248f6a9 100644 --- a/sol/simple_usertype_metatable.hpp +++ b/sol/simple_usertype_metatable.hpp @@ -289,7 +289,7 @@ namespace sol { template simple_usertype_metatable(usertype_detail::verified_tag, std::index_sequence, lua_State* L, Tuple&& args) : callconstructfunc(lua_nil), - indexfunc(&usertype_detail::indexing_fail), newindexfunc(&usertype_detail::metatable_newindex), + indexfunc(&usertype_detail::indexing_fail), newindexfunc(&usertype_detail::metatable_newindex), indexbase(&usertype_detail::simple_core_indexing_call), newindexbase(&usertype_detail::simple_core_indexing_call), indexbaseclasspropogation(usertype_detail::walk_all_bases), newindexbaseclasspropogation(&usertype_detail::walk_all_bases), baseclasscheck(nullptr), baseclasscast(nullptr), diff --git a/sol/stack_check.hpp b/sol/stack_check.hpp index 55c6f384..ad6260dc 100644 --- a/sol/stack_check.hpp +++ b/sol/stack_check.hpp @@ -198,6 +198,14 @@ namespace sol { } }; + template + struct checker, type::userdata, C> { + template + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + return stack::check(L, index, std::forward(handler), tracking); + } + }; + template struct checker, type::userdata, C> : checker, type::lightuserdata, C> {}; @@ -268,6 +276,28 @@ namespace sol { template struct checker { + template + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + tracking.use(1); + if (lua_getmetatable(L, index) == 0) { + return true; + } + type t = type_of(L, -1); + if (t == type::table || t == type::none || t == type::nil) { + lua_pop(L, 1); + return true; + } + if (t != type::userdata) { + lua_pop(L, 1); + handler(L, index, expected, t); + return false; + } + return true; + } + }; + + template + struct checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -288,8 +318,8 @@ namespace sol { } }; - template - struct checker { + template + struct checker, type::poly, C> { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); diff --git a/sol/table_core.hpp b/sol/table_core.hpp index bcd31c75..f1d37556 100644 --- a/sol/table_core.hpp +++ b/sol/table_core.hpp @@ -156,6 +156,12 @@ namespace sol { } basic_table_core(lua_State* L, detail::global_tag t) noexcept : base_t(L, t) { } + + protected: + basic_table_core(detail::no_safety_tag, lua_State* L, int index) : base_t(L, index) {} + basic_table_core(detail::no_safety_tag, lua_State* L, ref_index index) : base_t(L, index) {} + template , basic_table_core>>, meta::neg>, std::is_base_of>> = meta::enabler> + basic_table_core(detail::no_safety_tag, T&& r) noexcept : base_t(std::forward(r)) {} public: typedef basic_table_iterator iterator; @@ -175,19 +181,19 @@ namespace sol { lua_pop(L, 1); } } - basic_table_core(lua_State* L, int index = -1) : base_t(L, index) { + basic_table_core(lua_State* L, int index = -1) : basic_table_core(detail::no_safety, L, index) { #ifdef SOL_CHECK_ARGUMENTS stack::check(L, index, type_panic); #endif // Safety } - basic_table_core(lua_State* L, ref_index index) : base_t(L, index) { + basic_table_core(lua_State* L, ref_index index) : basic_table_core(detail::no_safety, L, index) { #ifdef SOL_CHECK_ARGUMENTS auto pp = stack::push_pop(*this); stack::check(L, -1, type_panic); #endif // Safety } template , basic_table_core>>, meta::neg>, std::is_base_of>> = meta::enabler> - basic_table_core(T&& r) noexcept : base_t(std::forward(r)) { + basic_table_core(T&& r) noexcept : basic_table_core(detail::no_safety, std::forward(r)) { #ifdef SOL_CHECK_ARGUMENTS if (!is_table>::value) { auto pp = stack::push_pop(*this); diff --git a/sol/types.hpp b/sol/types.hpp index 8cc61171..742ab835 100644 --- a/sol/types.hpp +++ b/sol/types.hpp @@ -704,14 +704,14 @@ namespace sol { template struct lua_type_of> : std::integral_constant { }; - template - struct lua_type_of> : std::integral_constant { }; - template <> struct lua_type_of : std::integral_constant { }; + template + struct lua_type_of> : std::integral_constant { }; + template <> - struct lua_type_of : std::integral_constant { }; + struct lua_type_of : std::integral_constant { }; template <> struct lua_type_of : std::integral_constant { }; @@ -941,6 +941,9 @@ namespace sol { template struct is_userdata> : std::true_type {}; + template + struct is_environment : std::integral_constant::value || is_table::value> {}; + template struct is_container : detail::is_container{}; diff --git a/sol/userdata.hpp b/sol/userdata.hpp index 9e1802b0..d49c4a2f 100644 --- a/sol/userdata.hpp +++ b/sol/userdata.hpp @@ -48,21 +48,21 @@ namespace sol { basic_userdata(stack_reference&& r) : basic_userdata(r.lua_state(), r.stack_index()) {} template >>, meta::neg, ref_index>>> = 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(L, index) { + basic_userdata(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) { #ifdef SOL_CHECK_ARGUMENTS - type_assert(L, index, type::userdata); + stack::check(L, index, type_panic); #endif // Safety } - basic_userdata(lua_State* L, ref_index index) : base_t(L, index) { + basic_userdata(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) { #ifdef SOL_CHECK_ARGUMENTS auto pp = stack::push_pop(*this); - type_assert(L, -1, type::userdata); + stack::check(L, index, type_panic); #endif // Safety } }; template - class basic_lightuserdata : public basic_object_base< base_type > { + class basic_lightuserdata : public basic_object_base { typedef basic_object_base base_t; public: basic_lightuserdata() noexcept = default; @@ -85,13 +85,13 @@ namespace sol { 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 - type_assert(L, index, type::lightuserdata); + stack::check(L, index, type_panic); #endif // Safety } basic_lightuserdata(lua_State* L, ref_index index) : base_t(L, index) { #ifdef SOL_CHECK_ARGUMENTS auto pp = stack::push_pop(*this); - type_assert(L, -1, type::lightuserdata); + stack::check(L, index, type_panic); #endif // Safety } }; diff --git a/sol/usertype_metatable.hpp b/sol/usertype_metatable.hpp index f164f906..edb92e2b 100644 --- a/sol/usertype_metatable.hpp +++ b/sol/usertype_metatable.hpp @@ -176,7 +176,7 @@ namespace sol { return stack::push(L, runtime[runtimetarget]); } - template + template inline int indexing_fail(lua_State* L) { if (is_index) { #if 0//def SOL_SAFE_USERTYPE @@ -184,6 +184,15 @@ namespace sol { string_detail::string_shim accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)")); return luaL_error(L, "sol: attempt to index (get) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.c_str()); #else + int isnum = 0; + lua_Integer magic = lua_tointegerx(L, upvalue_index(4), &isnum); + if (isnum != 0 && magic == toplevel_magic) { + if (lua_getmetatable(L, 1) == 1) { + int metatarget = lua_gettop(L); + stack::get_field(L, stack_reference(L, raw_index(2)), metatarget); + return 1; + } + } // With runtime extensibility, we can't hard-error things. They have to return nil, like regular table types, unfortunately... return stack::push(L, lua_nil); #endif @@ -223,34 +232,40 @@ namespace sol { } }; non_simple(); - for (std::size_t i = 0; i < 4; lua_pop(L, 1), ++i) { + for (std::size_t i = 0; i < 4; lua_settop(L, 3), ++i) { const char* metakey = nullptr; switch (i) { case 0: metakey = &usertype_traits::metatable()[0]; + luaL_getmetatable(L, metakey); break; case 1: metakey = &usertype_traits>::metatable()[0]; + luaL_getmetatable(L, metakey); break; case 2: - metakey = &usertype_traits::user_metatable()[0]; + metakey = &usertype_traits::metatable()[0]; + luaL_getmetatable(L, metakey); break; case 3: default: - metakey = &usertype_traits::metatable()[0]; + metakey = &usertype_traits::user_metatable()[0]; + { + luaL_getmetatable(L, metakey); + lua_getmetatable(L, -1); + } break; } - luaL_getmetatable(L, metakey); int tableindex = lua_gettop(L); if (type_of(L, tableindex) == type::lua_nil) { continue; } - stack::set_field(L, stack_reference(L, 2), stack_reference(L, 3), tableindex); + stack::set_field(L, stack_reference(L, raw_index(2)), stack_reference(L, raw_index(3)), tableindex); } lua_settop(L, 0); return 0; } - return indexing_fail(L); + return indexing_fail(L); } template @@ -459,7 +474,7 @@ namespace sol { } template > - usertype_metatable(Args&&... args) : usertype_metatable_core(&usertype_detail::indexing_fail, &usertype_detail::metatable_newindex), usertype_detail::registrar(), + usertype_metatable(Args&&... args) : usertype_metatable_core(&usertype_detail::indexing_fail, &usertype_detail::metatable_newindex), usertype_detail::registrar(), functions(std::forward(args)...), destructfunc(nullptr), callconstructfunc(nullptr), indexbase(&core_indexing_call), newindexbase(&core_indexing_call), diff --git a/test_environments.cpp b/test_environments.cpp index 91b824e3..ddbc878b 100644 --- a/test_environments.cpp +++ b/test_environments.cpp @@ -35,6 +35,8 @@ 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.set_function("check_f_env", [&lua, &env_f](sol::object target) { sol::stack_guard sg(lua); @@ -57,10 +59,18 @@ TEST_CASE("environments/get", "Envronments can be taken out of things like Lua f REQUIRE(env_g == target_env); } ); + lua.set_function("check_h_env", + [&lua](sol::function target) { + sol::stack_guard sg(lua); + sol::environment target_env = sol::get_environment(target); + REQUIRE_FALSE(target_env.valid()); + } + ); REQUIRE_NOTHROW([&lua]() { lua.script("check_f_env(f)"); lua.script("check_g_env(g)"); + lua.script("check_h_env(h)"); }()); } diff --git a/test_simple_usertypes.cpp b/test_simple_usertypes.cpp index cf8e3e5b..9b70dfa7 100644 --- a/test_simple_usertypes.cpp +++ b/test_simple_usertypes.cpp @@ -697,6 +697,30 @@ end } } +TEST_CASE("simple_usertype/runtime-replacement", "ensure that functions can be properly replaced at runtime for non-indexed things") { + struct heart_t {}; + + sol::state lua; + lua.open_libraries(sol::lib::base); + + 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()"); + }()); + int v1 = lua["v1"]; + int v2 = lua["v2"]; + int v3 = lua["v3"]; + REQUIRE(v1 == 1); + REQUIRE(v2 == 2); + REQUIRE(v3 == 3); +} + TEST_CASE("simple_usertype/meta-key-retrievals", "allow for special meta keys (__index, __newindex) to trigger methods even if overwritten directly") { SECTION("dynamically") { static int writes = 0; diff --git a/test_usertypes.cpp b/test_usertypes.cpp index 75b843b9..67bdec40 100644 --- a/test_usertypes.cpp +++ b/test_usertypes.cpp @@ -523,10 +523,9 @@ TEST_CASE("usertype/nonmember-functions", "let users set non-member functions th "gief_stuff", giver::gief_stuff, "gief", &giver::gief, "__tostring", [](const giver& t) { - return std::to_string(t.a) + ": giving value"; - } - ).get("giver") - .set_function("stuff", giver::stuff); + return std::to_string(t.a) + ": giving value"; + } + ).get("giver").set_function("stuff", giver::stuff); REQUIRE_NOTHROW(lua.script("giver.stuff()")); REQUIRE_NOTHROW(lua.script("t = giver.new()\n" @@ -1623,6 +1622,30 @@ end } } +TEST_CASE("usertype/runtime-replacement", "ensure that functions can be properly replaced at runtime for non-indexed things") { + struct heart_t {}; + + sol::state lua; + lua.open_libraries(sol::lib::base); + + 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()"); + }()); + int v1 = lua["v1"]; + int v2 = lua["v2"]; + int v3 = lua["v3"]; + REQUIRE(v1 == 1); + REQUIRE(v2 == 2); + REQUIRE(v3 == 3); +} + TEST_CASE("usertype/meta-key-retrievals", "allow for special meta keys (__index, __newindex) to trigger methods even if overwritten directly") { SECTION("dynamically") { static int writes = 0;