diff --git a/src/core/org/luaj/lib/TableLib.java b/src/core/org/luaj/lib/TableLib.java
index b502cd67..13eab744 100644
--- a/src/core/org/luaj/lib/TableLib.java
+++ b/src/core/org/luaj/lib/TableLib.java
@@ -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;
diff --git a/src/core/org/luaj/vm/LNumber.java b/src/core/org/luaj/vm/LNumber.java
index 457064d2..759b0caf 100644
--- a/src/core/org/luaj/vm/LNumber.java
+++ b/src/core/org/luaj/vm/LNumber.java
@@ -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());
diff --git a/src/core/org/luaj/vm/LuaState.java b/src/core/org/luaj/vm/LuaState.java
index 7644148d..85710455 100644
--- a/src/core/org/luaj/vm/LuaState.java
+++ b/src/core/org/luaj/vm/LuaState.java
@@ -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 nil)
+ * at position narg.
+ * @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 narg 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 narg is a number and
+ * returns this number cast to an int.
+ * @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 narg is a number and
+ * returns this number cast to a LInteger.
+ * @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 narg is a number and
+ * returns this number cast to a long.
+ * @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 narg 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 narg 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 narg 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 narg 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 narg has type
+ * t 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,
diff --git a/src/test/errors/args.lua b/src/test/errors/args.lua
index a935a8ed..33dc636e 100644
--- a/src/test/errors/args.lua
+++ b/src/test/errors/args.lua
@@ -52,14 +52,40 @@ local structtypes = {
['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