[lua] added %luacode feature, documentation & examples
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@10312 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
parent
39ad0f01f6
commit
e543cd9040
12 changed files with 279 additions and 25 deletions
|
|
@ -1,6 +1,11 @@
|
|||
Version 1.3.35 (in progress)
|
||||
============================
|
||||
|
||||
03/17/2008: mgossage
|
||||
[Lua] Added %luacode feature to add source code into wrappers.
|
||||
Updated documentation to document this.
|
||||
Added Examples/lua/arrays to show its use (and typemaps)
|
||||
|
||||
03/17/2008: olly
|
||||
Fix nonportable sed usage which failed on Mac OS X (and probably
|
||||
other platforms). Fixes SF#1903612.
|
||||
|
|
|
|||
|
|
@ -35,12 +35,13 @@
|
|||
<li><a href="#Lua_nn21">C++ Smart Pointers</a>
|
||||
<li><a href="#Lua_nn22">C++ exceptions</a>
|
||||
<li><a href="#Lua_nn23">Writing your own custom wrappers</a>
|
||||
<li><a href="#Lua_nn24">Adding additional Lua code</a>
|
||||
</ul>
|
||||
<li><a href="#Lua_nn24">Details on the Lua binding</a>
|
||||
<li><a href="#Lua_nn25">Details on the Lua binding</a>
|
||||
<ul>
|
||||
<li><a href="#Lua_nn25">Binding global data into the module.</a>
|
||||
<li><a href="#Lua_nn26">Userdata and Metatables</a>
|
||||
<li><a href="#Lua_nn27">Memory management</a>
|
||||
<li><a href="#Lua_nn26">Binding global data into the module.</a>
|
||||
<li><a href="#Lua_nn27">Userdata and Metatables</a>
|
||||
<li><a href="#Lua_nn28">Memory management</a>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
@ -1089,7 +1090,43 @@ int native_function(lua_State*L) // my native code
|
|||
The <tt>%native</tt> directive in the above example, tells SWIG that there is a function <tt>int native_function(lua_State*L);</tt> which is to be added into the module under the name '<tt>my_func</tt>'. SWIG will not add any wrappering for this function, beyond adding it into the function table. How you write your code is entirely up to you.
|
||||
</p>
|
||||
|
||||
<H2><a name="Lua_nn24"></a>22.4 Details on the Lua binding</H2>
|
||||
<H3><a name="Lua_nn24"></a>22.3.17 Adding additional Lua code</H3>
|
||||
<p>
|
||||
As well as adding additional C/C++ code, its also possible to add your own Lua code to the module as well.
|
||||
This code is executed once all other initialisation, including the %init code has been called.
|
||||
</p>
|
||||
<p>
|
||||
The directive <tt>%luacode</tt> adds code into the module which is executed upon loading. Normally you would
|
||||
use this to add your own functions to the module. Though you could easily perform other tasks.
|
||||
</p>
|
||||
<div class="code"><pre>%module example;
|
||||
|
||||
%luacode {
|
||||
function example.greet()
|
||||
print "hello world"
|
||||
end
|
||||
|
||||
print "Module loaded ok"
|
||||
}
|
||||
...
|
||||
%}
|
||||
</pre></div>
|
||||
<p>
|
||||
Notice that the code is not part of the module table. Therefore any references to the module must have the
|
||||
module name added.
|
||||
</p>
|
||||
<p>
|
||||
Should there be an error in the Lua code, this will <em>not</em> stop loading of the module.
|
||||
The default behaviour of SWIG is to print a error message to stderr and then continue.
|
||||
It is possible to change this behaviour by using a <tt>#define SWIG_DOSTRING_FAIL(STR)</tt> to
|
||||
define a different behaviour should the code fail.
|
||||
</p>
|
||||
<p>
|
||||
Good uses for this feature is adding of new code, or writing helper functions to simplify some of the code.
|
||||
See Examples/lua/arrays, for an example of this code.
|
||||
</p>
|
||||
|
||||
<H2><a name="Lua_nn25"></a>22.4 Details on the Lua binding</H2>
|
||||
|
||||
|
||||
<p>
|
||||
|
|
@ -1100,7 +1137,7 @@ The <tt>%native</tt> directive in the above example, tells SWIG that there is a
|
|||
</i>
|
||||
</p>
|
||||
|
||||
<H3><a name="Lua_nn25"></a>22.4.1 Binding global data into the module.</H3>
|
||||
<H3><a name="Lua_nn26"></a>22.4.1 Binding global data into the module.</H3>
|
||||
|
||||
|
||||
<p>
|
||||
|
|
@ -1160,7 +1197,7 @@ end
|
|||
<p>
|
||||
That way when you call '<tt>a=example.Foo</tt>', the interpreter looks at the table 'example' sees that there is no field 'Foo' and calls __index. This will in turn check in '.get' table and find the existence of 'Foo' and then return the value of the C function call 'Foo_get()'. Similarly for the code '<tt>example.Foo=10</tt>', the interpreter will check the table, then call the __newindex which will then check the '.set' table and call the C function 'Foo_set(10)'.
|
||||
</p>
|
||||
<H3><a name="Lua_nn26"></a>22.4.2 Userdata and Metatables</H3>
|
||||
<H3><a name="Lua_nn27"></a>22.4.2 Userdata and Metatables</H3>
|
||||
|
||||
|
||||
<p>
|
||||
|
|
@ -1240,7 +1277,7 @@ Note: Both the opaque structures (like the FILE*) and normal wrappered classes/s
|
|||
<p>
|
||||
Note: Operator overloads are basically done in the same way, by adding functions such as '__add' & '__call' to the classes metatable. The current implementation is a bit rough as it will add any member function beginning with '__' into the metatable too, assuming its an operator overload.
|
||||
</p>
|
||||
<H3><a name="Lua_nn27"></a>22.4.3 Memory management</H3>
|
||||
<H3><a name="Lua_nn28"></a>22.4.3 Memory management</H3>
|
||||
|
||||
|
||||
<p>
|
||||
|
|
|
|||
18
Examples/lua/arrays/Makefile
Normal file
18
Examples/lua/arrays/Makefile
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
TOP = ../..
|
||||
SWIG = $(TOP)/../preinst-swig
|
||||
SRCS = example.c
|
||||
TARGET = example
|
||||
INTERFACE = example.i
|
||||
|
||||
all::
|
||||
$(MAKE) -f $(TOP)/Makefile SRCS='$(SRCS)' SWIG='$(SWIG)' \
|
||||
TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' lua
|
||||
|
||||
static::
|
||||
$(MAKE) -f $(TOP)/Makefile SRCS='$(SRCS)' SWIG='$(SWIG)' \
|
||||
TARGET='mylua' INTERFACE='$(INTERFACE)' lua_static
|
||||
|
||||
clean::
|
||||
$(MAKE) -f $(TOP)/Makefile lua_clean
|
||||
|
||||
check: all
|
||||
25
Examples/lua/arrays/example.c
Normal file
25
Examples/lua/arrays/example.c
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/* File : example.c */
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* we are using the qsort function, which needs a helper function to sort */
|
||||
int compare_int(const void * a, const void * b)
|
||||
{
|
||||
return ( *(int*)a - *(int*)b );
|
||||
}
|
||||
|
||||
void sort_int(int* arr, int len)
|
||||
{
|
||||
qsort(arr, len, sizeof(int), compare_int);
|
||||
}
|
||||
|
||||
// ditto doubles
|
||||
int compare_double(const void * a, const void * b)
|
||||
{
|
||||
return ( *(double*)a - *(double*)b );
|
||||
}
|
||||
|
||||
void sort_double(double* arr, int len)
|
||||
{
|
||||
qsort(arr, len, sizeof(double), compare_double);
|
||||
}
|
||||
42
Examples/lua/arrays/example.i
Normal file
42
Examples/lua/arrays/example.i
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/* File : example.i */
|
||||
%module example
|
||||
|
||||
/* in this file there are two sorting functions
|
||||
and three different ways to wrap them.
|
||||
|
||||
See the lua code for how they are called
|
||||
*/
|
||||
|
||||
%include <carrays.i> // array helpers
|
||||
|
||||
// this declares a batch of function for manipulating C integer arrays
|
||||
%array_functions(int,int)
|
||||
|
||||
// this adds some lua code directly into the module
|
||||
// warning: you need the example. prefix if you want it added into the module
|
||||
// addmittedly this code is a bit tedious, but its a one off effort
|
||||
%luacode {
|
||||
function example.sort_int2(t)
|
||||
local len=table.maxn(t) -- the len
|
||||
local arr=example.new_int(len)
|
||||
for i=1,len do
|
||||
example.int_setitem(arr,i-1,t[i]) -- note: C index is one less then lua indea
|
||||
end
|
||||
example.sort_int(arr,len) -- call the fn
|
||||
-- copy back
|
||||
for i=1,len do
|
||||
t[i]=example.int_getitem(arr,i-1) -- note: C index is one less then lua indea
|
||||
end
|
||||
example.delete_int(arr) -- must delete it
|
||||
end
|
||||
}
|
||||
|
||||
// this way uses the SWIG-Lua typemaps to do the conversion for us
|
||||
// the %apply command states to apply this wherever the argument signature matches
|
||||
%include <typemaps.i>
|
||||
%apply (double *INOUT,int) {(double* arr,int len)};
|
||||
|
||||
%inline %{
|
||||
extern void sort_int(int* arr, int len);
|
||||
extern void sort_double(double* arr, int len);
|
||||
%}
|
||||
74
Examples/lua/arrays/runme.lua
Normal file
74
Examples/lua/arrays/runme.lua
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
---- 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','luaopen_example') or loadlib('example.so','luaopen_example')
|
||||
assert(lib)()
|
||||
else
|
||||
-- lua 5.1 does
|
||||
require('example')
|
||||
end
|
||||
|
||||
-- a helper to print a Lua table
|
||||
function print_table(t)
|
||||
print(table.concat(t,","))
|
||||
end
|
||||
|
||||
-- a helper to print a C array
|
||||
function print_array(arr,len)
|
||||
for i=0,len-1 do
|
||||
io.write(example.int_getitem(arr,i),",")
|
||||
end
|
||||
io.write("\n")
|
||||
end
|
||||
|
||||
math.randomseed(0) -- init random
|
||||
|
||||
|
||||
--[[ version 1: passing a C array to the code
|
||||
lets test call sort_int()
|
||||
this requires a C array, so is the hardest to use]]
|
||||
ARRAY_SIZE=10
|
||||
arr=example.new_int(ARRAY_SIZE)
|
||||
for i=0,ARRAY_SIZE-1 do
|
||||
example.int_setitem(arr,i,math.random(1000))
|
||||
end
|
||||
print "unsorted"
|
||||
print_array(arr,ARRAY_SIZE)
|
||||
example.sort_int(arr,ARRAY_SIZE)
|
||||
print "sorted"
|
||||
print_array(arr,ARRAY_SIZE)
|
||||
example.delete_int(arr) -- must delete it
|
||||
print ""
|
||||
|
||||
--[[ version 2: using %luacode to write a helper
|
||||
a simpler way is to use a %luacode
|
||||
which is a lua function added into the module
|
||||
this can do the conversion for us
|
||||
so we can just add a lua table directly
|
||||
(what we do is move the lua code into the module instead)
|
||||
]]
|
||||
t={}
|
||||
for i=1,ARRAY_SIZE do
|
||||
t[i]=math.random(1000)
|
||||
end
|
||||
print "unsorted"
|
||||
print_table(t)
|
||||
example.sort_int2(t) -- calls lua helper which then calls C
|
||||
print "sorted"
|
||||
print_table(t)
|
||||
print ""
|
||||
|
||||
--[[ version 3: use a typemap
|
||||
this is the best way
|
||||
it uses the SWIG-Lua typemaps to do the work
|
||||
one item of note: the typemap creates a copy, rather than edit-in-place]]
|
||||
t={}
|
||||
for i=1,ARRAY_SIZE do
|
||||
t[i]=math.random(1000)/10
|
||||
end
|
||||
print "unsorted"
|
||||
print_table(t)
|
||||
t=example.sort_double(t) -- replace t with the result
|
||||
print "sorted"
|
||||
print_table(t)
|
||||
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
# see top-level Makefile.in
|
||||
arrays
|
||||
class
|
||||
constants
|
||||
dual
|
||||
|
|
|
|||
|
|
@ -228,5 +228,8 @@ SWIG_fail;%}
|
|||
/* -----------------------------------------------------------------------------
|
||||
* extras
|
||||
* ----------------------------------------------------------------------------- */
|
||||
// this %define is to allow insertion of lua source code into the wrapper file
|
||||
#define %luacode %insert("luacode")
|
||||
|
||||
|
||||
/* ------------------------------ end lua.swg ------------------------------ */
|
||||
|
|
|
|||
|
|
@ -671,12 +671,6 @@ SWIGRUNTIME const char *SWIG_Lua_typename(lua_State *L, int tp)
|
|||
/* lua callable function to get the userdata's type */
|
||||
SWIGRUNTIME int SWIG_Lua_type(lua_State* L)
|
||||
{
|
||||
/* swig_lua_userdata* usr;
|
||||
if (!lua_isuserdata(L,1)) /* just in case */
|
||||
/* return 0; /* nil reply */
|
||||
/*usr=(swig_lua_userdata*)lua_touserdata(L,1); /* get data */
|
||||
/*lua_pushstring(L,usr->type->name);
|
||||
return 1;*/
|
||||
lua_pushstring(L,SWIG_Lua_typename(L,1));
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -698,9 +692,6 @@ SWIGRUNTIME int SWIG_Lua_equal(lua_State* L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* global variable support code: class/struct typemap functions
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
|
@ -747,6 +738,35 @@ SWIG_Lua_InstallConstants(lua_State* L, swig_lua_const_info constants[]) {
|
|||
}
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* executing lua code from within the wrapper
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef SWIG_DOSTRING_FAIL /* Allows redefining of error function */
|
||||
#define SWIG_DOSTRING_FAIL(S) fprintf(stderr,"%s\n",S)
|
||||
#endif
|
||||
/* Executes a C string in Lua a really simple way of calling lua from C
|
||||
Unfortunately lua keeps changing its API's, so we need a conditional compile
|
||||
In lua 5.0.X its lua_dostring()
|
||||
In lua 5.1.X its luaL_dostring()
|
||||
*/
|
||||
SWIGINTERN int
|
||||
SWIG_Lua_dostring(lua_State *L, const char* str) {
|
||||
int ok,top;
|
||||
if (str==0 || str[0]==0) return 0; /* nothing to do */
|
||||
top=lua_gettop(L); /* save stack */
|
||||
#if (defined(LUA_VERSION_NUM) && (LUA_VERSION_NUM>=501))
|
||||
ok=luaL_dostring(L,str); /* looks like this is lua 5.1.X or later, good */
|
||||
#else
|
||||
ok=lua_dostring(L,str); /* might be lua 5.0.x, using lua_dostring */
|
||||
#endif
|
||||
if (ok!=0) {
|
||||
SWIG_DOSTRING_FAIL(lua_tostring(L,-1));
|
||||
}
|
||||
lua_settop(L,top); /* restore the stack */
|
||||
return ok;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
/* Forward declaration of where the user's %init{} gets inserted */
|
||||
void SWIG_init_user(lua_State* L );
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ and quite a few functions defined
|
|||
assuming we have functions
|
||||
void process_array(int arr[3]); // nice fixed size array
|
||||
void process_var_array(float arr[],int len); // variable sized array
|
||||
void process_var_array_inout(double arr*,int len); // variable sized array
|
||||
void process_var_array_inout(double* arr,int len); // variable sized array
|
||||
// data passed in & out
|
||||
void process_enum_inout_array_var(enum Days *arrinout, int len); // using enums
|
||||
void return_array_5(int arrout[5]); // out array only
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ private:
|
|||
String *s_const_tab; // table of global constants
|
||||
String *s_methods_tab; // table of class methods
|
||||
String *s_attr_tab; // table of class atributes
|
||||
String *s_luacode; // luacode to be called during init
|
||||
|
||||
int have_constructor;
|
||||
int have_destructor;
|
||||
|
|
@ -137,7 +138,7 @@ public:
|
|||
f_initbeforefunc = 0;
|
||||
PrefixPlusUnderscore = 0;
|
||||
|
||||
s_cmd_tab = s_var_tab = s_const_tab = 0;
|
||||
s_cmd_tab = s_var_tab = s_const_tab = s_luacode = 0;
|
||||
current=NO_CPP;
|
||||
}
|
||||
|
||||
|
|
@ -240,6 +241,10 @@ public:
|
|||
s_var_tab = NewString("");
|
||||
// s_methods_tab = NewString("");
|
||||
s_const_tab = NewString("");
|
||||
|
||||
s_luacode = NewString("");
|
||||
Swig_register_filebyname("luacode", s_luacode);
|
||||
|
||||
current=NO_CPP;
|
||||
|
||||
/* Standard stuff for the SWIG runtime section */
|
||||
|
|
@ -256,6 +261,7 @@ public:
|
|||
Printf(f_header, "#define SWIG_name \"%s\"\n", module);
|
||||
Printf(f_header, "#define SWIG_init luaopen_%s\n", module);
|
||||
Printf(f_header, "#define SWIG_init_user luaopen_%s_user\n\n", module);
|
||||
Printf(f_header, "#define SWIG_LUACODE luaopen_%s_luacode\n\n", module);
|
||||
|
||||
Printf(s_cmd_tab, "\nstatic const struct luaL_reg swig_commands[] = {\n");
|
||||
Printf(s_var_tab, "\nstatic swig_lua_var_info swig_variables[] = {\n");
|
||||
|
|
@ -265,6 +271,7 @@ public:
|
|||
/* %init code inclusion, effectively in the SWIG_init function */
|
||||
Printf(f_init, "void SWIG_init_user(lua_State* L)\n{\n");
|
||||
Language::top(n);
|
||||
Printf(f_init,"/* exec Lua code if applicable */\nSWIG_Lua_dostring(L,SWIG_LUACODE);\n");
|
||||
Printf(f_init, "}\n");
|
||||
|
||||
Printf(f_wrappers, "#ifdef __cplusplus\n}\n#endif\n");
|
||||
|
|
@ -280,14 +287,18 @@ public:
|
|||
this basically combines several of the strings together
|
||||
and then writes it all to a file
|
||||
NEW LANGUAGE NOTE:END ************************************************/
|
||||
/* Close all of the files */
|
||||
Delete(s_cmd_tab);
|
||||
Delete(s_var_tab);
|
||||
Delete(s_const_tab);
|
||||
Dump(f_header, f_runtime);
|
||||
Dump(f_wrappers, f_runtime);
|
||||
Dump(f_initbeforefunc, f_runtime);
|
||||
/* for the Lua code it needs to be properly excaped to be added into the C/C++ code */
|
||||
EscapeCode(s_luacode);
|
||||
Printf(f_runtime, "const char* SWIG_LUACODE=\n \"%s\";\n\n",s_luacode);
|
||||
Wrapper_pretty_print(f_init, f_runtime);
|
||||
/* Close all of the files */
|
||||
Delete(s_luacode);
|
||||
Delete(s_cmd_tab);
|
||||
Delete(s_var_tab);
|
||||
Delete(s_const_tab);
|
||||
Delete(f_header);
|
||||
Delete(f_wrappers);
|
||||
Delete(f_init);
|
||||
|
|
@ -1123,6 +1134,24 @@ public:
|
|||
String *defaultExternalRuntimeFilename() {
|
||||
return NewString("swigluarun.h");
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* helpers
|
||||
* --------------------------------------------------------------------- */
|
||||
|
||||
/* This is to convert the string of Lua code into a proper string, which can then be
|
||||
emitted into the C/C++ code.
|
||||
Basically is is a lot of search & replacing of odd sequences
|
||||
*/
|
||||
void EscapeCode(String* str)
|
||||
{
|
||||
Printf(f_runtime,"/* original luacode:[[[\n%s\n]]]\n*/\n",str);
|
||||
Chop(str); // trim
|
||||
Replace(str,"\\","\\\\",DOH_REPLACE_ANY); // \ to \\ (this must be done first)
|
||||
Replace(str,"\"","\\\"",DOH_REPLACE_ANY); // " to \"
|
||||
Replace(str,"\n","\\n\"\n \"",DOH_REPLACE_ANY); // \n to \n"\n" (ie quoting every line)
|
||||
Printf(f_runtime,"/* hacked luacode:[[[\n%s\n]]]\n*/\n",str);
|
||||
}
|
||||
};
|
||||
|
||||
/* NEW LANGUAGE NOTE:***********************************************
|
||||
|
|
@ -1146,7 +1175,7 @@ swig_module modules[] = {
|
|||
{"-guile", swig_guile, "Guile"},
|
||||
{"-java", swig_java, "Java"},
|
||||
//etc,etc,etc...
|
||||
{"-Lua", swig_lua, "Lua"}, // this is my code
|
||||
{"-lua", swig_lua, "Lua"}, // this is my code
|
||||
{NULL, NULL, NULL} // this must come at the end of the list
|
||||
};
|
||||
======= end change ==========
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue