diff --git a/src/core/org/luaj/lib/TableLib.java b/src/core/org/luaj/lib/TableLib.java index 13eab744..0c8d8a45 100644 --- a/src/core/org/luaj/lib/TableLib.java +++ b/src/core/org/luaj/lib/TableLib.java @@ -97,12 +97,16 @@ public class TableLib extends LFunction { case CONCAT: { int n = vm.gettop(); 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()); + LString sep = vm.optlstring(3,null); + int i = vm.optint(4,1); + int j = vm.optint(5,-1); + if ( j == -1 ) + j = table.luaLength(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); for ( int k=i; k<=j; k++ ) { LValue v = table.get(k); + if ( ! v.isString() ) + vm.argerror(2, "table contains non-strings"); v.luaConcatTo(baos); if ( k=4? vm.checkint(3): 0); - LValue value = vm.topointer(-1); - table.luaInsertPos( pos, value ); + int pos = 0; + switch ( vm.gettop() ) { + case 3: + break; + case 4: + pos = vm.checkint(3); + break; + default: + vm.error( "wrong number of arguments to 'insert'" ); + } + table.luaInsertPos( pos, vm.topointer(-1) ); vm.resettop(); break; } @@ -175,7 +186,7 @@ public class TableLib extends LFunction { case REMOVE: { int n = vm.gettop(); LTable table = vm.checktable(2); - int pos = (n>=3? vm.checkint(3): 0); + int pos = vm.optint(3,0); vm.resettop(); LValue removed = table.luaRemovePos( pos ); if ( removed != LNil.NIL ) @@ -194,7 +205,7 @@ public class TableLib extends LFunction { */ case SORT: { LTable table = vm.checktable(2); - LValue compare = vm.checkfunction(3); + LValue compare = (vm.isnoneornil(3)? LNil.NIL: vm.checkfunction(3)); table.luaSort( vm, compare ); vm.resettop(); break; diff --git a/src/core/org/luaj/vm/LValue.java b/src/core/org/luaj/vm/LValue.java index 9088769d..7d9b88fd 100644 --- a/src/core/org/luaj/vm/LValue.java +++ b/src/core/org/luaj/vm/LValue.java @@ -309,7 +309,8 @@ public class LValue { /** Concatenate this value to a ByteArrayOutputStream */ public void luaConcatTo(ByteArrayOutputStream baos) { - throw new LuaErrorException( "attempt to concat ? (a "+luaGetTypeName()+" value)"); + byte[] b = toJavaString().getBytes(); + baos.write(b,0,b.length); } /** Return true if this is a LString */ diff --git a/src/core/org/luaj/vm/LuaState.java b/src/core/org/luaj/vm/LuaState.java index 85710455..2f4eaa10 100644 --- a/src/core/org/luaj/vm/LuaState.java +++ b/src/core/org/luaj/vm/LuaState.java @@ -2685,7 +2685,7 @@ public class LuaState extends Lua { */ public int checkint(int narg) { LValue v = tolnumber(narg); - if ( ! v.isInteger() ) + if ( v.isNil() ) typerror(narg, Lua.LUA_TNUMBER); return v.toJavaInt(); } @@ -2722,7 +2722,10 @@ public class LuaState extends Lua { * @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); + LValue v = topointer(narg).luaToNumber(); + if ( v.isNil() ) + typerror(narg, Lua.LUA_TNUMBER); + return (LNumber) v; } /** @@ -2799,11 +2802,101 @@ public class LuaState extends Lua { typerror(ud, expected.getName()); return null; } + + /** + * If the function argument narg is a number, returns this + * number cast to an int. If this argument is absent or is + * nil, returns d. Otherwise, raises an error. + * @param narg the argument number + * @param d the default value when the argument is nil or not supplied + * @throws LuaErrorException if the value cannot be converted to an int + * @return int value if the argument is an int, or d + */ + public int optint(int narg, int d) { + LNumber n = optnumber(narg,null); + return (n==null? d: n.toJavaInt()); + } + + /** + * If the function argument narg is a number, returns this + * number cast to a lua_Integer. + * If this argument is absent or is nil, returns d. + * Otherwise, raises an error. + * @param narg the argument number + * @param d the default value when the argument is nil or not supplied + * @throws LuaErrorException if the value cannot be converted to an int + * @return int value if the argument is an int, or d + */ + public LInteger optinteger(int narg, int d) { + return LInteger.valueOf(optint(narg,d)); + } + + /** + * If the function argument narg is a number, returns this + * number cast to a long. If this argument is absent or is + * nil, returns d. Otherwise, raises an error. + * @param narg the argument number + * @param d the default value when the argument is nil or not supplied + * @throws LuaErrorException if the value cannot be converted to an number + * @return int value if the argument is an number, or d + */ + public long optlong(int narg, long d) { + LNumber n = optnumber(narg,null); + return (n==null? d: n.toJavaLong()); + } /** - * Method to indicate a vm internal error has occurred. - * Generally, this is not recoverable, so we convert to - * a lua error during production so that the code may recover. + * If the function argument narg is a number, returns this + * number. If this argument is absent or is nil, returns + * d. Otherwise, raises an error. + * @param narg the argument number + * @param d the default value when the argument is nil or not supplied + * @throws LuaErrorException if the value cannot be converted to an number + * @return int value if the argument is an number, or d + */ + public LNumber optnumber(int narg, LNumber d) { + LValue v = topointer(narg); + if ( v.isNil() ) + return d; + v = v.luaToNumber(); + if ( v.isNil() ) + typerror(narg, Lua.LUA_TNUMBER); + return (LNumber) v; + + } + + /** + * If the function argument narg is a string, returns this + * string. If this argument is absent or is nil, returns + * d. Otherwise, raises an error. + */ + public LString optlstring(int narg, LString d) { + LValue v = topointer(narg); + if ( v.isNil() ) + return d; + if ( ! v.isString() ) + typerror(narg, Lua.LUA_TSTRING); + return v.luaAsString(); + } + + /** + * If the function argument narg is a string, returns this + * string. If this argument is absent or is nil, returns + * d. Otherwise, raises an error. + */ + public String optstring(int narg, String d) { + LValue v = topointer(narg); + if ( v.isNil() ) + return d; + if ( ! v.isString() ) + typerror(narg, Lua.LUA_TSTRING); + return v.toJavaString(); + } + + /** + * Method to indicate a vm internal error has occurred. Generally, this is + * not recoverable, so we convert to a lua error during production so that + * the code may recover. */ public static void vmerror(String description) { throw new LuaErrorException( "internal error: "+description ); diff --git a/src/test/res/baselib.lua b/src/test/res/baselib.lua index 80a75b17..be905f08 100644 --- a/src/test/res/baselib.lua +++ b/src/test/res/baselib.lua @@ -196,6 +196,9 @@ print( 'pcall(tonumber,false)', pcall(tonumber,false) ) print( 'pcall(tonumber,tonumber)', pcall(tonumber,tonumber) ) print( 'pcall(tonumber,function() end)', pcall(tonumber,function() end) ) print( 'pcall(tonumber,{"one","two",a="aa",b="bb"})', pcall(tonumber,{"one","two",a="aa",b="bb"}) ) +print( 'pcall(tonumber,"123.456")', pcall(tonumber,"123.456") ) +print( 'pcall(tonumber," 123.456")', pcall(tonumber," 123.456") ) +print( 'pcall(tonumber," 234qwer")', pcall(tonumber," 234qwer") ) -- tostring print( 'pcall(tostring)', pcall(tostring) )