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 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 {

View File

@@ -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;
}

View File

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

View File

@@ -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}

View File

@@ -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,36 +203,20 @@ 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;
public Varargs invoke(Varargs args) {
@@ -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<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
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()));
}

View File

@@ -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();

View File

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

View File

@@ -76,33 +76,30 @@ 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 _SEARCHERS = valueOf("searchers");
private static final LuaString _SEARCHPATH = valueOf("searchpath");
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() {
instance = this;
@@ -110,17 +107,16 @@ public class PackageLib extends OneArgFunction {
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;

View File

@@ -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<n; k++ )
v[k] = t.get(i+k);
return varargsOf(v);
}
}
return NONE;
}

View File

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

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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" +

View File

@@ -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 );

View File

@@ -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);
}

View File

@@ -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();

View File

@@ -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 );

View File

@@ -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()