From 7c8405368e04ada8997cccd8a452c3a29bdd5ff0 Mon Sep 17 00:00:00 2001 From: Artem Serebriyskiy Date: Tue, 15 Apr 2014 03:38:45 +0400 Subject: [PATCH 1/4] Finish implementation with proxy functions --- Examples/test-suite/cpp_basic.i | 13 + Examples/test-suite/lua/cpp_basic_runme.lua | 10 + .../lua/operator_overload_runme.lua | 32 +++ Lib/lua/luarun.swg | 232 +++++++++++++++++- 4 files changed, 285 insertions(+), 2 deletions(-) diff --git a/Examples/test-suite/cpp_basic.i b/Examples/test-suite/cpp_basic.i index bd1ec453a..a228af289 100644 --- a/Examples/test-suite/cpp_basic.i +++ b/Examples/test-suite/cpp_basic.i @@ -30,6 +30,19 @@ class Foo { } int (Foo::*func_ptr)(int); + + const char* __str__() const { return "Foo"; } +}; + +class FooSub : public Foo { + public: + FooSub() :Foo(42) {} +}; + +class FooSubSub : public FooSub { + public: + FooSubSub() : FooSub() {} + const char* __str__() const { return "FooSubSub"; } }; %} diff --git a/Examples/test-suite/lua/cpp_basic_runme.lua b/Examples/test-suite/lua/cpp_basic_runme.lua index 8a72f1bad..c7e0325c5 100644 --- a/Examples/test-suite/lua/cpp_basic_runme.lua +++ b/Examples/test-suite/lua/cpp_basic_runme.lua @@ -76,3 +76,13 @@ assert(cb.test_func_ptr(f,2)==-8) -- Test that __tostring metamethod produce no internal asserts f2_name = tostring(f2) + +f3 = cb.FooSub() +f3_name = tostring(f3) + +f4 = cb.FooSubSub() +f4_name = tostring(f4) + +assert( f2_name == "Foo" ) +assert( f3_name == "Foo" ) +assert( f4_name == "FooSubSub" ) diff --git a/Examples/test-suite/lua/operator_overload_runme.lua b/Examples/test-suite/lua/operator_overload_runme.lua index 983daa1e5..f3753749b 100644 --- a/Examples/test-suite/lua/operator_overload_runme.lua +++ b/Examples/test-suite/lua/operator_overload_runme.lua @@ -78,6 +78,38 @@ assert(i(1,2)==6) assert(tostring(Op(1))=="Op(1)") assert(tostring(Op(-3))=="Op(-3)") + +-- check that operator overloads is correctly propogated accross hierarchy + +a_d=OpDerived() +b_d=OpDerived(5) +c_d=OpDerived(5) +d_d=OpDerived(2) +-- test equality +assert(a_d~=b_d) +assert(b_d==c_d) +assert(a_d~=d_d) + +-- test < +assert(a_d=c_d) +assert(b_d>d_d) +assert(b_d>=d_d) +-- +-- test + inheritance +f_d=OpDerived(1) +g_d=OpDerived(1) +assert(f_d+g_d==Op(2)) +assert(f_d-g_d==Op(0)) +assert(f_d*g_d==Op(1)) +assert(f_d/g_d==Op(1)) +-- +-- plus add some code to check the __str__ fn inheritance +assert(tostring(OpDerived(1))=="Op(1)") +assert(tostring(OpDerived(-3))=="Op(-3)") + --[[ /* Sample test code in C++ diff --git a/Lib/lua/luarun.swg b/Lib/lua/luarun.swg index 49d5848eb..b9e2d409a 100644 --- a/Lib/lua/luarun.swg +++ b/Lib/lua/luarun.swg @@ -1163,8 +1163,10 @@ SWIGINTERN void SWIG_Lua_add_class_static_details(lua_State *L, swig_lua_class * SWIG_Lua_add_namespace_details(L, clss->cls_static); } +SWIGINTERN void SWIG_Lua_add_class_user_metamethods(lua_State *L, swig_lua_class *clss); /* forward declaration */ + /* helper to recursively add class details (attributes & operations) */ -SWIGINTERN void SWIG_Lua_add_class_instance_details(lua_State *L,swig_lua_class *clss) +SWIGINTERN void SWIG_Lua_add_class_instance_details(lua_State *L, swig_lua_class *clss) { int i; /* Add bases to .bases table */ @@ -1201,6 +1203,232 @@ SWIGINTERN void SWIG_Lua_add_class_instance_details(lua_State *L,swig_lua_class SWIG_Lua_add_function(L,clss->metatable[i].name,clss->metatable[i].func); } } + +#if !defined(SWIG_LUA_SQUASH_BASES) + /* Adding metamethods that are defined in base classes. If bases were squashed + * then it is obviously unnecessary + */ + SWIG_Lua_add_class_user_metamethods(L, clss); +#endif +} + +/* helpers to add user defined class metamedhods - __add, __sub etc. Necessity for those helpers + arise from the following issue: Lua runtime checks for metamethod existence with rawget function + ignoring our SWIG-provided __index and __newindex functions. Thus our inheritance-aware method + search algorithm doesn't work in such case. (Not to say that Lua runtime queries metamethod directly + in metatable and not in object). + Current solution is this: if somewhere in hierarchy metamethod __x is defined, then all descendants + are automatically given a special proxy __x that calls the real __x method. + Obvious idea - to copy __x instead of creating __x-proxy is wrong because if someone changes __x in runtime, + those changes must be reflected in all descendants. +*/ + +SWIGRUNTIME int SWIG_Lua_resolve_metamethod(lua_State *L); /*forward declaration*/ + +/* The real function that resolveds metamethod. + * Function searches given class and all it's bases(recursively) for first instance of something that is + * not equal to SWIG_Lua_resolve_metatmethod. (Almost always this 'something' is actuall metamethod implementation + * and it is a SWIG-generated C function.). It returns value on the top of the L and there is no garbage below the + * answer. + * Returns 1 if found, 0 otherwise. + * clss is class which metatable we will search for method + * metamethod_name_idx is index in L where metamethod name (as string) lies + * skip_check allows to skip searching metamethod in givel clss and immideatelly go to searching in bases. skip_check + * is not caried to subsequent recursive calls - false is always passed. It is set to true only at first call from + * SWIG_Lua_resolve_metamethod + * */ +SWIGINTERN int SWIG_Lua_do_resolve_metamethod(lua_State *L, const swig_lua_class *clss, int metamethod_name_idx, + int skip_check) +{ + const int beginIdx = lua_gettop(L); // TODO: REMOVE + /* This function is called recursively */ + if (!skip_check) { + SWIG_Lua_get_class_metatable(L, clss->fqname); + lua_pushvalue(L, metamethod_name_idx); + assert(!lua_isnil(L,-1)); // TODO: REMOVE + assert(lua_type(L,-1) == LUA_TSTRING); // TODO: REMOVE + lua_rawget(L,-2); + /* If this is cfunction and it is equal to SWIG_Lua_resolve_metamethod then + * this isn't the function we are looking for :) + * lua_tocfunction will return NULL if not cfunction + */ + if (!lua_isnil(L,-1) && lua_tocfunction(L,-1) != SWIG_Lua_resolve_metamethod ) { + lua_remove(L,-2); /* removing class metatable */ + assert(lua_gettop(L) == beginIdx + 1); // TODO: REMOVE + return 1; + } + lua_pop(L,2); /* remove class metatable and query result */ + } + + /* Forwarding calls to bases */ + int result = 0; + int i = 0; + for(i=0;clss->bases[i];i++) + { + result = SWIG_Lua_do_resolve_metamethod(L, clss->bases[i], metamethod_name_idx, 0); + if (result) + break; + } + + /* TODO: REMOVE */ + if (result) + assert(lua_gettop(L) == beginIdx + 1); + else + assert(lua_gettop(L) == beginIdx ); + /* END OF REMOVE */ + return result; +} + +/* The proxy function for metamethod. All parameters are passed as cclosure. Searches for actual method + * and calls it */ +SWIGRUNTIME int SWIG_Lua_resolve_metamethod(lua_State *L) +{ + lua_checkstack(L,5); + const int numargs = lua_gettop(L); /* number of arguments to pass to actuall metamethod */ + + /* Get upvalues from closure */ + lua_pushvalue(L, lua_upvalueindex(1)); /*Get function name*/ + assert( !lua_isnil(L,-1) ); // TODO: REMOVE + assert( lua_type(L,-1) == LUA_TSTRING ); // TODO: REMOVE + const int metamethod_name_idx = lua_gettop(L); + assert(metamethod_name_idx == numargs + 1); // TODO: REMOVE + + lua_pushvalue(L, lua_upvalueindex(2)); + assert( !lua_isnil(L,-1) ); // TODO: REMOVE + assert( lua_islightuserdata(L,-1) ); // TODO: REMOVE + const swig_lua_class* clss = (const swig_lua_class*)(lua_touserdata(L,-1)); + lua_pop(L,1); /* remove lightuserdata with clss from stack */ + + const int precall_idx = lua_gettop(L); // TODO: REMOVE + assert( precall_idx == metamethod_name_idx ); // TODO: REMOVE + /* Actuall work */ + const int result = SWIG_Lua_do_resolve_metamethod(L, clss, metamethod_name_idx, 1); + if (!result) { + SWIG_Lua_pushferrstring(L,"The metamethod proxy is set, but it failed to find actuall metamethod. Memory corruption is most likely explanation."); + lua_error(L); + return 0; + } + + assert( lua_gettop(L) == precall_idx + 1 ); // TODO: REMOVE + lua_remove(L,-2); /* remove metamethod key */ + assert(lua_iscfunction(L,-1)); // TODO: REMOVE + assert(lua_gettop(L) == numargs + 1); // TODO: REMOVE + lua_insert(L,1); /* move function to correct position */ + lua_call(L, numargs, LUA_MULTRET); + return lua_gettop(L); /* return all results */ +} + + +/* If given metamethod must be present in given class, then creates appropriate proxy + * Returns 1 if successfully added, 0 if not added because no base class has it, -1 + * if method is defined in the class metatable itself + */ +SWIGINTERN int SWIG_Lua_add_class_user_metamethod(lua_State *L, swig_lua_class *clss) +{ + const int begin = lua_gettop(L); // TODO:REMOVE + + /* Class metatable must be one below the top of the stack */ + assert(lua_istable(L,-2)); + /* and metamethod name - on the top of the stack */ + assert(lua_isstring(L,-1)); + + const int metatable_index = lua_gettop(L) - 1; + const int key_index = lua_gettop(L); + + /* Check whether method is already defined in metatable */ + lua_pushvalue(L,-1); /* copy of the key */ + lua_gettable(L,metatable_index); + if( !lua_isnil(L,-1) ) { + lua_pop(L,1); + assert( lua_gettop(L) == begin ); // TODO: REMOVE + return -1; + } + lua_pop(L,1); + + assert( lua_gettop(L) == begin ); // TODO: REMOVE + + /* Iterating over immediate bases */ + int success = 0; + int i = 0; + for(i=0;clss->bases[i];i++) + { + const swig_lua_class *base = clss->bases[i]; + SWIG_Lua_get_class_metatable(L, base->fqname); + lua_pushvalue(L, key_index); + lua_rawget(L, -2); + if( !lua_isnil(L,-1) ) { + assert( lua_gettop(L) == begin + 2); // TODO: REMOVE + + lua_pushvalue(L, key_index); + + /* Add proxy function */ + lua_pushvalue(L, key_index); /* first closure value is function name */ + lua_pushlightuserdata(L, clss); /* second closure value is swig_lua_class structure */ + lua_pushcclosure(L, SWIG_Lua_resolve_metamethod, 2); + + lua_rawset(L, metatable_index); + assert( lua_gettop(L) == begin + 2 ); // TODO: REMOVE + success = 1; + } + lua_pop(L,1); /* remove function or nil */ + lua_pop(L,1); /* remove base class metatable */ + + assert( lua_gettop(L) == begin ); // TODO: REMOVE + if( success ) + break; + } + + assert( lua_gettop(L) == begin ); // TODO: REMOVE + + return success; +} + +#define SWIG_ADD_CLASS_METAMETHOD( name ) \ + lua_pushstring(L,name);\ + SWIG_Lua_add_class_user_metamethod(L,clss);\ + lua_pop(L,1); + +SWIGINTERN void SWIG_Lua_add_class_user_metamethods(lua_State *L, swig_lua_class *clss) +{ + const int begin = lua_gettop(L); // TODO:REMOVE + /* TODO: This place desperately needs for optimization: + * 1. Hardcoded names of all metamethods is bad idea + * 2. We create a N lua strings for every class instead of creating those N strings + * only once + */ + SWIG_Lua_get_class_metatable(L, clss->fqname); + const int metatable_index = lua_gettop(L); + SWIG_ADD_CLASS_METAMETHOD( "__add" ); + SWIG_ADD_CLASS_METAMETHOD( "__sub" ); + SWIG_ADD_CLASS_METAMETHOD( "__mul" ); + SWIG_ADD_CLASS_METAMETHOD( "__div" ); + SWIG_ADD_CLASS_METAMETHOD( "__mod" ); + SWIG_ADD_CLASS_METAMETHOD( "__pow" ); + SWIG_ADD_CLASS_METAMETHOD( "__unm" ); + SWIG_ADD_CLASS_METAMETHOD( "__concat" ); + SWIG_ADD_CLASS_METAMETHOD( "__len" ); + SWIG_ADD_CLASS_METAMETHOD( "__eq" ); + SWIG_ADD_CLASS_METAMETHOD( "__lt" ); + SWIG_ADD_CLASS_METAMETHOD( "__le" ); + SWIG_ADD_CLASS_METAMETHOD( "__call" ); + + /* Special handling for __tostring method */ + lua_pushstring(L, "__tostring"); + const int tostring_result = SWIG_Lua_add_class_user_metamethod(L,clss); + if (tostring_result == 0) { + lua_pushcfunction(L, SWIG_Lua_class_tostring); + lua_rawset(L, metatable_index); + } else { + lua_pop(L,1); + } + + + /* Warning: __index and __newindex are SWIG-defined. For user-defined operator[] + * a __getitem/__setitem method should be defined + */ + lua_pop(L,1); + + assert(lua_gettop(L) == begin ); // TODO: REMOVE } /* Register class static methods,attributes etc as well as constructor proxy */ @@ -1303,7 +1531,7 @@ SWIGINTERN void SWIG_Lua_class_register_instance(lua_State *L,swig_lua_class *c SWIG_Lua_add_function(L,"__newindex",SWIG_Lua_class_set); SWIG_Lua_add_function(L,"__gc",SWIG_Lua_class_destruct); /* add tostring method for better output */ - SWIG_Lua_add_function(L,"__tostring",SWIG_Lua_class_tostring); + //SWIG_Lua_add_function(L,"__tostring",SWIG_Lua_class_tostring); // TODO: REMEVO after ensuring that add_class_user_metamethods works correctly /* add it */ lua_rawset(L,-3); /* metatable into registry */ lua_pop(L,1); /* tidy stack (remove registry) */ From c7e2f92a2254d8e101d79a8b063ada254f759aba Mon Sep 17 00:00:00 2001 From: Artem Serebriyskiy Date: Tue, 22 Apr 2014 12:46:26 +0400 Subject: [PATCH 2/4] Updating documentation --- Doc/Manual/Lua.html | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/Doc/Manual/Lua.html b/Doc/Manual/Lua.html index e6cf11b9f..fce7b8f07 100644 --- a/Doc/Manual/Lua.html +++ b/Doc/Manual/Lua.html @@ -990,7 +990,7 @@ The current list of operators which can be overloaded (and the alternative funct
  • __sub__ operator-
  • __mul__ operator *
  • __div__ operator/ -
  • __neg__ unary minus +
  • __unm__ unary minus
  • __call__ operator() (often used in functor classes)
  • __pow__ the exponential fn (no C++ equivalent, Lua uses ^)
  • __concat__ the concatenation operator (SWIG maps C++'s ~ to Lua's ..) @@ -1037,7 +1037,29 @@ It is also possible to overload the operator[], but currently this cann void __setitem__(int i,double d); // i is the index, d is the data }; - +

    +C++ operators are mapped to Lua predefined metafunctions. Class inherits from its bases the following list of metafunctions ( thus inheriting the folloging +operators and pseudo-operators):

    +
      +
    • __add__ +
    • __sub__ +
    • __mul__ +
    • __div__ +
    • __unm__ +
    • __mod__ +
    • __call__ +
    • __pow__ +
    • __concat__ +
    • __eq__ +
    • __lt__ +
    • __le__ +
    • __len__ +
    • __getitem__ +
    • __setitem__ +
    • __tostring used internaly by Lua for tostring() function. __str__ is mapped to this function +
    +

    No other lua metafunction is inherited. For example, __gc is not inherited and must be redefined in every class. __tostring is subject to a special handling. If absent in class and in class bases, a default one will be provided by SWIG

    +

    27.3.12 Class extension with %extend

    From d120c05fccd75c1393bed0a295c092cc2f8128e4 Mon Sep 17 00:00:00 2001 From: Artem Serebriyskiy Date: Tue, 22 Apr 2014 14:31:41 +0400 Subject: [PATCH 3/4] Optimize metamethods inheritance resolving * a table of metamethods that should be inherited is now stored in SWIG registry table. It optimizes memory usage. --- Lib/lua/luarun.swg | 135 ++++++++++++++++++++++++++++++++------------- 1 file changed, 97 insertions(+), 38 deletions(-) diff --git a/Lib/lua/luarun.swg b/Lib/lua/luarun.swg index b9e2d409a..398c2c8c7 100644 --- a/Lib/lua/luarun.swg +++ b/Lib/lua/luarun.swg @@ -332,6 +332,11 @@ typedef struct { lua_pushcfunction(L, f), \ lua_rawset(L,-3)) +#define SWIG_Lua_add_boolean(L,n,b) \ + (lua_pushstring(L, n), \ + lua_pushboolean(L, b), \ + lua_rawset(L,-3)) + /* special helper for allowing 'nil' for usertypes */ #define SWIG_isptrtype(L,I) (lua_isuserdata(L,I) || lua_isnil(L,I)) @@ -1016,7 +1021,52 @@ SWIGINTERN int SWIG_Lua_class_disown(lua_State *L) return 0; } -/* gets the swig class registry (or creates it) */ +/* populate table at the top of the stack with metamethods that ought to be inherited */ +SWIGINTERN void SWIG_Lua_populate_inheritable_metamethods(lua_State *L) +{ + assert(lua_istable(L,-1)); // TODO: REMOVE + SWIG_Lua_add_boolean(L, "__add", 1); + SWIG_Lua_add_boolean(L, "__sub", 1); + SWIG_Lua_add_boolean(L, "__mul", 1); + SWIG_Lua_add_boolean(L, "__div", 1); + SWIG_Lua_add_boolean(L, "__mod", 1); + SWIG_Lua_add_boolean(L, "__pow", 1); + SWIG_Lua_add_boolean(L, "__unm", 1); + SWIG_Lua_add_boolean(L, "__len", 1 ); + SWIG_Lua_add_boolean(L, "__concat", 1 ); + SWIG_Lua_add_boolean(L, "__eq", 1); + SWIG_Lua_add_boolean(L, "__lt", 1); + SWIG_Lua_add_boolean(L, "__le", 1); + SWIG_Lua_add_boolean(L, "__call", 1); + SWIG_Lua_add_boolean(L, "__tostring", 1); + SWIG_Lua_add_boolean(L, "__gc", 0); +} + +/* creates the swig registry */ +SWIGINTERN void SWIG_Lua_create_class_registry(lua_State *L) +{ + /* create main SWIG registry table */ + lua_pushstring(L,"SWIG"); + lua_newtable(L); + /* populate it with some predefined data */ + + /* .library table. Placeholder */ + lua_pushstring(L,".library"); + lua_newtable(L); + { + /* list of metamethods that class inherits from its bases */ + lua_pushstring(L,"inheritable_metamethods"); + lua_newtable(L); + /* populate with list of metamethods */ + SWIG_Lua_populate_inheritable_metamethods(L); + lua_rawset(L,-3); + } + lua_rawset(L,-3); + + lua_rawset(L,LUA_REGISTRYINDEX); +} + +/* gets the swig registry (or creates it) */ SWIGINTERN void SWIG_Lua_get_class_registry(lua_State *L) { /* add this all into the swig registry: */ @@ -1025,13 +1075,26 @@ SWIGINTERN void SWIG_Lua_get_class_registry(lua_State *L) if (!lua_istable(L,-1)) /* not there */ { /* must be first time, so add it */ lua_pop(L,1); /* remove the result */ - lua_pushstring(L,"SWIG"); - lua_newtable(L); - lua_rawset(L,LUA_REGISTRYINDEX); + SWIG_Lua_create_class_registry(L); /* then get it */ lua_pushstring(L,"SWIG"); lua_rawget(L,LUA_REGISTRYINDEX); } + assert(!lua_isnil(L,-1)); // TODO: REMOVE +} + +SWIGINTERN void SWIG_Lua_get_inheritable_metamethods(lua_State *L) +{ + SWIG_Lua_get_class_registry(L); + lua_pushstring(L, ".library"); + lua_rawget(L,-2); + assert( !lua_isnil(L,-1) ); + lua_pushstring(L, "inheritable_metamethods"); + lua_rawget(L,-2); + + /* Remove class registry and library table */ + lua_remove(L,-2); + lua_remove(L,-2); } /* Helper function to get the classes metatable from the register */ @@ -1323,20 +1386,18 @@ SWIGRUNTIME int SWIG_Lua_resolve_metamethod(lua_State *L) * Returns 1 if successfully added, 0 if not added because no base class has it, -1 * if method is defined in the class metatable itself */ -SWIGINTERN int SWIG_Lua_add_class_user_metamethod(lua_State *L, swig_lua_class *clss) +SWIGINTERN int SWIG_Lua_add_class_user_metamethod(lua_State *L, swig_lua_class *clss, const int metatable_index) { const int begin = lua_gettop(L); // TODO:REMOVE - /* Class metatable must be one below the top of the stack */ - assert(lua_istable(L,-2)); - /* and metamethod name - on the top of the stack */ + assert(lua_istable(L, metatable_index)); // TODO: REMOVE + /* metamethod name - on the top of the stack */ assert(lua_isstring(L,-1)); - const int metatable_index = lua_gettop(L) - 1; const int key_index = lua_gettop(L); /* Check whether method is already defined in metatable */ - lua_pushvalue(L,-1); /* copy of the key */ + lua_pushvalue(L,key_index); /* copy of the key */ lua_gettable(L,metatable_index); if( !lua_isnil(L,-1) ) { lua_pop(L,1); @@ -1355,6 +1416,7 @@ SWIGINTERN int SWIG_Lua_add_class_user_metamethod(lua_State *L, swig_lua_class * const swig_lua_class *base = clss->bases[i]; SWIG_Lua_get_class_metatable(L, base->fqname); lua_pushvalue(L, key_index); + assert(lua_istable(L,-2)); // TODO: REMOVE lua_rawget(L, -2); if( !lua_isnil(L,-1) ) { assert( lua_gettop(L) == begin + 2); // TODO: REMOVE @@ -1383,50 +1445,47 @@ SWIGINTERN int SWIG_Lua_add_class_user_metamethod(lua_State *L, swig_lua_class * return success; } -#define SWIG_ADD_CLASS_METAMETHOD( name ) \ - lua_pushstring(L,name);\ - SWIG_Lua_add_class_user_metamethod(L,clss);\ - lua_pop(L,1); - SWIGINTERN void SWIG_Lua_add_class_user_metamethods(lua_State *L, swig_lua_class *clss) { const int begin = lua_gettop(L); // TODO:REMOVE - /* TODO: This place desperately needs for optimization: - * 1. Hardcoded names of all metamethods is bad idea - * 2. We create a N lua strings for every class instead of creating those N strings - * only once - */ SWIG_Lua_get_class_metatable(L, clss->fqname); const int metatable_index = lua_gettop(L); - SWIG_ADD_CLASS_METAMETHOD( "__add" ); - SWIG_ADD_CLASS_METAMETHOD( "__sub" ); - SWIG_ADD_CLASS_METAMETHOD( "__mul" ); - SWIG_ADD_CLASS_METAMETHOD( "__div" ); - SWIG_ADD_CLASS_METAMETHOD( "__mod" ); - SWIG_ADD_CLASS_METAMETHOD( "__pow" ); - SWIG_ADD_CLASS_METAMETHOD( "__unm" ); - SWIG_ADD_CLASS_METAMETHOD( "__concat" ); - SWIG_ADD_CLASS_METAMETHOD( "__len" ); - SWIG_ADD_CLASS_METAMETHOD( "__eq" ); - SWIG_ADD_CLASS_METAMETHOD( "__lt" ); - SWIG_ADD_CLASS_METAMETHOD( "__le" ); - SWIG_ADD_CLASS_METAMETHOD( "__call" ); + SWIG_Lua_get_inheritable_metamethods(L); + assert(lua_istable(L,-1)); + const int metamethods_info_index = lua_gettop(L); + lua_pushnil(L); /* first key */ + while(lua_next(L, metamethods_info_index) != 0 ) { + /* key at index -2, value at index -1 */ + const int is_inheritable = lua_toboolean(L,-2); + lua_pop(L,1); /* remove value - we don't need it anymore */ + + if(is_inheritable) { /* if metamethod is inheritable */ + SWIG_Lua_add_class_user_metamethod(L,clss,metatable_index); + } + + assert(lua_gettop(L) == metamethods_info_index + 1 ); // TODO: REMOVE + } + + lua_pop(L,1); /* remove inheritable metatmethods table */ /* Special handling for __tostring method */ lua_pushstring(L, "__tostring"); - const int tostring_result = SWIG_Lua_add_class_user_metamethod(L,clss); - if (tostring_result == 0) { + lua_pushvalue(L,-1); + assert(lua_istable(L,metatable_index)); // TODO: REMOVE + lua_rawget(L,metatable_index); + const int tostring_undefined = lua_isnil(L,-1); + lua_pop(L,1); + if( tostring_undefined ) { lua_pushcfunction(L, SWIG_Lua_class_tostring); lua_rawset(L, metatable_index); } else { - lua_pop(L,1); + lua_pop(L,1); /* remove copy of the key */ } - /* Warning: __index and __newindex are SWIG-defined. For user-defined operator[] * a __getitem/__setitem method should be defined */ - lua_pop(L,1); + lua_pop(L,1); /* pop class metatable */ assert(lua_gettop(L) == begin ); // TODO: REMOVE } From 5506c7f624c2685c376e3f450be1f79c1e933031 Mon Sep 17 00:00:00 2001 From: Artem Serebriyskiy Date: Wed, 23 Apr 2014 01:37:14 +0400 Subject: [PATCH 4/4] Removed all unnecessary asserts --- Lib/lua/luarun.swg | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/Lib/lua/luarun.swg b/Lib/lua/luarun.swg index 398c2c8c7..691209f9c 100644 --- a/Lib/lua/luarun.swg +++ b/Lib/lua/luarun.swg @@ -1024,7 +1024,6 @@ SWIGINTERN int SWIG_Lua_class_disown(lua_State *L) /* populate table at the top of the stack with metamethods that ought to be inherited */ SWIGINTERN void SWIG_Lua_populate_inheritable_metamethods(lua_State *L) { - assert(lua_istable(L,-1)); // TODO: REMOVE SWIG_Lua_add_boolean(L, "__add", 1); SWIG_Lua_add_boolean(L, "__sub", 1); SWIG_Lua_add_boolean(L, "__mul", 1); @@ -1080,7 +1079,6 @@ SWIGINTERN void SWIG_Lua_get_class_registry(lua_State *L) lua_pushstring(L,"SWIG"); lua_rawget(L,LUA_REGISTRYINDEX); } - assert(!lua_isnil(L,-1)); // TODO: REMOVE } SWIGINTERN void SWIG_Lua_get_inheritable_metamethods(lua_State *L) @@ -1303,13 +1301,10 @@ SWIGRUNTIME int SWIG_Lua_resolve_metamethod(lua_State *L); /*forward declaration SWIGINTERN int SWIG_Lua_do_resolve_metamethod(lua_State *L, const swig_lua_class *clss, int metamethod_name_idx, int skip_check) { - const int beginIdx = lua_gettop(L); // TODO: REMOVE /* This function is called recursively */ if (!skip_check) { SWIG_Lua_get_class_metatable(L, clss->fqname); lua_pushvalue(L, metamethod_name_idx); - assert(!lua_isnil(L,-1)); // TODO: REMOVE - assert(lua_type(L,-1) == LUA_TSTRING); // TODO: REMOVE lua_rawget(L,-2); /* If this is cfunction and it is equal to SWIG_Lua_resolve_metamethod then * this isn't the function we are looking for :) @@ -1317,7 +1312,6 @@ SWIGINTERN int SWIG_Lua_do_resolve_metamethod(lua_State *L, const swig_lua_class */ if (!lua_isnil(L,-1) && lua_tocfunction(L,-1) != SWIG_Lua_resolve_metamethod ) { lua_remove(L,-2); /* removing class metatable */ - assert(lua_gettop(L) == beginIdx + 1); // TODO: REMOVE return 1; } lua_pop(L,2); /* remove class metatable and query result */ @@ -1333,12 +1327,6 @@ SWIGINTERN int SWIG_Lua_do_resolve_metamethod(lua_State *L, const swig_lua_class break; } - /* TODO: REMOVE */ - if (result) - assert(lua_gettop(L) == beginIdx + 1); - else - assert(lua_gettop(L) == beginIdx ); - /* END OF REMOVE */ return result; } @@ -1351,19 +1339,12 @@ SWIGRUNTIME int SWIG_Lua_resolve_metamethod(lua_State *L) /* Get upvalues from closure */ lua_pushvalue(L, lua_upvalueindex(1)); /*Get function name*/ - assert( !lua_isnil(L,-1) ); // TODO: REMOVE - assert( lua_type(L,-1) == LUA_TSTRING ); // TODO: REMOVE const int metamethod_name_idx = lua_gettop(L); - assert(metamethod_name_idx == numargs + 1); // TODO: REMOVE lua_pushvalue(L, lua_upvalueindex(2)); - assert( !lua_isnil(L,-1) ); // TODO: REMOVE - assert( lua_islightuserdata(L,-1) ); // TODO: REMOVE const swig_lua_class* clss = (const swig_lua_class*)(lua_touserdata(L,-1)); lua_pop(L,1); /* remove lightuserdata with clss from stack */ - const int precall_idx = lua_gettop(L); // TODO: REMOVE - assert( precall_idx == metamethod_name_idx ); // TODO: REMOVE /* Actuall work */ const int result = SWIG_Lua_do_resolve_metamethod(L, clss, metamethod_name_idx, 1); if (!result) { @@ -1372,10 +1353,7 @@ SWIGRUNTIME int SWIG_Lua_resolve_metamethod(lua_State *L) return 0; } - assert( lua_gettop(L) == precall_idx + 1 ); // TODO: REMOVE lua_remove(L,-2); /* remove metamethod key */ - assert(lua_iscfunction(L,-1)); // TODO: REMOVE - assert(lua_gettop(L) == numargs + 1); // TODO: REMOVE lua_insert(L,1); /* move function to correct position */ lua_call(L, numargs, LUA_MULTRET); return lua_gettop(L); /* return all results */ @@ -1388,9 +1366,7 @@ SWIGRUNTIME int SWIG_Lua_resolve_metamethod(lua_State *L) */ SWIGINTERN int SWIG_Lua_add_class_user_metamethod(lua_State *L, swig_lua_class *clss, const int metatable_index) { - const int begin = lua_gettop(L); // TODO:REMOVE - assert(lua_istable(L, metatable_index)); // TODO: REMOVE /* metamethod name - on the top of the stack */ assert(lua_isstring(L,-1)); @@ -1401,12 +1377,10 @@ SWIGINTERN int SWIG_Lua_add_class_user_metamethod(lua_State *L, swig_lua_class * lua_gettable(L,metatable_index); if( !lua_isnil(L,-1) ) { lua_pop(L,1); - assert( lua_gettop(L) == begin ); // TODO: REMOVE return -1; } lua_pop(L,1); - assert( lua_gettop(L) == begin ); // TODO: REMOVE /* Iterating over immediate bases */ int success = 0; @@ -1416,11 +1390,8 @@ SWIGINTERN int SWIG_Lua_add_class_user_metamethod(lua_State *L, swig_lua_class * const swig_lua_class *base = clss->bases[i]; SWIG_Lua_get_class_metatable(L, base->fqname); lua_pushvalue(L, key_index); - assert(lua_istable(L,-2)); // TODO: REMOVE lua_rawget(L, -2); if( !lua_isnil(L,-1) ) { - assert( lua_gettop(L) == begin + 2); // TODO: REMOVE - lua_pushvalue(L, key_index); /* Add proxy function */ @@ -1429,25 +1400,21 @@ SWIGINTERN int SWIG_Lua_add_class_user_metamethod(lua_State *L, swig_lua_class * lua_pushcclosure(L, SWIG_Lua_resolve_metamethod, 2); lua_rawset(L, metatable_index); - assert( lua_gettop(L) == begin + 2 ); // TODO: REMOVE success = 1; } lua_pop(L,1); /* remove function or nil */ lua_pop(L,1); /* remove base class metatable */ - assert( lua_gettop(L) == begin ); // TODO: REMOVE if( success ) break; } - assert( lua_gettop(L) == begin ); // TODO: REMOVE return success; } SWIGINTERN void SWIG_Lua_add_class_user_metamethods(lua_State *L, swig_lua_class *clss) { - const int begin = lua_gettop(L); // TODO:REMOVE SWIG_Lua_get_class_metatable(L, clss->fqname); const int metatable_index = lua_gettop(L); SWIG_Lua_get_inheritable_metamethods(L); @@ -1463,7 +1430,6 @@ SWIGINTERN void SWIG_Lua_add_class_user_metamethods(lua_State *L, swig_lua_class SWIG_Lua_add_class_user_metamethod(L,clss,metatable_index); } - assert(lua_gettop(L) == metamethods_info_index + 1 ); // TODO: REMOVE } lua_pop(L,1); /* remove inheritable metatmethods table */ @@ -1471,7 +1437,6 @@ SWIGINTERN void SWIG_Lua_add_class_user_metamethods(lua_State *L, swig_lua_class /* Special handling for __tostring method */ lua_pushstring(L, "__tostring"); lua_pushvalue(L,-1); - assert(lua_istable(L,metatable_index)); // TODO: REMOVE lua_rawget(L,metatable_index); const int tostring_undefined = lua_isnil(L,-1); lua_pop(L,1); @@ -1487,7 +1452,6 @@ SWIGINTERN void SWIG_Lua_add_class_user_metamethods(lua_State *L, swig_lua_class */ lua_pop(L,1); /* pop class metatable */ - assert(lua_gettop(L) == begin ); // TODO: REMOVE } /* Register class static methods,attributes etc as well as constructor proxy */ @@ -1589,8 +1553,6 @@ SWIGINTERN void SWIG_Lua_class_register_instance(lua_State *L,swig_lua_class *c SWIG_Lua_add_function(L,"__index",SWIG_Lua_class_get); SWIG_Lua_add_function(L,"__newindex",SWIG_Lua_class_set); SWIG_Lua_add_function(L,"__gc",SWIG_Lua_class_destruct); - /* add tostring method for better output */ - //SWIG_Lua_add_function(L,"__tostring",SWIG_Lua_class_tostring); // TODO: REMEVO after ensuring that add_class_user_metamethods works correctly /* add it */ lua_rawset(L,-3); /* metatable into registry */ lua_pop(L,1); /* tidy stack (remove registry) */