[lua] updated docs for exceptions
added new examples (exception,embed2) update typmaps git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@10300 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
parent
13c0b040fc
commit
8350c724f5
18 changed files with 749 additions and 149 deletions
|
|
@ -1,6 +1,11 @@
|
|||
Version 1.3.35 (in progress)
|
||||
============================
|
||||
|
||||
03/06/2008: mgossage
|
||||
[Lua] Updated documentation for Lua exceptions.
|
||||
Added Examples/lua/exception and Examples/lua/embed2.
|
||||
Small updates to the typemaps.
|
||||
|
||||
03/04/2008: wsfulton
|
||||
[Java, C#] Add char *& typemaps.
|
||||
|
||||
|
|
|
|||
|
|
@ -33,13 +33,14 @@
|
|||
<li><a href="#Lua_nn19">Class extension with %extend</a>
|
||||
<li><a href="#Lua_nn20">C++ templates</a>
|
||||
<li><a href="#Lua_nn21">C++ Smart Pointers</a>
|
||||
<li><a href="#Lua_nn22">Writing your own custom wrappers</a>
|
||||
<li><a href="#Lua_nn22">C++ exceptions</a>
|
||||
<li><a href="#Lua_nn23">Writing your own custom wrappers</a>
|
||||
</ul>
|
||||
<li><a href="#Lua_nn23">Details on the Lua binding</a>
|
||||
<li><a href="#Lua_nn24">Details on the Lua binding</a>
|
||||
<ul>
|
||||
<li><a href="#Lua_nn24">Binding global data into the module.</a>
|
||||
<li><a href="#Lua_nn25">Userdata and Metatables</a>
|
||||
<li><a href="#Lua_nn26">Memory management</a>
|
||||
<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>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
@ -308,7 +309,7 @@ Its is therefore not possible to 'move' the global variable into the global name
|
|||
4
|
||||
</pre></div>
|
||||
<p>
|
||||
If a variable is marked with the %immutable directive then any attempts to set this variable will cause an lua error. Given a global variable:
|
||||
If a variable is marked with the %immutable directive then any attempts to set this variable will cause an Lua error. Given a global variable:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>%module example
|
||||
|
|
@ -331,7 +332,7 @@ stack traceback:
|
|||
[C]: ?
|
||||
</pre></div>
|
||||
<p>
|
||||
For those people who would rather that SWIG silently ignore the setting of immutables (as previous versions of the lua bindings did), adding a <tt>-DSWIGLUA_IGNORE_SET_IMMUTABLE</tt> compile option will remove this.
|
||||
For those people who would rather that SWIG silently ignore the setting of immutables (as previous versions of the Lua bindings did), adding a <tt>-DSWIGLUA_IGNORE_SET_IMMUTABLE</tt> compile option will remove this.
|
||||
</p>
|
||||
<p>
|
||||
Unlike earlier versions of the binding, it is now possible to add new functions or variables to the module, just as if it were a normal table. This also allows the user to rename/remove existing functions and constants (but not linked variables, mutable or immutable). Therefore users are recommended to be careful when doing so.
|
||||
|
|
@ -949,13 +950,133 @@ If you ever need to access the underlying pointer returned by <tt>operator->(
|
|||
> f = p:__deref__() -- Returns underlying Foo *
|
||||
</pre></div>
|
||||
|
||||
<H3><a name="Lua_nn22"></a>22.3.15 Writing your own custom wrappers</H3>
|
||||
<H3><a name="Lua_nn22"></a>22.3.15 C++ Exceptions</H3>
|
||||
<p>
|
||||
Lua does not natively support exceptions, but it has errors which are similar. When a Lua function terminates with an error
|
||||
it returns one value back to the caller. SWIG automatically maps any basic type which is thrown into a Lua error.
|
||||
Therefore for a function:
|
||||
</p>
|
||||
<div class="code"><pre>
|
||||
int message() throw(const char *) {
|
||||
throw("I died.");
|
||||
return 1;
|
||||
}
|
||||
</pre></div>
|
||||
<p>
|
||||
SWIG will automatically convert this to a Lua error.
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>
|
||||
> message()
|
||||
I died.
|
||||
stack traceback:
|
||||
[C]: in function 'message'
|
||||
stdin:1: in main chunk
|
||||
[C]: ?
|
||||
>
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Sometimes, it may be neccesary to add your own special functions, which bypass the normal SWIG wrappering method, and just use the native lua-c API calls. These 'native' functions allow direct adding of your own code into the module. This is performed with the <tt>%native</tt> directive as follows:
|
||||
And similarly for numeric types, enums, chars, char*'s and std::string's.
|
||||
</p>
|
||||
<div class="code"><pre>%native(my_func) int native_function(lua_State*L); // registers it with SWIG
|
||||
<p>
|
||||
However its not so simple for objects. Thrown objects are not valid outside the 'catch' block. Therefore they cannot be
|
||||
returned to the interpreter.
|
||||
The obvious ways to overcome this would be to either return a copy of the object, or so convert the object to a string and
|
||||
return that. Though it seems obvious to perform the former, in some cases this is not possible, most notably when
|
||||
SWIG has no information about the object, or the object is not copyable/creatable.
|
||||
</p>
|
||||
<p>
|
||||
Therefore by default SWIG converts all thrown object into strings and returns them. So given a function:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
void throw_A() throw(A*) {
|
||||
throw new A();
|
||||
}
|
||||
</pre></div>
|
||||
<p>
|
||||
SWIG will just convert it (poorly) to a string and use that as its error. (Yes its not that useful, but it always works).
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>
|
||||
> throw_A()
|
||||
object exception:A *
|
||||
stack traceback:
|
||||
[C]: in function 'unknown'
|
||||
stdin:1: in main chunk
|
||||
[C]: ?
|
||||
>
|
||||
</pre></div>
|
||||
<p>
|
||||
To get a more useful behaviour out of SWIG you must either: provide a way to convert your exceptions into strings, or
|
||||
only throw objects which can be copied.
|
||||
</p>
|
||||
<p>
|
||||
SWIG has typemaps for std::exception and its children already written, so a function which throws any of these will
|
||||
automatically have its exception converted into an error string.
|
||||
</p>
|
||||
<p>
|
||||
If you have your own class which you want output as a string you will need to add a typemap something like this:
|
||||
</p>
|
||||
<div class="code"><pre>
|
||||
%typemap(throws) my_except
|
||||
%{
|
||||
lua_pushstring(L,$1.what()); // assuming what() returns a const char* message
|
||||
SWIG_fail; // trigger the error handler
|
||||
%}
|
||||
</pre></div>
|
||||
<p>
|
||||
If you wish your exception to be returned to the interpreter, it must firstly be copyable. Then you must have and additional
|
||||
<tt>%apply</tt> statement, to inform SWIG to return a copy of this object to the interpreter. For example:
|
||||
</p>
|
||||
<div class="code"><pre>
|
||||
%apply SWIGTYPE EXCEPTION_BY_VAL {Exc}; // tell SWIG to return Exc by value to interpreter
|
||||
|
||||
class Exc {
|
||||
public:
|
||||
Exc(int c, const char *m) {
|
||||
code = c;
|
||||
strncpy(msg,m,256);
|
||||
}
|
||||
int code;
|
||||
char msg[256];
|
||||
};
|
||||
|
||||
void throw_exc() throw(Exc) {
|
||||
throw(Exc(42,"Hosed"));
|
||||
}
|
||||
</pre></div>
|
||||
<p>
|
||||
Then the following code can be used (note: we use pcall to catch the error so we can process the exception).
|
||||
</p>
|
||||
<div class="targetlang"><pre>
|
||||
> ok,res=pcall(throw_exc)
|
||||
> print(ok)
|
||||
false
|
||||
> print(res)
|
||||
userdata: 0003D880
|
||||
> print(res.code,res.msg)
|
||||
42 Hosed
|
||||
>
|
||||
</pre></div>
|
||||
<p>
|
||||
Note: is is also possible (though tedious) to have a function throw several different kinds of exceptions. To process this
|
||||
will require a pcall, followed by a set of if statements checking the type of the error.
|
||||
</p>
|
||||
<p>
|
||||
All of this code assumes that your C++ code uses exception specification (which a lot doesn't).
|
||||
If it doesn't consult the "<a href="SWIGPlus.html#SWIGPlus_catches">Exception handling with %catches</a>" section
|
||||
and the "<a href="Customization.html#exception">Exception handling with %exception</a>" section, for more details on how to
|
||||
add exception specification to functions or globally (respectively).
|
||||
</p>
|
||||
|
||||
|
||||
<H3><a name="Lua_nn23"></a>22.3.16 Writing your own custom wrappers</H3>
|
||||
<p>
|
||||
Sometimes, it may be neccesary to add your own special functions, which bypass the normal SWIG wrappering method, and just use the native Lua API calls. These 'native' functions allow direct adding of your own code into the module. This is performed with the <tt>%native</tt> directive as follows:
|
||||
</p>
|
||||
<div class="code"><pre>%native(my_func) int native_function(lua_State*L); // registers native_function() with SWIG
|
||||
...
|
||||
%{
|
||||
int native_function(lua_State*L) // my native code
|
||||
|
|
@ -968,7 +1089,7 @@ 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_nn23"></a>22.4 Details on the Lua binding</H2>
|
||||
<H2><a name="Lua_nn24"></a>22.4 Details on the Lua binding</H2>
|
||||
|
||||
|
||||
<p>
|
||||
|
|
@ -979,7 +1100,7 @@ The <tt>%native</tt> directive in the above example, tells SWIG that there is a
|
|||
</i>
|
||||
</p>
|
||||
|
||||
<H3><a name="Lua_nn24"></a>22.4.1 Binding global data into the module.</H3>
|
||||
<H3><a name="Lua_nn25"></a>22.4.1 Binding global data into the module.</H3>
|
||||
|
||||
|
||||
<p>
|
||||
|
|
@ -995,7 +1116,7 @@ SWIG will effectively generate the pair of functions
|
|||
double Foo_get();
|
||||
</pre></div>
|
||||
<p>
|
||||
At initialisation time, it will then add to the interpreter a table called 'example', which represents the module. It will then add all its functions to the module. (Note: older versions of SWIG actually added the Foo_set() and Foo_get() functions, current implementation does not add these functions and more.) But it also adds a metatable to this table, which has two functions (<tt>__index</tt> and <tt>__newindex</tt>) as well as two tables (<tt>.get</tt> and <tt>.set</tt>) The following Lua code will show these hidden features.
|
||||
At initialisation time, it will then add to the interpreter a table called 'example', which represents the module. It will then add all its functions to the module. (Note: older versions of SWIG actually added the Foo_set() and Foo_get() functions, current implementation does not add these functions any more.) But it also adds a metatable to this table, which has two functions (<tt>__index</tt> and <tt>__newindex</tt>) as well as two tables (<tt>.get</tt> and <tt>.set</tt>) The following Lua code will show these hidden features.
|
||||
</p>
|
||||
<div class="targetlang"><pre>
|
||||
> print(example)
|
||||
|
|
@ -1039,7 +1160,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_nn25"></a>22.4.2 Userdata and Metatables</H3>
|
||||
<H3><a name="Lua_nn26"></a>22.4.2 Userdata and Metatables</H3>
|
||||
|
||||
|
||||
<p>
|
||||
|
|
@ -1119,7 +1240,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_nn26"></a>22.4.3 Memory management</H3>
|
||||
<H3><a name="Lua_nn27"></a>22.4.3 Memory management</H3>
|
||||
|
||||
|
||||
<p>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ class
|
|||
constants
|
||||
dual
|
||||
embed
|
||||
embed2
|
||||
exception
|
||||
funcptr3
|
||||
functest
|
||||
functor
|
||||
|
|
|
|||
|
|
@ -1,85 +1,85 @@
|
|||
/* embed.c a simple test for an embeded interpreter
|
||||
|
||||
The idea is that we wrapper a few simple function (example.c)
|
||||
and write our own app to call it.
|
||||
|
||||
What it will do is load the wrappered lib, load runme.lua and then call some functions.
|
||||
To make life easier, all the printf's have either [C] or [Lua] at the start
|
||||
so you can see where they are coming from.
|
||||
|
||||
We will be using the luaL_dostring()/lua_dostring() function to call into lua
|
||||
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
#include <lualib.h>
|
||||
|
||||
/* the SWIG wrappered library */
|
||||
extern int luaopen_example(lua_State*L);
|
||||
|
||||
/* a really simple way of calling lua from C
|
||||
just give it a lua state & a string to execute
|
||||
Unfortunately lua keeps changing its API's.
|
||||
In lua 5.0.X its lua_dostring()
|
||||
In lua 5.1.X its luaL_dostring()
|
||||
so we have a few extra compiles
|
||||
*/
|
||||
int dostring(lua_State *L, char* str)
|
||||
{
|
||||
int ok;
|
||||
#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)
|
||||
printf("[C] ERROR in dostring: %s\n",lua_tostring(L,-1));
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc,char* argv[])
|
||||
{
|
||||
lua_State *L;
|
||||
int ok;
|
||||
printf("[C] Welcome to the simple embedded lua example\n");
|
||||
printf("[C] We are in C\n");
|
||||
printf("[C] opening a lua state & loading the libraries\n");
|
||||
L=lua_open();
|
||||
luaopen_base(L);
|
||||
luaopen_string(L);
|
||||
luaopen_math(L);
|
||||
printf("[C] now loading the SWIG wrappered library\n");
|
||||
luaopen_example(L);
|
||||
printf("[C] all looks ok\n");
|
||||
printf("\n");
|
||||
printf("[C] lets load the file 'runme.lua'\n");
|
||||
printf("[C] any lua code in this file will be executed\n");
|
||||
if (luaL_loadfile(L, "runme.lua") || lua_pcall(L, 0, 0, 0))
|
||||
{
|
||||
printf("[C] ERROR: cannot run lua file: %s",lua_tostring(L, -1));
|
||||
exit(3);
|
||||
}
|
||||
printf("[C] We are now back in C, all looks ok\n");
|
||||
printf("\n");
|
||||
printf("[C] lets call the function 'do_tests()'\n");
|
||||
ok=dostring(L,"do_tests()");
|
||||
printf("[C] We are back in C, the dostring() function returned %d\n",ok);
|
||||
printf("\n");
|
||||
printf("[C] Lets call lua again, but create an error\n");
|
||||
ok=dostring(L,"no_such_function()");
|
||||
printf("[C] We are back in C, the dostring() function returned %d\n",ok);
|
||||
printf("[C] it should also have returned 1 and printed an error message\n");
|
||||
printf("\n");
|
||||
printf("[C] Lets call lua again, calling the greeting function\n");
|
||||
ok=dostring(L,"call_greeting()");
|
||||
printf("[C] This was C=>Lua=>C (getting a bit complex)\n");
|
||||
printf("\n");
|
||||
printf("[C] all finished, closing the lua state\n");
|
||||
lua_close(L);
|
||||
return 0;
|
||||
}
|
||||
/* embed.c a simple test for an embeded interpreter
|
||||
|
||||
The idea is that we wrapper a few simple function (example.c)
|
||||
and write our own app to call it.
|
||||
|
||||
What it will do is load the wrappered lib, load runme.lua and then call some functions.
|
||||
To make life easier, all the printf's have either [C] or [Lua] at the start
|
||||
so you can see where they are coming from.
|
||||
|
||||
We will be using the luaL_dostring()/lua_dostring() function to call into lua
|
||||
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
#include <lualib.h>
|
||||
|
||||
/* the SWIG wrappered library */
|
||||
extern int luaopen_example(lua_State*L);
|
||||
|
||||
/* a really simple way of calling lua from C
|
||||
just give it a lua state & a string to execute
|
||||
Unfortunately lua keeps changing its API's.
|
||||
In lua 5.0.X its lua_dostring()
|
||||
In lua 5.1.X its luaL_dostring()
|
||||
so we have a few extra compiles
|
||||
*/
|
||||
int dostring(lua_State *L, char* str) {
|
||||
int ok;
|
||||
#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)
|
||||
printf("[C] ERROR in dostring: %s\n",lua_tostring(L,-1));
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc,char* argv[]) {
|
||||
lua_State *L;
|
||||
int ok;
|
||||
printf("[C] Welcome to the simple embedded lua example\n");
|
||||
printf("[C] We are in C\n");
|
||||
printf("[C] opening a lua state & loading the libraries\n");
|
||||
L=lua_open();
|
||||
luaopen_base(L);
|
||||
luaopen_string(L);
|
||||
luaopen_math(L);
|
||||
printf("[C] now loading the SWIG wrappered library\n");
|
||||
luaopen_example(L);
|
||||
printf("[C] all looks ok\n");
|
||||
printf("\n");
|
||||
printf("[C] lets load the file 'runme.lua'\n");
|
||||
printf("[C] any lua code in this file will be executed\n");
|
||||
if (luaL_loadfile(L, "runme.lua") || lua_pcall(L, 0, 0, 0)) {
|
||||
printf("[C] ERROR: cannot run lua file: %s",lua_tostring(L, -1));
|
||||
exit(3);
|
||||
}
|
||||
printf("[C] We are now back in C, all looks ok\n");
|
||||
printf("\n");
|
||||
printf("[C] lets call the function 'do_tests()'\n");
|
||||
ok=dostring(L,"do_tests()");
|
||||
printf("[C] We are back in C, the dostring() function returned %d\n",ok);
|
||||
printf("\n");
|
||||
printf("[C] Lets call lua again, but create an error\n");
|
||||
ok=dostring(L,"no_such_function()");
|
||||
printf("[C] We are back in C, the dostring() function returned %d\n",ok);
|
||||
printf("[C] it should also have returned 1 and printed an error message\n");
|
||||
printf("\n");
|
||||
printf("[C] Lets call lua again, calling the greeting function\n");
|
||||
ok=dostring(L,"call_greeting()");
|
||||
printf("[C] This was C=>Lua=>C (getting a bit complex)\n");
|
||||
printf("\n");
|
||||
printf("[C] all finished, closing the lua state\n");
|
||||
lua_close(L);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,22 @@
|
|||
/* File : example.c */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* A global variable */
|
||||
double Foo = 3.0;
|
||||
|
||||
/* Compute the greatest common divisor of positive integers */
|
||||
int gcd(int x, int y) {
|
||||
int g;
|
||||
g = y;
|
||||
while (x > 0) {
|
||||
g = x;
|
||||
x = y % x;
|
||||
y = g;
|
||||
}
|
||||
return g;
|
||||
}
|
||||
|
||||
void greeting()
|
||||
{
|
||||
printf("Hello from the C function 'greeting'\n");
|
||||
}
|
||||
/* File : example.c */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* A global variable */
|
||||
double Foo = 3.0;
|
||||
|
||||
/* Compute the greatest common divisor of positive integers */
|
||||
int gcd(int x, int y) {
|
||||
int g;
|
||||
g = y;
|
||||
while (x > 0) {
|
||||
g = x;
|
||||
x = y % x;
|
||||
y = g;
|
||||
}
|
||||
return g;
|
||||
}
|
||||
|
||||
void greeting() {
|
||||
printf("Hello from the C function 'greeting'\n");
|
||||
}
|
||||
|
|
|
|||
18
Examples/lua/embed2/Makefile
Normal file
18
Examples/lua/embed2/Makefile
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
TOP = ../..
|
||||
SWIG = $(TOP)/../preinst-swig
|
||||
TARGET = embed2
|
||||
SRCS = example.c
|
||||
INTERFACE = example.i
|
||||
LUA_INTERP = embed2.c
|
||||
|
||||
# this is a little different to normal as we have our own special interpreter
|
||||
# which we want to static link
|
||||
all::
|
||||
$(MAKE) -f $(TOP)/Makefile $(SWIGLIB) SRCS='$(SRCS)' SWIG='$(SWIG)' \
|
||||
SWIGOPT='$(SWIGOPT)' TARGET='$(TARGET)' INTERFACE='example.i' LUA_INTERP='$(LUA_INTERP)' lua_static
|
||||
|
||||
clean::
|
||||
$(MAKE) -f $(TOP)/Makefile lua_clean
|
||||
|
||||
check: all
|
||||
|
||||
221
Examples/lua/embed2/embed2.c
Normal file
221
Examples/lua/embed2/embed2.c
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
/* embed2.c some more test for an embeded interpreter
|
||||
|
||||
This will go a bit further as it will pass values to and from the lua code.
|
||||
It uses less of the SWIG code, and more of the raw lua API's
|
||||
|
||||
What it will do is load the wrappered lib, load runme.lua and then call some functions.
|
||||
To make life easier, all the printf's have either [C] or [Lua] at the start
|
||||
so you can see where they are coming from.
|
||||
|
||||
We will be using the luaL_dostring()/lua_dostring() function to call into lua
|
||||
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
#include <lualib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
/* the SWIG wrappered library */
|
||||
extern int luaopen_example(lua_State*L);
|
||||
|
||||
/* This is an example of how to call the Lua function
|
||||
int add(int,int)
|
||||
its very tedious, but gives you an idea of the issues involded.
|
||||
(look below for a better idea)
|
||||
*/
|
||||
int call_add(lua_State *L,int a,int b,int* res) {
|
||||
int top;
|
||||
/* ok, here we go:
|
||||
push a, push b, call 'add' check & return res
|
||||
*/
|
||||
top=lua_gettop(L); /* for later */
|
||||
lua_pushstring(L, "add"); /* function name */
|
||||
lua_gettable(L, LUA_GLOBALSINDEX); /* function to be called */
|
||||
if (!lua_isfunction(L,-1)) {
|
||||
printf("[C] error: cannot find function 'add'\n");
|
||||
lua_settop(L,top); // reset
|
||||
return 0;
|
||||
}
|
||||
lua_pushnumber(L,a);
|
||||
lua_pushnumber(L,b);
|
||||
if (lua_pcall(L, 2, 1, 0) != 0) /* call function with 2 arguments and 1 result */
|
||||
{
|
||||
printf("[C] error running function `add': %s\n",lua_tostring(L, -1));
|
||||
lua_settop(L,top); // reset
|
||||
return 0;
|
||||
}
|
||||
// check results
|
||||
if (!lua_isnumber(L,-1)) {
|
||||
printf("[C] error: returned value is not a number\n");
|
||||
lua_settop(L,top); // reset
|
||||
return 0;
|
||||
}
|
||||
*res=(int)lua_tonumber(L,-1);
|
||||
lua_settop(L,top); /* reset stack */
|
||||
return 1; // ok
|
||||
}
|
||||
|
||||
/* This is a variargs call function for calling from C into Lua.
|
||||
Original Code from Programming in Lua (PIL) by Roberto Ierusalimschy
|
||||
ISBN 85-903798-1-7
|
||||
http://www.lua.org/pil/25.3.html
|
||||
This has been modified slightly to make it compile, and its still a bit rough.
|
||||
But it gives the idea of how to make it work.
|
||||
*/
|
||||
int call_va (lua_State *L,const char *func, const char *sig, ...) {
|
||||
va_list vl;
|
||||
int narg, nres; /* number of arguments and results */
|
||||
int top;
|
||||
top=lua_gettop(L); /* for later */
|
||||
|
||||
va_start(vl, sig);
|
||||
lua_getglobal(L, func); /* get function */
|
||||
|
||||
/* push arguments */
|
||||
narg = 0;
|
||||
while (*sig) { /* push arguments */
|
||||
switch (*sig++) {
|
||||
|
||||
case 'd': /* double argument */
|
||||
lua_pushnumber(L, va_arg(vl, double));
|
||||
break;
|
||||
|
||||
case 'i': /* int argument */
|
||||
lua_pushnumber(L, va_arg(vl, int));
|
||||
break;
|
||||
|
||||
case 's': /* string argument */
|
||||
lua_pushstring(L, va_arg(vl, char *));
|
||||
break;
|
||||
|
||||
case '>':
|
||||
goto endwhile;
|
||||
|
||||
default:
|
||||
printf("invalid option (%c)\n", *(sig - 1));
|
||||
goto fail;
|
||||
}
|
||||
narg++;
|
||||
/* do we need this?*/
|
||||
/* luaL_checkstack(L, 1, "too many arguments"); */
|
||||
}
|
||||
endwhile:
|
||||
|
||||
/* do the call */
|
||||
nres = strlen(sig); /* number of expected results */
|
||||
if (lua_pcall(L, narg, nres, 0) != 0) /* do the call */
|
||||
{
|
||||
printf("error running function `%s': %s\n",func, lua_tostring(L, -1));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* retrieve results */
|
||||
nres = -nres; /* stack index of first result */
|
||||
while (*sig) { /* get results */
|
||||
switch (*sig++) {
|
||||
|
||||
case 'd': /* double result */
|
||||
if (!lua_isnumber(L, nres)) {
|
||||
printf("wrong result type\n");
|
||||
goto fail;
|
||||
}
|
||||
*va_arg(vl, double *) = lua_tonumber(L, nres);
|
||||
break;
|
||||
|
||||
case 'i': /* int result */
|
||||
if (!lua_isnumber(L, nres)) {
|
||||
printf("wrong result type\n");
|
||||
goto fail;
|
||||
}
|
||||
*va_arg(vl, int *) = (int)lua_tonumber(L, nres);
|
||||
break;
|
||||
|
||||
case 's': /* string result */
|
||||
if (!lua_isstring(L, nres)) {
|
||||
printf("wrong result type\n");
|
||||
goto fail;
|
||||
}
|
||||
strcpy(va_arg(vl, char *),lua_tostring(L, nres));/* WARNING possible buffer overflow */
|
||||
break;
|
||||
|
||||
default: {
|
||||
printf("invalid option (%c)", *(sig - 1));
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
nres++;
|
||||
}
|
||||
va_end(vl);
|
||||
|
||||
lua_settop(L,top); /* reset stack */
|
||||
return 1; /* ok */
|
||||
fail:
|
||||
lua_settop(L,top); /* reset stack */
|
||||
return 0; /* error */
|
||||
}
|
||||
|
||||
int main(int argc,char* argv[]) {
|
||||
lua_State *L;
|
||||
int ok;
|
||||
int res;
|
||||
char str[80];
|
||||
printf("[C] Welcome to the simple embedded Lua example\n");
|
||||
printf("[C] We are in C\n");
|
||||
printf("[C] opening a Lua state & loading the libraries\n");
|
||||
L=lua_open();
|
||||
luaopen_base(L);
|
||||
luaopen_string(L);
|
||||
luaopen_math(L);
|
||||
printf("[C] now loading the SWIG wrappered library\n");
|
||||
luaopen_example(L);
|
||||
printf("[C] all looks ok\n");
|
||||
printf("\n");
|
||||
printf("[C] lets load the file 'runme.lua'\n");
|
||||
printf("[C] any lua code in this file will be executed\n");
|
||||
if (luaL_loadfile(L, "runme.lua") || lua_pcall(L, 0, 0, 0)) {
|
||||
printf("[C] ERROR: cannot run lua file: %s",lua_tostring(L, -1));
|
||||
exit(3);
|
||||
}
|
||||
printf("[C] We are now back in C, all looks ok\n");
|
||||
printf("\n");
|
||||
printf("[C] lets call the Lua function 'add(1,1)'\n");
|
||||
printf("[C] using the C function 'call_add'\n");
|
||||
ok=call_add(L,1,1,&res);
|
||||
printf("[C] the function returned %d with value %d\n",ok,res);
|
||||
printf("\n");
|
||||
printf("[C] lets do this rather easier\n");
|
||||
printf("[C] we will call the same Lua function using a generic C function 'call_va'\n");
|
||||
ok=call_va(L,"add","ii>i",1,1,&res);
|
||||
printf("[C] the function returned %d with value %d\n",ok,res);
|
||||
printf("\n");
|
||||
printf("[C] we will now use the same generic C function to call 'append(\"cat\",\"dog\")'\n");
|
||||
ok=call_va(L,"append","ss>s","cat","dog",str);
|
||||
printf("[C] the function returned %d with value %s\n",ok,str);
|
||||
printf("\n");
|
||||
printf("[C] we can also make some bad calls to ensure the code doesn't fail\n");
|
||||
printf("[C] calling adds(1,2)\n");
|
||||
ok=call_va(L,"adds","ii>i",1,2,&res);
|
||||
printf("[C] the function returned %d with value %d\n",ok,res);
|
||||
printf("[C] calling add(1,'fred')\n");
|
||||
ok=call_va(L,"add","is>i",1,"fred",&res);
|
||||
printf("[C] the function returned %d with value %d\n",ok,res);
|
||||
printf("\n");
|
||||
printf("[C] Note: no protection if you mess up the va-args, this is C\n");
|
||||
printf("\n");
|
||||
printf("[C] Finally we will call the wrappered gcd function gdc(6,9):\n");
|
||||
printf("[C] This will pass the values to Lua, then call the wrappered function\n");
|
||||
printf(" Which will get the values from Lua, call the C code \n");
|
||||
printf(" and return the value to Lua and eventually back to C\n");
|
||||
printf("[C] Certainly not the best way to do it :-)\n");
|
||||
ok=call_va(L,"gcd","ii>i",6,9,&res);
|
||||
printf("[C] the function returned %d with value %d\n",ok,res);
|
||||
printf("\n");
|
||||
printf("[C] all finished, closing the lua state\n");
|
||||
lua_close(L);
|
||||
return 0;
|
||||
}
|
||||
22
Examples/lua/embed2/example.c
Normal file
22
Examples/lua/embed2/example.c
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/* File : example.c */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* A global variable */
|
||||
double Foo = 3.0;
|
||||
|
||||
/* Compute the greatest common divisor of positive integers */
|
||||
int gcd(int x, int y) {
|
||||
int g;
|
||||
g = y;
|
||||
while (x > 0) {
|
||||
g = x;
|
||||
x = y % x;
|
||||
y = g;
|
||||
}
|
||||
return g;
|
||||
}
|
||||
|
||||
void greeting() {
|
||||
printf("Hello from the C function 'greeting'\n");
|
||||
}
|
||||
8
Examples/lua/embed2/example.i
Normal file
8
Examples/lua/embed2/example.i
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
/* File : example.i */
|
||||
%module example
|
||||
|
||||
%inline %{
|
||||
extern int gcd(int x, int y);
|
||||
extern double Foo;
|
||||
extern void greeting();
|
||||
%}
|
||||
27
Examples/lua/embed2/runme.lua
Normal file
27
Examples/lua/embed2/runme.lua
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
print "[lua] This is runme.lua"
|
||||
-- test program for embeded lua
|
||||
-- we do not need to load the library, as it was already in the intrepreter
|
||||
-- but lets check anyway
|
||||
assert(type(example)=='table',"Don't appear to have loaded the example module")
|
||||
|
||||
-- note: we will copy the functions from example table into global
|
||||
-- this will help us later
|
||||
for k,v in pairs(example) do _G[k]=v end
|
||||
|
||||
-- our add function
|
||||
-- we will be calling this from C
|
||||
function add(a,b)
|
||||
print("[lua] this is function add(",a,b,")")
|
||||
c=a+b
|
||||
print("[lua] returning",c)
|
||||
return c
|
||||
end
|
||||
|
||||
function append(a,b)
|
||||
print("[lua] this is function append(",a,b,")")
|
||||
c=a..b
|
||||
print("[lua] returning",c)
|
||||
return c
|
||||
end
|
||||
|
||||
|
||||
19
Examples/lua/exception/Makefile
Normal file
19
Examples/lua/exception/Makefile
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
TOP = ../..
|
||||
SWIG = $(TOP)/../preinst-swig
|
||||
CXXSRCS =
|
||||
TARGET = example
|
||||
INTERFACE = example.i
|
||||
LIBS = -lm
|
||||
|
||||
all::
|
||||
$(MAKE) -f $(TOP)/Makefile CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \
|
||||
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
|
||||
53
Examples/lua/exception/example.h
Normal file
53
Examples/lua/exception/example.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/* File : example.h */
|
||||
|
||||
#include <string>
|
||||
#ifndef SWIG
|
||||
struct A {
|
||||
};
|
||||
#endif
|
||||
|
||||
class Exc {
|
||||
public:
|
||||
Exc(int c, const char *m) {
|
||||
code = c;
|
||||
strncpy(msg,m,256);
|
||||
}
|
||||
int code;
|
||||
char msg[256];
|
||||
};
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(disable: 4290) // C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
|
||||
#endif
|
||||
|
||||
class Test {
|
||||
public:
|
||||
int simple() throw(int&) {
|
||||
throw(37);
|
||||
return 1;
|
||||
}
|
||||
int message() throw(const char *) {
|
||||
throw("I died.");
|
||||
return 1;
|
||||
}
|
||||
int hosed() throw(Exc) {
|
||||
throw(Exc(42,"Hosed"));
|
||||
return 1;
|
||||
}
|
||||
int unknown() throw(A*) {
|
||||
static A a;
|
||||
throw &a;
|
||||
return 1;
|
||||
}
|
||||
int multi(int x) throw(int, const char *, Exc) {
|
||||
if (x == 1) throw(37);
|
||||
if (x == 2) throw("Bleah!");
|
||||
if (x == 3) throw(Exc(42,"No-go-diggy-die"));
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(default: 4290) // C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
|
||||
#endif
|
||||
|
||||
17
Examples/lua/exception/example.i
Normal file
17
Examples/lua/exception/example.i
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
/* File : example.i */
|
||||
%module example
|
||||
|
||||
%{
|
||||
#include "example.h"
|
||||
%}
|
||||
|
||||
%include "std_string.i"
|
||||
|
||||
// we want to return Exc objects to the interpreter
|
||||
// therefore we add this typemap
|
||||
// note: only works if Exc is copyable
|
||||
%apply SWIGTYPE EXCEPTION_BY_VAL {Exc};
|
||||
|
||||
/* Let's just grab the original header file here */
|
||||
%include "example.h"
|
||||
|
||||
63
Examples/lua/exception/runme.lua
Normal file
63
Examples/lua/exception/runme.lua
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
-- file: example.lua
|
||||
|
||||
---- 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
|
||||
|
||||
-- throw a lot of exceptions:
|
||||
-- you must catch exceptions using pcall and then checking the result
|
||||
|
||||
t = example.Test()
|
||||
|
||||
print "calling t:unknown()"
|
||||
ok,res=pcall(function() t:unknown() end)
|
||||
if ok then
|
||||
print " that worked! Funny"
|
||||
else
|
||||
print(" call failed with error:",res)
|
||||
end
|
||||
|
||||
print "calling t:simple()"
|
||||
ok,res=pcall(function() t:simple() end)
|
||||
if ok then
|
||||
print " that worked! Funny"
|
||||
else
|
||||
print(" call failed with error:",res)
|
||||
end
|
||||
|
||||
print "calling t:message()"
|
||||
ok,res=pcall(function() t:message() end)
|
||||
if ok then
|
||||
print " that worked! Funny"
|
||||
else
|
||||
print(" call failed with error:",res)
|
||||
end
|
||||
|
||||
print "calling t:hosed()"
|
||||
ok,res=pcall(function() t:hosed() end)
|
||||
if ok then
|
||||
print " that worked! Funny"
|
||||
else
|
||||
print(" call failed with error:",res.code,res.msg)
|
||||
end
|
||||
|
||||
-- this is a rather strange way to perform the multiple catch of exceptions
|
||||
print "calling t:mutli()"
|
||||
for i=1,3 do
|
||||
ok,res=pcall(function() t:multi(i) end)
|
||||
if ok then
|
||||
print " that worked! Funny"
|
||||
else
|
||||
if swig_type(res)=="Exc *" then
|
||||
print(" call failed with Exc exception:",res.code,res.msg)
|
||||
else
|
||||
print(" call failed with error:",res)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
%include <luatypemaps.swg> /* The typemaps */
|
||||
%include <luaruntime.swg> /* The runtime stuff */
|
||||
|
||||
//%include <typemaps/swigmacros.swg>
|
||||
/* -----------------------------------------------------------------------------
|
||||
* constants typemaps
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
|
@ -154,51 +155,75 @@ Therefore currently its just enough to get a few test cases running ok
|
|||
note: if you wish to throw anything related to std::exception
|
||||
use %include <std_except.i> instead
|
||||
*/
|
||||
|
||||
// number as number+error
|
||||
%typemap(throws) int,unsigned int,signed int,
|
||||
long,unsigned long,signed long,
|
||||
short,unsigned short,signed short,
|
||||
bool,float,double,
|
||||
float,double,
|
||||
long long,unsigned long long,
|
||||
char, unsigned char, signed char,
|
||||
enum SWIGTYPE
|
||||
%{lua_pushfstring(L,"numeric exception:%f",(double)$1);SWIG_fail; %}
|
||||
unsigned char, signed char,
|
||||
int&,unsigned int&,signed int&,
|
||||
long&,unsigned long&,signed long&,
|
||||
short&,unsigned short&,signed short&,
|
||||
float&,double&,
|
||||
long long&,unsigned long long&,
|
||||
unsigned char&, signed char&
|
||||
%{lua_pushnumber(L,(lua_Number)$1);SWIG_fail; %}
|
||||
|
||||
%typemap(throws) bool,bool&
|
||||
%{lua_pushboolean(L,(int)($1==true));SWIG_fail; %}
|
||||
|
||||
// enum as number+error
|
||||
%typemap(throws) enum SWIGTYPE
|
||||
%{lua_pushnumber(L,(lua_Number)(int)$1);SWIG_fail; %}
|
||||
|
||||
// strings are just sent as errors
|
||||
%typemap(throws) char*, const char*
|
||||
%{lua_pushstring(L,$1);SWIG_fail;%}
|
||||
|
||||
// char is changed to a string
|
||||
%typemap(throws) char
|
||||
%{lua_pushfstring(L,"%c",$1);SWIG_fail;%}
|
||||
|
||||
/*
|
||||
Throwing object is a serious problem:
|
||||
Assuming some code throws a 'FooBar'
|
||||
There are a few options:
|
||||
- return a pointer to it: but its unclear how long this will last for.
|
||||
- return a copy of it: but not all objects are copyable
|
||||
(see exception_partial_info in the test suite for a case where you cannot)
|
||||
(see exception_partial_info in the test suite for a case where you cannot do this)
|
||||
- convert to a string & throw that
|
||||
its not so useful, but it works (this is more lua like).
|
||||
The third option (though not nice) is used
|
||||
For a more useful solution: see std_except for more details
|
||||
*/
|
||||
|
||||
// basic typemap for structs, classes, pointers & references
|
||||
// convert to string and error
|
||||
%typemap(throws) SWIGTYPE
|
||||
{
|
||||
(void)$1;
|
||||
lua_pushfstring(L,"object exception:%s",SWIG_TypePrettyName($1_descriptor));
|
||||
SWIG_fail;
|
||||
}
|
||||
|
||||
// old code: fails under exception_partial_info
|
||||
// if you have a function which throws a FooBar & you want SWIG to throw the actual object
|
||||
// then use
|
||||
// %apply SWIGTYPE BY_VAL {FooBar};
|
||||
%typemap(throws) SWIGTYPE BY_VAL
|
||||
{
|
||||
SWIG_NewPointerObj(L,(void *)new $1_ltype(($1_ltype &) $1),$&1_descriptor,1);
|
||||
SWIG_fail;
|
||||
}
|
||||
|
||||
%{(void)$1; /* ignore it */
|
||||
lua_pushfstring(L,"object exception:%s",SWIG_TypePrettyName($1_descriptor));
|
||||
SWIG_fail;%}
|
||||
|
||||
// code to make a copy of the object and return this
|
||||
// if you have a function which throws a FooBar & you want SWIG to return a copy of the object as its error
|
||||
// then use one of the below
|
||||
// %apply SWIGTYPE EXCEPTION_BY_VAL {FooBar};
|
||||
// %apply SWIGTYPE& EXCEPTION_BY_VAL {FooBar&}; // note: need & twice
|
||||
%typemap(throws) SWIGTYPE EXCEPTION_BY_VAL
|
||||
%{SWIG_NewPointerObj(L,(void *)new $1_ltype(($1_ltype &) $1),$&1_descriptor,1);
|
||||
SWIG_fail;%}
|
||||
|
||||
// similar for object reference
|
||||
// note: swig typemaps seem a little confused around here, therefore we use $basetype
|
||||
%typemap(throws) SWIGTYPE& EXCEPTION_BY_VAL
|
||||
%{SWIG_NewPointerObj(L,(void *)new $basetype($1),$1_descriptor,1);
|
||||
SWIG_fail;%}
|
||||
|
||||
|
||||
// note: no support for object pointers
|
||||
// its not clear how long the pointer is valid for, therefore not supporting it
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* extras
|
||||
|
|
|
|||
|
|
@ -73,15 +73,15 @@
|
|||
%{$1 = (lua_toboolean(L, $input)!=0);%}
|
||||
|
||||
%typemap(out) bool
|
||||
%{ lua_pushboolean(L,(int)$1); SWIG_arg++;%}
|
||||
%{ lua_pushboolean(L,(int)($1==true)); SWIG_arg++;%}
|
||||
|
||||
// for const bool&, SWIG treats this as a const bool* so we must dereference it
|
||||
%typemap(in,checkfn="lua_isboolean") const bool& (bool temp)
|
||||
%{temp=lua_toboolean(L, $input) ? true : false;
|
||||
%{temp=(lua_toboolean(L, $input)!=0);
|
||||
$1=&temp;%}
|
||||
|
||||
%typemap(out) const bool&
|
||||
%{ lua_pushboolean(L,(int)*$1); SWIG_arg++;%}
|
||||
%{ lua_pushboolean(L,(int)(*$1==true)); SWIG_arg++;%}
|
||||
|
||||
// strings (char* and char[])
|
||||
%typemap(in,checkfn="lua_isstring") const char*, char*
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ namespace std
|
|||
};
|
||||
}
|
||||
|
||||
// normally object whihc are thrown are returned to interpreter as errors
|
||||
// normally object which are thrown are returned to interpreter as errors
|
||||
// (which potentally may have problems if they are not copied)
|
||||
// therefore all classes based upon std::exception are converted to their strings & returned as errors
|
||||
%typemap(throws) std::bad_exception "SWIG_exception(SWIG_RuntimeError, $1.what());"
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ Not using: lua_tolstring() as this is only found in Lua 5.1 & not 5.0.2
|
|||
|
||||
// for throwing of any kind of string, string ref's and string pointers
|
||||
// we convert all to lua strings
|
||||
%typemap(throws) std::string,const std::string&
|
||||
%typemap(throws) std::string,std::string&,const std::string&
|
||||
%{ lua_pushlstring(L,$1.data(),$1.size()); SWIG_fail;%}
|
||||
%typemap(throws) std::string*,const std::string*
|
||||
%{ lua_pushlstring(L,$1->data(),$1->size()); SWIG_fail;%}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue