diff --git a/CHANGES.current b/CHANGES.current index 77d2df753..b2f007a92 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -5,6 +5,13 @@ See the RELEASENOTES file for a summary of changes in each release. Version 2.0.11 (in progress) ============================ +2013-09-12: wsfulton + [Lua] Pull Git patch #62. + 1) Static members and static functions inside class can be accessed as + ModuleName.ClassName.FunctionName (MemberName respectively). Old way such as + ModuleName.ClassName_FunctionName still works. + 2) Same goes for enums inside classes: ModuleName.ClassName.EnumValue1 etc. + 2013-09-12: wsfulton [UTL] Infinity is now by default an acceptable value for type 'float'. This fix makes the handling of type 'float' and 'double' the same. The implementation requires the diff --git a/Examples/test-suite/lua/cpp_basic_runme.lua b/Examples/test-suite/lua/cpp_basic_runme.lua index 02f88479b..3d5ccaadf 100644 --- a/Examples/test-suite/lua/cpp_basic_runme.lua +++ b/Examples/test-suite/lua/cpp_basic_runme.lua @@ -42,16 +42,22 @@ assert(f3.num==32) f4=cb.Foo(6) cb.Bar_global_fptr=f4 assert(cb.Bar_global_fptr.num==6) +assert(cb.Bar.global_fptr.num==6) f4.num=8 assert(cb.Bar_global_fptr.num==8) +assert(cb.Bar.global_fptr.num==8) assert(cb.Bar_global_fref.num==23) +assert(cb.Bar.global_fref.num==23) cb.Bar_global_fref=cb.Foo(-7) -- this will set the value assert(cb.Bar_global_fref.num==-7) +assert(cb.Bar.global_fref.num==-7) assert(cb.Bar_global_fval.num==3) +assert(cb.Bar.global_fval.num==3) cb.Bar_global_fval=cb.Foo(-34) assert(cb.Bar_global_fval.num==-34) +assert(cb.Bar.global_fval.num==-34) -- Now test member function pointers func1_ptr=cb.get_func1_ptr() diff --git a/Lib/lua/luarun.swg b/Lib/lua/luarun.swg index c705e38e5..4d851bdb1 100644 --- a/Lib/lua/luarun.swg +++ b/Lib/lua/luarun.swg @@ -140,6 +140,15 @@ typedef struct { lua_CFunction setmethod; } swig_lua_attribute; +// Can be used to create namespaces. Currently used to +// wrap class static methods/variables/constants +typedef struct { + const char *name; + swig_lua_method *ns_methods; + swig_lua_attribute *ns_attributes; + swig_lua_const_info *ns_constants; +} swig_lua_namespace; + typedef struct swig_lua_class { const char *name; swig_type_info **type; @@ -147,6 +156,7 @@ typedef struct swig_lua_class { void (*destructor)(void *); swig_lua_method *methods; swig_lua_attribute *attributes; + swig_lua_namespace cls_static; struct swig_lua_class **bases; const char **base_names; } swig_lua_class; @@ -415,6 +425,137 @@ SWIGINTERN void SWIG_Lua_module_add_function(lua_State* L,const char* name,lua_ SWIG_Lua_add_function(L,name,fn); } +/* ----------------------------------------------------------------------------- + * global variable support code: namespaces + * ----------------------------------------------------------------------------- */ + +SWIGINTERN int SWIG_Lua_namespace_get(lua_State* L) +{ +/* there should be 2 params passed in + (1) table (not the meta table) + (2) string name of the attribute +*/ + assert(lua_istable(L,-2)); /* just in case */ + lua_getmetatable(L,-2); + assert(lua_istable(L,-1)); + SWIG_Lua_get_table(L,".get"); /* find the .get table */ + assert(lua_istable(L,-1)); + /* look for the key in the .get table */ + lua_pushvalue(L,2); /* key */ + lua_rawget(L,-2); + lua_remove(L,-2); /* stack tidy, remove .get table */ + if (lua_iscfunction(L,-1)) + { /* found it so call the fn & return its value */ + lua_call(L,0,1); /* 1 value in (userdata),1 out (result) */ + lua_remove(L,-2); /* stack tidy, remove metatable */ + return 1; + } + lua_pop(L,1); /* remove whatever was there */ + /* ok, so try the .fn table */ + SWIG_Lua_get_table(L,".fn"); /* find the .get table */ + assert(lua_istable(L,-1)); /* just in case */ + lua_pushvalue(L,2); /* key */ + lua_rawget(L,-2); /* look for the fn */ + lua_remove(L,-2); /* stack tidy, remove .fn table */ + if (lua_isfunction(L,-1)) /* note: whether it's a C function or lua function */ + { /* found it so return the fn & let lua call it */ + lua_remove(L,-2); /* stack tidy, remove metatable */ + return 1; + } + lua_pop(L,1); /* remove whatever was there */ + return 0; +} + +SWIGINTERN int SWIG_Lua_namespace_set(lua_State* L) +{ +/* there should be 3 params passed in + (1) table (not the meta table) + (2) string name of the attribute + (3) any for the new value +*/ + + assert(lua_istable(L,1)); + lua_getmetatable(L,1); /* get the meta table */ + assert(lua_istable(L,-1)); + + SWIG_Lua_get_table(L,".set"); /* find the .set table */ + if (lua_istable(L,-1)) + { + /* look for the key in the .set table */ + lua_pushvalue(L,2); /* key */ + lua_rawget(L,-2); + if (lua_iscfunction(L,-1)) + { /* found it so call the fn & return its value */ + lua_pushvalue(L,3); /* value */ + lua_call(L,1,0); + return 0; + } + lua_pop(L,1); /* remove the value */ + } + lua_pop(L,1); /* remove the value .set table */ + return 0; +} + +SWIGINTERN void SWIG_Lua_InstallConstants(lua_State* L, swig_lua_const_info constants[]); // forward declaration +SWIGINTERN void SWIG_Lua_add_class_variable(lua_State* L,const char* name,lua_CFunction getFn,lua_CFunction setFn); // forward declaration + +/* helper function - register namespace methods and attributes into namespace */ +SWIGINTERN int SWIG_Lua_add_namespace_details(lua_State* L, swig_lua_namespace* ns) +{ + int i = 0; + assert(lua_istable(L,-1)); + /* There must be table at the top of the stack */ + SWIG_Lua_InstallConstants(L, ns->ns_constants); + + lua_getmetatable(L,-1); + + /* add fns */ + for(i=0;ns->ns_attributes[i].name;i++){ + SWIG_Lua_add_class_variable(L,ns->ns_attributes[i].name,ns->ns_attributes[i].getmethod,ns->ns_attributes[i].setmethod); + } + + /* add methods to the metatable */ + SWIG_Lua_get_table(L,".fn"); /* find the .fn table */ + assert(lua_istable(L,-1)); /* just in case */ + for(i=0;ns->ns_methods[i].name;i++){ + SWIG_Lua_add_function(L,ns->ns_methods[i].name,ns->ns_methods[i].method); + } + lua_pop(L,1); + + /* clear stack - remove metatble */ + lua_pop(L,1); + +} + +/* helper function. creates namespace table and add it to module table */ +SWIGINTERN int SWIG_Lua_namespace_register(lua_State* L, swig_lua_namespace* ns) +{ + assert(lua_istable(L,-1)); /* just in case. This is supposed to be module table */ + lua_checkstack(L,5); + lua_pushstring(L, ns->name); + lua_newtable(L); /* namespace itself */ + lua_newtable(L); /* metatable for namespace */ + + /* add a table called ".get" */ + lua_pushstring(L,".get"); + lua_newtable(L); + lua_rawset(L,-3); + /* add a table called ".set" */ + lua_pushstring(L,".set"); + lua_newtable(L); + lua_rawset(L,-3); + /* add a table called ".fn" */ + lua_pushstring(L,".fn"); + lua_newtable(L); + lua_rawset(L,-3); + + /* add accessor fns for using the .get,.set&.fn */ + SWIG_Lua_add_function(L,"__index",SWIG_Lua_namespace_get); + SWIG_Lua_add_function(L,"__newindex",SWIG_Lua_namespace_set); + + lua_setmetatable(L,-2); /* set metatable */ + lua_rawset(L,-3); /* add namespace to module table */ +} /* ----------------------------------------------------------------------------- * global variable support code: classes * ----------------------------------------------------------------------------- */ @@ -570,6 +711,23 @@ SWIGINTERN int SWIG_Lua_class_disown(lua_State* L) return 0; } +/* Constructor proxy. Used when class name entry in module is not class constructor, +but special table instead. */ +SWIGINTERN int SWIG_Lua_constructor_proxy(lua_State* L) +{ + /* unlimited number of parameters + First one is our proxy table and we should remove it + Other we should pass to real constructor + */ + assert(lua_istable(L,1)); + lua_pushstring(L,".constructor"); + lua_rawget(L,1); + assert(!lua_isnil(L,-1)); + lua_replace(L,1); /* replace our table with real constructor */ + lua_call(L,lua_gettop(L)-1,1); + return 1; +} + /* gets the swig class registry (or creates it) */ SWIGINTERN void SWIG_Lua_get_class_registry(lua_State* L) { @@ -614,6 +772,21 @@ SWIGINTERN void SWIG_Lua_add_class_variable(lua_State* L,const char* name,lua_C } } +/* helper to recursively add class static details (static attributes, operations and constants) */ +SWIGINTERN void SWIG_Lua_add_class_static_details(lua_State* L, swig_lua_class* clss) +{ + int i = 0; + /* The class namespace table must be on the top of the stack */ + assert(lua_istable(L,-1)); + /* call all the base classes first: we can then override these later: */ + for(i=0;clss->bases[i];i++) + { + SWIG_Lua_add_class_static_details(L,clss->bases[i]); + } + + SWIG_Lua_add_namespace_details(L, &clss->cls_static); +} + /* helper to recursively add class details (attributes & operations) */ SWIGINTERN void SWIG_Lua_add_class_details(lua_State* L,swig_lua_class* clss) { @@ -667,15 +840,42 @@ SWIGINTERN void SWIG_Lua_init_base_class(lua_State* L,swig_lua_class* clss) } } -/* performs the entire class registration process */ -SWIGINTERN void SWIG_Lua_class_register(lua_State* L,swig_lua_class* clss) +/* Register class static methods,attributes etc as well as constructor proxy */ +SWIGINTERN void SWIG_Lua_class_register_static(lua_State* L, swig_lua_class* clss) { + lua_checkstack(L,5); /* just in case */ + assert(lua_istable(L,-1)); /* just in case */ + assert(strcmp(clss->name, clss->cls_static.name) == 0); /* in class those 2 must be equal */ + + SWIG_Lua_namespace_register(L,&clss->cls_static); + + SWIG_Lua_get_table(L,clss->name); // Get namespace table back + assert(lua_istable(L,-1)); /* just in case */ + /* add its constructor to module with the name of the class so you can do MyClass(...) as well as new_MyClass(...) BUT only if a constructor is defined (this overcomes the problem of pure virtual classes without constructors)*/ if (clss->constructor) - SWIG_Lua_add_function(L,clss->name,clss->constructor); + { + SWIG_Lua_add_function(L,".constructor", clss->constructor); + lua_getmetatable(L,-1); + assert(lua_istable(L,-1)); /* just in case */ + SWIG_Lua_add_function(L,"__call", SWIG_Lua_constructor_proxy); + lua_pop(L,1); + } + + assert(lua_istable(L,-1)); /* just in case */ + SWIG_Lua_add_class_static_details(L, clss); + + /* clear stack */ + lua_pop(L,1); +} + +/* performs the entire class registration process */ +SWIGINTERN void SWIG_Lua_class_register(lua_State* L,swig_lua_class* clss) +{ + SWIG_Lua_class_register_static(L,clss); SWIG_Lua_get_class_registry(L); /* get the registry */ lua_pushstring(L,clss->name); /* get the name */ diff --git a/Source/Modules/lua.cxx b/Source/Modules/lua.cxx index cff3107db..b76945b95 100644 --- a/Source/Modules/lua.cxx +++ b/Source/Modules/lua.cxx @@ -45,6 +45,7 @@ */ #include "swigmod.h" +#include "cparse.h" /**** Diagnostics: With the #define REPORT(), you can change the amount of diagnostics given @@ -111,6 +112,9 @@ private: String *s_const_tab; // table of global constants String *s_methods_tab; // table of class methods String *s_attr_tab; // table of class attributes + String *s_cls_attr_tab; // table of class static attributes + String *s_cls_methods_tab; // table of class static methods + String *s_cls_const_tab; // tables of class constants(including enums) String *s_luacode; // luacode to be called during init String *s_dot_get; // table of variable 'get' functions String *s_dot_set; // table of variable 'set' functions @@ -154,6 +158,9 @@ public: s_const_tab(0), s_methods_tab(0), s_attr_tab(0), + s_cls_attr_tab(0), + s_cls_methods_tab(0), + s_cls_const_tab(0), s_luacode(0), s_dot_get(0), s_dot_set(0), @@ -736,13 +743,18 @@ public: NEW LANGUAGE NOTE:END ************************************************/ /* Now register the function with the interpreter. */ if (!Getattr(n, "sym:overloaded")) { + //REPORT("dispatchFunction", n); // add_method(n, iname, wname, description); if (current==NO_CPP || current==STATIC_FUNC) { // emit normal fns & static fns + String *wrapname = Swig_name_wrapper(iname); if(elua_ltr || eluac_ltr) Printv(s_cmd_tab, tab4, "{LSTRKEY(\"", iname, "\")", ", LFUNCVAL(", Swig_name_wrapper(iname), ")", "},\n", NIL); else Printv(s_cmd_tab, tab4, "{ \"", iname, "\", ", Swig_name_wrapper(iname), "},\n", NIL); // Printv(s_cmd_tab, tab4, "{ SWIG_prefix \"", iname, "\", (swig_wrapper_func) ", Swig_name_wrapper(iname), "},\n", NIL); + if (getCurrentClass()) { + Setattr(n,"luaclassobj:wrap:name", wrapname); + } } } else { if (!Getattr(n, "sym:nextSibling")) { @@ -775,6 +787,7 @@ public: look for %typecheck(SWIG_TYPECHECK_*) in the .swg file NEW LANGUAGE NOTE:END ************************************************/ void dispatchFunction(Node *n) { + //REPORT("dispatchFunction", n); /* Last node in overloaded chain */ int maxargs; @@ -822,10 +835,14 @@ public: if (current==NO_CPP || current==STATIC_FUNC) // emit normal fns & static fns Printv(s_cmd_tab, tab4, "{ \"", symname, "\",", wname, "},\n", NIL); + if (getCurrentClass()) + Setattr(n,"luaclassobj:wrap:name", wname); + else + Delete(wname); + DelWrapper(f); Delete(dispatch); Delete(tmp); - Delete(wname); } @@ -878,8 +895,13 @@ public: } else { Printf(s_var_tab, "%s{ \"%s\", %s, %s },\n", tab4, iname, getName, setName); } - Delete(getName); - Delete(setName); + if (getCurrentClass()) { + Setattr(n, "luaclassobj:wrap:get", getName); + Setattr(n, "luaclassobj:wrap:set", setName); + } else { + Delete(getName); + Delete(setName); + } return result; } @@ -887,7 +909,7 @@ public: * constantWrapper() * ------------------------------------------------------------ */ virtual int constantWrapper(Node *n) { - // REPORT("constantWrapper", n); + REPORT("constantWrapper", n); String *name = Getattr(n, "name"); String *iname = Getattr(n, "sym:name"); String *nsname = Copy(iname); @@ -923,6 +945,20 @@ public: Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); return SWIG_NOWRAP; } + if (cparse_cplusplus && getCurrentClass()) { + // Additionally add to class constants + Swig_require("luaclassobj_constantWrapper", n, "*sym:name", "luaclassobj:symname", NIL); + Setattr(n, "sym:name", Getattr(n, "luaclassobj:symname")); + String *cls_nsname = Getattr(n, "sym:name"); + if ((tm = Swig_typemap_lookup("consttab", n, name, 0))) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", name); + Replaceall(tm, "$value", value); + Replaceall(tm, "$nsname", cls_nsname); + Printf(s_cls_const_tab, " %s,\n", tm); + } + Swig_restore(n); + } Delete(nsname); return SWIG_OK; } @@ -1009,6 +1045,19 @@ public: Printf(s_methods_tab, "static swig_lua_method swig_"); Printv(s_methods_tab, mangled_classname, "_methods[] = {\n", NIL); + s_cls_methods_tab = NewString(""); + Printf(s_cls_methods_tab, "static swig_lua_method swig_"); + Printv(s_cls_methods_tab, mangled_classname, "_cls_methods[] = {\n", NIL); + + s_cls_attr_tab = NewString(""); + Printf(s_cls_attr_tab, "static swig_lua_attribute swig_"); + Printv(s_cls_attr_tab, mangled_classname, "_cls_attributes[] = {\n", NIL); + + s_cls_const_tab = NewString(""); + Printf(s_cls_const_tab, "static swig_lua_const_info swig_"); + Printv(s_cls_const_tab, mangled_classname, "_cls_constants[] = {\n", NIL); + + // Generate normal wrappers Language::classHandler(n); @@ -1047,8 +1096,21 @@ public: Printf(s_attr_tab, " {0,0,0}\n};\n"); Printv(f_wrappers, s_attr_tab, NIL); + Printf(s_cls_attr_tab, " {0,0,0}\n};\n"); + Printv(f_wrappers, s_cls_attr_tab, NIL); + + Printf(s_cls_methods_tab, " {0,0}\n};\n"); + Printv(f_wrappers, s_cls_methods_tab, NIL); + + Printf(s_cls_const_tab, " {0,0,0,0,0,0}\n};\n"); + Printv(f_wrappers, s_cls_const_tab, NIL); + + Delete(s_methods_tab); Delete(s_attr_tab); + Delete(s_cls_methods_tab); + Delete(s_cls_attr_tab); + Delete(s_cls_const_tab); // Handle inheritance // note: with the idea of class hierarchies spread over multiple modules @@ -1122,7 +1184,10 @@ public: } else { Printf(f_wrappers, ",0"); } - Printf(f_wrappers, ", swig_%s_methods, swig_%s_attributes, swig_%s_bases, swig_%s_base_names };\n\n", mangled_classname, mangled_classname, mangled_classname, mangled_classname); + Printf(f_wrappers, ", swig_%s_methods, swig_%s_attributes, { \"%s\", swig_%s_cls_methods, swig_%s_cls_attributes, swig_%s_cls_constants }, swig_%s_bases, swig_%s_base_names };\n\n", + mangled_classname, mangled_classname, + class_name, mangled_classname, mangled_classname, mangled_classname, + mangled_classname, mangled_classname); // Printv(f_wrappers, ", swig_", mangled_classname, "_methods, swig_", mangled_classname, "_attributes, swig_", mangled_classname, "_bases };\n\n", NIL); // Printv(s_cmd_tab, tab4, "{ SWIG_prefix \"", class_name, "\", (swig_wrapper_func) SWIG_ObjectConstructor, &_wrap_class_", mangled_classname, "},\n", NIL); @@ -1232,8 +1297,30 @@ public: * ---------------------------------------------------------------------- */ virtual int staticmemberfunctionHandler(Node *n) { + REPORT("staticmemberfunctionHandler", n); current = STATIC_FUNC; - return Language::staticmemberfunctionHandler(n); + String *symname = Getattr(n, "sym:name"); + int result = Language::staticmemberfunctionHandler(n); + + if (cparse_cplusplus && getCurrentClass()) { + Swig_restore(n); + } + current = NO_CPP; + if (result != SWIG_OK) + return result; + + if (Getattr(n, "sym:nextSibling")) + return SWIG_OK; + + Swig_require("luaclassobj_staticmemberfunctionHandler", n, "luaclassobj:wrap:name", NIL); + String *name = Getattr(n, "name"); + String *rname, *realname; + realname = symname ? symname : name; + rname = Getattr(n, "luaclassobj:wrap:name"); + Printv(s_cls_methods_tab, tab4, "{\"", realname, "\", ", rname, "}, \n", NIL); + Swig_restore(n); + + return SWIG_OK; } /* ------------------------------------------------------------ @@ -1243,8 +1330,17 @@ public: * ------------------------------------------------------------ */ virtual int memberconstantHandler(Node *n) { - // REPORT("memberconstantHandler",n); - return Language::memberconstantHandler(n); + REPORT("memberconstantHandler",n); + String *symname = Getattr(n, "sym:name"); + if (cparse_cplusplus && getCurrentClass()) { + Swig_save("luaclassobj_memberconstantHandler", n, "luaclassobj:symname", NIL); + Setattr(n, "luaclassobj:symname", symname); + } + int result = Language::memberconstantHandler(n); + if (cparse_cplusplus && getCurrentClass()) + Swig_restore(n); + + return result; } /* --------------------------------------------------------------------- @@ -1252,9 +1348,22 @@ public: * --------------------------------------------------------------------- */ virtual int staticmembervariableHandler(Node *n) { - // REPORT("staticmembervariableHandler",n); + REPORT("staticmembervariableHandler",n); current = STATIC_VAR; - return Language::staticmembervariableHandler(n); + String *symname = Getattr(n, "sym:name"); + int result = Language::staticmembervariableHandler(n); + + if (result != SWIG_OK) + return result; + + + if (Getattr(n, "wrappedasconstant")) + return SWIG_OK; + + Swig_require("luaclassobj_staticmembervariableHandler", n, "luaclassobj:wrap:get", "luaclassobj:wrap:set", NIL); + Printf(s_cls_attr_tab,"%s{ \"%s\", %s, %s},\n",tab4,symname,Getattr(n,"luaclassobj:wrap:get"), Getattr(n,"luaclassobj:wrap:set")); + Swig_restore(n); + return SWIG_OK; } /* ---------------------------------------------------------------------