[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:
Mark Gossage 2008-03-17 08:50:59 +00:00
commit e543cd9040
12 changed files with 279 additions and 25 deletions

View file

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

View file

@ -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' &amp; '__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>

View 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

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

View 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);
%}

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

View file

@ -1,4 +1,5 @@
# see top-level Makefile.in
arrays
class
constants
dual

View file

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

View file

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

View file

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

View file

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

View file

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