From 94a1898b372052d32fa3c75934f8c35e2f0342c0 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Wed, 10 Aug 2016 06:32:44 -0400 Subject: [PATCH] [OH GOD SO BROKEN WHY] This is tentative, untested "support" for calling inherited functions. --- sol/inheritance.hpp | 10 ++++ sol/usertype_metatable.hpp | 99 +++++++++++++++++++++++++++++--------- 2 files changed, 86 insertions(+), 23 deletions(-) diff --git a/sol/inheritance.hpp b/sol/inheritance.hpp index 120c36e5..3910ee92 100644 --- a/sol/inheritance.hpp +++ b/sol/inheritance.hpp @@ -67,6 +67,16 @@ namespace sol { return key; } + inline decltype(auto) base_class_index_propogation_key() { + static const auto& key = u8"\xF0\x9F\x8C\xB2.index"; + return key; + } + + inline decltype(auto) base_class_new_index_propogation_key() { + static const auto& key = u8"\xF0\x9F\x8C\xB2.new_index"; + return key; + } + template struct inheritance { static bool type_check_bases(types<>, std::size_t) { diff --git a/sol/usertype_metatable.hpp b/sol/usertype_metatable.hpp index 7ea66ddd..1f2a5692 100644 --- a/sol/usertype_metatable.hpp +++ b/sol/usertype_metatable.hpp @@ -138,11 +138,16 @@ namespace sol { typedef std::tuple ...> Tuple; template struct check_binding : is_variable_binding> {}; + typedef void (*base_walk)(lua_State*, bool&, int&, string_detail::string_shim&); Tuple functions; lua_CFunction indexfunc; lua_CFunction newindexfunc; lua_CFunction destructfunc; lua_CFunction callconstructfunc; + lua_CFunction indexbase; + lua_CFunction newindexbase; + base_walk indexbaseclasspropogation; + base_walk newindexbaseclasspropogation; void* baseclasscheck; void* baseclasscast; bool mustindex; @@ -194,6 +199,8 @@ namespace sol { static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report."); baseclasscheck = (void*)&detail::inheritance::type_check; baseclasscast = (void*)&detail::inheritance::type_cast; + indexbaseclasspropogation = walk_all_bases; + newindexbaseclasspropogation = walk_all_bases; } template , base_classes_tag, call_construction>::value>> @@ -226,7 +233,10 @@ namespace sol { template > usertype_metatable(Args&&... args) : functions(std::forward(args)...), indexfunc(usertype_detail::indexing_fail), newindexfunc(usertype_detail::indexing_fail), - destructfunc(nullptr), callconstructfunc(nullptr), baseclasscheck(nullptr), baseclasscast(nullptr), + destructfunc(nullptr), callconstructfunc(nullptr), + indexbase(&core_indexing_call), newindexbase(&core_indexing_call), + indexbaseclasspropogation(walk_all_bases), newindexbaseclasspropogation(walk_all_bases), + baseclasscheck(nullptr), baseclasscast(nullptr), mustindex(contains_variable() || contains_index()), secondarymeta(contains_variable()) { } @@ -251,32 +261,72 @@ namespace sol { ret = real_find_call(idx, L); } - static int real_index_call(lua_State* L) { - usertype_metatable& f = stack::get>(L, upvalue_index(1)); - if (stack::get(L, -1) == type::string) { - string_detail::string_shim accessor = stack::get(L, -1); - bool found = false; - int ret = 0; - (void)detail::swallow{ 0, (f.find_call(std::true_type(), L, found, ret, accessor), 0)... }; - if (found) { - return ret; - } + template + void propogating_call(lua_State* L, bool& found, int& ret, string_detail::string_shim& accessor) { + (void)detail::swallow{ 0, (find_call(std::integral_constant(), L, found, ret, accessor), 0)... }; + } + + template + static void walk_single_base(lua_State* L, bool& found, int& ret, string_detail::string_shim&) { + if (found) + return; + const char* metakey = &usertype_traits::metatable[0]; + const char* gcmetakey = &usertype_traits::gc_table[0]; + const char* basewalkkey = b ? detail::base_class_index_propogation_key() : detail::base_class_new_index_propogation_key(); + + luaL_getmetatable(L, metakey); + if (type_of(L, -1) == type::nil) { + lua_pop(L, 1); + return; } - return f.indexfunc(L); + stack::get_field(L, basewalkkey); + if (type_of(L, -1) == type::nil) { + lua_pop(L, 2); + return; + } + lua_CFunction basewalkfunc = stack::pop(L); + lua_pop(L, 1); + + stack::get_field(L, gcmetakey); + int value = basewalkfunc(L); + if (value > -1) { + found = true; + ret = value; + } + } + + template + static void walk_all_bases(lua_State* L, bool& found, int& ret, string_detail::string_shim& accessor) { + (void)detail::swallow{ 0, (walk_single_base(L, found, ret, accessor), 0)... }; + } + + template + static int core_indexing_call(lua_State* L) { + usertype_metatable& f = toplevel ? stack::get>(L, upvalue_index(1)) : stack::pop>(L); + if (toplevel && stack::get(L, -1) != type::string) { + return b ? f.indexfunc(L) : f.newindexfunc(L); + } + string_detail::string_shim accessor = stack::get(L, -1); + int ret = 0; + bool found = false; + f.propogating_call(L, found, ret, accessor); + if (found) { + return ret; + } + // Otherwise, we need to do propagating calls through the bases + f.indexbaseclasspropogation(L, found, ret, accessor); + if (found) { + return ret; + } + return toplevel ? (b ? f.indexfunc(L) : f.newindexfunc(L)) : -1; + } + + static int real_index_call(lua_State* L) { + return core_indexing_call(L); } static int real_new_index_call(lua_State* L) { - usertype_metatable& f = stack::get>(L, upvalue_index(1)); - if (stack::get(L, -2) == type::string) { - string_detail::string_shim accessor = stack::get(L, -2); - bool found = false; - int ret = 0; - (void)detail::swallow{ 0, (f.find_call(std::false_type(), L, found, ret, accessor), 0)... }; - if (found) { - return ret; - } - } - return f.newindexfunc(L); + return core_indexing_call(L); } template @@ -394,6 +444,9 @@ namespace sol { else { stack::set_field(L, detail::base_class_cast_key(), nil, t.stack_index()); } + + stack::set_field(L, detail::base_class_index_propogation_key(), make_closure(um.indexbase, make_light(um)), t.stack_index()); + stack::set_field(L, detail::base_class_new_index_propogation_key(), make_closure(um.newindexbase, make_light(um)), t.stack_index()); if (mustindex) { // Basic index pushing: specialize