Convert package lib to new style.

This commit is contained in:
James Roseborough
2012-09-23 01:13:59 +00:00
parent 0c93edfd56
commit f389d316e1
3 changed files with 199 additions and 216 deletions

View File

@@ -27,7 +27,10 @@ import java.io.PrintStream;
import org.luaj.vm2.LoadState.LuaCompiler; import org.luaj.vm2.LoadState.LuaCompiler;
import org.luaj.vm2.lib.BaseLib; import org.luaj.vm2.lib.BaseLib;
import org.luaj.vm2.lib.DebugLib; import org.luaj.vm2.lib.DebugLib;
import org.luaj.vm2.lib.PackageLib;
import org.luaj.vm2.lib.ResourceFinder; import org.luaj.vm2.lib.ResourceFinder;
import org.luaj.vm2.lib.jme.JmePlatform;
import org.luaj.vm2.lib.jse.JsePlatform;
/** /**
* Global environment used by luaj. * Global environment used by luaj.
@@ -71,6 +74,8 @@ public class Globals extends LuaTable {
public DebugLib debuglib; public DebugLib debuglib;
public PackageLib package_;
public Globals checkglobals() { public Globals checkglobals() {
return this; return this;
} }

View File

@@ -1462,6 +1462,13 @@ public class LuaValue extends Varargs {
*/ */
public LuaValue call(LuaValue arg) { return callmt().call(this,arg); } public LuaValue call(LuaValue arg) { return callmt().call(this,arg); }
/** Convenience function which calls a luavalue with a single, string argument.
* @param arg String argument to the function. This will be converted to a LuaString.
* @return return value of the invocation.
* @see #call(LuaValue)
*/
public LuaValue call(String arg) { return call(valueOf(arg)); }
/** Call {@link this} with 2 arguments, including metatag processing, /** Call {@link this} with 2 arguments, including metatag processing,
* and return only the first return value. * and return only the first return value.
* <p> * <p>

View File

@@ -40,20 +40,19 @@ import org.luaj.vm2.Varargs;
* To instantiate and use it directly, * To instantiate and use it directly,
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as: * link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code * <pre> {@code
* LuaTable _G = new LuaTable(); * Globals _G = new Globals();
* LuaThread.setGlobals(_G);
* _G.load(new BaseLib()); * _G.load(new BaseLib());
* _G.load(new PackageLib()); * _G.load(new PackageLib());
* System.out.println( _G.get("require").call(LuaValue.valueOf("hyperbolic")) ); * System.out.println( _G.package_.require.call"foo") );
* } </pre> * } </pre>
* In practice, the first 4 lines of the above are minimal requirements to get * In practice, the first 3 lines of the above are minimal requirements to get
* and initialize a globals table capable of basic reqire, print, and other functions, * and initialize a globals table capable of basic require, print, and other functions,
* so it is much more convenient to use the {@link JsePlatform} and {@link JmePlatform} * so it is much more convenient to use the {@link JsePlatform} and {@link JmePlatform}
* utility classes instead. * utility classes instead.
* <p> * <p>
* This has been implemented to match as closely as possible the behavior in the corresponding library in C. * This has been implemented to match as closely as possible the behavior in the corresponding library in C.
* However, the default filesystem search semantics are different and delegated to the bas library * However, the default filesystem search semantics are different and delegated to the bas library
* as outlined in the {@link BaseLib} and {@link JseBaseLib} documetnation. * as outlined in the {@link BaseLib} and {@link JseBaseLib} documentation.
* @see LibFunction * @see LibFunction
* @see BaseLib * @see BaseLib
* @see JseBaseLib * @see JseBaseLib
@@ -63,123 +62,82 @@ import org.luaj.vm2.Varargs;
*/ */
public class PackageLib extends OneArgFunction { public class PackageLib extends OneArgFunction {
public static String DEFAULT_LUA_PATH = "?.lua"; /** The default value to use for package.path. This can be set with the system property
* "luaj.package.path", and is "?.lua" by default. */
public static String DEFAULT_LUA_PATH = System.getProperty("luaj.package.path", "?.lua");
/** The globals that were used to load this library. */
Globals globals; Globals globals;
public LuaTable LOADED; /** The table used by require to check for loaded modules, and exposed initially as package.loaded. */
public LuaTable PACKAGE; public LuaTable loaded;
/** Loader that loads from preload table if found there */ /** The table used by the {@link preload_loader}, and exposed initially as package.preload. */
public LuaValue preload_searcher; public LuaTable preload;
/** Loader that loads as a lua script using the LUA_PATH */ /** The value in use as the package path, and set as the initial value of package.path. */
public LuaValue lua_searcher; public LuaString path;
/** Loader that loads as a Java class. Class must have public constructor and be a LuaValue */ /** The loadlib function used by the package library. */
public LuaValue java_searcher; public loadlib loadlib;
/** The searchpath function used by the package library. */
public searchpath searchpath;
/** The initial searchers list, and the list exposed initially as package.searchers */
public LuaTable searchers;
/** Loader that loads from {@link preload} table if found there */
public preload_searcher preload_searcher;
/** Loader that loads as a lua script using the lua path currently in {@link path} */
public lua_searcher lua_searcher;
/** Loader that loads as a Java class. Class must have public constructor and be a LuaValue. */
public java_searcher java_searcher;
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 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"); private static final String FILE_SEP = System.getProperty("file.separator");
public PackageLib() {} public PackageLib() {}
public LuaValue call(LuaValue env) { public LuaValue call(LuaValue env) {
globals = env.checkglobals(); globals = env.checkglobals();
env.set("require", new PkgLib1("require",OP_REQUIRE,this)); env.set("require", new require());
env.set( "package", PACKAGE=tableOf( new LuaValue[] { LuaTable package_ = new LuaTable();
_LOADED, LOADED=tableOf(), package_.set("loaded", loaded = new LuaTable());
_PRELOAD, tableOf(), package_.set("preload", preload = new LuaTable());
_PATH, valueOf(DEFAULT_LUA_PATH), package_.set("path", path = LuaValue.valueOf(DEFAULT_LUA_PATH));
_LOADLIB, new PkgLibV("loadlib",OP_LOADLIB,this), package_.set("loadlib", loadlib = new loadlib());
_SEARCHPATH, new PkgLibV("searchpath",OP_SEARCHPATH,this), package_.set("searchpath", searchpath = new searchpath());
_SEARCHERS, listOf(new LuaValue[] { searchers = new LuaTable();
preload_searcher = new PkgLibV("preload_searcher",OP_PRELOAD_SEARCHER, this), searchers.set(1, preload_searcher = new preload_searcher());
lua_searcher = new PkgLibV("lua_searcher",OP_LUA_SEARCHER, this), searchers.set(2, lua_searcher = new lua_searcher());
java_searcher = new PkgLibV("java_searcher",OP_JAVA_SEARCHER, this), searchers.set(3, java_searcher = new java_searcher());
}) }) ); package_.set("searchers", searchers);
LOADED.set("package", PACKAGE); loaded.set("package", package_);
env.set("package", package_);
globals.package_ = this;
return env; return env;
} }
static final class PkgLib1 extends OneArgFunction {
PackageLib lib;
public PkgLib1(String name, int opcode, PackageLib lib) {
this.name = name;
this.opcode = opcode;
this.lib = lib;
}
public LuaValue call(LuaValue arg) {
switch ( opcode ) {
case OP_REQUIRE:
return lib.require(arg);
}
return NIL;
}
}
static final class PkgLibV extends VarArgFunction {
PackageLib lib;
public PkgLibV(String name,int opcode, PackageLib lib) {
this.name = name;
this.opcode = opcode;
this.lib = lib;
}
public Varargs invoke(Varargs args) {
switch ( opcode ) {
case OP_LOADLIB: {
return loadlib(args);
}
case OP_PRELOAD_SEARCHER: {
return lib.searcher_preload(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;
}
}
/** Allow packages to mark themselves as loaded */ /** Allow packages to mark themselves as loaded */
public void setIsLoaded(String name, LuaTable value) { public void setIsLoaded(String name, LuaTable value) {
LOADED.set(name, value); loaded.set(name, value);
} }
/** Set the lua path used by this library instance to a new value.
* Merely sets the value of {@link path} to be used in subsequent searches. */
public void setLuaPath( String newLuaPath ) { public void setLuaPath( String newLuaPath ) {
PACKAGE.set( _PATH, valueOf(newLuaPath) ); path = LuaValue.valueOf(newLuaPath);
} }
public String tojstring() { public String tojstring() {
return "package"; return "package";
} }
// ======================== Package loading ============================= // ======================== Package loading =============================
/** /**
@@ -208,135 +166,148 @@ public class PackageLib extends OneArgFunction {
* If there is any error loading or running the module, or if it cannot find any loader for * If there is any error loading or running the module, or if it cannot find any loader for
* the module, then require signals an error. * the module, then require signals an error.
*/ */
public LuaValue require( LuaValue arg ) { public class require extends OneArgFunction {
LuaString name = arg.checkstring(); public LuaValue call( LuaValue arg ) {
LuaValue loaded = LOADED.get(name); LuaString name = arg.checkstring();
if ( loaded.toboolean() ) { LuaValue result = loaded.get(name);
if ( loaded == _SENTINEL ) if ( result.toboolean() ) {
error("loop or previous error loading module '"+name+"'"); if ( result == _SENTINEL )
return loaded; error("loop or previous error loading module '"+name+"'");
} return result;
/* else must load it; iterate over available loaders */
LuaTable tbl = PACKAGE.get(_SEARCHERS).checktable();
StringBuffer sb = new StringBuffer();
LuaValue chunk = null;
for ( int i=1; true; i++ ) {
LuaValue loader = tbl.get(i);
if ( loader.isnil() ) {
error( "module '"+name+"' not found: "+name+sb );
}
/* call loader with module name as argument */
chunk = loader.call(name);
if ( chunk.isfunction() )
break;
if ( chunk.isstring() )
sb.append( chunk.tojstring() );
}
// load the module using the loader
LOADED.set(name, _SENTINEL);
LuaValue result = chunk.call(name);
if ( ! result.isnil() )
LOADED.set( name, result );
else if ( (result = LOADED.get(name)) == _SENTINEL )
LOADED.set( name, result = LuaValue.TRUE );
return result;
}
public static Varargs loadlib( Varargs args ) {
args.checkstring(1);
return varargsOf(NIL, valueOf("dynamic libraries not enabled"), valueOf("absent"));
}
LuaValue searcher_preload( Varargs args ) {
LuaString name = args.checkstring(1);
LuaValue preload = PACKAGE.get(_PRELOAD).checktable();
LuaValue val = preload.get(name);
return val.isnil()?
valueOf("\n\tno field package.preload['"+name+"']"):
val;
}
Varargs searcher_Lua( Varargs args ) {
LuaString name = args.checkstring(1);
InputStream is = null;
// get package path
LuaValue path = PACKAGE.get(_PATH);
if ( ! path.isstring() )
return valueOf("package.path is not a string");
// 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 = globals.loadFile(filename.tojstring());
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(sep.charAt(0), rep.charAt(0));
while ( e < n ) {
// find next template
int b = e+1;
e = path.indexOf(';',b);
if ( e < 0 )
e = path.length();
String template = path.substring(b,e);
// create filename
int q = template.indexOf('?');
String filename = template;
if ( q >= 0 ) {
filename = template.substring(0,q) + name + template.substring(q+1);
} }
// try opening the file /* else must load it; iterate over available loaders */
InputStream is = globals.FINDER.findResource(filename); LuaTable tbl = PackageLib.this.searchers.checktable();
if (is != null) { StringBuffer sb = new StringBuffer();
try { is.close(); } catch ( java.io.IOException ioe ) {} LuaValue chunk = null;
return valueOf(filename); for ( int i=1; true; i++ ) {
LuaValue loader = tbl.get(i);
if ( loader.isnil() ) {
error( "module '"+name+"' not found: "+name+sb );
}
/* call loader with module name as argument */
chunk = loader.call(name);
if ( chunk.isfunction() )
break;
if ( chunk.isstring() )
sb.append( chunk.tojstring() );
} }
// load the module using the loader
loaded.set(name, _SENTINEL);
result = chunk.call(name);
if ( ! result.isnil() )
loaded.set( name, result );
else if ( (result = PackageLib.this.loaded.get(name)) == _SENTINEL )
loaded.set( name, result = LuaValue.TRUE );
return result;
}
}
public static class loadlib extends VarArgFunction {
public Varargs loadlib( Varargs args ) {
args.checkstring(1);
return varargsOf(NIL, valueOf("dynamic libraries not enabled"), valueOf("absent"));
}
}
public class preload_searcher extends VarArgFunction {
public Varargs invoke(Varargs args) {
LuaString name = args.checkstring(1);
LuaValue val = preload.get(name);
return val.isnil()?
valueOf("\n\tno field package.preload['"+name+"']"):
val;
}
}
public class lua_searcher extends VarArgFunction {
public Varargs invoke(Varargs args) {
LuaString name = args.checkstring(1);
InputStream is = null;
// get package path
if ( ! path.isstring() )
return valueOf("package.path is not a string");
// get the searchpath function.
Varargs v = searchpath.invoke(varargsOf(name, path));
// Did we get a result?
if (!v.isstring(1))
return v.arg(2).tostring();
LuaString filename = v.arg1().strvalue();
// Try to load the file.
v = globals.loadFile(filename.tojstring());
if ( v.arg1().isfunction() )
return LuaValue.varargsOf(v.arg1(), filename);
// report error // report error
if ( sb == null ) return varargsOf(NIL, valueOf("'"+filename+"': "+v.arg(2).tojstring()));
sb = new StringBuffer();
sb.append( "\n\t"+filename );
} }
return varargsOf(NIL, valueOf(sb.toString()));
} }
LuaValue searcher_Java( Varargs args ) { public class searchpath extends VarArgFunction {
String name = args.checkjstring(1); public Varargs invoke(Varargs args) {
String classname = toClassname( name ); String name = args.checkjstring(1);
Class c = null; String path = args.checkjstring(2);
LuaValue v = null; String sep = args.optjstring(3, ".");
try { String rep = args.optjstring(4, FILE_SEP);
c = Class.forName(classname);
v = (LuaValue) c.newInstance(); // check the path elements
return v; int e = -1;
} catch ( ClassNotFoundException cnfe ) { int n = path.length();
return valueOf("\n\tno class '"+classname+"'" ); StringBuffer sb = null;
} catch ( Exception e ) { name = name.replace(sep.charAt(0), rep.charAt(0));
return valueOf("\n\tjava load failed on '"+classname+"', "+e ); while ( e < n ) {
// find next template
int b = e+1;
e = path.indexOf(';',b);
if ( e < 0 )
e = path.length();
String template = path.substring(b,e);
// create filename
int q = template.indexOf('?');
String filename = template;
if ( q >= 0 ) {
filename = template.substring(0,q) + name + template.substring(q+1);
}
// try opening the file
InputStream is = globals.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 );
}
return varargsOf(NIL, valueOf(sb.toString()));
}
}
public class java_searcher extends VarArgFunction {
public Varargs invoke(Varargs args) {
String name = args.checkjstring(1);
String classname = toClassname( name );
Class c = null;
LuaValue v = null;
try {
c = Class.forName(classname);
v = (LuaValue) c.newInstance();
return v;
} catch ( ClassNotFoundException cnfe ) {
return valueOf("\n\tno class '"+classname+"'" );
} catch ( Exception e ) {
return valueOf("\n\tjava load failed on '"+classname+"', "+e );
}
} }
} }