From a5fddce465b4e77f7a8d38e7e20d925b1e6a5b95 Mon Sep 17 00:00:00 2001 From: James Roseborough Date: Thu, 6 Sep 2012 04:01:28 +0000 Subject: [PATCH] Lua 5.2 compatibility updates to VM and base and package libraries. --- src/core/org/luaj/vm2/LoadState.java | 3 +- src/core/org/luaj/vm2/LuaString.java | 4 + src/core/org/luaj/vm2/LuaTable.java | 6 +- src/core/org/luaj/vm2/LuaValue.java | 6 + src/core/org/luaj/vm2/lib/BaseLib.java | 193 +++++++------- src/core/org/luaj/vm2/lib/DebugLib.java | 41 +-- src/core/org/luaj/vm2/lib/MathLib.java | 1 - src/core/org/luaj/vm2/lib/PackageLib.java | 236 ++++++------------ src/core/org/luaj/vm2/lib/TableLib.java | 18 +- src/jse/lua.java | 17 +- src/jse/org/luaj/vm2/lib/jse/JseMathLib.java | 7 +- .../org/luaj/vm2/script/LuaScriptEngine.java | 2 +- test/junit/org/luaj/vm2/FragmentsTest.java | 1 - test/junit/org/luaj/vm2/MathLibTest.java | 16 -- .../org/luaj/vm2/OrphanedThreadTest.java | 6 +- test/junit/org/luaj/vm2/ScriptDrivenTest.java | 2 +- .../vm2/compiler/DumpLoadEndianIntTest.java | 2 +- test/lua/baselib.lua | 11 + 18 files changed, 244 insertions(+), 328 deletions(-) diff --git a/src/core/org/luaj/vm2/LoadState.java b/src/core/org/luaj/vm2/LoadState.java index 78d37fd1..20410631 100644 --- a/src/core/org/luaj/vm2/LoadState.java +++ b/src/core/org/luaj/vm2/LoadState.java @@ -373,11 +373,12 @@ public class LoadState { * @param firstByte the first byte of the input stream * @param stream InputStream to read, after having read the first byte already * @param name Name to apply to the loaded chunk + * @param mode "b" for binary only, "t" for text only, "bt" for binary or text. * @return {@link Prototype} that was loaded * @throws IllegalArgumentException if the signature is bac * @throws IOException if an IOException occurs */ - public static LuaFunction load( InputStream stream, String name, LuaValue env ) throws IOException { + public static LuaFunction load( InputStream stream, String name, String mode, LuaValue env ) throws IOException { if ( compiler != null ) return compiler.load(stream, name, env); else { diff --git a/src/core/org/luaj/vm2/LuaString.java b/src/core/org/luaj/vm2/LuaString.java index 50326eed..5e540dee 100644 --- a/src/core/org/luaj/vm2/LuaString.java +++ b/src/core/org/luaj/vm2/LuaString.java @@ -420,6 +420,10 @@ public class LuaString extends LuaValue { return m_length; } + public int rawlen() { + return m_length; + } + public int luaByte(int index) { return m_bytes[m_offset + index] & 0x0FF; } diff --git a/src/core/org/luaj/vm2/LuaTable.java b/src/core/org/luaj/vm2/LuaTable.java index 93cf9980..9e9a08c8 100644 --- a/src/core/org/luaj/vm2/LuaTable.java +++ b/src/core/org/luaj/vm2/LuaTable.java @@ -393,7 +393,11 @@ public class LuaTable extends LuaValue { public LuaValue len() { return LuaInteger.valueOf(length()); } - + + public int rawlen() { + return length(); + } + /** Return table.maxn() as defined by lua 5.0. *

* Provided for compatibility, not a scalable operation. diff --git a/src/core/org/luaj/vm2/LuaValue.java b/src/core/org/luaj/vm2/LuaValue.java index e88fb706..0f979644 100644 --- a/src/core/org/luaj/vm2/LuaValue.java +++ b/src/core/org/luaj/vm2/LuaValue.java @@ -2014,6 +2014,12 @@ public class LuaValue extends Varargs { */ public int length() { return len().toint(); } + /** Get raw length of table or string without metatag processing. + * @return the length of the table or string. + * @throws LuaError if {@code this} is not a table or string. + */ + public int rawlen() { typerror("table or string"); return 0; } + /** Implementation of lua 5.0 getn() function. * @return value of getn() as defined in lua 5.0 spec if {@code this} is a {@link LuaTable} * @throws LuaError if {@code this} is not a {@link LuaTable} diff --git a/src/core/org/luaj/vm2/lib/BaseLib.java b/src/core/org/luaj/vm2/lib/BaseLib.java index 9b5ecffe..cbe9593d 100644 --- a/src/core/org/luaj/vm2/lib/BaseLib.java +++ b/src/core/org/luaj/vm2/lib/BaseLib.java @@ -89,30 +89,29 @@ public class BaseLib extends OneArgFunction implements ResourceFinder { 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 - "setfenv", // (f, table) -> void + "rawequal", // (v1, v2) -> boolean + "rawget", // (table, index) -> value }; private static final String[] LIBV_KEYS = { "assert", // ( v [,message] ) -> v, message | ERR "dofile", // ( filename ) -> result1, ... - "getfenv", // ( [f] ) -> env - "getmetatable", // ( object ) -> table - "load", // ( func [,chunkname] ) -> chunk | nil, msg - "loadfile", // ( [filename] ) -> chunk | nil, msg - "loadstring", // ( string [,chunkname] ) -> chunk | nil, msg + "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, ... - "unpack", // (list [,i [,j]]) -> result1, ... - "type", // (v) -> value - "rawequal", // (v1, v2) -> boolean - "rawget", // (table, index) -> value "rawset", // (table, index, value) -> table "setmetatable", // (table, metatable) -> table - "tostring", // (e) -> value "tonumber", // (e [,base]) -> value "pairs", // "pairs" (t) -> iter-func, t, nil "ipairs", // "ipairs", // (t) -> iter-func, t, 0 @@ -130,6 +129,7 @@ public class BaseLib extends OneArgFunction implements ResourceFinder { public LuaValue call(LuaValue arg) { 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 ); @@ -156,12 +156,42 @@ public class BaseLib extends OneArgFunction implements ResourceFinder { return c.getResourceAsStream(filename.startsWith("/")? filename: "/"+filename); } + static final class BaseLib1 extends OneArgFunction { + public LuaValue call(LuaValue arg) { + switch ( opcode ) { + case 0: // "getmetatable", // ( object ) -> 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; + } + } + 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(); - int result = 0; if ( "collect".equals(s) ) { System.gc(); return ZERO; @@ -173,35 +203,19 @@ public class BaseLib extends OneArgFunction implements ResourceFinder { System.gc(); return LuaValue.TRUE; } else { - this.argerror(1, "gc op"); + 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: { // "setfenv", // (f, table) -> void - LuaTable t = arg2.checktable(); - LuaValue f = getfenvobj(arg1); - if ( ! f.isfunction() && ! f.isclosure() ) - error("'setfenv' cannot change environment of given object"); - f.setfenv(t); - return f.isthread()? NONE: f; - } + case 2: // "rawequal", // (v1, v2) -> boolean + return valueOf(arg1.raweq(arg2)); + case 3: // "rawget", // (table, index) -> value + return arg1.rawget(arg2); } return NIL; } } - - private static LuaValue getfenvobj(LuaValue arg) { - if ( arg.isfunction() ) - return arg; - int level = arg.optint(1); - arg.argcheck(level>=0, 1, "level must be non-negative"); - if ( level == 0 ) - return LuaThread.getRunning(); - LuaValue f = LuaThread.getCallstackFunction(level); - arg.argcheck(f != null, 1, "invalid level"); - return f; - } static final class BaseLibV extends VarArgFunction { public BaseLib baselib; @@ -213,41 +227,34 @@ public class BaseLib extends OneArgFunction implements ResourceFinder { return args; case 1: // "dofile", // ( filename ) -> result1, ... { - Varargs v = args.isnil(1)? - BaseLib.loadStream( baselib.STDIN, "=stdin" ): - BaseLib.loadFile( args.checkjstring(1) ); + 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", LuaThread.getGlobals() ): + BaseLib.loadFile( args.checkjstring(1), "bt", LuaThread.getGlobals() ); return v.isnil(1)? error(v.tojstring(2)): v.arg1().invoke(); } - case 2: // "getfenv", // ( [f] ) -> env + case 2: // "load", // ( ld [, source [, mode [, env]]] ) -> chunk | nil, msg { - LuaValue f = getfenvobj(args.arg1()); - LuaValue e = f.getfenv(); - return e!=null? e: NIL; + 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, LuaThread.getGlobals()); + return BaseLib.loadStream(ld.isstring()? ld.strvalue().toInputStream(): + new StringInputStream(ld.checkfunction()), source, mode, env); } - case 3: // "getmetatable", // ( object ) -> table + case 3: // "loadfile", // ( [filename [, mode [, env]]] ) -> chunk | nil, msg { - LuaValue mt = args.checkvalue(1).getmetatable(); - return mt!=null? mt.rawget(METATABLE).optvalue(mt): NIL; + 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, LuaThread.getGlobals()); + return filename == null? + BaseLib.loadStream( baselib.STDIN, "=stdin", mode, env ): + BaseLib.loadFile( filename, mode, env ); } - case 4: // "load", // ( func [,chunkname] ) -> chunk | nil, msg - { - LuaValue func = args.checkfunction(1); - String chunkname = args.optjstring(2, "function"); - return BaseLib.loadStream(new StringInputStream(func), chunkname); - } - case 5: // "loadfile", // ( [filename] ) -> chunk | nil, msg - { - return args.isnil(1)? - BaseLib.loadStream( baselib.STDIN, "stdin" ): - BaseLib.loadFile( args.checkjstring(1) ); - } - case 6: // "loadstring", // ( string [,chunkname] ) -> chunk | nil, msg - { - LuaString script = args.checkstring(1); - String chunkname = args.optjstring(2, "string"); - return BaseLib.loadStream(script.toInputStream(),chunkname); - } - case 7: // "pcall", // (f, arg1, ...) -> status, result1, ... + case 4: // "pcall", // (f, arg1, ...) -> status, result1, ... { LuaValue func = args.checkvalue(1); LuaThread.CallStack cs = LuaThread.onCall(this); @@ -257,7 +264,7 @@ public class BaseLib extends OneArgFunction implements ResourceFinder { cs.onReturn(); } } - case 8: // "xpcall", // (f, err) -> result1, ... + case 5: // "xpcall", // (f, err) -> result1, ... { LuaThread.CallStack cs = LuaThread.onCall(this); try { @@ -266,7 +273,7 @@ public class BaseLib extends OneArgFunction implements ResourceFinder { cs.onReturn(); } } - case 9: // "print", // (...) -> void + case 6: // "print", // (...) -> void { LuaValue tostring = LuaThread.getGlobals().get("tostring"); for ( int i=1, n=args.narg(); i<=n; i++ ) { @@ -278,7 +285,7 @@ public class BaseLib extends OneArgFunction implements ResourceFinder { baselib.STDOUT.println(); return NONE; } - case 10: // "select", // (f, ...) -> value1, ... + case 7: // "select", // (f, ...) -> value1, ... { int n = args.narg()-1; if ( args.arg1().equals(valueOf("#")) ) @@ -288,34 +295,12 @@ public class BaseLib extends OneArgFunction implements ResourceFinder { argerror(1,"index out of range"); return args.subargs(i<0? n+i+2: i+1); } - case 11: // "unpack", // (list [,i [,j]]) -> result1, ... - { - int na = args.narg(); - LuaTable t = args.checktable(1); - int n = t.length(); - int i = na>=2? args.checkint(2): 1; - int j = na>=3? args.checkint(3): n; - n = j-i+1; - if ( n<0 ) return NONE; - if ( n==1 ) return t.get(i); - if ( n==2 ) return varargsOf(t.get(i),t.get(j)); - LuaValue[] v = new LuaValue[n]; - for ( int k=0; k value - return valueOf(args.checkvalue(1).typename()); - case 13: // "rawequal", // (v1, v2) -> boolean - return valueOf(args.checkvalue(1) == args.checkvalue(2)); - case 14: // "rawget", // (table, index) -> value - return args.checktable(1).rawget(args.checkvalue(2)); - case 15: { // "rawset", // (table, index, value) -> table + case 8: { // "rawset", // (table, index, value) -> table LuaTable t = args.checktable(1); t.rawset(args.checknotnil(2), args.checkvalue(3)); return t; } - case 16: { // "setmetatable", // (table, metatable) -> table + case 9: { // "setmetatable", // (table, metatable) -> table final LuaValue t = args.arg1(); final LuaValue mt0 = t.getmetatable(); if ( mt0!=null && !mt0.rawget(METATABLE).isnil() ) @@ -323,17 +308,7 @@ public class BaseLib extends OneArgFunction implements ResourceFinder { final LuaValue mt = args.checkvalue(2); return t.setmetatable(mt.isnil()? null: mt.checktable()); } - case 17: { // "tostring", // (e) -> value - LuaValue arg = args.checkvalue(1); - 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 18: { // "tonumber", // (e [,base]) -> value + case 10: { // "tonumber", // (e [,base]) -> value LuaValue arg1 = args.checkvalue(1); final int base = args.optint(2,10); if (base == 10) { /* standard conversion */ @@ -344,13 +319,13 @@ public class BaseLib extends OneArgFunction implements ResourceFinder { return arg1.checkstring().tonumber(base); } } - case 19: // "pairs" (t) -> iter-func, t, nil + case 11: // "pairs" (t) -> iter-func, t, nil return varargsOf( baselib.next, args.checktable(1), NIL ); - case 20: // "ipairs", // (t) -> iter-func, t, 0 + case 12: // "ipairs", // (t) -> iter-func, t, 0 return varargsOf( baselib.inext, args.checktable(1), ZERO ); - case 21: // "next" ( table, [index] ) -> next-index, next-value + case 13: // "next" ( table, [index] ) -> next-index, next-value return args.checktable(1).next(args.arg(2)); - case 22: // "inext" ( table, [int-index] ) -> next-index, next-value + case 14: // "inext" ( table, [int-index] ) -> next-index, next-value return args.checktable(1).inext(args.arg(2)); } return NONE; @@ -376,14 +351,16 @@ public class BaseLib extends OneArgFunction implements ResourceFinder { /** * Load from a named file, returning the chunk or nil,error of can't load + * @param env + * @param mode * @return Varargs containing chunk, or NIL,error-text on error */ - public static Varargs loadFile(String filename) { + public static Varargs loadFile(String filename, String mode, LuaValue env) { InputStream is = FINDER.findResource(filename); if ( is == null ) return varargsOf(NIL, valueOf("cannot open "+filename+": No such file or directory")); try { - return loadStream(is, "@"+filename); + return loadStream(is, "@"+filename, mode, env); } finally { try { is.close(); @@ -393,11 +370,11 @@ public class BaseLib extends OneArgFunction implements ResourceFinder { } } - public static Varargs loadStream(InputStream is, String chunkname) { + public static Varargs loadStream(InputStream is, String chunkname, String mode, LuaValue env) { try { if ( is == null ) return varargsOf(NIL, valueOf("not found: "+chunkname)); - return LoadState.load(is, chunkname, LuaThread.getGlobals()); + return LoadState.load(is, chunkname, mode, env); } catch (Exception e) { return varargsOf(NIL, valueOf(e.getMessage())); } diff --git a/src/core/org/luaj/vm2/lib/DebugLib.java b/src/core/org/luaj/vm2/lib/DebugLib.java index 55f74858..1b423e8c 100644 --- a/src/core/org/luaj/vm2/lib/DebugLib.java +++ b/src/core/org/luaj/vm2/lib/DebugLib.java @@ -76,14 +76,12 @@ public class DebugLib extends VarArgFunction { static final String[] NAMES = { "debug", - "getfenv", "gethook", "getinfo", "getlocal", "getmetatable", "getregistry", "getupvalue", - "setfenv", "sethook", "setlocal", "setmetatable", @@ -93,19 +91,17 @@ public class DebugLib extends VarArgFunction { private static final int INIT = 0; private static final int DEBUG = 1; - private static final int GETFENV = 2; - private static final int GETHOOK = 3; - private static final int GETINFO = 4; - private static final int GETLOCAL = 5; - private static final int GETMETATABLE = 6; - private static final int GETREGISTRY = 7; - private static final int GETUPVALUE = 8; - private static final int SETFENV = 9; - private static final int SETHOOK = 10; - private static final int SETLOCAL = 11; - private static final int SETMETATABLE = 12; - private static final int SETUPVALUE = 13; - private static final int TRACEBACK = 14; + private static final int GETHOOK = 2; + private static final int GETINFO = 3; + private static final int GETLOCAL = 4; + private static final int GETMETATABLE = 5; + private static final int GETREGISTRY = 6; + private static final int GETUPVALUE = 7; + private static final int SETHOOK = 8; + private static final int SETLOCAL = 9; + private static final int SETMETATABLE = 10; + private static final int SETUPVALUE = 11; + private static final int TRACEBACK = 12; /* maximum stack for a Lua function */ private static final int MAXSTACK = 250; @@ -153,14 +149,12 @@ public class DebugLib extends VarArgFunction { switch ( opcode ) { case INIT: return init(); case DEBUG: return _debug(args); - case GETFENV: return _getfenv(args); case GETHOOK: return _gethook(args); case GETINFO: return _getinfo(args,this); case GETLOCAL: return _getlocal(args); case GETMETATABLE: return _getmetatable(args); case GETREGISTRY: return _getregistry(args); case GETUPVALUE: return _getupvalue(args); - case SETFENV: return _setfenv(args); case SETHOOK: return _sethook(args); case SETLOCAL: return _setlocal(args); case SETMETATABLE: return _setmetatable(args); @@ -438,19 +432,6 @@ public class DebugLib extends VarArgFunction { return NONE; } - static Varargs _getfenv(Varargs args) { - LuaValue object = args.arg1(); - LuaValue env = object.getfenv(); - return env!=null? env: LuaValue.NIL; - } - - static Varargs _setfenv(Varargs args) { - LuaValue object = args.arg1(); - LuaTable table = args.checktable(2); - object.setfenv(table); - return object; - } - protected static Varargs _getinfo(Varargs args, LuaValue level0func) { int a=1; LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning(); diff --git a/src/core/org/luaj/vm2/lib/MathLib.java b/src/core/org/luaj/vm2/lib/MathLib.java index 7146a8bc..e55b5b40 100644 --- a/src/core/org/luaj/vm2/lib/MathLib.java +++ b/src/core/org/luaj/vm2/lib/MathLib.java @@ -42,7 +42,6 @@ import org.luaj.vm2.Varargs; *

  • atan
  • *
  • cosh
  • *
  • log
  • - *
  • log10
  • *
  • sinh
  • *
  • tanh
  • *
  • atan2
  • diff --git a/src/core/org/luaj/vm2/lib/PackageLib.java b/src/core/org/luaj/vm2/lib/PackageLib.java index 256c2519..cdaa8b74 100644 --- a/src/core/org/luaj/vm2/lib/PackageLib.java +++ b/src/core/org/luaj/vm2/lib/PackageLib.java @@ -76,51 +76,47 @@ public class PackageLib extends OneArgFunction { public static PackageLib instance; /** Loader that loads from preload table if found there */ - public LuaValue preload_loader; + public LuaValue preload_searcher; /** Loader that loads as a lua script using the LUA_PATH */ - public LuaValue lua_loader; + public LuaValue lua_searcher; /** Loader that loads as a Java class. Class must have public constructor and be a LuaValue */ - public LuaValue java_loader; + public LuaValue java_searcher; - private static final LuaString _M = valueOf("_M"); - private static final LuaString _NAME = valueOf("_NAME"); - private static final LuaString _PACKAGE = valueOf("_PACKAGE"); - private static final LuaString _DOT = valueOf("."); - private static final LuaString _LOADERS = valueOf("loaders"); - private static final LuaString _LOADED = valueOf("loaded"); - private static final LuaString _LOADLIB = valueOf("loadlib"); - private static final LuaString _PRELOAD = valueOf("preload"); - private static final LuaString _PATH = valueOf("path"); - private static final LuaString _SEEALL = valueOf("seeall"); - private static final LuaString _SENTINEL = valueOf("\u0001"); - - private static final int OP_MODULE = 0; - private static final int OP_REQUIRE = 1; - private static final int OP_LOADLIB = 2; - private static final int OP_SEEALL = 3; - private static final int OP_PRELOAD_LOADER = 4; - private static final int OP_LUA_LOADER = 5; - private static final int OP_JAVA_LOADER = 6; + private static final LuaString _LOADED = valueOf("loaded"); + private static final LuaString _LOADLIB = valueOf("loadlib"); + private static final LuaString _PRELOAD = valueOf("preload"); + private static final LuaString _PATH = valueOf("path"); + private static final LuaString _SEARCHERS = valueOf("searchers"); + private static final LuaString _SEARCHPATH = valueOf("searchpath"); + private static final LuaString _SENTINEL = valueOf("\u0001"); + private static final int OP_REQUIRE = 0; + private static final int OP_LOADLIB = 1; + private static final int OP_SEARCHPATH = 2; + private static final int OP_PRELOAD_SEARCHER = 3; + private static final int OP_LUA_SEARCHER = 4; + private static final int OP_JAVA_SEARCHER = 5; + + private static final String FILE_SEP = System.getProperty("file.separator"); + public PackageLib() { instance = this; } public LuaValue call(LuaValue arg) { env.set("require", new PkgLib1(env,"require",OP_REQUIRE,this)); - env.set("module", new PkgLibV(env,"module",OP_MODULE,this)); env.set( "package", PACKAGE=tableOf( new LuaValue[] { _LOADED, LOADED=tableOf(), _PRELOAD, tableOf(), _PATH, valueOf(DEFAULT_LUA_PATH), _LOADLIB, new PkgLibV(env,"loadlib",OP_LOADLIB,this), - _SEEALL, new PkgLib1(env,"seeall",OP_SEEALL,this), - _LOADERS, listOf(new LuaValue[] { - preload_loader = new PkgLibV(env,"preload_loader", OP_PRELOAD_LOADER,this), - lua_loader = new PkgLibV(env,"lua_loader", OP_LUA_LOADER,this), - java_loader = new PkgLibV(env,"java_loader", OP_JAVA_LOADER,this), + _SEARCHPATH, new PkgLibV(env,"searchpath",OP_SEARCHPATH,this), + _SEARCHERS, listOf(new LuaValue[] { + preload_searcher = new PkgLibV(env,"preload_searcher", OP_PRELOAD_SEARCHER,this), + lua_searcher = new PkgLibV(env,"lua_searcher", OP_LUA_SEARCHER,this), + java_searcher = new PkgLibV(env,"java_searcher", OP_JAVA_SEARCHER,this), }) }) ); LOADED.set("package", PACKAGE); return env; @@ -138,14 +134,6 @@ public class PackageLib extends OneArgFunction { switch ( opcode ) { case OP_REQUIRE: return lib.require(arg); - case OP_SEEALL: { - LuaTable t = arg.checktable(); - LuaValue m = t.getmetatable(); - if ( m == null ) - t.setmetatable(m=tableOf()); - m.set( INDEX, LuaThread.getGlobals() ); - return NONE; - } } return NIL; } @@ -161,18 +149,24 @@ public class PackageLib extends OneArgFunction { } public Varargs invoke(Varargs args) { switch ( opcode ) { - case OP_MODULE: - return lib.module(args); - case OP_LOADLIB: + case OP_LOADLIB: { return loadlib(args); - case OP_PRELOAD_LOADER: { - return lib.loader_preload(args); } - case OP_LUA_LOADER: { - return lib.loader_Lua(args); + case OP_PRELOAD_SEARCHER: { + return lib.searcher_preload(args); } - case OP_JAVA_LOADER: { - return lib.loader_Java(args); + case OP_LUA_SEARCHER: { + return lib.searcher_Lua(args); + } + case OP_JAVA_SEARCHER: { + return lib.searcher_Java(args); + } + case OP_SEARCHPATH: { + String name = args.checkjstring(1); + String path = args.checkjstring(2); + String sep = args.optjstring(3, "."); + String rep = args.optjstring(4, FILE_SEP); + return lib.searchpath(name, path, sep, rep); } } return NONE; @@ -184,6 +178,7 @@ public class PackageLib extends OneArgFunction { LOADED.set(name, value); } + public void setLuaPath( String newLuaPath ) { PACKAGE.set( _PATH, valueOf(newLuaPath) ); } @@ -193,102 +188,7 @@ public class PackageLib extends OneArgFunction { } - // ======================== Module, Package loading ============================= - /** - * module (name [, ...]) - * - * Creates a module. If there is a table in package.loaded[name], this table - * is the module. Otherwise, if there is a global table t with the given - * name, this table is the module. Otherwise creates a new table t and sets - * it as the value of the global name and the value of package.loaded[name]. - * This function also initializes t._NAME with the given name, t._M with the - * module (t itself), and t._PACKAGE with the package name (the full module - * name minus last component; see below). Finally, module sets t as the new - * environment of the current function and the new value of - * package.loaded[name], so that require returns t. - * - * If name is a compound name (that is, one with components separated by - * dots), module creates (or reuses, if they already exist) tables for each - * component. For instance, if name is a.b.c, then module stores the module - * table in field c of field b of global a. - * - * This function may receive optional options after the module name, where - * each option is a function to be applied over the module. - */ - public Varargs module(Varargs args) { - LuaString modname = args.checkstring(1); - int n = args.narg(); - LuaValue value = LOADED.get(modname); - LuaValue module; - if ( ! value.istable() ) { /* not found? */ - - /* try global variable (and create one if it does not exist) */ - LuaValue globals = LuaThread.getGlobals(); - module = findtable( globals, modname ); - if ( module == null ) - error( "name conflict for module '"+modname+"'" ); - LOADED.set(modname, module); - } else { - module = (LuaTable) value; - } - - - /* check whether table already has a _NAME field */ - LuaValue name = module.get(_NAME); - if ( name.isnil() ) { - modinit( module, modname ); - } - - // set the environment of the current function - LuaFunction f = LuaThread.getCallstackFunction(1); - if ( f == null ) - error("no calling function"); - if ( ! f.isclosure() ) - error("'module' not called from a Lua function"); - f.setfenv(module); - - // apply the functions - for ( int i=2; i<=n; i++ ) - args.arg(i).call( module ); - - // returns no results - return NONE; - } - - /** - * - * @param table the table at which to start the search - * @param fname the name to look up or create, such as "abc.def.ghi" - * @return the table for that name, possible a new one, or null if a non-table has that name already. - */ - private static final LuaValue findtable(LuaValue table, LuaString fname) { - int b, e=(-1); - do { - e = fname.indexOf(_DOT, b=e+1 ); - if ( e < 0 ) - e = fname.m_length; - LuaString key = fname.substring(b, e); - LuaValue val = table.rawget(key); - if ( val.isnil() ) { /* no such field? */ - LuaTable field = new LuaTable(); /* new table for field */ - table.set(key, field); - table = field; - } else if ( ! val.istable() ) { /* field has a non-table value? */ - return null; - } else { - table = val; - } - } while ( e < fname.m_length ); - return table; - } - - private static final void modinit(LuaValue module, LuaString modname) { - /* module._M = module */ - module.set(_M, module); - int e = modname.lastIndexOf(_DOT); - module.set(_NAME, modname ); - module.set(_PACKAGE, (e<0? EMPTYSTRING: modname.substring(0,e+1)) ); - } + // ======================== Package loading ============================= /** * require (modname) @@ -326,7 +226,7 @@ public class PackageLib extends OneArgFunction { } /* else must load it; iterate over available loaders */ - LuaTable tbl = PACKAGE.get(_LOADERS).checktable(); + LuaTable tbl = PACKAGE.get(_SEARCHERS).checktable(); StringBuffer sb = new StringBuffer(); LuaValue chunk = null; for ( int i=1; true; i++ ) { @@ -358,7 +258,7 @@ public class PackageLib extends OneArgFunction { return varargsOf(NIL, valueOf("dynamic libraries not enabled"), valueOf("absent")); } - LuaValue loader_preload( Varargs args ) { + LuaValue searcher_preload( Varargs args ) { LuaString name = args.checkstring(1); LuaValue preload = PACKAGE.get(_PRELOAD).checktable(); LuaValue val = preload.get(name); @@ -367,22 +267,40 @@ public class PackageLib extends OneArgFunction { val; } - LuaValue loader_Lua( Varargs args ) { - String name = args.checkjstring(1); + Varargs searcher_Lua( Varargs args ) { + LuaString name = args.checkstring(1); InputStream is = null; - - + // get package path - LuaValue pp = PACKAGE.get(_PATH); - if ( ! pp.isstring() ) + LuaValue path = PACKAGE.get(_PATH); + if ( ! path.isstring() ) return valueOf("package.path is not a string"); - String path = pp.tojstring(); + + // get the searchpath function. + LuaValue searchpath = PACKAGE.get(_SEARCHPATH); + Varargs v = searchpath.invoke(varargsOf(name, path)); + + // Didd we get a result? + if (!v.isstring(1)) + return v.arg(2).tostring(); + LuaString filename = v.arg1().strvalue(); + + // Try to load the file. + v = BaseLib.loadFile(filename.tojstring(), "bt", LuaThread.getGlobals()); + if ( v.arg1().isfunction() ) + return LuaValue.varargsOf(v.arg1(), filename); + + // report error + return varargsOf(NIL, valueOf("'"+filename+"': "+v.arg(2).tojstring())); + } + + public Varargs searchpath(String name, String path, String sep, String rep) { // check the path elements int e = -1; int n = path.length(); StringBuffer sb = null; - name = name.replace('.','/'); + name = name.replace(sep.charAt(0), rep.charAt(0)); while ( e < n ) { // find next template @@ -399,20 +317,22 @@ public class PackageLib extends OneArgFunction { filename = template.substring(0,q) + name + template.substring(q+1); } - // try loading the file - Varargs v = BaseLib.loadFile(filename); - if ( v.arg1().isfunction() ) - return v.arg1(); + // try opening the file + InputStream is = BaseLib.FINDER.findResource(filename); + if (is != null) { + try { is.close(); } catch ( java.io.IOException ioe ) {} + return valueOf(filename); + } // report error if ( sb == null ) sb = new StringBuffer(); - sb.append( "\n\t'"+filename+"': "+v.arg(2) ); + sb.append( "\n\t"+filename ); } - return valueOf(sb.toString()); + return varargsOf(NIL, valueOf(sb.toString())); } - LuaValue loader_Java( Varargs args ) { + LuaValue searcher_Java( Varargs args ) { String name = args.checkjstring(1); String classname = toClassname( name ); Class c = null; diff --git a/src/core/org/luaj/vm2/lib/TableLib.java b/src/core/org/luaj/vm2/lib/TableLib.java index c26b9d40..e5c92f75 100644 --- a/src/core/org/luaj/vm2/lib/TableLib.java +++ b/src/core/org/luaj/vm2/lib/TableLib.java @@ -65,7 +65,7 @@ public class TableLib extends OneArgFunction { LuaTable t = new LuaTable(); bind(t, TableLib.class, new String[] { "getn", "maxn", }, 1 ); bind(t, TableLibV.class, new String[] { - "remove", "concat", "insert", "sort", "foreach", "foreachi", } ); + "remove", "concat", "insert", "sort", "foreach", "foreachi", "unpack", } ); env.set("table", t); PackageLib.instance.LOADED.set("table", t); return t; @@ -117,6 +117,22 @@ public class TableLib extends OneArgFunction { case 5: { // "foreachi" (table, func) -> void return args.checktable(1).foreachi( args.checkfunction(2) ); } + case 6: // "unpack", // (list [,i [,j]]) -> result1, ... + { + int na = args.narg(); + LuaTable t = args.checktable(1); + int n = t.length(); + int i = na>=2? args.checkint(2): 1; + int j = na>=3? args.checkint(3): n; + n = j-i+1; + if ( n<0 ) return NONE; + if ( n==1 ) return t.get(i); + if ( n==2 ) return varargsOf(t.get(i),t.get(j)); + LuaValue[] v = new LuaValue[n]; + for ( int k=0; k 2 ) usageExit(); @@ -190,7 +198,14 @@ public class lua { try { LuaFunction c; try { - c = LoadState.load(script, chunkname, _G); + c = LoadState.load(script, chunkname, "bt", _G); + if (c instanceof LuaClosure) { + LuaClosure closure = (LuaClosure) c; + Print.print(closure.p); + // DebugLib.DEBUG_ENABLED = true; + } else { + System.out.println( "Not a LuaClosure: "+c); + } } finally { script.close(); } diff --git a/src/jse/org/luaj/vm2/lib/jse/JseMathLib.java b/src/jse/org/luaj/vm2/lib/jse/JseMathLib.java index 1f8d2e69..3b028a2a 100644 --- a/src/jse/org/luaj/vm2/lib/jse/JseMathLib.java +++ b/src/jse/org/luaj/vm2/lib/jse/JseMathLib.java @@ -64,7 +64,7 @@ public class JseMathLib extends org.luaj.vm2.lib.MathLib { LuaValue t = super.call(arg); bind( t, JseMathLib1.class, new String[] { "acos", "asin", "atan", "cosh", - "exp", "log", "log10", "sinh", + "exp", "log", "sinh", "tanh" } ); bind( t, JseMathLib2.class, new String[] { "atan2", "pow", } ); @@ -80,9 +80,8 @@ public class JseMathLib extends org.luaj.vm2.lib.MathLib { case 3: return valueOf(Math.cosh(arg.checkdouble())); case 4: return valueOf(Math.exp(arg.checkdouble())); case 5: return valueOf(Math.log(arg.checkdouble())); - case 6: return valueOf(Math.log10(arg.checkdouble())); - case 7: return valueOf(Math.sinh(arg.checkdouble())); - case 8: return valueOf(Math.tanh(arg.checkdouble())); + case 6: return valueOf(Math.sinh(arg.checkdouble())); + case 7: return valueOf(Math.tanh(arg.checkdouble())); } return NIL; } diff --git a/src/jse/org/luaj/vm2/script/LuaScriptEngine.java b/src/jse/org/luaj/vm2/script/LuaScriptEngine.java index 468a095d..4b69305a 100644 --- a/src/jse/org/luaj/vm2/script/LuaScriptEngine.java +++ b/src/jse/org/luaj/vm2/script/LuaScriptEngine.java @@ -162,7 +162,7 @@ public class LuaScriptEngine implements ScriptEngine, Compilable { try { InputStream ris = new Utf8Encoder(reader); try { - final LuaFunction f = LoadState.load(ris, "script", null); + final LuaFunction f = LoadState.load(ris, "script", "bt", null); if ( f.isclosure() ) { // most compiled functions are closures with prototypes final Prototype p = f.checkclosure().p; diff --git a/test/junit/org/luaj/vm2/FragmentsTest.java b/test/junit/org/luaj/vm2/FragmentsTest.java index 25132deb..3b7c9d6e 100644 --- a/test/junit/org/luaj/vm2/FragmentsTest.java +++ b/test/junit/org/luaj/vm2/FragmentsTest.java @@ -123,7 +123,6 @@ public class FragmentsTest extends TestSuite { } public void testArgParamUseNone() { - // the name "arg" is treated specially, and ends up masking the argument value in 5.1 runFragment( LuaValue.valueOf("string"), "function v(arg,...)\n" + " return type(arg)\n" + diff --git a/test/junit/org/luaj/vm2/MathLibTest.java b/test/junit/org/luaj/vm2/MathLibTest.java index 47e34238..d9bba861 100644 --- a/test/junit/org/luaj/vm2/MathLibTest.java +++ b/test/junit/org/luaj/vm2/MathLibTest.java @@ -93,22 +93,6 @@ public class MathLibTest extends TestCase { tryMathOp( "log", -9 ); } - public void testLog10() { - supportedOnJ2me = false; - tryMathOp( "log10", 0.1 ); - tryMathOp( "log10", .9 ); - tryMathOp( "log10", 1. ); - tryMathOp( "log10", 9 ); - tryMathOp( "log10", 10 ); - tryMathOp( "log10", 100 ); - tryMathOp( "log10", -.1 ); - tryMathOp( "log10", -.9 ); - tryMathOp( "log10", -1. ); - tryMathOp( "log10", -9 ); - tryMathOp( "log10", -10 ); - tryMathOp( "log10", -100 ); - } - public void testRad() { tryMathOp( "rad", 0 ); tryMathOp( "rad", 0.1 ); diff --git a/test/junit/org/luaj/vm2/OrphanedThreadTest.java b/test/junit/org/luaj/vm2/OrphanedThreadTest.java index 2c801abb..ed8e67ab 100644 --- a/test/junit/org/luaj/vm2/OrphanedThreadTest.java +++ b/test/junit/org/luaj/vm2/OrphanedThreadTest.java @@ -75,7 +75,7 @@ public class OrphanedThreadTest extends TestCase { "print('leakage in closure.3, arg is '..arg)\n" + "return 'done'\n"; LuaC.install(); - function = LoadState.load(new ByteArrayInputStream(script.getBytes()), "script", env); + function = LoadState.load(new ByteArrayInputStream(script.getBytes()), "script", "bt", env); doTest(LuaValue.TRUE, LuaValue.ZERO); } @@ -91,7 +91,7 @@ public class OrphanedThreadTest extends TestCase { "end\n" + "print( 'pcall-closre.result:', pcall( f, ... ) )\n"; LuaC.install(); - function = LoadState.load(new ByteArrayInputStream(script.getBytes()), "script", env); + function = LoadState.load(new ByteArrayInputStream(script.getBytes()), "script", "bt", env); doTest(LuaValue.TRUE, LuaValue.ZERO); } @@ -108,7 +108,7 @@ public class OrphanedThreadTest extends TestCase { "end\n" + "load(f)()\n"; LuaC.install(); - function = LoadState.load(new ByteArrayInputStream(script.getBytes()), "script", env); + function = LoadState.load(new ByteArrayInputStream(script.getBytes()), "script", "bt", env); doTest(LuaValue.TRUE, LuaValue.ONE); } diff --git a/test/junit/org/luaj/vm2/ScriptDrivenTest.java b/test/junit/org/luaj/vm2/ScriptDrivenTest.java index ed6de2e2..a2964af5 100644 --- a/test/junit/org/luaj/vm2/ScriptDrivenTest.java +++ b/test/junit/org/luaj/vm2/ScriptDrivenTest.java @@ -125,7 +125,7 @@ public class ScriptDrivenTest extends TestCase { } default: script = new FileInputStream(file); - return LoadState.load(script, "=stdin", _G); + return LoadState.load(script, "=stdin", "bt", _G); } } catch ( Exception e ) { e.printStackTrace(); diff --git a/test/junit/org/luaj/vm2/compiler/DumpLoadEndianIntTest.java b/test/junit/org/luaj/vm2/compiler/DumpLoadEndianIntTest.java index 119d0ea5..7b5d9e0a 100644 --- a/test/junit/org/luaj/vm2/compiler/DumpLoadEndianIntTest.java +++ b/test/junit/org/luaj/vm2/compiler/DumpLoadEndianIntTest.java @@ -108,7 +108,7 @@ public class DumpLoadEndianIntTest extends TestCase { // load again using compiler is = new ByteArrayInputStream(dumped); - f = LoadState.load(is, "dumped", _G); + f = LoadState.load(is, "dumped", "bt", _G); r = f.call(); actual = r.tojstring(); assertEquals( expectedPostDump, actual ); diff --git a/test/lua/baselib.lua b/test/lua/baselib.lua index dae00527..fb84ce94 100644 --- a/test/lua/baselib.lua +++ b/test/lua/baselib.lua @@ -152,6 +152,17 @@ printtables() print( 'pcall(rawset,t,"dd","zzz")', rawset(t,"dd","zzz")) printtables() +-- rawlen +print( 'pcall(rawlen, {})', pcall(rawlen, {})) +print( 'pcall(rawlen, {"a"})', pcall(rawlen, {'a'})) +print( 'pcall(rawlen, {"a","b"})', pcall(rawlen, {'a','b'})) +print( 'pcall(rawlen, "")', pcall(rawlen, "")) +print( 'pcall(rawlen, "a")', pcall(rawlen, 'a')) +print( 'pcall(rawlen, "ab")', pcall(rawlen, 'ab')) +print( 'pcall(rawlen, 1)', pcall(rawlen, 1)) +print( 'pcall(rawlen, nil)', pcall(rawlen, nil)) +print( 'pcall(rawlen)', pcall(rawlen)) + printtables() print( 's["ee"]="ppp"' ); s["ee"]="ppp" printtables()