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:
William S Fulton 2005-09-20 20:57:30 +00:00
commit bf48768e04
5 changed files with 442 additions and 0 deletions

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

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