diff --git a/src/core/org/luaj/vm2/lib/BaseLib.java b/src/core/org/luaj/vm2/lib/BaseLib.java index 9a9a472f..75a1d299 100644 --- a/src/core/org/luaj/vm2/lib/BaseLib.java +++ b/src/core/org/luaj/vm2/lib/BaseLib.java @@ -86,39 +86,6 @@ public class BaseLib extends OneArgFunction implements ResourceFinder { */ public static ResourceFinder FINDER; - private LuaValue next; - private LuaValue inext; - - private static final String[] LIB1_KEYS = { - "getmetatable", // ( object ) -> table - "rawlen", // (v) -> value - "tostring", // (e) -> value - "type", // (v) -> value - }; - private static final String[] LIB2_KEYS = { - "collectgarbage", // ( opt [,arg] ) -> value - "error", // ( message [,level] ) -> ERR - "rawequal", // (v1, v2) -> boolean - "rawget", // (table, index) -> value - }; - private static final String[] LIBV_KEYS = { - "assert", // ( v [,message] ) -> v, message | ERR - "dofile", // ( filename ) -> result1, ... - "load", // ( ld [, source [, mode [, env]]] ) -> chunk | nil, msg - "loadfile", // ( [filename [, mode [, env]]] ) -> chunk | nil, msg - "pcall", // (f, arg1, ...) -> status, result1, ... - "xpcall", // (f, err) -> result1, ... - "print", // (...) -> void - "select", // (f, ...) -> value1, ... - "rawset", // (table, index, value) -> table - "setmetatable", // (table, metatable) -> table - "tonumber", // (e [,base]) -> value - "pairs", // "pairs" (t) -> iter-func, t, nil - "ipairs", // "ipairs", // (t) -> iter-func, t, 0 - "next", // "next" ( table, [index] ) -> next-index, next-value - "__inext", // "inext" ( table, [int-index] ) -> next-index, next-value - }; - /** * Construct a base libarary instance. */ @@ -129,17 +96,30 @@ public class BaseLib extends OneArgFunction implements ResourceFinder { public LuaValue call(LuaValue env) { env.set( "_G", env ); env.set( "_VERSION", Lua._VERSION ); - bind( env, BaseLib1.class, LIB1_KEYS ); - bind( env, BaseLib2.class, LIB2_KEYS ); - bind( env, BaseLibV.class, LIBV_KEYS ); - - // remember next, and inext for use in pairs and ipairs - next = env.get("next"); - inext = env.get("__inext"); - - // inject base lib int vararg instances - for ( int i=0; i table - { - LuaValue mt = arg.getmetatable(); - return mt!=null? mt.rawget(METATABLE).optvalue(mt): NIL; - } - case 1: // "rawlen", // (v) -> value - { - return valueOf(arg.rawlen()); - } - case 2: // "tostring", // (e) -> value - { - LuaValue h = arg.metatag(TOSTRING); - if ( ! h.isnil() ) - return h.call(arg); - LuaValue v = arg.tostring(); - if ( ! v.isnil() ) - return v; - return valueOf(arg.tojstring()); - } - case 3: // "type", // (v) -> value - { - return valueOf(arg.typename()); - } - } - return NIL; + + // "assert", // ( v [,message] ) -> v, message | ERR + static final class _assert extends VarArgFunction { + public Varargs invoke(Varargs args) { + if ( !args.arg1().toboolean() ) + error( args.narg()>1? args.optjstring(2,"assertion failed!"): "assertion failed!" ); + return args; } } - - static final class BaseLib2 extends TwoArgFunction { - public LuaValue call(LuaValue arg1, LuaValue arg2) { - switch ( opcode ) { - case 0: // "collectgarbage", // ( opt [,arg] ) -> value - String s = arg1.checkjstring(); - if ( "collect".equals(s) ) { - System.gc(); - return ZERO; - } else if ( "count".equals(s) ) { - Runtime rt = Runtime.getRuntime(); - long used = rt.totalMemory() - rt.freeMemory(); - return valueOf(used/1024.); - } else if ( "step".equals(s) ) { - System.gc(); - return LuaValue.TRUE; - } else { - this.argerror("gc op"); - } - return NIL; - case 1: // "error", // ( message [,level] ) -> ERR - throw new LuaError( arg1.isnil()? null: arg1.tojstring(), arg2.optint(1) ); - case 2: // "rawequal", // (v1, v2) -> boolean - return valueOf(arg1.raweq(arg2)); - case 3: // "rawget", // (table, index) -> value - return arg1.rawget(arg2); + + // "collectgarbage", // ( opt [,arg] ) -> value + static final class collectgarbage extends VarArgFunction { + public Varargs invoke(Varargs args) { + String s = args.checkjstring(1); + if ( "collect".equals(s) ) { + System.gc(); + return ZERO; + } else if ( "count".equals(s) ) { + Runtime rt = Runtime.getRuntime(); + long used = rt.totalMemory() - rt.freeMemory(); + return varargsOf(valueOf(used/1024.), valueOf(used%1024)); + } else if ( "step".equals(s) ) { + System.gc(); + return LuaValue.TRUE; + } else { + this.argerror("gc op"); } return NIL; } } - static final class BaseLibV extends VarArgFunction { - public BaseLib baselib; + // "dofile", // ( filename ) -> result1, ... + static final class dofile extends VarArgFunction { + final BaseLib baselib; + dofile(BaseLib baselib) { + this.baselib = baselib; + } public Varargs invoke(Varargs args) { - switch ( opcode ) { - case 0: // "assert", // ( v [,message] ) -> v, message | ERR - if ( !args.arg1().toboolean() ) - error( args.narg()>1? args.optjstring(2,"assertion failed!"): "assertion failed!" ); - return args; - case 1: // "dofile", // ( filename ) -> result1, ... - { - args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil"); - String filename = args.isstring(1)? args.tojstring(1): null; - Varargs v = filename == null? - BaseLib.loadStream( baselib.STDIN, "=stdin", "bt",LuaValue._G ): - BaseLib.loadFile( args.checkjstring(1), "bt",LuaValue._G ); - return v.isnil(1)? error(v.tojstring(2)): v.arg1().invoke(); + args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil"); + String filename = args.isstring(1)? args.tojstring(1): null; + Varargs v = filename == null? + BaseLib.loadStream( baselib.STDIN, "=stdin", "bt",LuaValue._G ): + BaseLib.loadFile( args.checkjstring(1), "bt",LuaValue._G ); + return v.isnil(1)? error(v.tojstring(2)): v.arg1().invoke(); + } + } + + // "error", // ( message [,level] ) -> ERR + static final class error extends TwoArgFunction { + public LuaValue call(LuaValue arg1, LuaValue arg2) { + throw new LuaError( arg1.isnil()? null: arg1.tojstring(), arg2.optint(1) ); + } + } + + // "getmetatable", // ( object ) -> table + static final class getmetatable extends LibFunction { + public LuaValue call() { + return argerror(1, "value"); + } + public LuaValue call(LuaValue arg) { + LuaValue mt = arg.getmetatable(); + return mt!=null? mt.rawget(METATABLE).optvalue(mt): NIL; + } + } + // "load", // ( ld [, source [, mode [, env]]] ) -> chunk | nil, msg + static final class load extends VarArgFunction { + public Varargs invoke(Varargs args) { + LuaValue ld = args.arg1(); + args.argcheck(ld.isstring() || ld.isfunction(), 1, "ld must be string or function"); + String source = args.optjstring(2, ld.isstring()? ld.tojstring(): "=(load)"); + String mode = args.optjstring(3, "bt"); + LuaValue env = args.optvalue(4,LuaValue._G); + return BaseLib.loadStream(ld.isstring()? ld.strvalue().toInputStream(): + new StringInputStream(ld.checkfunction()), source, mode, env); + } + } + + // "loadfile", // ( [filename [, mode [, env]]] ) -> chunk | nil, msg + static final class loadfile extends VarArgFunction { + final BaseLib baselib; + loadfile(BaseLib baselib) { + this.baselib = baselib; + } + public Varargs invoke(Varargs args) { + args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil"); + String filename = args.isstring(1)? args.tojstring(1): null; + String mode = args.optjstring(2, "bt"); + LuaValue env = args.optvalue(3,LuaValue._G); + return filename == null? + BaseLib.loadStream( baselib.STDIN, "=stdin", mode, env ): + BaseLib.loadFile( filename, mode, env ); + } + } + + // "pcall", // (f, arg1, ...) -> status, result1, ... + static final class pcall extends VarArgFunction { + public Varargs invoke(Varargs args) { + LuaValue func = args.checkvalue(1); + LuaThread.CallStack cs = LuaThread.onCall(this); + try { + return pcall(func,args.subargs(2),null); + } finally { + cs.onReturn(); } - case 2: // "load", // ( ld [, source [, mode [, env]]] ) -> chunk | nil, msg - { - LuaValue ld = args.arg1(); - args.argcheck(ld.isstring() || ld.isfunction(), 1, "ld must be string or function"); - String source = args.optjstring(2, ld.isstring()? ld.tojstring(): "=(load)"); - String mode = args.optjstring(3, "bt"); - LuaValue env = args.optvalue(4,LuaValue._G); - return BaseLib.loadStream(ld.isstring()? ld.strvalue().toInputStream(): - new StringInputStream(ld.checkfunction()), source, mode, env); - } - case 3: // "loadfile", // ( [filename [, mode [, env]]] ) -> chunk | nil, msg - { - args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil"); - String filename = args.isstring(1)? args.tojstring(1): null; - String mode = args.optjstring(2, "bt"); - LuaValue env = args.optvalue(3,LuaValue._G); - return filename == null? - BaseLib.loadStream( baselib.STDIN, "=stdin", mode, env ): - BaseLib.loadFile( filename, mode, env ); - } - case 4: // "pcall", // (f, arg1, ...) -> status, result1, ... - { - LuaValue func = args.checkvalue(1); - LuaThread.CallStack cs = LuaThread.onCall(this); - try { - return pcall(func,args.subargs(2),null); - } finally { - cs.onReturn(); - } - } - case 5: // "xpcall", // (f, err) -> result1, ... - { - LuaThread.CallStack cs = LuaThread.onCall(this); - try { - return pcall(args.arg1(),NONE,args.checkvalue(2)); - } finally { - cs.onReturn(); - } - } - case 6: // "print", // (...) -> void - { - LuaValue tostring =LuaValue._G.get("tostring"); - for ( int i=1, n=args.narg(); i<=n; i++ ) { - if ( i>1 ) baselib.STDOUT.write( '\t' ); - LuaString s = tostring.call( args.arg(i) ).strvalue(); - int z = s.indexOf((byte)0, 0); - baselib.STDOUT.write( s.m_bytes, s.m_offset, z>=0? z: s.m_length ); - } - baselib.STDOUT.println(); - return NONE; - } - case 7: // "select", // (f, ...) -> value1, ... - { - int n = args.narg()-1; - if ( args.arg1().equals(valueOf("#")) ) - return valueOf(n); - int i = args.checkint(1); - if ( i == 0 || i < -n ) - argerror(1,"index out of range"); - return args.subargs(i<0? n+i+2: i+1); - } - case 8: { // "rawset", // (table, index, value) -> table - LuaTable t = args.checktable(1); - t.rawset(args.checknotnil(2), args.checkvalue(3)); - return t; - } - case 9: { // "setmetatable", // (table, metatable) -> table - final LuaValue t = args.arg1(); - final LuaValue mt0 = t.getmetatable(); - if ( mt0!=null && !mt0.rawget(METATABLE).isnil() ) - error("cannot change a protected metatable"); - final LuaValue mt = args.checkvalue(2); - return t.setmetatable(mt.isnil()? null: mt.checktable()); - } - case 10: { // "tonumber", // (e [,base]) -> value - LuaValue arg1 = args.checkvalue(1); - final int base = args.optint(2,10); - if (base == 10) { /* standard conversion */ - return arg1.tonumber(); - } else { - if ( base < 2 || base > 36 ) - argerror(2, "base out of range"); - return arg1.checkstring().tonumber(base); - } - } - case 11: // "pairs" (t) -> iter-func, t, nil - return varargsOf( baselib.next, args.checktable(1), NIL ); - case 12: // "ipairs", // (t) -> iter-func, t, 0 - return varargsOf( baselib.inext, args.checktable(1), ZERO ); - case 13: // "next" ( table, [index] ) -> next-index, next-value - return args.checktable(1).next(args.arg(2)); - case 14: // "inext" ( table, [int-index] ) -> next-index, next-value - return args.checktable(1).inext(args.arg(2)); + } + } + + // "print", // (...) -> void + static final class print extends VarArgFunction { + final BaseLib baselib; + print(BaseLib baselib) { + this.baselib = baselib; + } + public Varargs invoke(Varargs args) { + LuaValue tostring =LuaValue._G.get("tostring"); + for ( int i=1, n=args.narg(); i<=n; i++ ) { + if ( i>1 ) baselib.STDOUT.write( '\t' ); + LuaString s = tostring.call( args.arg(i) ).strvalue(); + int z = s.indexOf((byte)0, 0); + baselib.STDOUT.write( s.m_bytes, s.m_offset, z>=0? z: s.m_length ); } + baselib.STDOUT.println(); return NONE; } } + + + // "rawequal", // (v1, v2) -> boolean + static final class rawequal extends LibFunction { + public LuaValue call() { + return argerror(1, "value"); + } + public LuaValue call(LuaValue arg) { + return argerror(2, "value"); + } + public LuaValue call(LuaValue arg1, LuaValue arg2) { + return valueOf(arg1.raweq(arg2)); + } + } + + // "rawget", // (table, index) -> value + static final class rawget extends LibFunction { + public LuaValue call() { + return argerror(1, "value"); + } + public LuaValue call(LuaValue arg) { + return argerror(2, "value"); + } + public LuaValue call(LuaValue arg1, LuaValue arg2) { + return arg1.checktable().rawget(arg2); + } + } + + + // "rawlen", // (v) -> value + static final class rawlen extends LibFunction { + public LuaValue call(LuaValue arg) { + return valueOf(arg.rawlen()); + } + } + + // "rawset", // (table, index, value) -> table + static final class rawset extends LibFunction { + public LuaValue call(LuaValue table) { + return argerror(2,"value"); + } + public LuaValue call(LuaValue table, LuaValue index) { + return argerror(3,"value"); + } + public LuaValue call(LuaValue table, LuaValue index, LuaValue value) { + LuaTable t = table.checktable(); + t.rawset(index.checknotnil(), value); + return t; + } + } + + // "select", // (f, ...) -> value1, ... + static final class select extends VarArgFunction { + public Varargs invoke(Varargs args) { + int n = args.narg()-1; + if ( args.arg1().equals(valueOf("#")) ) + return valueOf(n); + int i = args.checkint(1); + if ( i == 0 || i < -n ) + argerror(1,"index out of range"); + return args.subargs(i<0? n+i+2: i+1); + } + } + + // "setmetatable", // (table, metatable) -> table + static final class setmetatable extends LibFunction { + public LuaValue call(LuaValue table) { + return argerror(2,"value"); + } + public LuaValue call(LuaValue table, LuaValue metatable) { + final LuaValue mt0 = table.getmetatable(); + if ( mt0!=null && !mt0.rawget(METATABLE).isnil() ) + error("cannot change a protected metatable"); + return table.setmetatable(metatable.isnil()? null: metatable.checktable()); + } + } + + // "tonumber", // (e [,base]) -> value + static final class tonumber extends LibFunction { + public LuaValue call(LuaValue e) { + return e.tonumber(); + } + public LuaValue call(LuaValue e, LuaValue base) { + if (base.isnil()) + return e.tonumber(); + final int b = base.optint(10); + if ( b < 2 || b > 36 ) + argerror(2, "base out of range"); + return e.checkstring().tonumber(b); + } + } + + // "tostring", // (e) -> value + static final class tostring extends LibFunction { + public LuaValue call(LuaValue arg) { + LuaValue h = arg.metatag(TOSTRING); + if ( ! h.isnil() ) + return h.call(arg); + LuaValue v = arg.tostring(); + if ( ! v.isnil() ) + return v; + return valueOf(arg.tojstring()); + } + } + + // "type", // (v) -> value + static final class type extends LibFunction { + public LuaValue call(LuaValue arg) { + return valueOf(arg.typename()); + } + } + + // "xpcall", // (f, err) -> result1, ... + static final class xpcall extends VarArgFunction { + public Varargs invoke(Varargs args) { + LuaThread.CallStack cs = LuaThread.onCall(this); + try { + return pcall(args.arg1(),NONE,args.checkvalue(2)); + } finally { + cs.onReturn(); + } + } + } + + // "pairs" (t) -> iter-func, t, nil + static final class pairs extends VarArgFunction { + final next next; + pairs(next next) { + this.next = next; + } + public Varargs invoke(Varargs args) { + return varargsOf( next, args.checktable(1), NIL ); + } + } + + // // "ipairs", // (t) -> iter-func, t, 0 + static final class ipairs extends VarArgFunction { + inext inext = new inext(); + public Varargs invoke(Varargs args) { + return varargsOf( inext, args.checktable(1), ZERO ); + } + } + + // "next" ( table, [index] ) -> next-index, next-value + static final class next extends VarArgFunction { + public Varargs invoke(Varargs args) { + return args.checktable(1).next(args.arg(2)); + } + } + + // "inext" ( table, [int-index] ) -> next-index, next-value + static final class inext extends VarArgFunction { + public Varargs invoke(Varargs args) { + return args.checktable(1).inext(args.arg(2)); + } + } public static Varargs pcall(LuaValue func, Varargs args, LuaValue errfunc) { LuaValue olderr = LuaThread.setErrorFunc(errfunc); diff --git a/src/core/org/luaj/vm2/lib/LibFunction.java b/src/core/org/luaj/vm2/lib/LibFunction.java index fb84018e..a1d26aaa 100644 --- a/src/core/org/luaj/vm2/lib/LibFunction.java +++ b/src/core/org/luaj/vm2/lib/LibFunction.java @@ -193,7 +193,7 @@ abstract public class LibFunction extends LuaFunction { } public LuaValue call() { - return typerror("value"); + return argerror(1,"value"); } public LuaValue call(LuaValue a) { return call();