added support for passing function pointers as well as native lua object

into wrappered function
added example funcptr3


git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@9264 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
Mark Gossage 2006-09-11 06:45:03 +00:00
commit db5bb83440
8 changed files with 312 additions and 0 deletions

View file

@ -2,6 +2,7 @@
class
constants
functest
funcptr3
pointer
simple
variables

View file

@ -0,0 +1,13 @@
example.py
example.pyc
*_wrap.c
*_wrap.cxx
*.dll
*.dsw
*.exp
*.lib
*.ncb
*.opt
*.plg
Release
Debug

View file

@ -0,0 +1,19 @@
TOP = ../..
SWIG = $(TOP)/../preinst-swig
CXXSRCS = example.c
TARGET = example
INTERFACE = example.i
LIBS =
all::
$(MAKE) -f $(TOP)/Makefile CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \
TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' lua
static::
$(MAKE) -f $(TOP)/Makefile CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \
TARGET='mylua' INTERFACE='$(INTERFACE)' lua_static
clean::
$(MAKE) -f $(TOP)/Makefile lua_clean
check: all

View file

@ -0,0 +1,19 @@
/* File : example.c */
int do_op(int a, int b, int (*op)(int,int)) {
return (*op)(a,b);
}
int add(int a, int b) {
return a+b;
}
int sub(int a, int b) {
return a-b;
}
int mul(int a, int b) {
return a*b;
}
int (*funcvar)(int,int) = add;

View file

@ -0,0 +1,9 @@
/* file: example.h */
extern int do_op(int,int, int (*op)(int,int));
extern int add(int,int);
extern int sub(int,int);
extern int mul(int,int);
extern int (*funcvar)(int,int);

View file

@ -0,0 +1,69 @@
/* File : example.i */
/*
This demonstrates how to pass a lua function, into some C code and then call it.
There are two examples, the first is as a parameter, the second as a global variable.
*/
%module example
%{
#include "example.h"
%}
/* the extra wrappers for lua functions, see SWIG/Lib/lua/lua_fnptr.i for more details */
%include "lua_fnptr.i"
/* these are a bunch of C functions which we want to be able to call from lua */
extern int add(int,int);
extern int sub(int,int);
extern int mul(int,int);
/* this function takes a lua function as a parameter and calls it.
As this is takes a lua fn it needs lua code
*/
%inline %{
int callback(int a, int b, SWIGLUA_FN fn)
{
SWIGLUA_FN_GET(fn);
lua_pushnumber(fn.L,a);
lua_pushnumber(fn.L,b);
lua_call(fn.L,2,1); /* 2 in, 1 out */
return luaL_checknumber(fn.L,-1);
}
%}
/******************
Second code uses a stored reference.
*******************/
%inline %{
/* note: this is not so good to just have it as a raw ref
people could set anything to this
a better solution would to be to have a fn which wants a SWIGLUA_FN, then
checks the type & converts to a SWIGLUA_REF.
*/
SWIGLUA_REF the_func={0,0};
void call_the_func(int a)
{
int i;
if (the_func.L==0){
printf("the_func is zero\n");
return;
}
swiglua_ref_get(&the_func);
if (!lua_isfunction(the_func.L,-1))
{
printf("the_func is not a function\n");
return;
}
lua_pop(the_func.L,1); /* tidy stack */
for(i=0;i<a;i++)
{
swiglua_ref_get(&the_func);
lua_pushnumber(the_func.L,i);
lua_call(the_func.L,1,0); /* 1 in, 0 out */
}
}
%}

View file

@ -0,0 +1,54 @@
---- 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 = 37
b = 42
-- Now call our C function
print("Trying some C functions")
print(" a =", a)
print(" b =", b)
print(" add(a,b) =", example.add(a,b))
print(" sub(a,b) =", example.sub(a,b))
print(" mul(a,b) =", example.mul(a,b))
print("Calling them using the my_func()")
print(" add(a,b) =", example.callback(a,b,example.add))
print(" sub(a,b) =", example.callback(a,b,example.sub))
print(" mul(a,b) =", example.callback(a,b,example.mul))
print("Now let us write our own function")
function foo(a,b) return 101 end
print(" foo(a,b) =", example.callback(a,b,foo))
print("Now let us try something that will fail")
local ok,c=pcall(example.callback,a,b,print)
if ok==false then
print("this failed as expected, error:",c)
else
print("oops, that worked! result:",c)
end
-- part2 stored function
print("trying a stored fn")
print("the_func=",example.the_func)
print("setting to print")
example.the_func=print
print("the_func=",example.the_func)
print("call_the_func(5)")
example.call_the_func(5)
function bar(i) print("bar",i) end
print("setting to bar")
example.the_func=bar
print("call_the_func(5)")
example.call_the_func(5)

128
SWIG/Lib/lua/lua_fnptr.i Normal file
View file

@ -0,0 +1,128 @@
/* -----------------------------------------------------------------------------
* See the LICENSE file for information on copyright, usage and redistribution
* of SWIG, and the README file for authors - http://www.swig.org/release.html.
*
* lua_fnptr.i
*
* SWIG Library file containing the main typemap code to support Lua modules.
* ----------------------------------------------------------------------------- */
/* -----------------------------------------------------------------------------
* Basic function pointer support
* ----------------------------------------------------------------------------- */
/*
The structure: SWIGLUA_FN provides a simple (local only) wrappering for a function.
For example if you wanted to have a C/C++ function take a lua function as a parameter.
You could declare it as:
int my_func(int a, int b, SWIGLUA_FN fn);
note: it should be passed by value, not byref or as a pointer.
The SWIGLUA_FN holds a pointer to the lua_State, and the stack index where the function is held.
The macro SWIGLUA_FN_GET() will put a copy of the lua function at the top of the stack.
After that its fairly simple to write the rest of the code (assuming know how to use lua),
just push the parameters, call the function and return the result.
int my_func(int a, int b, SWIGLUA_FN fn)
{
SWIGLUA_FN_GET(fn);
lua_pushnumber(fn.L,a);
lua_pushnumber(fn.L,b);
lua_call(fn.L,2,1); // 2 in, 1 out
return luaL_checknumber(fn.L,-1);
}
SWIG will automatically performs the wrappering of the arguments in and out.
However: if you wish to store the function between calls, look to the SWIGLUA_REF below.
*/
// this is for the C code only, we don't want SWIG to wrapper it for us.
%{
typedef struct{
lua_State* L; /* the state */
int idx; /* the index on the stack */
}SWIGLUA_FN;
#define SWIGLUA_FN_GET(fn) {lua_pushvalue(fn.L,fn.idx);}
%}
// the actual typemap
%typemap(in,checkfn="lua_isfunction") SWIGLUA_FN
%{ $1.L=L; $1.idx=$input; %}
/* -----------------------------------------------------------------------------
* Storing lua object support
* ----------------------------------------------------------------------------- */
/*
The structure: SWIGLUA_REF provides a mechanism to store object (usually functions)
between calls to the interpreter.
For example if you wanted to have a C/C++ function take a lua function as a parameter.
Then call it later, You could declare it as:
SWIGLUA_REF myref;
void set_func(SWIGLUA_REF ref);
SWIGLUA_REF get_func();
void call_func(int val);
note: it should be passed by value, not byref or as a pointer.
The SWIGLUA_REF holds a pointer to the lua_State, and an integer reference to the object.
Because it holds a permenet ref to an object, the SWIGLUA_REF must be handled with a bit more care.
It should be initalised to {0,0}. The function swiglua_ref_set() should be used to set it.
swiglua_ref_clear() should be used to clear it when not in use, and swiglua_ref_get() to get the
data back.
Note: the typemap does not check that the object is in fact a function,
if you need that you must add it yourself.
int my_func(int a, int b, SWIGLUA_FN fn)
{
SWIGLUA_FN_GET(fn);
lua_pushnumber(fn.L,a);
lua_pushnumber(fn.L,b);
lua_call(fn.L,2,1); // 2 in, 1 out
return luaL_checknumber(fn.L,-1);
}
SWIG will automatically performs the wrappering of the arguments in and out.
However: if you wish to store the function between calls, look to the SWIGLUA_REF below.
*/
%{
typedef struct{
lua_State* L; /* the state */
int ref; /* a ref in the lua global index */
}SWIGLUA_REF;
void swiglua_ref_clear(SWIGLUA_REF* pref){
if (pref->L!=0 && pref->ref!=LUA_NOREF && pref->ref!=LUA_REFNIL){
luaL_unref(pref->L,LUA_REGISTRYINDEX,pref->ref);
}
pref->L=0; pref->ref=0;
}
void swiglua_ref_set(SWIGLUA_REF* pref,lua_State* L,int idx){
// swiglua_ref_clear(pref); /* just in case */
pref->L=L;
lua_pushvalue(L,idx); /* copy obj to top */
pref->ref=luaL_ref(L,LUA_REGISTRYINDEX); /* remove obj from top & put into registry */
}
void swiglua_ref_get(SWIGLUA_REF* pref){
if (pref->L!=0)
lua_rawgeti(pref->L,LUA_REGISTRYINDEX,pref->ref);
}
%}
%typemap(in) SWIGLUA_REF
%{ swiglua_ref_set(&$1,L,$input); %}
%typemap(out) SWIGLUA_REF
%{ if ($1.L!=0) {swiglua_ref_get(&$1);} else {lua_pushnil(L);}
SWIG_arg++; %}