From 1d40b523488cfdd1c98b1d7571f8d4d6dd4b1cfc Mon Sep 17 00:00:00 2001 From: James Roseborough Date: Thu, 9 Apr 2009 16:27:01 +0000 Subject: [PATCH] Let all libraries implement invoke() instead of luaStackCall, correct off-by-one error on argument type check functions. --- src/core/org/luaj/lib/BaseLib.java | 225 +++++++++++------------- src/core/org/luaj/lib/CoroutineLib.java | 51 +++--- src/core/org/luaj/lib/DebugLib.java | 183 +++++++++---------- src/core/org/luaj/lib/IoLib.java | 87 +++++---- src/core/org/luaj/lib/MathLib.java | 91 ++++------ src/core/org/luaj/lib/OsLib.java | 62 +++---- src/core/org/luaj/lib/PackageLib.java | 83 ++++----- src/core/org/luaj/lib/StringLib.java | 188 +++++++++----------- src/core/org/luaj/lib/TableLib.java | 72 ++++---- src/core/org/luaj/vm/LThread.java | 5 +- src/core/org/luaj/vm/LuaState.java | 14 +- 11 files changed, 478 insertions(+), 583 deletions(-) diff --git a/src/core/org/luaj/lib/BaseLib.java b/src/core/org/luaj/lib/BaseLib.java index 5197af67..6b735a03 100644 --- a/src/core/org/luaj/lib/BaseLib.java +++ b/src/core/org/luaj/lib/BaseLib.java @@ -120,112 +120,104 @@ public class BaseLib extends LFunction { vm.pushstring( message ); } - public boolean luaStackCall(LuaState vm) { + public int invoke(LuaState vm) { switch ( id ) { case PRINT: { int n = vm.gettop(); vm.getglobal("tostring"); - for ( int i=2; i<=n; i++ ) { + for ( int i=1; i<=n; i++ ) { vm.pushvalue(-1); vm.pushvalue(i); vm.call(1, 1); if ( vm.type(-1) != Lua.LUA_TSTRING ) vm.error( "'tostring' must return a string to 'print'" ); - if ( i > 2 ) + if ( i > 1 ) STDOUT.print( "\t" ); STDOUT.print( vm.tostring(-1) ); vm.poplvalue(); } STDOUT.println(); - vm.resettop(); - break; + return 0; } case IPAIRS: { - LTable t = vm.checktable(2); - vm.resettop(); + LTable t = vm.checktable(1); vm.pushfunction( inext ); vm.pushlvalue( t ); vm.pushinteger( 0 ); - break; + return 3; } case PAIRS: { - LTable t = vm.checktable(2); - vm.resettop(); + LTable t = vm.checktable(1); vm.pushfunction( next ); vm.pushlvalue( t ); vm.pushnil(); - break; + return 3; } case INEXT: { - int i = vm.checkint(3) + 1; - LTable t = vm.checktable(2); + int i = vm.checkint(2) + 1; + LTable t = vm.checktable(1); LValue v = t.get(i); - vm.resettop(); if ( !v.isNil() ) { vm.pushinteger(i); vm.pushlvalue(v); + return 2; } - break; + return 0; } case NEXT: { - LTable t = vm.checktable(2); - LValue k = vm.topointer(3); + LTable t = vm.checktable(1); + LValue k = vm.topointer(2); vm.resettop(); t.next(vm,k,false); - break; + return -1; } case GETMETATABLE: { - vm.checkany(2); - if ( ! vm.getmetatable(2) ) { - vm.resettop(); + vm.checkany(1); + if ( ! vm.getmetatable(1) ) { vm.pushnil(); + return 1; } else { - vm.replace(1); - vm.settop(1); vm.getfield(-1,LValue.TM_METATABLE); if ( vm.isnil(-1) ) vm.pop(1); - else - vm.remove(1); } - break; + return 1; } case SETMETATABLE: { - LTable t = vm.checktable(2); - LValue v = vm.checkany(3); - vm.argcheck(v.isTable() || v.isNil(), 3, "table or nil expected"); + LTable t = vm.checktable(1); + LValue v = vm.checkany(2); + vm.argcheck(v.isTable() || v.isNil(), 2, "table or nil expected"); t = t.luaSetMetatable(v); - vm.resettop(); vm.pushlvalue(t); - break; + return 1; } case TYPE: { - LValue v = vm.checkany(2); - vm.resettop(); + LValue v = vm.checkany(1); vm.pushlstring( v.luaGetTypeName() ); - break; + return 1; } case PCALL: { - vm.checkany(2); + vm.checkany(1); int n = vm.gettop(); - int s = vm.pcall( n-2, Lua.LUA_MULTRET, 0 ); - if ( s == 0 ) { // success, results are on stack above the pcall - vm.remove( 1 ); + int s = vm.pcall( n-1, Lua.LUA_MULTRET, 0 ); + if ( s == 0 ) { // success, results are on stack vm.pushboolean( true ); vm.insert( 1 ); + return -1; } else { // error, error message is on the stack vm.pushboolean( false ); - vm.insert( 1 ); + vm.insert( -2 ); + return 2; } - break; } case XPCALL: { LValue errfun = vm.checkany(3); - vm.settop(2); + vm.settop(1); 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 vm.pushboolean( true ); - vm.replace( 1 ); + vm.insert( 1 ); + return -1; } else { // error, error message is on the stack vm.pushlvalue( errfun ); vm.insert( 1 ); @@ -233,113 +225,105 @@ public class BaseLib extends LFunction { if ( s == 0 ) { vm.pushboolean( false ); vm.insert( 1 ); + return -1; } else { // error in error handler - vm.resettop(); vm.pushboolean(false); - vm.pushstring("error in error handling"); + vm.pushstring("error in error handling"); + return 2; } } - break; } case ERROR: { - vm.error(vm.optstring(2,null), vm.optint(3,1)); - break; + vm.error(vm.optstring(1,null), vm.optint(2,1)); + return 0; } case ASSERT: { - if ( ! vm.toboolean(2) ) - vm.error( vm.optstring(3,"assertion failed!") ); - vm.remove(1); - break; + if ( ! vm.toboolean(1) ) + vm.error( vm.optstring(2,"assertion failed!") ); + return -1; } case LOADFILE: - loadfile(vm, vm.optstring(2,null)); - break; + loadfile(vm, vm.optstring(1,null)); + return -1; case TONUMBER: { - int base = vm.optint(3, 10); + int base = vm.optint(2, 10); if (base == 10) { /* standard conversion */ - vm.checkany(2); - LValue v = vm.tolnumber(2); - vm.resettop(); + vm.checkany(1); + LValue v = vm.tolnumber(1); vm.pushlvalue(v); + return 1; } else { if ( base < 2 || base > 36 ) - vm.typerror(3, "base out of range"); - LString s = vm.checklstring(2); - vm.resettop(); + vm.argerror(2, "base out of range"); + LString s = vm.checklstring(1); vm.pushlvalue( s.luaToNumber(base) ); + return 1; } - break; } case RAWEQUAL: { - LValue a = vm.checkany(2); - LValue b = vm.checkany(3); - vm.resettop(); + LValue a = vm.checkany(1); + LValue b = vm.checkany(2); vm.pushboolean(a == b); - break; + return 1; } case RAWGET: { - LTable t = vm.checktable(2); - LValue k = vm.checkany(3); - vm.resettop(); + LTable t = vm.checktable(1); + LValue k = vm.checkany(2); vm.pushlvalue( t.get( k ) ); - break; + return 1; } case RAWSET: { - LTable t = vm.checktable(2); - LValue k = vm.checkany(3); - LValue v = vm.checkany(4); + LTable t = vm.checktable(1); + LValue k = vm.checkany(2); + LValue v = vm.checkany(3); t.put( k, v ); - vm.resettop(); vm.pushlvalue(t); - break; + return 1; } case GETFENV: { LValue f = getfunc(vm, true); - vm.resettop(); vm.pushlvalue(f.luaGetEnv(vm._G)); - break; + return 1; } case SETFENV: { - LTable t = vm.checktable(3); - LValue f = getfunc(vm, false); - if ( vm.isnumber(2) && vm.tointeger(2) == 0 ) { + LTable t = vm.checktable(2); + if ( vm.isnumber(1) && vm.tointeger(1) == 0 ) { vm._G = t; - } else if ( (!(f instanceof LClosure)) || ! f.luaSetEnv(t) ) { - vm.error( "'setfenv' cannot change environment of given object" ); + } else { + LValue f = getfunc(vm, false); + if ( (!(f instanceof LClosure)) || ! f.luaSetEnv(t) ) + vm.error( "'setfenv' cannot change environment of given object" ); + vm.pushlvalue(f); + return 1; } - vm.resettop(); - vm.pushlvalue(f); - break; } case SELECT: { - vm.checkany(2); + vm.checkany(1); int n = vm.gettop(); - if ( vm.isnumber(2) ) { - int index = vm.tolnumber(2).toJavaInt(); + if ( vm.isnumber(1) ) { + int index = vm.tolnumber(1).toJavaInt(); if ( index < 0 ) - index += n-1; + index += n; if ( index <= 0 ) - vm.typerror( 2, "index out of range" ); + vm.argerror( 1, "index out of range" ); if ( index >= n ) - vm.resettop(); + return 0; else { - for ( int i=0; i<=index; i++ ) - vm.remove(1); + return n-index; } - } else if ( vm.checkstring(2).equals( "#" ) ) { - vm.resettop(); - vm.pushnumber( n - 2 ); + } else if ( vm.checkstring(1).equals( "#" ) ) { + vm.pushnumber( n - 1 ); + return 1; } else { - vm.typerror(2,"expected number or '#'"); + vm.typerror(1,"expected number or '#'"); + return 0; } - break; } case COLLECTGARBAGE: { - String s = vm.optstring(2, "collect"); + String s = vm.optstring(1, "collect"); int result = 0; - vm.resettop(); if ( "collect".equals(s) ) System.gc(); else if ( "count".equals(s) ) { @@ -347,33 +331,32 @@ public class BaseLib extends LFunction { long used = rt.totalMemory() - rt.freeMemory(); result = (int) (used >> 10); } else { - vm.typerror(2,"gc op"); + vm.argerror(2,"gc op"); } vm.pushnumber(result); - break; + return 1; } case DOFILE: dofile(vm); - break; + return -1; case LOADSTRING: - loadstring(vm, vm.checklstring(2), vm.optstring(3,"(string)")); - break; + loadstring(vm, vm.checklstring(1), vm.optstring(2,"(string)")); + return -1; case LOAD: load(vm); - break; + return -1; case TOSTRING: { - LValue v = vm.checkany(2); - vm.resettop(); + LValue v = vm.checkany(1); vm.pushlvalue( v.luaAsString() ); - break; + return 1; } case UNPACK: { - LTable list = vm.checktable(2); + LTable list = vm.checktable(1); int n = vm.gettop(); - int i = vm.optint(3,1); + int i = vm.optint(2,1); int j; - if ( n >= 4 ) { - j = vm.checkint(4); + if ( n >= 3 ) { + j = vm.checkint(3); } else { j = list.luaLength(); } @@ -381,21 +364,21 @@ public class BaseLib extends LFunction { vm.checkstack(j+1-i); for ( int k=i; k<=j; k++ ) vm.pushlvalue(list.get(k)); - break; + return -1; } default: LuaState.vmerror( "bad base id" ); + return 0; } - return false; } private static LValue getfunc (LuaState vm, boolean opt) { - if ( vm.isfunction(2) ) - return vm.tofunction(2); + if ( vm.isfunction(1) ) + return vm.tofunction(1); 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"); + int level = opt? vm.optint(1, 1): vm.checkint(1); + vm.argcheck(level >= 0, 1, "level must be non-negative"); + vm.argcheck(level-1 <= vm.cc, 1, "invalid level"); CallInfo ci = vm.getStackFrame(level-1); if ( ci == null || ci.closure == null ) return LNil.NIL; @@ -483,7 +466,7 @@ public class BaseLib extends LFunction { // if load succeeds, return 0 for success, 1 for error (as per lua spec) private void dofile( LuaState vm ) { - String filename = vm.optstring(2,null); + String filename = vm.optstring(1,null); if ( loadfile( vm, filename ) ) { vm.call(0, 0); } else { diff --git a/src/core/org/luaj/lib/CoroutineLib.java b/src/core/org/luaj/lib/CoroutineLib.java index 351f742a..6f465810 100644 --- a/src/core/org/luaj/lib/CoroutineLib.java +++ b/src/core/org/luaj/lib/CoroutineLib.java @@ -21,7 +21,6 @@ ******************************************************************************/ package org.luaj.lib; -import org.luaj.vm.LClosure; import org.luaj.vm.LFunction; import org.luaj.vm.LTable; import org.luaj.vm.LThread; @@ -79,21 +78,21 @@ public class CoroutineLib extends LFunction { this.thread = thread; } - public boolean luaStackCall( LuaState vm ) { + public int invoke( LuaState vm ) { switch ( id ) { case INSTALL: { install(vm._G); - break; + return 0; } case CREATE: { - LFunction c = vm.checkfunction(2); + LFunction c = vm.checkfunction(1); vm.pushlvalue( new LThread( c, c.luaGetEnv(vm._G) ) ); - break; + return 1; } case RESUME: { - LThread t = vm.checkthread(2); - t.resumeFrom( vm, vm.gettop()-2 ); - return false; + LThread t = vm.checkthread(1); + t.resumeFrom( vm, vm.gettop()-1 ); + return -1; } case RUNNING: { LThread r = LThread.getRunning(); @@ -102,39 +101,41 @@ public class CoroutineLib extends LFunction { } else { vm.pushnil(); } - break; + return 1; } case STATUS: { - vm.pushstring( vm.checkthread(2).getStatus() ); - break; + vm.pushstring( vm.checkthread(1).getStatus() ); + return 1; } case WRAP: { - LFunction c = vm.checkfunction(2); + LFunction c = vm.checkfunction(1); vm.pushlvalue( new CoroutineLib(WRAPPED,new LThread(c, c.luaGetEnv(vm._G))) ); - break; + return 1; } case YIELD: { LThread r = LThread.getRunning(); - if ( r == null ) + if ( r == null ) { vm.error("main thread can't yield"); - else { - return r.yield(); + return 0; } + r.yield(); + return -1; } case WRAPPED: { LThread t = this.thread; - t.resumeFrom( vm, vm.gettop()-1 ); - if ( vm.toboolean(1) ) + t.resumeFrom( vm, vm.gettop() ); + if ( vm.toboolean(1) ) { vm.remove(1); - else + return -1; + } else { vm.error( vm.tostring(2) ); - return false; + return 0; + } + } + default: { + LuaState.vmerror( "bad coroutine id" ); + return 0; } } - vm.insert(1); - vm.settop(1); - return false; } - - } diff --git a/src/core/org/luaj/lib/DebugLib.java b/src/core/org/luaj/lib/DebugLib.java index 2b633b7f..13de74ef 100644 --- a/src/core/org/luaj/lib/DebugLib.java +++ b/src/core/org/luaj/lib/DebugLib.java @@ -108,88 +108,74 @@ public class DebugLib extends LFunction { return NAMES[id]+"()"; } - public boolean luaStackCall( LuaState vm ) { + public int invoke( LuaState vm ) { switch ( id ) { case INSTALL: install(vm); - break; + return 0; case DEBUG: - debug(vm); - break; + return debug(vm); case GETFENV: - getfenv(vm); - break; + return getfenv(vm); case GETHOOK: - gethook(vm); - break; + return gethook(vm); case GETINFO: - getinfo(vm); - break; + return getinfo(vm); case GETLOCAL: - getlocal(vm); - break; + return getlocal(vm); case GETMETATABLE: - getmetatable(vm); - break; + return getmetatable(vm); case GETREGISTRY: - getregistry(vm); - break; + return getregistry(vm); case GETUPVALUE: - getupvalue(vm); - break; + return getupvalue(vm); case SETFENV: - setfenv(vm); - break; + return setfenv(vm); case SETHOOK: - sethook(vm); - break; + return sethook(vm); case SETLOCAL: - setlocal(vm); - break; + return setlocal(vm); case SETMETATABLE: - setmetatable(vm); - break; + return setmetatable(vm); case SETUPVALUE: - setupvalue(vm); - break; + return setupvalue(vm); case TRACEBACK: - traceback(vm); - break; + return traceback(vm); default: LuaState.vmerror( "bad package id" ); + return 0; } - return false; } // j2se subclass may wish to override and provide actual console here. // j2me platform has not System.in to provide console. - protected void debug(LuaState vm) { - vm.resettop(); + protected int debug(LuaState vm) { + return 0; } - protected void gethook(LuaState vm) { + protected int gethook(LuaState vm) { LuaState threadVm = vm; if ( vm.gettop() >= 2 ) - threadVm = vm.checkthread(2).vm; - vm.resettop(); + threadVm = vm.checkthread(1).vm; vm.pushlvalue(threadVm.gethook()); vm.pushinteger(threadVm.gethookmask()); vm.pushinteger(threadVm.gethookcount()); + return 3; } protected LuaState optthreadvm(LuaState vm, int index) { - if ( ! vm.isthread(2) ) + if ( ! vm.isthread(index) ) return vm; - LuaState threadVm = vm.checkthread(2).vm; - vm.remove(2); + LuaState threadVm = vm.checkthread(index).vm; + vm.remove(index); return threadVm; } - protected void sethook(LuaState vm) { - LuaState threadVm = optthreadvm(vm, 2); - LFunction func = vm.isnoneornil(2)? null: vm.checkfunction(2); - String str = vm.optstring(3,""); - int count = vm.optint(4,0); + protected int sethook(LuaState vm) { + LuaState threadVm = optthreadvm(vm, 1); + LFunction func = vm.isnoneornil(1)? null: vm.checkfunction(2); + String str = vm.optstring(2,""); + int count = vm.optint(3,0); int mask = 0; for ( int i=0; i0? ci.pc-1: 0): null); if ( name != null ) { LValue value = threadVm.stack[ci.base+(local-1)]; - vm.resettop(); vm.pushlvalue( name ); vm.pushlvalue( value ); + return 2; } else { - vm.resettop(); vm.pushnil(); + return 1; } } - protected void setlocal(LuaState vm) { - LuaState threadVm = optthreadvm(vm, 2); - int level = vm.checkint(2); - int local = vm.checkint(3); - LValue value = vm.topointer(4); + protected int setlocal(LuaState vm) { + LuaState threadVm = optthreadvm(vm, 1); + int level = vm.checkint(1); + int local = vm.checkint(2); + LValue value = vm.topointer(3); StackInfo si = getstackinfo(threadVm, level, 1)[0]; CallInfo ci = (si!=null? si.luainfo: null); LPrototype p = (ci!=null? ci.closure.p: null); LString name = (p!=null? p.getlocalname(local, ci.pc>0? ci.pc-1: 0): null); if ( name != null ) { threadVm.stack[ci.base+(local-1)] = value; - vm.resettop(); vm.pushlvalue(name); } else { - vm.resettop(); vm.pushnil(); } + return 1; } - protected void getmetatable(LuaState vm) { - LValue object = vm.topointer(2); - vm.resettop(); + protected int getmetatable(LuaState vm) { + LValue object = vm.topointer(1); LValue mt = object.luaGetMetatable(); if ( mt != null ) vm.pushlvalue( object.luaGetMetatable() ); else vm.pushnil(); + return 1; } - protected void setmetatable(LuaState vm) { - LValue object = vm.topointer(2); + protected int setmetatable(LuaState vm) { + LValue object = vm.topointer(1); try { - if ( ! vm.isnoneornil(3) ) + if ( ! vm.isnoneornil(2) ) object.luaSetMetatable(vm.checktable(3)); else object.luaSetMetatable(null); - vm.resettop(); vm.pushboolean(true); + return 1; } catch ( LuaErrorException e ) { - vm.resettop(); vm.pushboolean(false); vm.pushstring(e.toString()); + return 2; } } - protected void getregistry(LuaState vm) { - vm.resettop(); + protected int getregistry(LuaState vm) { vm.pushlvalue( new LTable() ); + return 1; } private LString findupvalue(LClosure c, int up) { @@ -369,9 +354,9 @@ public class DebugLib extends LFunction { return null; } - protected void getupvalue(LuaState vm) { - LFunction func = vm.checkfunction(2); - int up = vm.checkint(3); + protected int getupvalue(LuaState vm) { + LFunction func = vm.checkfunction(1); + int up = vm.checkint(2); vm.resettop(); if ( func instanceof LClosure ) { LClosure c = (LClosure) func; @@ -379,16 +364,17 @@ public class DebugLib extends LFunction { if ( name != null ) { vm.pushlstring(name); vm.pushlvalue(c.upVals[up-1].getValue()); - return; + return 2; } } vm.pushnil(); + return 1; } - protected void setupvalue(LuaState vm) { - LFunction func = vm.checkfunction(2); - int up = vm.checkint(3); - LValue value = vm.topointer(4); + protected int setupvalue(LuaState vm) { + LFunction func = vm.checkfunction(1); + int up = vm.checkint(2); + LValue value = vm.topointer(3); vm.resettop(); if ( func instanceof LClosure ) { LClosure c = (LClosure) func; @@ -396,18 +382,19 @@ public class DebugLib extends LFunction { if ( name != null ) { c.upVals[up-1].setValue(value); vm.pushlstring(name); - return; + return 1; } } vm.pushnil(); + return 1; } - protected void traceback(LuaState vm) { - LuaState threadVm = optthreadvm(vm, 2); + protected int traceback(LuaState vm) { + LuaState threadVm = optthreadvm(vm, 1); String message = ""; - int level = vm.optint(3,1); - if ( ! vm.isnoneornil(2) ) - message = vm.checkstring(2)+"\n"; + int level = vm.optint(2,1); + if ( ! vm.isnoneornil(1) ) + message = vm.checkstring(1)+"\n"; StackInfo[] s = getstackinfo(threadVm, level, 10); StringBuffer sb = new StringBuffer("stack traceback:"); for ( int i=0; i LAST_DOUBLE_ARG ) { - setResult( vm, platform.mathop(id, vm.checknumber(2) ) ); + vm.pushlvalue( platform.mathop(id, vm.checknumber(1) ) ); + return 1; } else if ( id > LAST_IRREGULAR ) { - setResult( vm, platform.mathop(id, vm.checknumber(2), vm.checknumber(3) ) ); + vm.pushlvalue( platform.mathop(id, vm.checknumber(1), vm.checknumber(2) ) ); + return 1; } else { switch ( id ) { case INSTALL: install( vm._G ); - break; + return 0; case MAX: { int n = vm.gettop(); - double x = vm.checkdouble(2); - for ( int i=3; i<=n; i++ ) + double x = vm.checkdouble(1); + for ( int i=2; i<=n; i++ ) x = Math.max(x, vm.checkdouble(i)); - setResult( vm, x ); - break; + vm.pushnumber( x ); + return 1; } case MIN: { int n = vm.gettop(); - double x = vm.checkdouble(2); - for ( int i=3; i<=n; i++ ) + double x = vm.checkdouble(1); + for ( int i=2; i<=n; i++ ) x = Math.min(x, vm.checkdouble(i)); - setResult(vm,x); - break; + vm.pushnumber( x ); + return 1; } case MODF: { - double x = vm.checkdouble(2); + double x = vm.checkdouble(1); double intPart = ( x > 0 ) ? Math.floor( x ) : Math.ceil( x ); double fracPart = x - intPart; - vm.resettop(); vm.pushnumber( intPart ); vm.pushnumber( fracPart ); - break; + return 2; } case CEIL: - setResult( vm, (int) Math.ceil( vm.checkdouble(2) ) ); - break; + vm.pushnumber( Math.ceil( vm.checkdouble(1) ) ); + return 1; case FLOOR: - setResult( vm, (int) Math.floor( vm.checkdouble(2) ) ); - break; + vm.pushnumber( Math.floor( vm.checkdouble(1) ) ); + return 1; case FREXP: { - long bits = Double.doubleToLongBits( vm.checkdouble(2) ); - vm.resettop(); + long bits = Double.doubleToLongBits( vm.checkdouble(1) ); vm.pushnumber( ((bits & (~(-1L<<52))) + (1L<<52)) * ((bits >= 0)? (.5 / (1L<<52)): (-.5 / (1L<<52))) ); vm.pushinteger( (((int) (bits >> 52)) & 0x7ff) - 1022 ); - break; + return 2; } case LDEXP: { - double m = vm.checkdouble(2); - int e = vm.checkint(3); - vm.resettop(); + double m = vm.checkdouble(1); + int e = vm.checkint(2); vm.pushnumber( m * Double.longBitsToDouble(((long)(e+1023)) << 52) ); - break; + return 1; } case RANDOM: { if ( random == null ) random = new Random(1); switch ( vm.gettop() ) { - case 1: - vm.resettop(); + case 0: vm.pushnumber(random.nextDouble()); - break; - case 2: { - int m = vm.checkint(2); + return 1; + case 1: { + int m = vm.checkint(1); vm.argcheck(1<=m, 1, "interval is empty"); - vm.resettop(); vm.pushinteger(1+random.nextInt(m)); - break; + return 1; } default: { - int m = vm.checkint(2); - int n = vm.checkint(3); + int m = vm.checkint(1); + int n = vm.checkint(2); vm.argcheck(m<=n, 2, "interval is empty"); - vm.resettop(); vm.pushinteger(m+random.nextInt(n+1-m)); - break; + return 1; } } - break; } case RSEED: - random = new Random( vm.checkint(2) ); - vm.resettop(); - break; + random = new Random( vm.checkint(1) ); + return 0; default: LuaState.vmerror( "bad math id" ); + return 0; } } - return false; } } diff --git a/src/core/org/luaj/lib/OsLib.java b/src/core/org/luaj/lib/OsLib.java index 52c243eb..591b58c9 100644 --- a/src/core/org/luaj/lib/OsLib.java +++ b/src/core/org/luaj/lib/OsLib.java @@ -122,7 +122,7 @@ public class OsLib extends LFunction { return NAMES[id]+"()"; } - public boolean luaStackCall( LuaState vm ) { + public int invoke( LuaState vm ) { LValue v; long t,t2; int c; @@ -131,72 +131,62 @@ public class OsLib extends LFunction { switch ( id ) { case INSTALL: install(vm._G, this); - break; + return 0; case CLOCK: - vm.resettop(); vm.pushnumber(clock()); - break; + return 1; case DATE: - s = vm.optstring(2, null); - t = vm.optlong(3,-1); - vm.resettop(); + s = vm.optstring(1, null); + t = vm.optlong(2,-1); vm.pushlvalue( date(s, t==-1? System.currentTimeMillis(): t) ); - break; + return 1; case DIFFTIME: - t2 = vm.checklong(2); - t = vm.checklong(3); - vm.resettop(); + t2 = vm.checklong(1); + t = vm.checklong(2); vm.pushnumber(difftime(t2,t)); - break; + return 1; case EXECUTE: - c = execute(vm.optstring(2, null)); - vm.resettop(); + c = execute(vm.optstring(1, null)); vm.pushinteger(c); - break; + return 1; case EXIT: - exit(vm.optint(2, 0)); - break; + exit(vm.optint(1, 0)); + return 0; case GETENV: - s = getenv(vm.checkstring(2)); - vm.resettop(); + s = getenv(vm.checkstring(1)); vm.pushstring(s); - break; + return 1; case REMOVE: - remove(vm.checkstring(2)); - vm.resettop(); + remove(vm.checkstring(1)); vm.pushboolean(true); - break; + return 1; case RENAME: - rename(vm.checkstring(2), vm.checkstring(3)); - vm.resettop(); + rename(vm.checkstring(1), vm.checkstring(2)); vm.pushboolean(true); - break; + return 1; case SETLOCALE: - s = setlocale(vm.optstring(2,null), vm.optstring(3, "all")); - vm.resettop(); + s = setlocale(vm.optstring(1,null), vm.optstring(2, "all")); if ( s != null ) vm.pushstring(s); else vm.pushnil(); - break; + return 1; case TIME: - t = time(vm.isnoneornil(2)? null: vm.checktable(2)); - vm.resettop(); + t = time(vm.isnoneornil(1)? null: vm.checktable(1)); vm.pushnumber(t); - break; + return 1; case TMPNAME: - vm.resettop(); vm.pushstring(tmpname()); - break; + return 1; default: LuaState.vmerror( "bad os id" ); + return 0; } } catch ( IOException e ) { - vm.resettop(); vm.pushnil(); vm.pushstring(e.getMessage()); + return 2; } - return false; } /** diff --git a/src/core/org/luaj/lib/PackageLib.java b/src/core/org/luaj/lib/PackageLib.java index f03dd084..57061895 100644 --- a/src/core/org/luaj/lib/PackageLib.java +++ b/src/core/org/luaj/lib/PackageLib.java @@ -115,45 +115,38 @@ public class PackageLib extends LFunction { return NAMES[id]+"()"; } - public boolean luaStackCall( LuaState vm ) { + public int invoke( LuaState vm ) { switch ( id ) { case INSTALL: install(vm._G); - break; + return 0; case MODULE: - module(vm); - break; + return module(vm); case REQUIRE: - require(vm); - break; + return require(vm); case LOADLIB: - loadlib(vm); - break; + return loadlib(vm); case SEEALL: { - LTable t = vm.checktable(2); + LTable t = vm.checktable(1); LTable m = t.luaGetMetatable(); if ( m == null ) t.luaSetMetatable(m = new LTable()); m.put(__INDEX, vm._G); - vm.resettop(); - break; + return 0; } case PRELOAD_LOADER: { - loader_preload(vm); - break; + return loader_preload(vm); } case LUA_LOADER: { - loader_Lua(vm); - break; + return loader_Lua(vm); } case JAVA_LOADER: { - loader_Java(vm); - break; + return loader_Java(vm); } default: LuaState.vmerror( "bad package id" ); + return 0; } - return false; } @@ -179,8 +172,8 @@ public class PackageLib extends LFunction { * This function may receive optional options after the module name, where * each option is a function to be applied over the module. */ - public static void module(LuaState vm) { - LString modname = vm.checklstring(2); + public static int module(LuaState vm) { + LString modname = vm.checklstring(1); int n = vm.gettop(); LValue value = LOADED.luaGetTable(vm, modname); LTable module; @@ -207,14 +200,14 @@ public class PackageLib extends LFunction { ci.closure.env = module; // apply the functions - for ( int i=3; i<=n; i++ ) { + for ( int i=2; i<=n; i++ ) { vm.pushvalue( i ); /* get option (a function) */ vm.pushlvalue( module ); /* module */ vm.call( 1, 0 ); } // returns no results - vm.resettop(); + return 0; } /** @@ -278,30 +271,29 @@ public class PackageLib extends LFunction { * If there is any error loading or running the module, or if it cannot find any loader for * the module, then require signals an error. */ - public void require( LuaState vm ) { - LString name = vm.checklstring(2); + public int require( LuaState vm ) { + LString name = vm.checklstring(1); LValue loaded = LOADED.luaGetTable(vm, name); if ( loaded.toJavaBoolean() ) { if ( loaded == _SENTINEL ) vm.error("loop or previous error loading module '"+name+"'"); - vm.resettop(); vm.pushlvalue( loaded ); - return; + return 1; } - vm.resettop(); /* else must load it; iterate over available loaders */ LValue val = pckg.luaGetTable(vm, _LOADERS); if ( ! val.isTable() ) vm.error( "'package.loaders' must be a table" ); - vm.pushlvalue(val); + LTable tbl = (LTable) val; Vector v = new Vector(); for ( int i=1; true; i++ ) { - vm.rawgeti(1, i); - if ( vm.isnil(-1) ) { + LValue loader = tbl.get(i); + if ( loader.isNil() ) { vm.error( "module '"+name+"' not found: "+v ); } /* call loader with module name as argument */ + vm.pushlvalue(loader); vm.pushlstring(name); vm.call(1, 1); if ( vm.isfunction(-1) ) @@ -321,45 +313,45 @@ public class PackageLib extends LFunction { if ( result == _SENTINEL ) { /* module did not set a value? */ LOADED.luaSetTable(vm, name, result=LBoolean.TRUE ); /* _LOADED[name] = true */ } - vm.resettop(); vm.pushlvalue(result); + return 1; } - public static void loadlib( LuaState vm ) { - vm.checkstring(2); - vm.resettop(); + public static int loadlib( LuaState vm ) { + vm.checkstring(1); vm.pushnil(); vm.pushstring("dynamic libraries not enabled"); vm.pushstring("absent"); + return 3; } - private void loader_preload( LuaState vm ) { - LString name = vm.tolstring(2); + private int loader_preload( LuaState vm ) { + LString name = vm.tolstring(1); LValue preload = pckg.luaGetTable(vm, _PRELOAD); if ( ! preload.isTable() ) vm.error("package.preload '"+name+"' must be a table"); LValue val = preload.luaGetTable(vm, name); if ( val.isNil() ) vm.pushstring("\n\tno field package.preload['"+name+"']"); - vm.resettop(); - vm.pushlvalue(val); + else + vm.pushlvalue(val); + return 1; } - private void loader_Lua( LuaState vm ) { - String name = vm.tostring(2); + private int loader_Lua( LuaState vm ) { + String name = vm.tostring(1); InputStream is = findfile( vm, name, _PATH ); if ( is != null ) { String filename = vm.tostring(-1); if ( ! BaseLib.loadis(vm, is, filename) ) loaderror( vm, filename ); } - vm.insert(1); - vm.settop(1); + return 1; } - private void loader_Java( LuaState vm ) { - String name = vm.tostring(2); + private int loader_Java( LuaState vm ) { + String name = vm.tostring(1); Class c = null; LValue v = null; try { @@ -371,8 +363,7 @@ public class PackageLib extends LFunction { } catch ( Exception e ) { vm.pushstring("\n\tjava load failed on '"+name+"', "+e ); } - vm.insert(1); - vm.settop(1); + return 1; } private InputStream findfile(LuaState vm, String name, LString pname) { diff --git a/src/core/org/luaj/lib/StringLib.java b/src/core/org/luaj/lib/StringLib.java index 425fb092..4c4632c4 100644 --- a/src/core/org/luaj/lib/StringLib.java +++ b/src/core/org/luaj/lib/StringLib.java @@ -92,58 +92,44 @@ public class StringLib extends LFunction { return NAMES[id]+"()"; } - public boolean luaStackCall( LuaState vm ) { + public int invoke( LuaState vm ) { switch ( id ) { case INSTALL: install( vm._G ); - break; + return 0; case BYTE: - StringLib.byte_( vm ); - break; + return StringLib.byte_( vm ); case CHAR: - StringLib.char_( vm ); - break; + return StringLib.char_( vm ); case DUMP: - StringLib.dump( vm ); - break; + return StringLib.dump( vm ); case FIND: - StringLib.find( vm ); - break; + return StringLib.find( vm ); case FORMAT: - StringLib.format( vm ); - break; + return StringLib.format( vm ); case GMATCH: - StringLib.gmatch( vm ); - break; + return StringLib.gmatch( vm ); case GSUB: - StringLib.gsub( vm ); - break; + return StringLib.gsub( vm ); case LEN: - StringLib.len( vm ); - break; + return StringLib.len( vm ); case LOWER: - StringLib.lower( vm ); - break; + return StringLib.lower( vm ); case MATCH: - StringLib.match( vm ); - break; + return StringLib.match( vm ); case REP: - StringLib.rep( vm ); - break; + return StringLib.rep( vm ); case REVERSE: - StringLib.reverse( vm ); - break; + return StringLib.reverse( vm ); case SUB: - StringLib.sub( vm ); - break; + return StringLib.sub( vm ); case UPPER: - StringLib.upper( vm ); - break; + return StringLib.upper( vm ); default: vm.error( "bad id" ); + return 0; } - return false; } /** @@ -157,22 +143,22 @@ public class StringLib extends LFunction { * * @param vm the calling vm */ - static void byte_( LuaState vm ) { - LString s = vm.checklstring(2); + static int byte_( LuaState vm ) { + LString s = vm.checklstring(1); int l = s.m_length; - int posi = posrelat( vm.optint(3,1), l ); - int pose = posrelat( vm.optint(4,posi), l ); - vm.resettop(); + int posi = posrelat( vm.optint(2,1), l ); + int pose = posrelat( vm.optint(3,posi), l ); int n,i; if (posi <= 0) posi = 1; if (pose > l) pose = l; - if (posi > pose) return; /* empty interval; return no values */ + if (posi > pose) return 0; /* empty interval; return no values */ n = (int)(pose - posi + 1); if (posi + n <= pose) /* overflow? */ vm.error("string slice too long"); vm.checkstack(n); for (i=0; i=0 && c<256), a, "invalid value"); bytes[i] = (byte) c; } - vm.resettop(); vm.pushlstring( bytes ); + return 1; } /** @@ -207,15 +193,16 @@ public class StringLib extends LFunction { * * TODO: port dumping code as optional add-on */ - static void dump( LuaState vm ) { - LFunction f = vm.checkfunction(2); + static int dump( LuaState vm ) { + LFunction f = vm.checkfunction(1); ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { DumpState.dump( ((LClosure)f).p, baos, true ); - vm.resettop(); vm.pushlstring(baos.toByteArray()); + return 1; } catch (IOException e) { vm.error( e.getMessage() ); + return 0; } } @@ -235,8 +222,8 @@ public class StringLib extends LFunction { * If the pattern has captures, then in a successful match the captured values * are also returned, after the two indices. */ - static void find( LuaState vm ) { - str_find_aux( vm, true ); + static int find( LuaState vm ) { + return str_find_aux( vm, true ); } /** @@ -262,11 +249,11 @@ public class StringLib extends LFunction { * This function does not accept string values containing embedded zeros, * except as arguments to the q option. */ - static void format( LuaState vm ) { - LString fmt = vm.checklstring( 2 ); + static int format( LuaState vm ) { + LString fmt = vm.checklstring( 1 ); final int n = fmt.length(); LBuffer result = new LBuffer(n); - int arg = 2; + int arg = 1; for ( int i = 0; i < n; ) { int c = fmt.luaByte( i++ ); @@ -320,8 +307,8 @@ public class StringLib extends LFunction { } } - vm.resettop(); vm.pushlstring( result.toLuaString() ); + return 1; } private static void addquoted(LBuffer buf, LString s) { @@ -528,11 +515,11 @@ public class StringLib extends LFunction { * For this function, a '^' at the start of a pattern does not work as an anchor, * as this would prevent the iteration. */ - static void gmatch( LuaState vm ) { - LString src = vm.checklstring( 2 ); - LString pat = vm.checklstring( 3 ); - vm.resettop(); + static int gmatch( LuaState vm ) { + LString src = vm.checklstring( 1 ); + LString pat = vm.checklstring( 2 ); vm.pushlvalue( new GMatchAux(vm, src, pat) ); + return 1; } static class GMatchAux extends LFunction { @@ -544,7 +531,7 @@ public class StringLib extends LFunction { this.ms = new MatchState(vm, src, pat); this.soffset = 0; } - public boolean luaStackCall(LuaState vm) { + public int invoke(LuaState vm) { vm.resettop(); for ( ; soffset x="lua-5.1.tar.gz" */ - static void gsub( LuaState vm ) { - LString src = vm.checklstring(2); + static int gsub( LuaState vm ) { + LString src = vm.checklstring( 1 ); final int srclen = src.length(); - LString p = vm.checklstring(3); - LValue repl = vm.topointer( 4 ); - int max_s = vm.optint( 5, srclen + 1 ); + LString p = vm.checklstring( 2 ); + LValue repl = vm.topointer( 3 ); + int max_s = vm.optint( 4, srclen + 1 ); final boolean anchor = p.length() > 0 && p.charAt( 0 ) == '^'; LBuffer lbuf = new LBuffer( srclen ); @@ -637,9 +624,9 @@ public class StringLib extends LFunction { break; } lbuf.append( src.substring( soffset, srclen ) ); - vm.resettop(); vm.pushlstring( lbuf.toLuaString() ); vm.pushinteger( n ); + return 2; } /** @@ -648,10 +635,9 @@ public class StringLib extends LFunction { * Receives a string and returns its length. The empty string "" has length 0. * Embedded zeros are counted, so "a\000bc\000" has length 5. */ - static void len( LuaState vm ) { - int l = vm.checklstring(2).length(); - vm.resettop(); - vm.pushinteger( l ); + static int len( LuaState vm ) { + vm.pushinteger( vm.checklstring(1).length() ); + return 1; } /** @@ -661,10 +647,9 @@ public class StringLib extends LFunction { * changed to lowercase. All other characters are left unchanged. * The definition of what an uppercase letter is depends on the current locale. */ - static void lower( LuaState vm ) { - String s = vm.checkstring(2).toLowerCase(); - vm.resettop(); - vm.pushstring( s ); + static int lower( LuaState vm ) { + vm.pushstring( vm.checkstring(1).toLowerCase() ); + return 1; } /** @@ -676,8 +661,8 @@ public class StringLib extends LFunction { * A third, optional numerical argument init specifies where to start the * search; its default value is 1 and may be negative. */ - static void match( LuaState vm ) { - str_find_aux( vm, false ); + static int match( LuaState vm ) { + return str_find_aux( vm, false ); } /** @@ -685,18 +670,16 @@ public class StringLib extends LFunction { * * Returns a string that is the concatenation of n copies of the string s. */ - static void rep( LuaState vm ) { - LString s = vm.checklstring(2); - int n = vm.checkint( 3 ); - vm.resettop(); - if ( n >= 0 ) { - final byte[] bytes = new byte[ s.length() * n ]; - int len = s.length(); - for ( int offset = 0; offset < bytes.length; offset += len ) { - s.copyInto( 0, bytes, offset, len ); - } - vm.pushlstring( bytes ); + static int rep( LuaState vm ) { + LString s = vm.checklstring( 1 ); + int n = vm.checkint( 2 ); + final byte[] bytes = new byte[ s.length() * n ]; + int len = s.length(); + for ( int offset = 0; offset < bytes.length; offset += len ) { + s.copyInto( 0, bytes, offset, len ); } + vm.pushlstring( bytes ); + return 1; } /** @@ -704,14 +687,14 @@ public class StringLib extends LFunction { * * Returns a string that is the string s reversed. */ - static void reverse( LuaState vm ) { - LString s = vm.checklstring(2); + static int reverse( LuaState vm ) { + LString s = vm.checklstring(1); int n = s.length(); byte[] b = new byte[n]; for ( int i=0, j=n-1; i 0 ) { init = Math.min( init - 1, s.length() ); @@ -774,14 +757,13 @@ public class StringLib extends LFunction { } boolean fastMatch = find && ( vm.toboolean( 5 ) || pat.indexOfAny( SPECIALS ) == -1 ); - vm.resettop(); if ( fastMatch ) { int result = s.indexOf( pat, init ); if ( result != -1 ) { vm.pushinteger( result + 1 ); vm.pushinteger( result + pat.length() ); - return; + return 2; } } else { MatchState ms = new MatchState( vm, s, pat ); @@ -794,6 +776,7 @@ public class StringLib extends LFunction { } int soff = init; + vm.resettop(); do { int res; ms.reset(); @@ -805,11 +788,12 @@ public class StringLib extends LFunction { } else { ms.push_captures( true, soff, res ); } - return; + return -1; } } while ( soff++ < s.length() && !anchor ); } vm.pushnil(); + return 1; } private static int posrelat( int pos, int len ) { diff --git a/src/core/org/luaj/lib/TableLib.java b/src/core/org/luaj/lib/TableLib.java index 9597a969..0dbdd3f2 100644 --- a/src/core/org/luaj/lib/TableLib.java +++ b/src/core/org/luaj/lib/TableLib.java @@ -79,14 +79,14 @@ public class TableLib extends LFunction { return NAMES[id]+"()"; } - public boolean luaStackCall( LuaState vm ) { + public int invoke( LuaState vm ) { switch ( id ) { /* Load the table library dynamically */ case INSTALL: install(vm._G); - break; + return 0; /* table.concat (table [, sep [, i [, j]]]) @@ -96,25 +96,24 @@ public class TableLib extends LFunction { * If i is greater than j, returns the empty string. */ case CONCAT: { - int n = vm.gettop(); - LTable table = vm.checktable(2); - LString sep = vm.optlstring(3,null); - int i = vm.optint(4,1); - int j = vm.optint(5,-1); + // int n = vm.gettop(); + LTable table = vm.checktable(1); + LString sep = vm.optlstring(2,null); + int i = vm.optint(3,1); + int j = vm.optint(4,-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"); + vm.argerror(1, "table contains non-strings"); v.luaConcatTo(baos); if ( k= 0 ) { vm.pushboolean(status != STATUS_DEAD); - this.vm.xmove(vm, this.vm.gettop() - 1); + this.vm.xmove(vm, this.vm.gettop()); } else { vm.pushboolean(true); this.vm.base = 0; diff --git a/src/core/org/luaj/vm/LuaState.java b/src/core/org/luaj/vm/LuaState.java index f27cf16b..f8ff91ff 100644 --- a/src/core/org/luaj/vm/LuaState.java +++ b/src/core/org/luaj/vm/LuaState.java @@ -247,16 +247,12 @@ public class LuaState extends Lua { * @param javaFunction */ public void invokeJavaFunction(LFunction javaFunction) { - int resultbase = base; - int resultsneeded = nresults; ++base; int nactual = javaFunction.invoke(this); - debugAssert(nactual>=0); - debugAssert(top-nactual>=base); - System.arraycopy(stack, top-nactual, stack, base=resultbase, nactual); - settop( nactual ); - if ( resultsneeded >= 0 ) - settop( resultsneeded ); + if (nactual < 0) + nactual = top - base; + System.arraycopy(stack, top-nactual, stack, --base, nactual); + luaV_settop_fillabove( base+nactual ); } // ================== error processing ================= @@ -1969,7 +1965,7 @@ public class LuaState extends Lua { * @param extramsg String to include in error message */ public void argerror(int narg, String extramsg) { - error("bad argument #" + (narg - 1) + " (" + extramsg + ")"); + error("bad argument #" + (narg) + " (" + extramsg + ")"); } /**