diff --git a/SWIG/CHANGES.current b/SWIG/CHANGES.current index a0c2c24a2..a20072578 100644 --- a/SWIG/CHANGES.current +++ b/SWIG/CHANGES.current @@ -1,6 +1,11 @@ Version 1.3.30 (in progress) ============================ +10/24/2006: mgossage + [lua] added support for native methods & member function pointers. + fixed test cases arrays_dimensionless & cpp_basic. Added new example (functor). + tidied up a little of the code (around classHandler). + 10/17/2006: wsfulton [C#, Java] directorout typemap changes to fall in line with the other director languages. $result is now used where $1 used to be used. Please change your typemaps diff --git a/SWIG/Examples/lua/check.list b/SWIG/Examples/lua/check.list index 2055af1b9..72102d124 100644 --- a/SWIG/Examples/lua/check.list +++ b/SWIG/Examples/lua/check.list @@ -1,8 +1,9 @@ # see top-level Makefile.in class constants -functest funcptr3 +functest +functor pointer simple variables diff --git a/SWIG/Examples/lua/functor/.cvsignore b/SWIG/Examples/lua/functor/.cvsignore new file mode 100644 index 000000000..82d460ff8 --- /dev/null +++ b/SWIG/Examples/lua/functor/.cvsignore @@ -0,0 +1,5 @@ +*wrap* +*.so +*.dll +*.exp +*.lib diff --git a/SWIG/Examples/lua/functor/Makefile b/SWIG/Examples/lua/functor/Makefile new file mode 100644 index 000000000..432bfbef3 --- /dev/null +++ b/SWIG/Examples/lua/functor/Makefile @@ -0,0 +1,20 @@ +TOP = ../.. +SWIG = $(TOP)/../preinst-swig +CXXSRCS = +TARGET = example +INTERFACE = example.i +LIBS = -lm +SWIGOPT = + +all:: + $(MAKE) -f $(TOP)/Makefile CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \ + SWIGOPT='$(SWIGOPT)' TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' lua_cpp + +static:: + $(MAKE) -f $(TOP)/Makefile CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \ + TARGET='mylua' INTERFACE='$(INTERFACE)' lua_cpp_static + +clean:: + $(MAKE) -f $(TOP)/Makefile lua_clean + +check: all diff --git a/SWIG/Examples/lua/functor/example.i b/SWIG/Examples/lua/functor/example.i new file mode 100644 index 000000000..cc7a67990 --- /dev/null +++ b/SWIG/Examples/lua/functor/example.i @@ -0,0 +1,29 @@ +/* File : example.i */ +%module example + + +%inline %{ +// From B. Strousjoup, "The C++ Programming Language, Third Edition", p. 514 +template class Sum { + T res; +public: + Sum(T i = 0) : res(i) { } + void operator() (T x) { res += x; } + T result() const { return res; } +}; + +%} + +// Rename the application operator to __call. +// Note: this is normally automatic, but if you had to do it yourself +// you would use this directive: +// +// %rename(__call) *::operator(); // the fn call operator + +// Instantiate a few versions +%template(intSum) Sum; +%template(doubleSum) Sum; + + + + diff --git a/SWIG/Examples/lua/functor/runme.lua b/SWIG/Examples/lua/functor/runme.lua new file mode 100644 index 000000000..03d299e9f --- /dev/null +++ b/SWIG/Examples/lua/functor/runme.lua @@ -0,0 +1,24 @@ +-- Operator overloading example +---- importing ---- +if string.sub(_VERSION,1,7)=='Lua 5.0' then + -- lua5.0 doesnt have a nice way to do this + lib=loadlib('example.dll','Example_Init') or loadlib('example.so','Example_Init') + assert(lib)() +else + -- lua 5.1 does + require('example') +end + +a = example.intSum(0) +b = example.doubleSum(100.0) + +-- Use the objects. They should be callable just like a normal +-- lua function. + +for i=0,100 do + a(i) -- Note: function call + b(math.sqrt(i)) -- Note: function call +end +print(a:result()) -- should be 5050 +print(b:result()) -- should be ~771.46 + diff --git a/SWIG/Examples/test-suite/lua/cpp_basic_runme.lua b/SWIG/Examples/test-suite/lua/cpp_basic_runme.lua new file mode 100644 index 000000000..b63b89cdc --- /dev/null +++ b/SWIG/Examples/test-suite/lua/cpp_basic_runme.lua @@ -0,0 +1,64 @@ +require("import") -- the import fn +import("cpp_basic") -- import code +cb=cpp_basic -- renaming import + +-- catch "undefined" global variables +setmetatable(getfenv(),{__index=function (t,i) error("undefined global variable `"..i.."'",2) end}) + +f=cb.Foo(4) +assert(f.num==4) +f.num=-17 +assert(f.num==-17) + +b=cb.Bar() + +b.fptr=f +assert(b.fptr.num==-17) +assert(b:test(-3,b.fptr)==-5) +f.num=12 +assert(b.fptr.num==12) + +assert(b.fref.num==-4) +assert(b:test(12,b.fref)==23) + +-- references don't take ownership, so if we didn't define this here it might get garbage collected +f2=cb.Foo(23) +b.fref=f2 +assert(b.fref.num==23) +assert(b:test(-3,b.fref)==35) + +assert(b.fval.num==15) +assert(b:test(3,b.fval)==33) +b.fval=cb.Foo(-15) -- this is safe as it is copied into the C++ +assert(b.fval.num==-15) +assert(b:test(3,b.fval)==-27) + +f3=b:testFoo(12,b.fref) +assert(f3.num==32) + +-- now test global +f4=cb.Foo(6) +cb.Bar_global_fptr=f4 +assert(cb.Bar_global_fptr.num==6) +f4.num=8 +assert(cb.Bar_global_fptr.num==8) + +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_fval.num==3) +cb.Bar_global_fval=cb.Foo(-34) +assert(cb.Bar_global_fval.num==-34) + +-- Now test member function pointers +func1_ptr=cb.get_func1_ptr() +func2_ptr=cb.get_func2_ptr() +f.num=4 +assert(f:func1(2)==16) +assert(f:func2(2)==-8) + +f.func_ptr=func1_ptr +assert(cb.test_func_ptr(f,2)==16) +f.func_ptr=func2_ptr +assert(cb.test_func_ptr(f,2)==-8) diff --git a/SWIG/Lib/lua/lua.swg b/SWIG/Lib/lua/lua.swg index 424e7ddb8..53db5573a 100644 --- a/SWIG/Lib/lua/lua.swg +++ b/SWIG/Lib/lua/lua.swg @@ -54,7 +54,7 @@ /* ----------------------------------------------------------------------------- * Overloaded operator support * ----------------------------------------------------------------------------- */ -// lua likes to call the + operator '__add' +// lua calls the + operator '__add' // python likes to call it '__add__' // Assuming most SWIGers will probably use the __add__ if they extend their classes // we have two sets of renames @@ -73,13 +73,13 @@ %rename(__unm) *::operator-(); %rename(__unm) *::operator-() const; -%rename(__eq) *::operator==; // note: Lua does not have a not equal +%rename(__eq) *::operator==; +%ignore *::operator!=; // note: Lua does not have a notequal operator // it just uses 'not (a==b)' -%ignore *::operator!=; -%rename(__lt) *::operator<; // ditto less than vs greater than -%ignore *::operator>; -%rename(__le) *::operator<=; // ditto less than vs greater than -%ignore *::operator>=; +%rename(__lt) *::operator<; +%ignore *::operator>; // ditto less than vs greater than +%rename(__le) *::operator<=; +%ignore *::operator>=; // ditto less than vs greater than %rename(__call) *::operator(); // the fn call operator diff --git a/SWIG/Lib/lua/luarun.swg b/SWIG/Lib/lua/luarun.swg index e4acbc939..c08f3ea54 100644 --- a/SWIG/Lib/lua/luarun.swg +++ b/SWIG/Lib/lua/luarun.swg @@ -67,20 +67,32 @@ typedef struct swig_lua_class { struct swig_lua_class **bases; } swig_lua_class; +/* this is the struct for wrappering all pointers in SwigLua +*/ typedef struct { - void *ptr; swig_type_info *type; int own; /* 1 if owned & must be destroyed */ + void *ptr; } swig_lua_userdata; +/* this is the struct for wrappering arbitary packed binary data +(currently it is only used for member fn pointers) +the data ordering is similar to swig_lua_userdata, but its currently not possible +to tell the two structres apart within Swig, other than by looking at the type +*/ +typedef struct { + swig_type_info *type; + int own; /* 1 if owned & must be destroyed */ + char data[1]; /* arbitary amount of data */ +} swig_lua_rawdata; /* Common SWIG API */ -#define SWIG_NewPointerObj(L, ptr, type, owner) \ - SWIG_Lua_NewPointerObj(L, (void *)ptr, type, owner) -#define SWIG_ConvertPtr(L,idx, ptr, type, flags) \ - SWIG_Lua_ConvertPtr(L,idx,ptr,type,flags) -#define SWIG_MustGetPtr(L,idx, type,flags, argnum,fnname) \ - SWIG_Lua_MustGetPtr(L,idx, type,flags, argnum,fnname) +#define SWIG_NewPointerObj(L, ptr, type, owner) SWIG_Lua_NewPointerObj(L, (void *)ptr, type, owner) +#define SWIG_ConvertPtr(L,idx, ptr, type, flags) SWIG_Lua_ConvertPtr(L,idx,ptr,type,flags) +#define SWIG_MustGetPtr(L,idx, type,flags, argnum,fnname) SWIG_Lua_MustGetPtr(L,idx, type,flags, argnum,fnname) +/* for C++ member pointers, ie, member methods */ +#define SWIG_ConvertMember(L, idx, ptr, sz, ty) SWIG_Lua_ConvertPacked(L, idx, ptr, sz, ty) +#define SWIG_NewMemberObj(L, ptr, sz, type) SWIG_Lua_NewPackedObj(L, ptr, sz, type) /* Runtime API */ #define SWIG_GetModule(clientdata) SWIG_Lua_GetModule((lua_State*)(clientdata)) @@ -111,9 +123,9 @@ typedef struct { #define SWIG_isptrtype(L,I) (lua_isuserdata(L,I) || lua_isnil(L,I)) #ifdef __cplusplus -/* Special helper for member function pointers */ -#define SWIG_as_voidptr(a) const_cast< void * >(static_cast< const void * >(a)) -#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),reinterpret_cast< void** >(a)) +/* Special helper for member function pointers +it gets the address, casts it, then dereferences it */ +#define SWIG_mem_fn_as_voidptr(a) (*((char**)&(a))) #endif /* ----------------------------------------------------------------------------- @@ -482,18 +494,9 @@ SWIGINTERN void SWIG_Lua_class_register(lua_State* L,swig_lua_class* clss) * Class/structure conversion fns * ----------------------------------------------------------------------------- */ -/* pushes a new object into the lua stack */ -SWIGRUNTIME void SWIG_Lua_NewPointerObj(lua_State* L,void* ptr,swig_type_info *type, int own) +/* helper to add metatable to new lua object */ +SWIGINTERN void _SWIG_Lua_AddMetatable(lua_State* L,swig_type_info *type) { - swig_lua_userdata* usr; - if (!ptr){ - lua_pushnil(L); - return; - } - usr=(swig_lua_userdata*)lua_newuserdata(L,sizeof(swig_lua_userdata)); /* get data */ - usr->ptr=ptr; /* set the ptr */ - usr->type=type; - usr->own=own; if (type->clientdata) /* there is clientdata: so add the metatable */ { SWIG_Lua_get_class_metatable(L,((swig_lua_class*)(type->clientdata))->name); @@ -508,6 +511,21 @@ SWIGRUNTIME void SWIG_Lua_NewPointerObj(lua_State* L,void* ptr,swig_type_info *t } } +/* pushes a new object into the lua stack */ +SWIGRUNTIME void SWIG_Lua_NewPointerObj(lua_State* L,void* ptr,swig_type_info *type, int own) +{ + swig_lua_userdata* usr; + if (!ptr){ + lua_pushnil(L); + return; + } + usr=(swig_lua_userdata*)lua_newuserdata(L,sizeof(swig_lua_userdata)); /* get data */ + usr->ptr=ptr; /* set the ptr */ + usr->type=type; + usr->own=own; + _SWIG_Lua_AddMetatable(L,type); /* add metatable */ +} + /* takes a object from the lua stack & converts it into an object of the correct type (if possible) */ SWIGRUNTIME int SWIG_Lua_ConvertPtr(lua_State* L,int index,void** ptr,swig_type_info *type,int flags) @@ -544,6 +562,33 @@ SWIGRUNTIME void* SWIG_Lua_MustGetPtr(lua_State* L,int index,swig_type_info *typ return result; } +/* pushes a packed userdata. user for member fn pointers only */ +SWIGRUNTIME void SWIG_Lua_NewPackedObj(lua_State* L,void* ptr,size_t size,swig_type_info *type) +{ + swig_lua_rawdata* raw; + assert(ptr); /* not acceptable to pass in a NULL value */ + raw=(swig_lua_rawdata*)lua_newuserdata(L,sizeof(swig_lua_rawdata)-1+size); /* alloc data */ + raw->type=type; + raw->own=0; + memcpy(raw->data,ptr,size); /* copy the data */ + _SWIG_Lua_AddMetatable(L,type); /* add metatable */ +} + +/* converts a packed userdata. user for member fn pointers only */ +SWIGRUNTIME int SWIG_Lua_ConvertPacked(lua_State* L,int index,void* ptr,size_t size,swig_type_info *type) +{ + swig_lua_rawdata* raw; + swig_cast_info *cast; + raw=(swig_lua_rawdata*)lua_touserdata(L,index); /* get data */ + if (!raw) return SWIG_ERROR; /* error */ + if (type==0 || type==raw->type) /* void* or identical type */ + { + memcpy(ptr,raw->data,size); /* copy it */ + return SWIG_OK; /* ok */ + } + return SWIG_ERROR; /* error */ +} + /* lua callable function to get the userdata's type */ SWIGRUNTIME int SWIG_Lua_type(lua_State* L) { diff --git a/SWIG/Lib/lua/luatypemaps.swg b/SWIG/Lib/lua/luatypemaps.swg index fe314710c..acfdf9158 100644 --- a/SWIG/Lib/lua/luatypemaps.swg +++ b/SWIG/Lib/lua/luatypemaps.swg @@ -119,26 +119,15 @@ // passing objects by value // SWIG expects the object pointer (the $<ype argp) -// then dereferences it +// then dereferences it to get the object %typemap(in,checkfn="lua_isuserdata") SWIGTYPE ($<ype argp) %{ - if (!SWIG_IsOK(SWIG_ConvertPtr(L,$input,(void**)(&argp),$&descriptor,0))){ + if (!SWIG_IsOK(SWIG_ConvertPtr(L,$input,(void**)&argp,$&descriptor,0))){ SWIG_fail_ptr("$symname",$argnum,$descriptor); } $1 = *argp; %} -// member function pointer -// currently does not work as C++ doesn't like casting member fn pointer to void* -/*%typemap(in,checkfn="lua_isuserdata") SWIGTYPE (CLASS::*) -%{ - if (SWIG_ConvertPtr(L,$input,(void**)(&$1),$descriptor,0) == -1) - SWIG_fail_ptr("$symname",$argnum,$descriptor); -%} - -%typemap(out) SWIGTYPE (CLASS::*) -%{SWIG_NewPointerObj(L,SWIG_as_voidptr($1),$descriptor,$owner); SWIG_arg++; %}*/ - // Primitive types--return by value // must make a new object, copy the data & return the new object #ifdef __cplusplus @@ -173,6 +162,24 @@ %} #endif*/ +// member function pointer +// a member fn ptr is not 4 bytes like a normal pointer, but 8 bytes +// so the standard wrappering cannot be done +// nor can you cast a member function pointer to a void* (obviously) +#ifdef __cplusplus +%typemap(in,checkfn="lua_isuserdata") SWIGTYPE (CLASS::*) +%{ + if (!SWIG_IsOK(SWIG_ConvertMember(L,$input,(void*)(&$1),sizeof($type),$descriptor))) + SWIG_fail_ptr("$symname",$argnum,$descriptor); +%} + +%typemap(out) SWIGTYPE (CLASS::*) +%{ + SWIG_NewMemberObj(L,(void*)(&$1),sizeof($type),$descriptor); SWIG_arg++; +%} +#endif + + // void (must be empty without the SWIG_arg++) %typemap(out) void ""; diff --git a/SWIG/Source/Modules/lua.cxx b/SWIG/Source/Modules/lua.cxx index faa6cb60f..f6a8beb5a 100644 --- a/SWIG/Source/Modules/lua.cxx +++ b/SWIG/Source/Modules/lua.cxx @@ -315,6 +315,7 @@ NEW LANGUAGE NOTE:END ************************************************/ * --------------------------------------------------------------------- */ virtual int functionWrapper(Node *n) { +// REPORT("functionWrapper",n); String *name = Getattr(n,"name"); String *iname = Getattr(n,"sym:name"); @@ -680,36 +681,32 @@ NEW LANGUAGE NOTE:END ************************************************/ virtual int variableWrapper(Node *n) { /* NEW LANGUAGE NOTE:*********************************************** -FIXME -this is mainly guesswork Language::variableWrapper(n) will generate two wrapper fns Foo_get & Foo_set by calling functionWrapper() so we will just add these into the variable lists -ideally we should not have reghistered these as functions, -only WRT this variable -will look into this later +ideally we should not have registered these as functions, +only WRT this variable will look into this later. NEW LANGUAGE NOTE:END ************************************************/ -// String *name = Getattr(n,"name"); + REPORT("variableWrapper",n); String *iname = Getattr(n,"sym:name"); -// Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, -// "variableWrapper %s : %s : %s \n",iname,Swig_name_set(iname),Swig_name_get(iname)); + SwigType *type = Getattr(n,"type"); + // let SWIG generate the wrappers int result=Language::variableWrapper(n); - if (!GetFlag(n,"feature:immutable")) { - Printv(s_var_tab, tab4, "{ \"", iname, "\", ", Swig_name_wrapper(Swig_name_get(iname)), - ", ", Swig_name_wrapper(Swig_name_set(iname)),"},\n", NIL); - } - else { //imutable - Printv(s_var_tab, tab4, "{ \"", iname, "\", ", Swig_name_wrapper(Swig_name_get(iname)), - ", ","0","},\n", NIL); - } -// Printf(s_var_tab,"%s{ \"%s\", (swig_wrapper_func)%s, (swig_wrapper_func)%s },\n", -// tab4,iname,iname,iname); -// Printv(s_var_tab, tab4, "{ \"", iname, "\", (swig_wrapper_func) ", Swig_name_wrapper(iname), "},\n", NIL); - + // normally SWIG will generate 2 wrappers, a get and a set + // but in certain scenarios (immutable, or if its arrays), it will not + String *getName=Swig_name_wrapper(Swig_name_get(iname)); + String *setName=0; + if (is_assignable(n)==false || SwigType_isarray(type)) { + // TODO: how about calling a 'this is not settable' error message? + setName=NewString("0"); + } else { + setName=Swig_name_wrapper(Swig_name_set(iname)); + } + // register the variable + Printf(s_var_tab,"%s{ \"%s\", %s, %s },\n",tab4,iname,getName,setName); + Delete(getName); + Delete(setName); return result; - //return Language::variableWrapper(n); - - } /* ------------------------------------------------------------ @@ -763,14 +760,14 @@ virtual int constantWrapper(Node *n) { * ------------------------------------------------------------ */ virtual int nativeWrapper(Node *n) { - return Language::nativeWrapper(n); -/* String *name = Getattr(n,"sym:name"); + REPORT("nativeWrapper",n); + String *symname = Getattr(n,"sym:name"); String *wrapname = Getattr(n,"wrap:name"); - if (!addSymbol(wrapname,n)) return SWIG_ERROR; - add_method(n, name, wrapname,0); - return SWIG_OK;*/ + Printv(s_cmd_tab, tab4, "{ \"", symname, "\",", wrapname, "},\n", NIL); + // return Language::nativeWrapper(n); // this does nothing... + return SWIG_OK; } /* ------------------------------------------------------------ @@ -802,6 +799,7 @@ virtual int constantWrapper(Node *n) { * ------------------------------------------------------------ */ virtual int classHandler(Node *n) { + REPORT("classHandler",n); String *mangled_classname = 0; String *real_classname = 0; @@ -816,6 +814,12 @@ virtual int constantWrapper(Node *n) { real_classname = Getattr(n,"name"); mangled_classname = Swig_name_mangle(real_classname); +// note: tcl has a static hashtable of all classes emitted, I wonder why? +/* static Hash* emitted = NewHash(); + Printf(stdout,"classHandler %s\n",mangled_classname); + if (Getattr(emitted,mangled_classname)) return SWIG_NOWRAP; + Setattr(emitted,mangled_classname,"1"); */ + s_attr_tab = NewString(""); Printf(s_attr_tab, "static swig_lua_attribute swig_"); Printv(s_attr_tab, mangled_classname, "_attributes[] = {\n", NIL); @@ -825,13 +829,13 @@ virtual int constantWrapper(Node *n) { Printv(s_methods_tab, mangled_classname, "_methods[] = {\n", NIL); // Generate normal wrappers +//return SWIG_OK; Language::classHandler(n); - +//return SWIG_OK; SwigType *t = Copy(Getattr(n,"name")); SwigType_add_pointer(t); // Catch all: eg. a class with only static functions and/or variables will not have 'remembered' - SwigType_remember(t); String *wrap_class = NewStringf("&_wrap_class_%s", mangled_classname); SwigType_remember_clientdata(t,wrap_class); @@ -964,7 +968,7 @@ virtual int constantWrapper(Node *n) { * ------------------------------------------------------------ */ virtual int membervariableHandler(Node *n) { - REPORT("membervariableHandler",n); +// REPORT("membervariableHandler",n); String *symname = Getattr(n,"sym:name"); String *rname; @@ -1023,7 +1027,7 @@ virtual int constantWrapper(Node *n) { * ------------------------------------------------------------ */ virtual int memberconstantHandler(Node *n) { - REPORT("memberconstantHandler",n); +// REPORT("memberconstantHandler",n); return Language::memberconstantHandler(n); } @@ -1032,7 +1036,7 @@ virtual int constantWrapper(Node *n) { * --------------------------------------------------------------------- */ virtual int staticmembervariableHandler(Node *n) { - REPORT("staticmembervariableHandler",n); +// REPORT("staticmembervariableHandler",n); return Language::staticmembervariableHandler(n); }