Argument type checking on basic lib

This commit is contained in:
James Roseborough
2008-07-22 14:56:13 +00:00
parent 289a0df9f5
commit 9113435e57
7 changed files with 95 additions and 86 deletions

View File

@@ -10,6 +10,7 @@ import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.PrintStream; import java.io.PrintStream;
import org.luaj.vm.CallInfo;
import org.luaj.vm.LClosure; import org.luaj.vm.LClosure;
import org.luaj.vm.LFunction; import org.luaj.vm.LFunction;
import org.luaj.vm.LInteger; import org.luaj.vm.LInteger;
@@ -43,6 +44,7 @@ public class BaseLib extends LFunction {
"assert", "assert",
"loadfile", "loadfile",
"tonumber", "tonumber",
"rawequal",
"rawget", "rawget",
"rawset", "rawset",
"getfenv", "getfenv",
@@ -71,20 +73,21 @@ public class BaseLib extends LFunction {
private static final int ASSERT = 9; private static final int ASSERT = 9;
private static final int LOADFILE = 10; private static final int LOADFILE = 10;
private static final int TONUMBER = 11; private static final int TONUMBER = 11;
private static final int RAWGET = 12; private static final int RAWEQUAL = 12;
private static final int RAWSET = 13; private static final int RAWGET = 13;
private static final int GETFENV = 14; private static final int RAWSET = 14;
private static final int SETFENV = 15; private static final int GETFENV = 15;
private static final int SELECT = 16; private static final int SETFENV = 16;
private static final int COLLECTGARBAGE = 17; private static final int SELECT = 17;
private static final int DOFILE = 18; private static final int COLLECTGARBAGE = 18;
private static final int LOADSTRING = 19; private static final int DOFILE = 19;
private static final int LOAD = 20; private static final int LOADSTRING = 20;
private static final int TOSTRING = 21; private static final int LOAD = 21;
private static final int UNPACK = 22; private static final int TOSTRING = 22;
private static final int XPCALL = 23; private static final int UNPACK = 23;
private static final int NEXT = 24; private static final int XPCALL = 24;
private static final int INEXT = 25; private static final int NEXT = 25;
private static final int INEXT = 26;
private static LFunction next; private static LFunction next;
private static LFunction inext; private static LFunction inext;
@@ -165,15 +168,16 @@ public class BaseLib extends LFunction {
break; break;
} }
case SETMETATABLE: { case SETMETATABLE: {
vm.checktable(2); LTable t = vm.checktable(2);
vm.setmetatable(2); LValue v = vm.checkany(3);
vm.remove(1); vm.argcheck(v.isTable() || v.isNil(), 3, "table or nil expected");
vm.settop(1); t.luaSetMetatable(v);
vm.resettop();
vm.pushlvalue(t);
break; break;
} }
case TYPE: { case TYPE: {
vm.checkany(2); LValue v = vm.checkany(2);
LValue v = vm.topointer(2);
vm.resettop(); vm.resettop();
vm.pushlstring( v.luaGetTypeName() ); vm.pushlstring( v.luaGetTypeName() );
break; break;
@@ -193,8 +197,7 @@ public class BaseLib extends LFunction {
break; break;
} }
case XPCALL: { case XPCALL: {
vm.checkany(3); LValue errfun = vm.checkany(3);
LValue errfun = vm.topointer(3);
vm.settop(2); vm.settop(2);
int s = vm.pcall( 0, Lua.LUA_MULTRET, 0 ); int s = vm.pcall( 0, Lua.LUA_MULTRET, 0 );
if ( s == 0 ) { // success, results are on stack above the xpcall if ( s == 0 ) { // success, results are on stack above the xpcall
@@ -247,56 +250,45 @@ public class BaseLib extends LFunction {
} }
break; break;
} }
case RAWEQUAL: {
LValue a = vm.checkany(2);
LValue b = vm.checkany(3);
vm.resettop();
vm.pushboolean(a == b);
break;
}
case RAWGET: { case RAWGET: {
vm.checkany(3);
LTable t = vm.checktable(2); LTable t = vm.checktable(2);
LValue k = vm.topointer(3); LValue k = vm.checkany(3);
vm.resettop(); vm.resettop();
vm.pushlvalue( t.get( k ) ); vm.pushlvalue( t.get( k ) );
} break; break;
}
case RAWSET: { case RAWSET: {
vm.checkany(3);
vm.checkany(4);
LTable t = vm.checktable(2); LTable t = vm.checktable(2);
LValue k = vm.topointer(3); LValue k = vm.checkany(3);
LValue v = vm.topointer(4); LValue v = vm.checkany(4);
t.put( k, v ); t.put( k, v );
vm.resettop(); vm.resettop();
vm.pushlvalue(t); vm.pushlvalue(t);
} break; break;
case GETFENV: {
if ( vm.isfunction(2) ) {
vm.getfenv(-1);
} else {
int i = vm.optint(2,1);
if ( i <= 0 )
vm.pushlvalue(vm._G);
else if ( i-1 <= vm.cc )
vm.pushlvalue( vm.getStackFrame(i-1).closure.env );
else
vm.pushnil();
} }
vm.insert(1); case GETFENV: {
vm.settop(1); LValue f = getfunc(vm, true);
vm.resettop();
vm.pushlvalue(f.luaGetEnv(vm._G));
break; break;
} }
case SETFENV: { case SETFENV: {
LTable t = vm.checktable(-1); LTable t = vm.checktable(3);
LFunction f = vm.checkfunction(2); LValue f = getfunc(vm, false);
if ( vm.setfenv(2) != 0 ) { if ( vm.isnumber(2) && vm.tointeger(2) == 0 ) {
vm.remove(1);
break;
}
int i = vm.tointeger(2);
if ( i == 0 ) {
vm._G = t; vm._G = t;
vm.resettop(); } else if ( (!(f instanceof LClosure)) || ! f.luaSetEnv(t) ) {
} else { vm.error( "'setfenv' cannot change environment of given object" );
LClosure c = vm.getStackFrame(i-1).closure;
c.luaSetEnv(t);
vm.resettop();
vm.pushlvalue(c);
} }
vm.resettop();
vm.pushlvalue(f);
break; break;
} }
case SELECT: { case SELECT: {
@@ -307,7 +299,7 @@ public class BaseLib extends LFunction {
if ( index < 0 ) if ( index < 0 )
index += n-1; index += n-1;
if ( index <= 0 ) if ( index <= 0 )
vm.error( "bad argument #1 to '?' (index out of range)" ); vm.typerror( 2, "index out of range" );
if ( index >= n ) if ( index >= n )
vm.resettop(); vm.resettop();
else { else {
@@ -317,6 +309,8 @@ public class BaseLib extends LFunction {
} else if ( vm.checkstring(2).equals( "#" ) ) { } else if ( vm.checkstring(2).equals( "#" ) ) {
vm.resettop(); vm.resettop();
vm.pushnumber( n - 2 ); vm.pushnumber( n - 2 );
} else {
vm.typerror(2,"expected number or '#'");
} }
break; break;
} }
@@ -346,8 +340,7 @@ public class BaseLib extends LFunction {
load(vm); load(vm);
break; break;
case TOSTRING: { case TOSTRING: {
vm.checkany(2); LValue v = vm.checkany(2);
LValue v = vm.topointer(2);
vm.resettop(); vm.resettop();
vm.pushlvalue( v.luaAsString() ); vm.pushlvalue( v.luaAsString() );
break; break;
@@ -374,6 +367,21 @@ public class BaseLib extends LFunction {
return false; return false;
} }
private static LValue getfunc (LuaState vm, boolean opt) {
if ( vm.isfunction(2) )
return vm.tojavafunction(2);
else {
int level = opt? vm.optint(2, 1): vm.checkint(2);
vm.argcheck(level >= 0, 2, "level must be non-negative");
vm.argcheck(level-1 <= vm.cc, 2, "invalid level");
CallInfo ci = vm.getStackFrame(level-1);
if ( ci == null || ci.closure == null )
return LNil.NIL;
return ci.closure;
}
}
public static void redirectOutput( OutputStream newStdOut ) { public static void redirectOutput( OutputStream newStdOut ) {
STDOUT = new PrintStream( newStdOut ); STDOUT = new PrintStream( newStdOut );
} }

View File

@@ -49,9 +49,9 @@ public class LClosure extends LFunction {
} }
/** Set the environment if a thread, or closure, and return 1, otherwise return 0 */ /** Set the environment if a thread, or closure, and return 1, otherwise return 0 */
public int luaSetEnv(LTable t) { public boolean luaSetEnv(LTable t) {
this.env = t; this.env = t;
return 1; return true;
} }
/** Get the enviroment for this closure */ /** Get the enviroment for this closure */

View File

@@ -37,18 +37,6 @@ public class LFunction extends LValue {
return Lua.LUA_TFUNCTION; return Lua.LUA_TFUNCTION;
} }
/**
* Get the environment of the object if it is a closure, or d if not a closure.
*
* @param d global environment
* @return environment for this object, or d if it is not an LClosure
* @see LClosure
* @see LTable
*/
public LTable luaGetEnv(LTable d) {
return d;
}
/** /**
* Set up a Java invocation, and leave the results on the stack * Set up a Java invocation, and leave the results on the stack
* starting at base. The default implementation for LFunction * starting at base. The default implementation for LFunction

View File

@@ -60,9 +60,9 @@ public class LThread extends LValue implements Runnable {
} }
/** Set the environment if a thread, or closure, and return 1, otherwise return 0 */ /** Set the environment if a thread, or closure, and return 1, otherwise return 0 */
public int luaSetEnv(LTable t) { public boolean luaSetEnv(LTable t) {
threadVm._G = t; threadVm._G = t;
return 1; return true;
} }
public String getStatus() { public String getStatus() {

View File

@@ -292,11 +292,19 @@ public class LValue {
return null; return null;
} }
/** Set the environment if a thread, or closure, and return 1, otherwise return 0 */ /** Set the environment if a thread, or closure, and return true, otherwise return false */
public int luaSetEnv(LTable t) { public boolean luaSetEnv(LTable t) {
return 0; return false;
} }
/** Get the environment of the object if it is a closure, or d if not a closure.
* @param d global environment to return if this is not a closure
*/
public LTable luaGetEnv(LTable d) {
return d;
}
/** Convert to a number if possible, or nil otherwise */ /** Convert to a number if possible, or nil otherwise */
public LValue luaToNumber() { public LValue luaToNumber() {
return LNil.NIL; return LNil.NIL;

View File

@@ -1248,9 +1248,9 @@ public class LuaState extends Lua {
* Pops a table from the stack and sets it as the new environment for the * Pops a table from the stack and sets it as the new environment for the
* value at the given index. If the value at the given index is neither a * value at the given index. If the value at the given index is neither a
* function nor a thread nor a userdata, <a href="#lua_setfenv"><code>lua_setfenv</code></a> * function nor a thread nor a userdata, <a href="#lua_setfenv"><code>lua_setfenv</code></a>
* returns 0. Otherwise it returns 1. * returns false. Otherwise it returns true.
*/ */
public int setfenv(int index) { public boolean setfenv(int index) {
LTable t = totable(-1); LTable t = totable(-1);
LValue f = topointer(index); LValue f = topointer(index);
pop(1); pop(1);
@@ -2661,11 +2661,13 @@ public class LuaState extends Lua {
* Checks whether the function has an argument of any type (including <b>nil</b>) * Checks whether the function has an argument of any type (including <b>nil</b>)
* at position <code>narg</code>. * at position <code>narg</code>.
* @param narg the argument number * @param narg the argument number
* @return the value at the index
* @throws LuaErrorException if there is no argument at position narg * @throws LuaErrorException if there is no argument at position narg
*/ */
public void checkany(int narg) { public LValue checkany(int narg) {
if ( gettop() < narg ) if ( gettop() < narg )
argerror(narg, "value expected"); argerror(narg, "value expected");
return topointer(narg);
} }
/** /**

View File

@@ -71,7 +71,7 @@ checkallerrors('pairs', {notatable}, 'bad argument #1')
-- pcall -- pcall
banner('pcall') banner('pcall')
checkallpass('pcall', {notanil,anylua}) checkallpass('pcall', {notanil,anylua}, true)
checkallerrors('pcall',{},'bad argument #1') checkallerrors('pcall',{},'bad argument #1')
-- print -- print
@@ -109,9 +109,12 @@ checkallerrors('select', {notanumber}, 'bad argument #1')
-- setfenv -- setfenv
banner('setfenv') banner('setfenv')
local g = _G
checkallpass('setfenv', {{function()end},sometable}) checkallpass('setfenv', {{function()end},sometable})
checkallerrors('setfenv', {{1.23, '1.33'},{getfenv()}}, 'cannot change environment of given object') checkallerrors('setfenv', {{-1, '-2'},{g}}, 'level must be non-negative')
checkallerrors('setfenv', {{atable,athread,aboolean,astring},sometable}, 'bad argument #1') checkallerrors('setfenv', {{10, '11'},{g}}, 'invalid level')
checkallerrors('setfenv', {{rawset},{g}}, 'cannot change environment of given object')
checkallerrors('setfenv', {{atable,athread,aboolean,astring},{g}}, 'bad argument #1')
checkallerrors('setfenv', {notafunction}, 'bad argument #2') checkallerrors('setfenv', {notafunction}, 'bad argument #2')
checkallerrors('setfenv', {anylua}, 'bad argument #2') checkallerrors('setfenv', {anylua}, 'bad argument #2')
checkallerrors('setfenv', {{function()end},notatable}, 'bad argument #2') checkallerrors('setfenv', {{function()end},notatable}, 'bad argument #2')
@@ -119,7 +122,7 @@ checkallerrors('setfenv', {{function()end},notatable}, 'bad argument #2')
-- setmetatable -- setmetatable
banner('setmetatable') banner('setmetatable')
checkallpass('setmetatable', {sometable,sometable}) checkallpass('setmetatable', {sometable,sometable})
checkallpass('setmetatable', {sometable,{nil,atable},{'anchor'}}) checkallpass('setmetatable', {sometable,{}})
checkallerrors('setmetatable',{notatable,sometable},'bad argument #1') checkallerrors('setmetatable',{notatable,sometable},'bad argument #1')
checkallerrors('setmetatable',{sometable,notatable},'bad argument #2') checkallerrors('setmetatable',{sometable,notatable},'bad argument #2')