added support for native methods & member function pointers.

fixed test cases arrays_dimensionless & cpp_basic. Added new example (functor).


git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@9472 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
Mark Gossage 2006-10-24 06:26:48 +00:00
commit fec2f8f9b7
11 changed files with 279 additions and 75 deletions

View file

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

View file

@ -1,8 +1,9 @@
# see top-level Makefile.in
class
constants
functest
funcptr3
functest
functor
pointer
simple
variables

View file

@ -0,0 +1,5 @@
*wrap*
*.so
*.dll
*.exp
*.lib

View file

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

View file

@ -0,0 +1,29 @@
/* File : example.i */
%module example
%inline %{
// From B. Strousjoup, "The C++ Programming Language, Third Edition", p. 514
template<class T> 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<int>;
%template(doubleSum) Sum<double>;

View file

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

View file

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

View file

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

View file

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

View file

@ -119,26 +119,15 @@
// passing objects by value
// SWIG expects the object pointer (the $&ltype argp)
// then dereferences it
// then dereferences it to get the object
%typemap(in,checkfn="lua_isuserdata") SWIGTYPE ($&ltype 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 "";

View file

@ -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);
}