Lua 5.2 compatibility updates to VM and base and package libraries.

This commit is contained in:
James Roseborough
2012-09-06 04:01:28 +00:00
parent 41d9dd6176
commit a5fddce465
18 changed files with 244 additions and 328 deletions

View File

@@ -373,11 +373,12 @@ public class LoadState {
* @param firstByte the first byte of the input stream * @param firstByte the first byte of the input stream
* @param stream InputStream to read, after having read the first byte already * @param stream InputStream to read, after having read the first byte already
* @param name Name to apply to the loaded chunk * @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 * @return {@link Prototype} that was loaded
* @throws IllegalArgumentException if the signature is bac * @throws IllegalArgumentException if the signature is bac
* @throws IOException if an IOException occurs * @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 ) if ( compiler != null )
return compiler.load(stream, name, env); return compiler.load(stream, name, env);
else { else {

View File

@@ -420,6 +420,10 @@ public class LuaString extends LuaValue {
return m_length; return m_length;
} }
public int rawlen() {
return m_length;
}
public int luaByte(int index) { public int luaByte(int index) {
return m_bytes[m_offset + index] & 0x0FF; return m_bytes[m_offset + index] & 0x0FF;
} }

View File

@@ -393,7 +393,11 @@ public class LuaTable extends LuaValue {
public LuaValue len() { public LuaValue len() {
return LuaInteger.valueOf(length()); return LuaInteger.valueOf(length());
} }
public int rawlen() {
return length();
}
/** Return table.maxn() as defined by lua 5.0. /** Return table.maxn() as defined by lua 5.0.
* <p> * <p>
* Provided for compatibility, not a scalable operation. * Provided for compatibility, not a scalable operation.

View File

@@ -2014,6 +2014,12 @@ public class LuaValue extends Varargs {
*/ */
public int length() { return len().toint(); } 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. /** 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} * @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} * @throws LuaError if {@code this} is not a {@link LuaTable}

View File

@@ -89,30 +89,29 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
private LuaValue next; private LuaValue next;
private LuaValue inext; 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 = { private static final String[] LIB2_KEYS = {
"collectgarbage", // ( opt [,arg] ) -> value "collectgarbage", // ( opt [,arg] ) -> value
"error", // ( message [,level] ) -> ERR "error", // ( message [,level] ) -> ERR
"setfenv", // (f, table) -> void "rawequal", // (v1, v2) -> boolean
"rawget", // (table, index) -> value
}; };
private static final String[] LIBV_KEYS = { private static final String[] LIBV_KEYS = {
"assert", // ( v [,message] ) -> v, message | ERR "assert", // ( v [,message] ) -> v, message | ERR
"dofile", // ( filename ) -> result1, ... "dofile", // ( filename ) -> result1, ...
"getfenv", // ( [f] ) -> env "load", // ( ld [, source [, mode [, env]]] ) -> chunk | nil, msg
"getmetatable", // ( object ) -> table "loadfile", // ( [filename [, mode [, env]]] ) -> chunk | nil, msg
"load", // ( func [,chunkname] ) -> chunk | nil, msg
"loadfile", // ( [filename] ) -> chunk | nil, msg
"loadstring", // ( string [,chunkname] ) -> chunk | nil, msg
"pcall", // (f, arg1, ...) -> status, result1, ... "pcall", // (f, arg1, ...) -> status, result1, ...
"xpcall", // (f, err) -> result1, ... "xpcall", // (f, err) -> result1, ...
"print", // (...) -> void "print", // (...) -> void
"select", // (f, ...) -> value1, ... "select", // (f, ...) -> value1, ...
"unpack", // (list [,i [,j]]) -> result1, ...
"type", // (v) -> value
"rawequal", // (v1, v2) -> boolean
"rawget", // (table, index) -> value
"rawset", // (table, index, value) -> table "rawset", // (table, index, value) -> table
"setmetatable", // (table, metatable) -> table "setmetatable", // (table, metatable) -> table
"tostring", // (e) -> value
"tonumber", // (e [,base]) -> value "tonumber", // (e [,base]) -> value
"pairs", // "pairs" (t) -> iter-func, t, nil "pairs", // "pairs" (t) -> iter-func, t, nil
"ipairs", // "ipairs", // (t) -> iter-func, t, 0 "ipairs", // "ipairs", // (t) -> iter-func, t, 0
@@ -130,6 +129,7 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
public LuaValue call(LuaValue arg) { public LuaValue call(LuaValue arg) {
env.set( "_G", env ); env.set( "_G", env );
env.set( "_VERSION", Lua._VERSION ); env.set( "_VERSION", Lua._VERSION );
bind( env, BaseLib1.class, LIB1_KEYS );
bind( env, BaseLib2.class, LIB2_KEYS ); bind( env, BaseLib2.class, LIB2_KEYS );
bind( env, BaseLibV.class, LIBV_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); 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 { static final class BaseLib2 extends TwoArgFunction {
public LuaValue call(LuaValue arg1, LuaValue arg2) { public LuaValue call(LuaValue arg1, LuaValue arg2) {
switch ( opcode ) { switch ( opcode ) {
case 0: // "collectgarbage", // ( opt [,arg] ) -> value case 0: // "collectgarbage", // ( opt [,arg] ) -> value
String s = arg1.checkjstring(); String s = arg1.checkjstring();
int result = 0;
if ( "collect".equals(s) ) { if ( "collect".equals(s) ) {
System.gc(); System.gc();
return ZERO; return ZERO;
@@ -173,35 +203,19 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
System.gc(); System.gc();
return LuaValue.TRUE; return LuaValue.TRUE;
} else { } else {
this.argerror(1, "gc op"); this.argerror("gc op");
} }
return NIL; return NIL;
case 1: // "error", // ( message [,level] ) -> ERR case 1: // "error", // ( message [,level] ) -> ERR
throw new LuaError( arg1.isnil()? null: arg1.tojstring(), arg2.optint(1) ); throw new LuaError( arg1.isnil()? null: arg1.tojstring(), arg2.optint(1) );
case 2: { // "setfenv", // (f, table) -> void case 2: // "rawequal", // (v1, v2) -> boolean
LuaTable t = arg2.checktable(); return valueOf(arg1.raweq(arg2));
LuaValue f = getfenvobj(arg1); case 3: // "rawget", // (table, index) -> value
if ( ! f.isfunction() && ! f.isclosure() ) return arg1.rawget(arg2);
error("'setfenv' cannot change environment of given object");
f.setfenv(t);
return f.isthread()? NONE: f;
}
} }
return NIL; 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 { static final class BaseLibV extends VarArgFunction {
public BaseLib baselib; public BaseLib baselib;
@@ -213,41 +227,34 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
return args; return args;
case 1: // "dofile", // ( filename ) -> result1, ... case 1: // "dofile", // ( filename ) -> result1, ...
{ {
Varargs v = args.isnil(1)? args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil");
BaseLib.loadStream( baselib.STDIN, "=stdin" ): String filename = args.isstring(1)? args.tojstring(1): null;
BaseLib.loadFile( args.checkjstring(1) ); 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(); 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 ld = args.arg1();
LuaValue e = f.getfenv(); args.argcheck(ld.isstring() || ld.isfunction(), 1, "ld must be string or function");
return e!=null? e: NIL; 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(); args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil");
return mt!=null? mt.rawget(METATABLE).optvalue(mt): 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 case 4: // "pcall", // (f, arg1, ...) -> status, result1, ...
{
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, ...
{ {
LuaValue func = args.checkvalue(1); LuaValue func = args.checkvalue(1);
LuaThread.CallStack cs = LuaThread.onCall(this); LuaThread.CallStack cs = LuaThread.onCall(this);
@@ -257,7 +264,7 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
cs.onReturn(); cs.onReturn();
} }
} }
case 8: // "xpcall", // (f, err) -> result1, ... case 5: // "xpcall", // (f, err) -> result1, ...
{ {
LuaThread.CallStack cs = LuaThread.onCall(this); LuaThread.CallStack cs = LuaThread.onCall(this);
try { try {
@@ -266,7 +273,7 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
cs.onReturn(); cs.onReturn();
} }
} }
case 9: // "print", // (...) -> void case 6: // "print", // (...) -> void
{ {
LuaValue tostring = LuaThread.getGlobals().get("tostring"); LuaValue tostring = LuaThread.getGlobals().get("tostring");
for ( int i=1, n=args.narg(); i<=n; i++ ) { for ( int i=1, n=args.narg(); i<=n; i++ ) {
@@ -278,7 +285,7 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
baselib.STDOUT.println(); baselib.STDOUT.println();
return NONE; return NONE;
} }
case 10: // "select", // (f, ...) -> value1, ... case 7: // "select", // (f, ...) -> value1, ...
{ {
int n = args.narg()-1; int n = args.narg()-1;
if ( args.arg1().equals(valueOf("#")) ) if ( args.arg1().equals(valueOf("#")) )
@@ -288,34 +295,12 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
argerror(1,"index out of range"); argerror(1,"index out of range");
return args.subargs(i<0? n+i+2: i+1); return args.subargs(i<0? n+i+2: i+1);
} }
case 11: // "unpack", // (list [,i [,j]]) -> result1, ... case 8: { // "rawset", // (table, index, value) -> table
{
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<n; k++ )
v[k] = t.get(i+k);
return varargsOf(v);
}
case 12: // "type", // (v) -> 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
LuaTable t = args.checktable(1); LuaTable t = args.checktable(1);
t.rawset(args.checknotnil(2), args.checkvalue(3)); t.rawset(args.checknotnil(2), args.checkvalue(3));
return t; return t;
} }
case 16: { // "setmetatable", // (table, metatable) -> table case 9: { // "setmetatable", // (table, metatable) -> table
final LuaValue t = args.arg1(); final LuaValue t = args.arg1();
final LuaValue mt0 = t.getmetatable(); final LuaValue mt0 = t.getmetatable();
if ( mt0!=null && !mt0.rawget(METATABLE).isnil() ) if ( mt0!=null && !mt0.rawget(METATABLE).isnil() )
@@ -323,17 +308,7 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
final LuaValue mt = args.checkvalue(2); final LuaValue mt = args.checkvalue(2);
return t.setmetatable(mt.isnil()? null: mt.checktable()); return t.setmetatable(mt.isnil()? null: mt.checktable());
} }
case 17: { // "tostring", // (e) -> value case 10: { // "tonumber", // (e [,base]) -> 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
LuaValue arg1 = args.checkvalue(1); LuaValue arg1 = args.checkvalue(1);
final int base = args.optint(2,10); final int base = args.optint(2,10);
if (base == 10) { /* standard conversion */ if (base == 10) { /* standard conversion */
@@ -344,13 +319,13 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
return arg1.checkstring().tonumber(base); 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 ); 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 ); 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)); 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 args.checktable(1).inext(args.arg(2));
} }
return NONE; 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 * 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 * @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); InputStream is = FINDER.findResource(filename);
if ( is == null ) if ( is == null )
return varargsOf(NIL, valueOf("cannot open "+filename+": No such file or directory")); return varargsOf(NIL, valueOf("cannot open "+filename+": No such file or directory"));
try { try {
return loadStream(is, "@"+filename); return loadStream(is, "@"+filename, mode, env);
} finally { } finally {
try { try {
is.close(); 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 { try {
if ( is == null ) if ( is == null )
return varargsOf(NIL, valueOf("not found: "+chunkname)); return varargsOf(NIL, valueOf("not found: "+chunkname));
return LoadState.load(is, chunkname, LuaThread.getGlobals()); return LoadState.load(is, chunkname, mode, env);
} catch (Exception e) { } catch (Exception e) {
return varargsOf(NIL, valueOf(e.getMessage())); return varargsOf(NIL, valueOf(e.getMessage()));
} }

View File

@@ -76,14 +76,12 @@ public class DebugLib extends VarArgFunction {
static final String[] NAMES = { static final String[] NAMES = {
"debug", "debug",
"getfenv",
"gethook", "gethook",
"getinfo", "getinfo",
"getlocal", "getlocal",
"getmetatable", "getmetatable",
"getregistry", "getregistry",
"getupvalue", "getupvalue",
"setfenv",
"sethook", "sethook",
"setlocal", "setlocal",
"setmetatable", "setmetatable",
@@ -93,19 +91,17 @@ public class DebugLib extends VarArgFunction {
private static final int INIT = 0; private static final int INIT = 0;
private static final int DEBUG = 1; private static final int DEBUG = 1;
private static final int GETFENV = 2; private static final int GETHOOK = 2;
private static final int GETHOOK = 3; private static final int GETINFO = 3;
private static final int GETINFO = 4; private static final int GETLOCAL = 4;
private static final int GETLOCAL = 5; private static final int GETMETATABLE = 5;
private static final int GETMETATABLE = 6; private static final int GETREGISTRY = 6;
private static final int GETREGISTRY = 7; private static final int GETUPVALUE = 7;
private static final int GETUPVALUE = 8; private static final int SETHOOK = 8;
private static final int SETFENV = 9; private static final int SETLOCAL = 9;
private static final int SETHOOK = 10; private static final int SETMETATABLE = 10;
private static final int SETLOCAL = 11; private static final int SETUPVALUE = 11;
private static final int SETMETATABLE = 12; private static final int TRACEBACK = 12;
private static final int SETUPVALUE = 13;
private static final int TRACEBACK = 14;
/* maximum stack for a Lua function */ /* maximum stack for a Lua function */
private static final int MAXSTACK = 250; private static final int MAXSTACK = 250;
@@ -153,14 +149,12 @@ public class DebugLib extends VarArgFunction {
switch ( opcode ) { switch ( opcode ) {
case INIT: return init(); case INIT: return init();
case DEBUG: return _debug(args); case DEBUG: return _debug(args);
case GETFENV: return _getfenv(args);
case GETHOOK: return _gethook(args); case GETHOOK: return _gethook(args);
case GETINFO: return _getinfo(args,this); case GETINFO: return _getinfo(args,this);
case GETLOCAL: return _getlocal(args); case GETLOCAL: return _getlocal(args);
case GETMETATABLE: return _getmetatable(args); case GETMETATABLE: return _getmetatable(args);
case GETREGISTRY: return _getregistry(args); case GETREGISTRY: return _getregistry(args);
case GETUPVALUE: return _getupvalue(args); case GETUPVALUE: return _getupvalue(args);
case SETFENV: return _setfenv(args);
case SETHOOK: return _sethook(args); case SETHOOK: return _sethook(args);
case SETLOCAL: return _setlocal(args); case SETLOCAL: return _setlocal(args);
case SETMETATABLE: return _setmetatable(args); case SETMETATABLE: return _setmetatable(args);
@@ -438,19 +432,6 @@ public class DebugLib extends VarArgFunction {
return NONE; 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) { protected static Varargs _getinfo(Varargs args, LuaValue level0func) {
int a=1; int a=1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning(); LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();

View File

@@ -42,7 +42,6 @@ import org.luaj.vm2.Varargs;
* <li>atan</li> * <li>atan</li>
* <li>cosh</li> * <li>cosh</li>
* <li>log</li> * <li>log</li>
* <li>log10</li>
* <li>sinh</li> * <li>sinh</li>
* <li>tanh</li> * <li>tanh</li>
* <li>atan2</li> * <li>atan2</li>

View File

@@ -76,51 +76,47 @@ public class PackageLib extends OneArgFunction {
public static PackageLib instance; public static PackageLib instance;
/** Loader that loads from preload table if found there */ /** 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 */ /** 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 */ /** 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 _LOADED = valueOf("loaded");
private static final LuaString _NAME = valueOf("_NAME"); private static final LuaString _LOADLIB = valueOf("loadlib");
private static final LuaString _PACKAGE = valueOf("_PACKAGE"); private static final LuaString _PRELOAD = valueOf("preload");
private static final LuaString _DOT = valueOf("."); private static final LuaString _PATH = valueOf("path");
private static final LuaString _LOADERS = valueOf("loaders"); private static final LuaString _SEARCHERS = valueOf("searchers");
private static final LuaString _LOADED = valueOf("loaded"); private static final LuaString _SEARCHPATH = valueOf("searchpath");
private static final LuaString _LOADLIB = valueOf("loadlib"); private static final LuaString _SENTINEL = valueOf("\u0001");
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 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() { public PackageLib() {
instance = this; instance = this;
} }
public LuaValue call(LuaValue arg) { public LuaValue call(LuaValue arg) {
env.set("require", new PkgLib1(env,"require",OP_REQUIRE,this)); 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[] { env.set( "package", PACKAGE=tableOf( new LuaValue[] {
_LOADED, LOADED=tableOf(), _LOADED, LOADED=tableOf(),
_PRELOAD, tableOf(), _PRELOAD, tableOf(),
_PATH, valueOf(DEFAULT_LUA_PATH), _PATH, valueOf(DEFAULT_LUA_PATH),
_LOADLIB, new PkgLibV(env,"loadlib",OP_LOADLIB,this), _LOADLIB, new PkgLibV(env,"loadlib",OP_LOADLIB,this),
_SEEALL, new PkgLib1(env,"seeall",OP_SEEALL,this), _SEARCHPATH, new PkgLibV(env,"searchpath",OP_SEARCHPATH,this),
_LOADERS, listOf(new LuaValue[] { _SEARCHERS, listOf(new LuaValue[] {
preload_loader = new PkgLibV(env,"preload_loader", OP_PRELOAD_LOADER,this), preload_searcher = new PkgLibV(env,"preload_searcher", OP_PRELOAD_SEARCHER,this),
lua_loader = new PkgLibV(env,"lua_loader", OP_LUA_LOADER,this), lua_searcher = new PkgLibV(env,"lua_searcher", OP_LUA_SEARCHER,this),
java_loader = new PkgLibV(env,"java_loader", OP_JAVA_LOADER,this), java_searcher = new PkgLibV(env,"java_searcher", OP_JAVA_SEARCHER,this),
}) }) ); }) }) );
LOADED.set("package", PACKAGE); LOADED.set("package", PACKAGE);
return env; return env;
@@ -138,14 +134,6 @@ public class PackageLib extends OneArgFunction {
switch ( opcode ) { switch ( opcode ) {
case OP_REQUIRE: case OP_REQUIRE:
return lib.require(arg); 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; return NIL;
} }
@@ -161,18 +149,24 @@ public class PackageLib extends OneArgFunction {
} }
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
switch ( opcode ) { switch ( opcode ) {
case OP_MODULE: case OP_LOADLIB: {
return lib.module(args);
case OP_LOADLIB:
return loadlib(args); return loadlib(args);
case OP_PRELOAD_LOADER: {
return lib.loader_preload(args);
} }
case OP_LUA_LOADER: { case OP_PRELOAD_SEARCHER: {
return lib.loader_Lua(args); return lib.searcher_preload(args);
} }
case OP_JAVA_LOADER: { case OP_LUA_SEARCHER: {
return lib.loader_Java(args); 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; return NONE;
@@ -184,6 +178,7 @@ public class PackageLib extends OneArgFunction {
LOADED.set(name, value); LOADED.set(name, value);
} }
public void setLuaPath( String newLuaPath ) { public void setLuaPath( String newLuaPath ) {
PACKAGE.set( _PATH, valueOf(newLuaPath) ); PACKAGE.set( _PATH, valueOf(newLuaPath) );
} }
@@ -193,102 +188,7 @@ public class PackageLib extends OneArgFunction {
} }
// ======================== Module, Package loading ============================= // ======================== 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)) );
}
/** /**
* require (modname) * require (modname)
@@ -326,7 +226,7 @@ public class PackageLib extends OneArgFunction {
} }
/* else must load it; iterate over available loaders */ /* else must load it; iterate over available loaders */
LuaTable tbl = PACKAGE.get(_LOADERS).checktable(); LuaTable tbl = PACKAGE.get(_SEARCHERS).checktable();
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
LuaValue chunk = null; LuaValue chunk = null;
for ( int i=1; true; i++ ) { 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")); 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); LuaString name = args.checkstring(1);
LuaValue preload = PACKAGE.get(_PRELOAD).checktable(); LuaValue preload = PACKAGE.get(_PRELOAD).checktable();
LuaValue val = preload.get(name); LuaValue val = preload.get(name);
@@ -367,22 +267,40 @@ public class PackageLib extends OneArgFunction {
val; val;
} }
LuaValue loader_Lua( Varargs args ) { Varargs searcher_Lua( Varargs args ) {
String name = args.checkjstring(1); LuaString name = args.checkstring(1);
InputStream is = null; InputStream is = null;
// get package path // get package path
LuaValue pp = PACKAGE.get(_PATH); LuaValue path = PACKAGE.get(_PATH);
if ( ! pp.isstring() ) if ( ! path.isstring() )
return valueOf("package.path is not a string"); 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 // check the path elements
int e = -1; int e = -1;
int n = path.length(); int n = path.length();
StringBuffer sb = null; StringBuffer sb = null;
name = name.replace('.','/'); name = name.replace(sep.charAt(0), rep.charAt(0));
while ( e < n ) { while ( e < n ) {
// find next template // find next template
@@ -399,20 +317,22 @@ public class PackageLib extends OneArgFunction {
filename = template.substring(0,q) + name + template.substring(q+1); filename = template.substring(0,q) + name + template.substring(q+1);
} }
// try loading the file // try opening the file
Varargs v = BaseLib.loadFile(filename); InputStream is = BaseLib.FINDER.findResource(filename);
if ( v.arg1().isfunction() ) if (is != null) {
return v.arg1(); try { is.close(); } catch ( java.io.IOException ioe ) {}
return valueOf(filename);
}
// report error // report error
if ( sb == null ) if ( sb == null )
sb = new StringBuffer(); 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 name = args.checkjstring(1);
String classname = toClassname( name ); String classname = toClassname( name );
Class c = null; Class c = null;

View File

@@ -65,7 +65,7 @@ public class TableLib extends OneArgFunction {
LuaTable t = new LuaTable(); LuaTable t = new LuaTable();
bind(t, TableLib.class, new String[] { "getn", "maxn", }, 1 ); bind(t, TableLib.class, new String[] { "getn", "maxn", }, 1 );
bind(t, TableLibV.class, new String[] { bind(t, TableLibV.class, new String[] {
"remove", "concat", "insert", "sort", "foreach", "foreachi", } ); "remove", "concat", "insert", "sort", "foreach", "foreachi", "unpack", } );
env.set("table", t); env.set("table", t);
PackageLib.instance.LOADED.set("table", t); PackageLib.instance.LOADED.set("table", t);
return t; return t;
@@ -117,6 +117,22 @@ public class TableLib extends OneArgFunction {
case 5: { // "foreachi" (table, func) -> void case 5: { // "foreachi" (table, func) -> void
return args.checktable(1).foreachi( args.checkfunction(2) ); 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<n; k++ )
v[k] = t.get(i+k);
return varargsOf(v);
}
} }
return NONE; return NONE;
} }

View File

@@ -30,10 +30,13 @@ import java.util.Vector;
import org.luaj.vm2.LoadState; import org.luaj.vm2.LoadState;
import org.luaj.vm2.Lua; import org.luaj.vm2.Lua;
import org.luaj.vm2.LuaClosure;
import org.luaj.vm2.LuaFunction; import org.luaj.vm2.LuaFunction;
import org.luaj.vm2.LuaTable; import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Print;
import org.luaj.vm2.Varargs; import org.luaj.vm2.Varargs;
import org.luaj.vm2.lib.DebugLib;
import org.luaj.vm2.lib.jse.JsePlatform; import org.luaj.vm2.lib.jse.JsePlatform;
import org.luaj.vm2.lua2java.Lua2Java; import org.luaj.vm2.lua2java.Lua2Java;
import org.luaj.vm2.luajc.LuaJC; import org.luaj.vm2.luajc.LuaJC;
@@ -55,6 +58,7 @@ public class lua {
" -j use lua2java source-to-source compiler\n" + " -j use lua2java source-to-source compiler\n" +
" -b use luajc bytecode-to-bytecode compiler (requires bcel on class path)\n" + " -b use luajc bytecode-to-bytecode compiler (requires bcel on class path)\n" +
" -n nodebug - do not load debug library by default\n" + " -n nodebug - do not load debug library by default\n" +
" -p pretty-print the prototype\n" +
" -- stop handling options\n" + " -- stop handling options\n" +
" - execute stdin and stop handling options"; " - execute stdin and stop handling options";
@@ -72,6 +76,7 @@ public class lua {
boolean versioninfo = false; boolean versioninfo = false;
boolean processing = true; boolean processing = true;
boolean nodebug = false; boolean nodebug = false;
boolean print = false;
boolean luajc = false; boolean luajc = false;
boolean lua2java = false; boolean lua2java = false;
Vector libs = null; Vector libs = null;
@@ -112,6 +117,9 @@ public class lua {
case 'n': case 'n':
nodebug = true; nodebug = true;
break; break;
case 'p':
print = true;
break;
case '-': case '-':
if ( args[i].length() > 2 ) if ( args[i].length() > 2 )
usageExit(); usageExit();
@@ -190,7 +198,14 @@ public class lua {
try { try {
LuaFunction c; LuaFunction c;
try { 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 { } finally {
script.close(); script.close();
} }

View File

@@ -64,7 +64,7 @@ public class JseMathLib extends org.luaj.vm2.lib.MathLib {
LuaValue t = super.call(arg); LuaValue t = super.call(arg);
bind( t, JseMathLib1.class, new String[] { bind( t, JseMathLib1.class, new String[] {
"acos", "asin", "atan", "cosh", "acos", "asin", "atan", "cosh",
"exp", "log", "log10", "sinh", "exp", "log", "sinh",
"tanh" } ); "tanh" } );
bind( t, JseMathLib2.class, new String[] { bind( t, JseMathLib2.class, new String[] {
"atan2", "pow", } ); "atan2", "pow", } );
@@ -80,9 +80,8 @@ public class JseMathLib extends org.luaj.vm2.lib.MathLib {
case 3: return valueOf(Math.cosh(arg.checkdouble())); case 3: return valueOf(Math.cosh(arg.checkdouble()));
case 4: return valueOf(Math.exp(arg.checkdouble())); case 4: return valueOf(Math.exp(arg.checkdouble()));
case 5: return valueOf(Math.log(arg.checkdouble())); case 5: return valueOf(Math.log(arg.checkdouble()));
case 6: return valueOf(Math.log10(arg.checkdouble())); case 6: return valueOf(Math.sinh(arg.checkdouble()));
case 7: return valueOf(Math.sinh(arg.checkdouble())); case 7: return valueOf(Math.tanh(arg.checkdouble()));
case 8: return valueOf(Math.tanh(arg.checkdouble()));
} }
return NIL; return NIL;
} }

View File

@@ -162,7 +162,7 @@ public class LuaScriptEngine implements ScriptEngine, Compilable {
try { try {
InputStream ris = new Utf8Encoder(reader); InputStream ris = new Utf8Encoder(reader);
try { try {
final LuaFunction f = LoadState.load(ris, "script", null); final LuaFunction f = LoadState.load(ris, "script", "bt", null);
if ( f.isclosure() ) { if ( f.isclosure() ) {
// most compiled functions are closures with prototypes // most compiled functions are closures with prototypes
final Prototype p = f.checkclosure().p; final Prototype p = f.checkclosure().p;

View File

@@ -123,7 +123,6 @@ public class FragmentsTest extends TestSuite {
} }
public void testArgParamUseNone() { public void testArgParamUseNone() {
// the name "arg" is treated specially, and ends up masking the argument value in 5.1
runFragment( LuaValue.valueOf("string"), runFragment( LuaValue.valueOf("string"),
"function v(arg,...)\n" + "function v(arg,...)\n" +
" return type(arg)\n" + " return type(arg)\n" +

View File

@@ -93,22 +93,6 @@ public class MathLibTest extends TestCase {
tryMathOp( "log", -9 ); 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() { public void testRad() {
tryMathOp( "rad", 0 ); tryMathOp( "rad", 0 );
tryMathOp( "rad", 0.1 ); tryMathOp( "rad", 0.1 );

View File

@@ -75,7 +75,7 @@ public class OrphanedThreadTest extends TestCase {
"print('leakage in closure.3, arg is '..arg)\n" + "print('leakage in closure.3, arg is '..arg)\n" +
"return 'done'\n"; "return 'done'\n";
LuaC.install(); 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); doTest(LuaValue.TRUE, LuaValue.ZERO);
} }
@@ -91,7 +91,7 @@ public class OrphanedThreadTest extends TestCase {
"end\n" + "end\n" +
"print( 'pcall-closre.result:', pcall( f, ... ) )\n"; "print( 'pcall-closre.result:', pcall( f, ... ) )\n";
LuaC.install(); 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); doTest(LuaValue.TRUE, LuaValue.ZERO);
} }
@@ -108,7 +108,7 @@ public class OrphanedThreadTest extends TestCase {
"end\n" + "end\n" +
"load(f)()\n"; "load(f)()\n";
LuaC.install(); 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); doTest(LuaValue.TRUE, LuaValue.ONE);
} }

View File

@@ -125,7 +125,7 @@ public class ScriptDrivenTest extends TestCase {
} }
default: default:
script = new FileInputStream(file); script = new FileInputStream(file);
return LoadState.load(script, "=stdin", _G); return LoadState.load(script, "=stdin", "bt", _G);
} }
} catch ( Exception e ) { } catch ( Exception e ) {
e.printStackTrace(); e.printStackTrace();

View File

@@ -108,7 +108,7 @@ public class DumpLoadEndianIntTest extends TestCase {
// load again using compiler // load again using compiler
is = new ByteArrayInputStream(dumped); is = new ByteArrayInputStream(dumped);
f = LoadState.load(is, "dumped", _G); f = LoadState.load(is, "dumped", "bt", _G);
r = f.call(); r = f.call();
actual = r.tojstring(); actual = r.tojstring();
assertEquals( expectedPostDump, actual ); assertEquals( expectedPostDump, actual );

View File

@@ -152,6 +152,17 @@ printtables()
print( 'pcall(rawset,t,"dd","zzz")', rawset(t,"dd","zzz")) print( 'pcall(rawset,t,"dd","zzz")', rawset(t,"dd","zzz"))
printtables() 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() printtables()
print( 's["ee"]="ppp"' ); s["ee"]="ppp" print( 's["ee"]="ppp"' ); s["ee"]="ppp"
printtables() printtables()