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.
This commit is contained in:
Artem Serebriyskiy 2013-09-12 19:49:51 +01:00 committed by William S Fulton
commit c3f3880d0c
4 changed files with 335 additions and 13 deletions

View file

@ -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

View file

@ -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()

View file

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

View file

@ -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;
}
/* ---------------------------------------------------------------------