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) */