summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArtem Serebriyskiy <v.for.vandal@gmail.com>2013-09-12 19:49:51 +0100
committerWilliam S Fulton <wsf@fultondesigns.co.uk>2013-09-12 21:32:26 +0100
commitc3f3880d0c55f55d9f83dd2d84be685b6b361cc7 (patch)
tree2a52691b4dbdd78ff053376dafaa47f06760705d
parenta91cd0bc5c1550bfa2c922c7434323c30ca1fb87 (diff)
downloadswig-c3f3880d0c55f55d9f83dd2d84be685b6b361cc7.tar.gz
Lua static member access improvements.
1) Static members and static functions inside class can be accessed as ModuleName.ClassName.FunctionName (MemberName respectively). Old way aka ModuleName.ClassName_FunctionName still works. 2) Same goes for enums inside classes: ModuleName.ClassName.EnumValue1 etc. 3) More 'runme' tests for lua + modifications to existing tests to test new changes. Code is loosely based upon python implemenation of the same thing. Patch #62.
-rw-r--r--CHANGES.current7
-rw-r--r--Examples/test-suite/lua/cpp_basic_runme.lua6
-rw-r--r--Lib/lua/luarun.swg206
-rw-r--r--Source/Modules/lua.cxx129
4 files changed, 335 insertions, 13 deletions
diff --git a/CHANGES.current b/CHANGES.current
index 77d2df753..b2f007a92 100644
--- a/CHANGES.current
+++ b/CHANGES.current
@@ -6,6 +6,13 @@ 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
C99 isfinite() macro, or otherwise some platform dependent equivalents, to be available.
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;
@@ -416,6 +426,137 @@ SWIGINTERN void SWIG_Lua_module_add_function(lua_State* L,const char* name,lua_
}
/* -----------------------------------------------------------------------------
+ * 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;
}
/* ---------------------------------------------------------------------