Lua improvements - Mark Gossage patch #1295168
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@7476 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
parent
b4a56ba679
commit
bf48768e04
5 changed files with 442 additions and 0 deletions
104
Examples/test-suite/lua/li_std_string_runme.lua
Normal file
104
Examples/test-suite/lua/li_std_string_runme.lua
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
require("import") -- the import fn
|
||||||
|
import("li_std_string") -- import lib
|
||||||
|
|
||||||
|
for k,v in pairs(li_std_string) do _G[k]=v end -- move to global
|
||||||
|
|
||||||
|
-- catch "undefined" global variables
|
||||||
|
setmetatable(getfenv(),{__index=function (t,i) error("undefined global variable `"..i.."'",2) end})
|
||||||
|
|
||||||
|
-- helper to check type
|
||||||
|
function is_std_string(s)
|
||||||
|
return type(s)=='userdata' and swig_type(s)=='_p_std__string'
|
||||||
|
end
|
||||||
|
|
||||||
|
-- std::string by value is just a Lua string
|
||||||
|
s=test_value("foo")
|
||||||
|
assert(type(s)=="string" and s=="foo")
|
||||||
|
|
||||||
|
-- std::string by const ref is also just a Lua string
|
||||||
|
s=test_const_reference("foo")
|
||||||
|
assert(type(s)=="string" and s=="foo")
|
||||||
|
|
||||||
|
-- std:string* is an object
|
||||||
|
obj=test_pointer_out()
|
||||||
|
assert(is_std_string(obj) and obj:c_str()=="x") -- check type & value
|
||||||
|
|
||||||
|
test_pointer(obj) -- this wants an object
|
||||||
|
|
||||||
|
cobj=test_const_pointer_out()
|
||||||
|
assert(is_std_string(cobj) and cobj:c_str()=="x") -- check type & value
|
||||||
|
|
||||||
|
test_const_pointer(cobj)
|
||||||
|
|
||||||
|
-- this shouldnt work, but it does
|
||||||
|
-- swig doesnt appear to diff between const object ptrs & object ptrs very well
|
||||||
|
test_pointer(cobj) -- this wants an non const object (give it a const one!)
|
||||||
|
|
||||||
|
-- refs are also wrappered as ptrs (unless the correct typemaps are applied)
|
||||||
|
robj=test_reference_out()
|
||||||
|
assert(is_std_string(robj) and robj:c_str()=="test_reference_out message") -- check type & value
|
||||||
|
|
||||||
|
test_reference(robj)
|
||||||
|
test_reference(obj) -- object ptr is ok
|
||||||
|
test_reference(cobj) -- obj const ptr is also ok
|
||||||
|
|
||||||
|
-- throwing string
|
||||||
|
ok,ex=pcall(test_throw)
|
||||||
|
assert(ok==false and type(ex)=="string") -- failed & threw string
|
||||||
|
|
||||||
|
ok,ex=pcall(test_const_reference_throw)
|
||||||
|
assert(ok==false and type(ex)=="string") -- failed & threw string
|
||||||
|
|
||||||
|
-- const ptrs are thrown as str::string**
|
||||||
|
-- not quite right
|
||||||
|
ok,ex=pcall(test_const_pointer_throw)
|
||||||
|
assert(ok==false and type(ex)=="userdata") -- failed & threw object
|
||||||
|
|
||||||
|
-- ditto non const ptrs
|
||||||
|
ok,ex=pcall(test_pointer_throw)
|
||||||
|
assert(ok==false and type(ex)=="userdata") -- failed & threw object
|
||||||
|
|
||||||
|
-- testing the structure:
|
||||||
|
|
||||||
|
s=Structure()
|
||||||
|
|
||||||
|
-- because of the SWIG's 'everything else is a ptr'
|
||||||
|
-- member strings are a little unusal
|
||||||
|
assert(is_std_string(s.MemberString)) -- std::string*
|
||||||
|
assert(type(s.MemberString2)=="string") -- typemaps make this a string
|
||||||
|
assert(is_std_string(s.ConstMemberString)) -- std::string*
|
||||||
|
|
||||||
|
-- set them
|
||||||
|
s.MemberString:assign("a") -- as its std::string* must use assign
|
||||||
|
s.MemberString2="b" -- typemaps ok
|
||||||
|
s.ConstMemberString="c" -- silently ignored
|
||||||
|
s.ConstMemberString:assign("c") -- works (oops!!!)
|
||||||
|
--print(s.MemberString:data(),s.MemberString2,s.ConstMemberString:data())
|
||||||
|
|
||||||
|
--check type again
|
||||||
|
assert(is_std_string(s.MemberString)) -- std::string*
|
||||||
|
assert(type(s.MemberString2)=="string") -- typemaps make this a string
|
||||||
|
assert(is_std_string(s.ConstMemberString)) -- std::string*
|
||||||
|
|
||||||
|
-- for static types: they are really variables,
|
||||||
|
-- so we must still use the module name
|
||||||
|
|
||||||
|
-- check static type
|
||||||
|
assert(is_std_string(li_std_string.Structure_StaticMemberString))
|
||||||
|
assert(type(li_std_string.Structure_StaticMemberString2)=="string")
|
||||||
|
assert(is_std_string(li_std_string.Structure_ConstStaticMemberString))
|
||||||
|
|
||||||
|
-- try setting
|
||||||
|
li_std_string.Structure_StaticMemberString:assign('d')
|
||||||
|
li_std_string.Structure_StaticMemberString2='e'
|
||||||
|
li_std_string.Structure_ConstStaticMemberString='f' -- silently ignored
|
||||||
|
li_std_string.Structure_ConstStaticMemberString:assign('f') -- works (oops!!!)
|
||||||
|
--[[print(li_std_string.Structure_StaticMemberString:data(),
|
||||||
|
li_std_string.Structure_StaticMemberString2,
|
||||||
|
li_std_string.Structure_ConstStaticMemberString:data())]]
|
||||||
|
|
||||||
|
-- check static type again
|
||||||
|
assert(is_std_string(li_std_string.Structure_StaticMemberString))
|
||||||
|
assert(type(li_std_string.Structure_StaticMemberString2)=="string")
|
||||||
|
assert(is_std_string(li_std_string.Structure_ConstStaticMemberString))
|
||||||
|
|
||||||
66
Examples/test-suite/lua/li_std_vector_runme.lua
Normal file
66
Examples/test-suite/lua/li_std_vector_runme.lua
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
require("import") -- the import fn
|
||||||
|
import("li_std_vector") -- import code
|
||||||
|
|
||||||
|
for k,v in pairs(li_std_vector) do _G[k]=v end -- move to global
|
||||||
|
|
||||||
|
iv = IntVector(4)
|
||||||
|
for i=0,3 do
|
||||||
|
iv[i] = i
|
||||||
|
end
|
||||||
|
|
||||||
|
for i=0,3 do assert(iv[i]==i) end
|
||||||
|
|
||||||
|
x = average(iv)
|
||||||
|
|
||||||
|
function near(x,y) return math.abs(x-y)<0.001 end
|
||||||
|
|
||||||
|
assert(near(x,1.5))
|
||||||
|
|
||||||
|
rv = RealVector()
|
||||||
|
rv:push_back(10)
|
||||||
|
rv:push_back(10.5)
|
||||||
|
rv:push_back(11)
|
||||||
|
rv:push_back(11.5)
|
||||||
|
|
||||||
|
a=half(rv)
|
||||||
|
for i=0,rv:size()-1 do
|
||||||
|
assert(near(a[i],rv[i]/2))
|
||||||
|
end
|
||||||
|
|
||||||
|
dv = DoubleVector(10)
|
||||||
|
for i=0,9 do dv[i] = i/2.0 end
|
||||||
|
|
||||||
|
halve_in_place(dv)
|
||||||
|
|
||||||
|
for i=0,9 do
|
||||||
|
assert(near(dv[i],i/4))
|
||||||
|
end
|
||||||
|
|
||||||
|
sv=StructVector(4)
|
||||||
|
|
||||||
|
for i=0,3 do
|
||||||
|
sv[i]=Struct(i)
|
||||||
|
end
|
||||||
|
|
||||||
|
for i=0,3 do
|
||||||
|
assert( swig_type(sv[i]) =='_p_Struct' and sv[i].num==i)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- range checking
|
||||||
|
idx=0
|
||||||
|
function test_set() iv[idx]=0 end
|
||||||
|
function test_get() iv[idx]=0 end
|
||||||
|
|
||||||
|
idx=0 --ok
|
||||||
|
assert(pcall(test_get)==true)
|
||||||
|
assert(pcall(test_set)==true)
|
||||||
|
idx=-1 --should error
|
||||||
|
assert(pcall(test_get)==false)
|
||||||
|
assert(pcall(test_set)==false)
|
||||||
|
idx=3 --ok
|
||||||
|
assert(pcall(test_get)==true)
|
||||||
|
assert(pcall(test_set)==true)
|
||||||
|
idx=4 --should error
|
||||||
|
assert(pcall(test_get)==false)
|
||||||
|
assert(pcall(test_set)==false)
|
||||||
|
|
||||||
17
Lib/lua/std_except.i
Normal file
17
Lib/lua/std_except.i
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
// Typemaps used by the STL wrappers that throw exceptions.
|
||||||
|
// These typemaps are used when methods are declared with an STL exception specification, such as
|
||||||
|
// size_t at() const throw (std::out_of_range);
|
||||||
|
|
||||||
|
%{
|
||||||
|
#include <stdexcept>
|
||||||
|
%}
|
||||||
|
%include "exception.i"
|
||||||
|
|
||||||
|
%typemap(throws) std::out_of_range %{
|
||||||
|
SWIG_exception(SWIG_IndexError, $1.what()); %}
|
||||||
|
|
||||||
|
%typemap(throws) std::exception %{
|
||||||
|
SWIG_exception(SWIG_SystemError, $1.what()); %}
|
||||||
|
|
||||||
|
%typemap(throws) std::exception& %{
|
||||||
|
SWIG_exception(SWIG_SystemError, ($1)->what()); %}
|
||||||
122
Lib/lua/std_string.i
Normal file
122
Lib/lua/std_string.i
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
/***********************************************************************
|
||||||
|
* std_string.i
|
||||||
|
*
|
||||||
|
* std::string typemaps for LUA
|
||||||
|
*
|
||||||
|
* Author : Mark Gossage (mark@gossage.cjb.net)
|
||||||
|
************************************************************************/
|
||||||
|
|
||||||
|
%{
|
||||||
|
#include <string>
|
||||||
|
%}
|
||||||
|
/*
|
||||||
|
Only std::string and const std::string& are typemaped
|
||||||
|
they are converted to the Lua strings automatically
|
||||||
|
|
||||||
|
eg.
|
||||||
|
|
||||||
|
std::string test_value(std::string x) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
can be used as
|
||||||
|
|
||||||
|
s="hello world"
|
||||||
|
s2=test_value(s)
|
||||||
|
assert(s==s2)
|
||||||
|
|
||||||
|
*/
|
||||||
|
%typemap(in,checkfn="lua_isstring") std::string
|
||||||
|
%{$1 = (char*)lua_tostring(L, $input);%}
|
||||||
|
|
||||||
|
%typemap(out) std::string
|
||||||
|
%{ lua_pushstring(L,$1.c_str()); SWIG_arg++;%}
|
||||||
|
|
||||||
|
%typemap(in,checkfn="lua_isstring") const std::string& (std::string temp)
|
||||||
|
%{temp=(char*)lua_tostring(L, $input); $1=&temp;%}
|
||||||
|
%typemap(out) const std::string&
|
||||||
|
%{ lua_pushstring(L,$1->c_str()); SWIG_arg++;%}
|
||||||
|
|
||||||
|
%typemap(throws) std::string,const std::string&
|
||||||
|
%{lua_pushstring(L,$1.c_str());
|
||||||
|
SWIG_fail; %}
|
||||||
|
|
||||||
|
/*
|
||||||
|
std::string& can be wrappered, but you must inform SWIG if it is in or out
|
||||||
|
|
||||||
|
eg:
|
||||||
|
void fn(std::string& str);
|
||||||
|
Is this an in/out/inout value?
|
||||||
|
|
||||||
|
Therefore you need the usual
|
||||||
|
%apply (std::string& INOUT) {(std::string& str)};
|
||||||
|
or
|
||||||
|
%apply std::string& INOUT {std::string& str};
|
||||||
|
typemaps to tell SWIG what to do.
|
||||||
|
*/
|
||||||
|
|
||||||
|
%typemap(in) std::string &INPUT=const std::string &;
|
||||||
|
%typemap(in, numinputs=0) std::string &OUTPUT (std::string temp)
|
||||||
|
%{ $1 = &temp; %}
|
||||||
|
%typemap(argout) std::string &OUTPUT
|
||||||
|
%{ lua_pushstring(L,$1.c_str()); SWIG_arg++;%}
|
||||||
|
%typemap(in) std::string &INOUT =const std::string &;
|
||||||
|
%typemap(argout) std::string &INOUT = std::string &OUTPUT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
For const std::string* and std::string* is not clear
|
||||||
|
is this a pointer or an array?
|
||||||
|
|
||||||
|
Therefore just leaving it as is
|
||||||
|
(there is some rough code below which could be used if needed
|
||||||
|
|
||||||
|
// SWIG wraps const ref's as pointer
|
||||||
|
// typemaps to deal with this and const ptrs
|
||||||
|
%typemap(in,checkfn="lua_isstring")
|
||||||
|
const std::string& INPUT(std::string temp),
|
||||||
|
const std::string* INPUT(std::string temp)
|
||||||
|
%{temp=(char*)lua_tostring(L, $input); $1=&temp;%}
|
||||||
|
%typemap(out) const std::string&, const std::string*
|
||||||
|
%{ lua_pushstring(L,$1->c_str()); SWIG_arg++;%}
|
||||||
|
|
||||||
|
// the non-const pointer version
|
||||||
|
%typemap(in) std::string *INPUT=const std::string *INPUT;
|
||||||
|
%typemap(in, numinputs=0) std::string *OUTPUT (std::string temp)
|
||||||
|
%{ $1 = &temp; %}
|
||||||
|
%typemap(argout) std::string *OUTPUT
|
||||||
|
%{ lua_pushstring(L,$1->c_str()); SWIG_arg++;%}
|
||||||
|
%typemap(in) std::string *INOUT = std::string *INPUT;
|
||||||
|
%typemap(argout) std::string *INOUT = std::string *OUTPUT;
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
A really cut down version of the string class
|
||||||
|
|
||||||
|
This provides basic mapping of lua strings <-> std::string
|
||||||
|
and little else
|
||||||
|
(the std::string has a lot of unneeded functions anyway)
|
||||||
|
|
||||||
|
*/
|
||||||
|
namespace std {
|
||||||
|
|
||||||
|
class string {
|
||||||
|
public:
|
||||||
|
string();
|
||||||
|
string(const char*);
|
||||||
|
string(const string&);
|
||||||
|
unsigned int size() const;
|
||||||
|
unsigned int length() const;
|
||||||
|
bool empty() const;
|
||||||
|
// no support for operator[]
|
||||||
|
const char* c_str()const;
|
||||||
|
const char* data()const;
|
||||||
|
// assign does not return a copy of this object
|
||||||
|
// (no point in a scripting language)
|
||||||
|
void assign(const char*);
|
||||||
|
void assign(const string&);
|
||||||
|
// no support for all the other features
|
||||||
|
// its probably better to do it in lua
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
133
Lib/lua/std_vector.i
Normal file
133
Lib/lua/std_vector.i
Normal file
|
|
@ -0,0 +1,133 @@
|
||||||
|
/***********************************************************************
|
||||||
|
* std_vector.i
|
||||||
|
*
|
||||||
|
* std::vector typemaps for LUA
|
||||||
|
*
|
||||||
|
* Author : Mark Gossage (mark@gossage.cjb.net)
|
||||||
|
************************************************************************/
|
||||||
|
|
||||||
|
%{
|
||||||
|
#include <vector>
|
||||||
|
%}
|
||||||
|
%include <std_except.i> // the general exepctions
|
||||||
|
/*
|
||||||
|
A really cut down version of the vector class.
|
||||||
|
|
||||||
|
Note: this does not match the true std::vector class
|
||||||
|
but instead is an approximate, so that SWIG knows how to wrapper it.
|
||||||
|
(Eg, all access is by value, not ref, as SWIG turns refs to pointers)
|
||||||
|
|
||||||
|
And no support for iterators & insert/erase
|
||||||
|
|
||||||
|
It would be useful to have a vector<->Lua table conversion routine
|
||||||
|
|
||||||
|
*/
|
||||||
|
namespace std {
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
class vector {
|
||||||
|
public:
|
||||||
|
vector();
|
||||||
|
vector(unsigned int);
|
||||||
|
vector(const vector&);
|
||||||
|
vector(unsigned int,T);
|
||||||
|
unsigned int size() const;
|
||||||
|
unsigned int max_size() const;
|
||||||
|
bool empty() const;
|
||||||
|
void clear();
|
||||||
|
void push_back(T val);
|
||||||
|
void pop_back();
|
||||||
|
T front()const; // only read front & back
|
||||||
|
T back()const; // not write to them
|
||||||
|
// operator [] given later:
|
||||||
|
|
||||||
|
%extend // this is a extra bit of SWIG code
|
||||||
|
{
|
||||||
|
// [] is replaced by __getitem__ & __setitem__
|
||||||
|
// simply throws a string, which causes a lua error
|
||||||
|
T __getitem__(unsigned int idx) throw (std::out_of_range)
|
||||||
|
{
|
||||||
|
if (idx>=self->size())
|
||||||
|
throw std::out_of_range("in vector::__getitem__()");
|
||||||
|
return (*self)[idx];
|
||||||
|
}
|
||||||
|
void __setitem__(unsigned int idx,T val) throw (std::out_of_range)
|
||||||
|
{
|
||||||
|
if (idx>=self->size())
|
||||||
|
throw std::out_of_range("in vector::__setitem__()");
|
||||||
|
(*self)[idx]=val;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Vector<->LuaTable fns
|
||||||
|
These look a bit like the array<->LuaTable fns
|
||||||
|
but are templated, not %defined
|
||||||
|
(you must have template support for STL)
|
||||||
|
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
%{
|
||||||
|
// reads a table into a vector of numbers
|
||||||
|
// lua numbers will be cast into the type required (rounding may occur)
|
||||||
|
// return 0 if non numbers found in the table
|
||||||
|
// returns new'ed ptr if ok
|
||||||
|
template<class T>
|
||||||
|
std::vector<T>* SWIG_read_number_vector(lua_State* L,int index)
|
||||||
|
{
|
||||||
|
int i=0;
|
||||||
|
std::vector<T>* vec=new std::vector<T>();
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
lua_rawgeti(L,index,i+1);
|
||||||
|
if (!lua_isnil(L,-1))
|
||||||
|
{
|
||||||
|
lua_pop(L,1);
|
||||||
|
break; // finished
|
||||||
|
}
|
||||||
|
if (!lua_isnumber(L,-1))
|
||||||
|
{
|
||||||
|
lua_pop(L,1);
|
||||||
|
delete vec;
|
||||||
|
return 0; // error
|
||||||
|
}
|
||||||
|
vec->push_back((T)lua_tonumber(L,-1));
|
||||||
|
lua_pop(L,1);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return vec; // ok
|
||||||
|
}
|
||||||
|
// writes a vector of numbers out as a lua table
|
||||||
|
template<class T>
|
||||||
|
int SWIG_write_number_vector(lua_State* L,std::vector<T> *vec)
|
||||||
|
{
|
||||||
|
lua_newtable(L);
|
||||||
|
for(int i=0;i<vec->size();++i)
|
||||||
|
{
|
||||||
|
lua_pushnumber(L,(double)((*vec)[i]));
|
||||||
|
lua_rawseti(L,-2,i+1);// -1 is the number, -2 is the table
|
||||||
|
}
|
||||||
|
}
|
||||||
|
%}
|
||||||
|
|
||||||
|
// then the typemaps
|
||||||
|
|
||||||
|
%define SWIG_TYPEMAP_NUM_VECTOR(T)
|
||||||
|
|
||||||
|
// in
|
||||||
|
%typemap(in) std::vector<T> *INPUT
|
||||||
|
%{ $1 = SWIG_read_number_vector<T>(L,$input);
|
||||||
|
if (!$1) SWIG_fail;%}
|
||||||
|
|
||||||
|
%typemap(freearg) std::vector<T> *INPUT
|
||||||
|
%{ delete $1;%}
|
||||||
|
|
||||||
|
// out
|
||||||
|
%typemap(argout) std::vector<T> *OUTPUT
|
||||||
|
%{ SWIG_write_number_vector(L,$1); SWIG_arg++; %}
|
||||||
|
|
||||||
|
%enddef
|
||||||
|
*/
|
||||||
Loading…
Add table
Add a link
Reference in a new issue