diff --git a/CHANGES.current b/CHANGES.current index 0ddd92cc5..9410e51bd 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -1,6 +1,11 @@ Version 1.3.37 (30 December 2008) ================================= +2009-01-13: mgossage + [Lua] Added contract support for requiring that unsigned numbers are >=0 + Rewrote much of Examples/Lua/embed3. + Added a lot of to the Lua documentation. + 2009-01-12: drjoe Fixed handling of integer arrays diff --git a/Doc/Manual/Lua.html b/Doc/Manual/Lua.html index 99c7c9a3c..e5fc8217a 100644 --- a/Doc/Manual/Lua.html +++ b/Doc/Manual/Lua.html @@ -34,14 +34,29 @@
-SWIG is able to throw numeric types, enums, chars, char*'s and std::string's without problem. -However its not so simple for to throw objects. +SWIG is able to throw numeric types, enums, chars, char*'s and std::string's without problem. It has also written typemaps for std::exception and its derived classes, which convert the exception into and error string.
++However its not so simple for to throw other types of 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 @@ -1038,10 +1054,6 @@ To get a more useful behaviour out of SWIG you must either: provide a way to con throw objects which can be copied.
-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. -
-If you have your own class which you want output as a string you will need to add a typemap something like this:
@@ -1098,8 +1110,259 @@ add exception specification to functions or globally (respectively). -23.3.16 Writing your own custom wrappers
+23.4 Typemaps
+This section explains what typemaps are and the usage of them. The default wrappering behaviour of SWIG is enough in most cases. However sometimes SWIG may need a little additional assistance to know which typemap to apply to provide the best wrappering. This section will be explaining how to use typemaps to best effect
+ +23.4.1 What is a typemap?
+ +A typemap is nothing more than a code generation rule that is attached to a specific C datatype. For example, to convert integers from Lua to C, you might define a typemap like this:
+ ++ +%module example + +%typemap(in) int { + $1 = (int) lua_tonumber(L,$input); + printf("Received an integer : %d\n",$1); +} +%inline %{ +extern int fact(int n); +%} +Note: you shouldn't use this typemap, as SWIG already has a typemap for this task. This is purely for example.
+ +Typemaps are always associated with some specific aspect of code generation. In this case, the "in" method refers to the conversion of input arguments to C/C++. The datatype int is the datatype to which the typemap will be applied. The supplied C code is used to convert values. In this code a number of special variable prefaced by a $ are used. The $1 variable is placeholder for a local variable of type int. The $input is the index on the Lua stack for the value to be used.
+ +When this example is compiled into a Lua module, it operates as follows:
+ ++ +> require "example" +> print(example.fact(6)) +Received an integer : 6 +720 +23.4.2 Using typemaps
+ +There are many ready written typemaps built into SWIG for all common types (int, float, short, long, char*, enum and more), which SWIG uses automatically, with no effort required on your part.
+ +However for more complex functions which use input/output parameters or arrays, you will need to make use of <typemaps.i>, which contains typemaps for these situations. For example, consider these functions:
+ ++ +void add(int x, int y, int *result) { + *result = x + y; +} + +int sub(int *x1, int *y1) { + return *x1-*y1; +} + +void swap(int *sx, int *sy) { + int t=*sx; + *sx=*sy; + *sy=t; +} +It is clear to the programmer, that 'result' is an output parameter, 'x1' and 'y1' are input parameters and 'sx' and 'sy' are input/output parameters. However is not apparent to SWIG, so SWIG must to informed about which kind they are, so it can wrapper accordingly.
+ +One means would be to rename the argument name to help SWIG, eg void add(int x, int y, int *OUTPUT), however it is easier to use the %apply to achieve the same result, as shown below.
+ ++ +%include <typemaps.i> +%apply int* OUTPUT {int *result}; // int *result is output +%apply int* INPUT {int *x1, int *y1}; // int *x1 and int *y1 are input +%apply int* INOUT {int *sx, int *sy}; // int *sx and int *sy are input and output + +void add(int x, int y, int *result); +int sub(int *x1, int *y1); +void swap(int *sx, int *sy); +When wrapped, it gives the following results:
+ ++ +> require "example" +> print(example.add(1,2)) +3 +> print(demo.sub(1,2)) +-1 +> a,b=1,2 +> c,d=demo.swap(a,b) +> print(a,b,c,d) +1 2 2 1 +Notice, that 'result' is not required in the arguments to call the function, as it an output parameter only. For 'sx' and 'sy' they must be passed in (as they are input), but the original value is not modified (Lua does not have a pass by reference feature). The modified results are then returned as two return values. All INPUT/OUTPUT/INOUT arguments will behave in a similar manner.
+ +Note: C++ references must be handled exactly the same way. However SWIG will automatically wrap a const int& as an input parameter (since that it obviously input).
+ +23.4.3 Typemaps and arrays
+ +Arrays present a challenge for SWIG, because like pointers SWIG does not know whether these are input or output values, nor +does SWIG have any indication of how large an array should be. However with the proper guidance SWIG can easily wrapper +arrays for convenient usage.
+ +Given the functions:
++ +extern void sort_int(int* arr, int len); +extern void sort_double(double* arr, int len); +There are basically two ways that SWIG can deal with this. The first way, uses the <carrays.i> library +to create an array in C/C++ then this can be filled within Lua and passed into the function. It works, but its a bit tedious. +More details can be found in the carrays.i documention.
+ +The second and more intuitive way, would be to pass a Lua table directly into the function, and have SWIG automatically convert between Lua-table and C-array. Within the <typemaps.i> file there are typemaps ready written to perform this task. To use them is again a matter of using %appy in the correct manner.
+ +The wrapper file below, shows both the use of carrays as well as the use of the typemap to wrap arrays.
+ ++ +// using the C-array +%include <carrays.i> +// this declares a batch of function for manipulating C integer arrays +%array_functions(int,int) + +extern void sort_int(int* arr, int len); // the function to wrap + +// using typemaps +%include <typemaps.i> +%apply (double *INOUT,int) {(double* arr,int len)}; + +extern void sort_double(double* arr, int len); // the function to wrap +Once wrappered, the functions can both be called, though with different ease of use:
+ ++ +require "example" +ARRAY_SIZE=10 + +-- passing a C array to the sort_int() +arr=example.new_int(ARRAY_SIZE) -- create the array +for i=0,ARRAY_SIZE-1 do -- index 0..9 (just like C) + example.int_setitem(arr,i,math.random(1000)) +end +example.sort_int(arr,ARRAY_SIZE) -- call the function +example.delete_int(arr) -- must delete the allocated memory + +-- use a typemap to call with a Lua-table +-- one item of note: the typemap creates a copy, rather than edit-in-place +t={} -- a Lua table +for i=1,ARRAY_SIZE do -- index 1..10 (Lua style) + t[i]=math.random(1000)/10 +end +t=example.sort_double(t) -- replace t with the result +Obviously the first version could be made less tedious by writing a Lua function to perform the conversion from a table +to a C-array. The %luacode directive is good for this. See SWIG\Examples\lua\arrays for an example of this.
+ +Warning: in C indexes start at ZERO, in Lua indexes start at ONE. SWIG expects C-arrays to be filled for 0..N-1 +and Lua tables to be 1..N, (the indexing follows the norm for the language). In the typemap when it converts the table to an array it quietly changes the indexing accordingly. Take note of this behaviour if you have a C function which returns indexes.
+ +Note: SWIG also can support arrays of pointers in a similar manner.
+ +23.4.4 Typemaps and pointer-pointer functions
+ +Several C++ libraries use a pointer-pointer functions to create its objects. These functions require a pointer to a pointer which is then filled with the pointer to the new object. Microsoft's COM and DirectX as well as many other libraries have this kind of function. An example is given below:
+ ++ +struct iMath; // some structure +int Create_Math(iMath** pptr); // its creator (assume it mallocs) +Which would be used with the following C code:
+ ++ +iMath* ptr; +int ok; +ok=Create_Math(&ptr); +// do things with ptr +//... +free(ptr); // dispose of iMath +SWIG has a ready written typemap to deal with such a kind of function in <typemaps.i>. It provides the correct wrappering as well as setting the flag to inform Lua that the object in question should be garbage collected. Therefore the code is simply:
+ ++ +%include <typemaps.i> +%apply SWIGTYPE** OUTPUT{iMath **pptr }; // tell SWIG its an output + +struct iMath; // some structure +int Create_Math(iMath** pptr); // its creator (assume it mallocs) +The usage is as follows:
+ ++ +ok,ptr=Create_Math() -- ptr is a iMath* which is returned with the int (ok) +ptr=nil -- the iMath* will be GC'ed as normal +23.5 Writing typemaps
+ +This section describes how you can modify SWIG's default wrapping behavior for various C/C++ datatypes using the %typemap directive. This is an advanced topic that assumes familiarity with the Lua C API as well as the material in the "Typemaps" chapter.
+ +Before proceeding, it should be stressed that writing typemaps is rarely needed unless you want to change some aspect of the wrappering, or to achieve an effect which in not available with the default bindings.
+ +Before proceeding, you should read the previous section on using typemaps, as well as read the ready written typemaps found in luatypemaps.swg and typemaps.i. These are both well documented and fairly easy to read. You should not attempt to write your own typemaps until you have read and can understand both of these files (they may well also give you a idea to base your worn on).
+ +23.5.1 Typemaps you can write
+ +There are many different types of typemap that can be written, the full list can be found in the "Typemaps" chapter. However the following are the most commonly used ones.
+ +
This section explains the SWIG specific Lua-C API. It does not cover the main Lua-C api, as this is well documented and not worth covering.
+ +int SWIG_ConvertPtr(lua_State* L,int index,void** ptr,swig_type_info *type,int flags);
+ +void SWIG_NewPointerObj(lua_State* L,void* ptr,swig_type_info *type,int own);
+ +void* SWIG_MustGetPtr(lua_State* L,int index,swig_type_info *type,int flags,int argnum,const char* func_name);
+ +SWIG_fail
+ +
+if (!SWIG_IsOK(SWIG_ConvertPtr( .....)){
+ lua_pushstring(L,"something bad happened");
+ SWIG_fail;
+}SWIG_fail_arg(char* func_name,int argnum,char* type)
+ +SWIG_fail_ptr(const char* fn_name,int argnum,swig_type_info* type);
+ ++This section covers adding of some small extra bits to your module to add the last finishing touches. +
+ + + +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 %native directive as follows: @@ -1117,7 +1380,7 @@ int native_function(lua_State*L) // my native code The %native directive in the above example, tells SWIG that there is a function int native_function(lua_State*L); which is to be added into the module under the name 'my_func'. 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.
-@@ -1155,7 +1418,7 @@ Good uses for this feature is adding of new code, or writing helper functions to See Examples/lua/arrays for an example of this code.
-@@ -1166,7 +1429,7 @@ See Examples/lua/arrays for an example of this code.
-@@ -1226,7 +1489,7 @@ end
That way when you call 'a=example.Foo', 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 'example.Foo=10', 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)'.
-@@ -1306,7 +1569,7 @@ Note: Both the opaque structures (like the FILE*) and normal wrappered classes/s
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.
-
diff --git a/Examples/lua/embed3/embed3.cpp b/Examples/lua/embed3/embed3.cpp
index c2424f9af..e5e0e0a7d 100644
--- a/Examples/lua/embed3/embed3.cpp
+++ b/Examples/lua/embed3/embed3.cpp
@@ -26,7 +26,12 @@ extern "C" {
#include