Improve argument type checking.

This commit is contained in:
James Roseborough
2008-07-17 18:49:43 +00:00
parent a18c16dabb
commit 06908c3b60
4 changed files with 196 additions and 31 deletions

View File

@@ -96,10 +96,10 @@ public class TableLib extends LFunction {
*/
case CONCAT: {
int n = vm.gettop();
LTable table = vm.totable(2);
LString sep = (n>=3? vm.tolstring(3): null);
int i = (n>=4? vm.tointeger(4): 1);
int j = (n>=5? vm.tointeger(5): table.luaLength());
LTable table = vm.checktable(2);
LString sep = (n>=3? vm.checklstring(3): null);
int i = (n>=4? vm.checkint(4): 1);
int j = (n>=5? vm.checkint(5): table.luaLength());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
for ( int k=i; k<=j; k++ ) {
LValue v = table.get(k);
@@ -119,8 +119,8 @@ public class TableLib extends LFunction {
case FOREACH:
case FOREACHI:
{
LTable table = vm.totable(2);
LFunction function = vm.tojavafunction(3);
LTable table = vm.checktable(2);
LFunction function = vm.checkfunction(3);
LValue result = table.foreach( vm, function, id==FOREACHI );
vm.resettop();
vm.pushlvalue( result );
@@ -132,7 +132,7 @@ public class TableLib extends LFunction {
* Get length of table t.
*/
case GETN: {
LTable table = vm.totable(2);
LTable table = vm.checktable(2);
vm.resettop();
vm.pushinteger(table.luaLength());
break;
@@ -146,10 +146,11 @@ public class TableLib extends LFunction {
*/
case INSERT: {
int n = vm.gettop();
LTable table = vm.totable(2);
int pos = (n>=4? vm.tointeger(3): 0);
LTable table = vm.checktable(2);
int pos = (n>=4? vm.checkint(3): 0);
LValue value = vm.topointer(-1);
table.luaInsertPos( pos, value );
vm.resettop();
break;
}
@@ -159,7 +160,7 @@ public class TableLib extends LFunction {
* indices. (To do its job this function does a linear traversal of the whole table.)
*/
case MAXN: {
LTable table = vm.totable(2);
LTable table = vm.checktable(2);
vm.resettop();
vm.pushlvalue( table.luaMaxN() );
break;
@@ -173,8 +174,8 @@ public class TableLib extends LFunction {
*/
case REMOVE: {
int n = vm.gettop();
LTable table = vm.totable(2);
int pos = (n>=3? vm.tointeger(3): 0);
LTable table = vm.checktable(2);
int pos = (n>=3? vm.checkint(3): 0);
vm.resettop();
LValue removed = table.luaRemovePos( pos );
if ( removed != LNil.NIL )
@@ -192,8 +193,8 @@ public class TableLib extends LFunction {
* The sort algorithm is not stable; that is, elements considered equal by the given order may have their relative positions changed by the sort.
*/
case SORT: {
LTable table = vm.totable(2);
LValue compare = vm.topointer(3);
LTable table = vm.checktable(2);
LValue compare = vm.checkfunction(3);
table.luaSort( vm, compare );
vm.resettop();
break;

View File

@@ -45,6 +45,13 @@ public class LNumber extends LValue {
*/
public abstract boolean isInteger();
/**
* In lua all numbers are strings !
*/
public boolean isString() {
return true;
}
/** Convert to a Byte value */
public Byte toJavaBoxedByte() {
return new Byte(toJavaByte());

View File

@@ -2614,14 +2614,14 @@ public class LuaState extends Lua {
// ================= Error Reporting Functions =================
/**
* Report an error with an argument.
*
* @param narg
* Stack index of the bad argument
* @param extramsg
* String to include in error message
*/
/**
* Report an error with an argument.
*
* @param narg
* Stack index of the bad argument
* @param extramsg
* String to include in error message
*/
public void argerror(int narg, String extramsg) {
// TODO: port ldebug.c and provide mode useful error messages.
error("bad argument #" + (narg - 1) + " (" + extramsg + ")");
@@ -2651,6 +2651,136 @@ public class LuaState extends Lua {
public void typerror(int narg, int typenum) {
typerror(narg, TYPE_NAMES[typenum]);
}
/**
* Checks whether the function has an argument of any type (including <b>nil</b>)
* at position <code>narg</code>.
* @param narg the argument number
* @throws LuaErrorException if there is no argument at position narg
*/
public void checkany(int narg) {
if ( gettop() < narg )
argerror(narg, "value expected");
}
/**
* Checks whether the function argument <code>narg</code> is a function and
* returns this function.
* @see LFunction
* @param narg the argument number
* @throws LuaErrorException if the value is not a function
* @return LFunction value if the argument is a function
*/
public LFunction checkfunction(int narg) {
return (LFunction) checktype(narg, Lua.LUA_TFUNCTION);
}
/**
* Checks whether the function argument <code>narg</code> is a number and
* returns this number cast to an <code>int</code>.
* @param narg the argument number
* @throws LuaErrorException if the number cannot be converted to an int
* @return int value if the argument is an int or can be converted to one
*/
public int checkint(int narg) {
LValue v = tolnumber(narg);
if ( ! v.isInteger() )
typerror(narg, Lua.LUA_TNUMBER);
return v.toJavaInt();
}
/**
* Checks whether the function argument <code>narg</code> is a number and
* returns this number cast to a <code>LInteger</code></a>.
* @see LInteger
* @param narg the argument number
* @throws LuaErrorException if the value cannot be converted to an int
* @return LInteger value if the argument is an int or can be converted to one
*/
public LInteger checkinteger(int narg) {
return LInteger.valueOf(checkint(narg));
}
/**
* Checks whether the function argument <code>narg</code> is a number and
* returns this number cast to a <code>long</code>.
* @param narg the argument number
* @throws LuaErrorException if the value cannot be converted to a long
* @return long value if the argument is a number or can be converted to long
*/
public long checklong(int narg) {
return checknumber(narg).toJavaLong();
}
/**
* Checks whether the function argument <code>narg</code> is a number and
* returns this number.
* @see LNumber
* @param narg the argument number
* @throws LuaErrorException if the value cannot be converted to a number
* @return LNumber value if the argument is a number or can be converted to one
*/
public LNumber checknumber(int narg) {
return (LNumber) checktype(narg, Lua.LUA_TTABLE);
}
/**
* Checks whether the function argument <code>narg</code> is a string and
* returns this string as a lua string.
* @see LString
* @param narg the argument number
* @throws LuaErrorException if the value cannot be converted to a string
* @return LString value if the argument is a string or can be converted to one
*/
public LString checklstring(int narg) {
LValue v = topointer(narg);
if ( ! v.isString() )
typerror(narg, Lua.LUA_TSTRING);
return v.luaAsString();
}
/**
* Checks whether the function argument <code>narg</code> is a string and
* returns this string as a Java String.
* @param narg the argument number
* @throws LuaErrorException if the value cannot be converted to a string
* @return String value if the argument is a string or can be converted to one
*/
public String checkstring(int narg) {
LValue v = topointer(narg);
if ( ! v.isString() )
typerror(narg, Lua.LUA_TSTRING);
return v.toJavaString();
}
/**
* Checks whether the function argument <code>narg</code> is a table and
* returns this table.
* @see LTable
* @param narg the argument number
* @throws LuaErrorException if the value is not a table
* @return LTable value if the argument is a table
*/
public LTable checktable(int narg) {
return (LTable) checktype(narg, Lua.LUA_TTABLE);
}
/**
* Checks whether the function argument <code>narg</code> has type
* <code>t</code> and return it as an LValue.
* @param narg the argument number
* @param t the type number to check against
* @return the lua value
* @throws LuaErrorException if the value is not of type t
*/
public LValue checktype(int narg, int t) {
LValue v = topointer(narg);
if ( v.luaGetType() != t )
typerror(narg, t);
return v;
}
/**
* Check that the type of userdata on the stack matches the required type,

View File

@@ -52,14 +52,40 @@ local structtypes = {
['userdata']='<userdata>',
}
local function signature(name,arglist)
local function bracket(v)
return "<"..type(v)..">"
end
local function quote(v)
return "'"..v.."'"
end
local function ellipses(v)
local s = tostring(v)
return #s <= 8 and s or string.sub(s,8)..'...'
end
local pretty = {
['table']=bracket,
['function']=bracket,
['thread']=bracket,
['userdata']=bracket,
['string']= quote,
['number']= ellipses,
}
local function values(list)
local t = {}
for i=1,#arglist do
local ai = arglist[i]
local ti = type(ai)
t[i] = structtypes[ti] or tostring(ai)
for i=1,#list do
local ai = list[i]
local fi = pretty[type(ai)]
t[i] = fi and fi(ai) or tostring(ai)
end
return name..'('..table.concat(t,',')..')'
return table.concat(t,',')
end
local function signature(name,arglist)
return name..'('..values(arglist)..')'
end
local function dup(t)
@@ -123,11 +149,12 @@ function checkallpass( name, typesets )
subbanner('checkallpass')
for i,v in arglists(typesets) do
local sig = signature(name,v)
local s,e = invoke( name, v )
local r = { invoke( name, v ) }
local s = table.remove( r, 1 )
if s then
print( ok, sig )
print( ok, sig, values(r) )
else
print( fail, sig, e )
print( fail, sig, values(r) )
end
end
end