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/SWIG@9264 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
parent
be3662e29b
commit
20c2d4bf01
8 changed files with 312 additions and 0 deletions
|
|
@ -2,6 +2,7 @@
|
||||||
class
|
class
|
||||||
constants
|
constants
|
||||||
functest
|
functest
|
||||||
|
funcptr3
|
||||||
pointer
|
pointer
|
||||||
simple
|
simple
|
||||||
variables
|
variables
|
||||||
|
|
|
||||||
13
Examples/lua/funcptr3/.cvsignore
Normal file
13
Examples/lua/funcptr3/.cvsignore
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
example.py
|
||||||
|
example.pyc
|
||||||
|
*_wrap.c
|
||||||
|
*_wrap.cxx
|
||||||
|
*.dll
|
||||||
|
*.dsw
|
||||||
|
*.exp
|
||||||
|
*.lib
|
||||||
|
*.ncb
|
||||||
|
*.opt
|
||||||
|
*.plg
|
||||||
|
Release
|
||||||
|
Debug
|
||||||
19
Examples/lua/funcptr3/Makefile
Normal file
19
Examples/lua/funcptr3/Makefile
Normal 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
|
||||||
19
Examples/lua/funcptr3/example.c
Normal file
19
Examples/lua/funcptr3/example.c
Normal 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;
|
||||||
9
Examples/lua/funcptr3/example.h
Normal file
9
Examples/lua/funcptr3/example.h
Normal 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);
|
||||||
|
|
||||||
69
Examples/lua/funcptr3/example.i
Normal file
69
Examples/lua/funcptr3/example.i
Normal 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 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
%}
|
||||||
54
Examples/lua/funcptr3/runme.lua
Normal file
54
Examples/lua/funcptr3/runme.lua
Normal 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
Lib/lua/lua_fnptr.i
Normal file
128
Lib/lua/lua_fnptr.i
Normal 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++; %}
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue