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.lib.BaseLib;
import org.luaj.vm2.lib.DebugLib;
import org.luaj.vm2.lib.PackageLib;
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.
@@ -70,6 +73,8 @@ public class Globals extends LuaTable {
public LuaThread running_thread = new LuaThread(this);
public DebugLib debuglib;
public PackageLib package_;
public Globals checkglobals() {
return this;

View File

@@ -1462,6 +1462,13 @@ public class LuaValue extends Varargs {
*/
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,
* and return only the first return value.
* <p>

View File

@@ -40,20 +40,19 @@ import org.luaj.vm2.Varargs;
* To instantiate and use it directly,
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code
* LuaTable _G = new LuaTable();
* LuaThread.setGlobals(_G);
* Globals _G = new Globals();
* _G.load(new BaseLib());
* _G.load(new PackageLib());
* System.out.println( _G.get("require").call(LuaValue.valueOf("hyperbolic")) );
* System.out.println( _G.package_.require.call"foo") );
* } </pre>
* In practice, the first 4 lines of the above are minimal requirements to get
* and initialize a globals table capable of basic reqire, print, and other functions,
* In practice, the first 3 lines of the above are minimal requirements to get
* 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}
* utility classes instead.
* <p>
* 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
* as outlined in the {@link BaseLib} and {@link JseBaseLib} documetnation.
* as outlined in the {@link BaseLib} and {@link JseBaseLib} documentation.
* @see LibFunction
* @see BaseLib
* @see JseBaseLib
@@ -63,123 +62,82 @@ import org.luaj.vm2.Varargs;
*/
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;
public LuaTable LOADED;
public LuaTable PACKAGE;
/** Loader that loads from preload table if found there */
public LuaValue preload_searcher;
/** The table used by require to check for loaded modules, and exposed initially as package.loaded. */
public LuaTable loaded;
/** The table used by the {@link preload_loader}, and exposed initially as package.preload. */
public LuaTable preload;
/** Loader that loads as a lua script using the LUA_PATH */
public LuaValue lua_searcher;
/** The value in use as the package path, and set as the initial value of package.path. */
public LuaString path;
/** Loader that loads as a Java class. Class must have public constructor and be a LuaValue */
public LuaValue java_searcher;
/** The loadlib function used by the package library. */
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;
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");
/** 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 _SENTINEL = valueOf("\u0001");
private static final int OP_REQUIRE = 0;
private static final int OP_LOADLIB = 1;
private static final int OP_SEARCHPATH = 2;
private static final int OP_PRELOAD_SEARCHER = 3;
private static final int OP_LUA_SEARCHER = 4;
private static final int OP_JAVA_SEARCHER = 5;
private static final String FILE_SEP = System.getProperty("file.separator");
public PackageLib() {}
public LuaValue call(LuaValue env) {
globals = env.checkglobals();
env.set("require", new PkgLib1("require",OP_REQUIRE,this));
env.set( "package", PACKAGE=tableOf( new LuaValue[] {
_LOADED, LOADED=tableOf(),
_PRELOAD, tableOf(),
_PATH, valueOf(DEFAULT_LUA_PATH),
_LOADLIB, new PkgLibV("loadlib",OP_LOADLIB,this),
_SEARCHPATH, new PkgLibV("searchpath",OP_SEARCHPATH,this),
_SEARCHERS, listOf(new LuaValue[] {
preload_searcher = new PkgLibV("preload_searcher",OP_PRELOAD_SEARCHER, this),
lua_searcher = new PkgLibV("lua_searcher",OP_LUA_SEARCHER, this),
java_searcher = new PkgLibV("java_searcher",OP_JAVA_SEARCHER, this),
}) }) );
LOADED.set("package", PACKAGE);
env.set("require", new require());
LuaTable package_ = new LuaTable();
package_.set("loaded", loaded = new LuaTable());
package_.set("preload", preload = new LuaTable());
package_.set("path", path = LuaValue.valueOf(DEFAULT_LUA_PATH));
package_.set("loadlib", loadlib = new loadlib());
package_.set("searchpath", searchpath = new searchpath());
searchers = new LuaTable();
searchers.set(1, preload_searcher = new preload_searcher());
searchers.set(2, lua_searcher = new lua_searcher());
searchers.set(3, java_searcher = new java_searcher());
package_.set("searchers", searchers);
loaded.set("package", package_);
env.set("package", package_);
globals.package_ = this;
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 */
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 ) {
PACKAGE.set( _PATH, valueOf(newLuaPath) );
path = LuaValue.valueOf(newLuaPath);
}
public String tojstring() {
return "package";
}
// ======================== 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
* the module, then require signals an error.
*/
public LuaValue require( LuaValue arg ) {
LuaString name = arg.checkstring();
LuaValue loaded = LOADED.get(name);
if ( loaded.toboolean() ) {
if ( loaded == _SENTINEL )
error("loop or previous error loading module '"+name+"'");
return loaded;
}
/* 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);
public class require extends OneArgFunction {
public LuaValue call( LuaValue arg ) {
LuaString name = arg.checkstring();
LuaValue result = loaded.get(name);
if ( result.toboolean() ) {
if ( result == _SENTINEL )
error("loop or previous error loading module '"+name+"'");
return result;
}
// try opening the file
InputStream is = globals.FINDER.findResource(filename);
if (is != null) {
try { is.close(); } catch ( java.io.IOException ioe ) {}
return valueOf(filename);
/* else must load it; iterate over available loaders */
LuaTable tbl = PackageLib.this.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);
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
if ( sb == null )
sb = new StringBuffer();
sb.append( "\n\t"+filename );
return varargsOf(NIL, valueOf("'"+filename+"': "+v.arg(2).tojstring()));
}
}
public class searchpath extends VarArgFunction {
public Varargs invoke(Varargs args) {
String name = args.checkjstring(1);
String path = args.checkjstring(2);
String sep = args.optjstring(3, ".");
String rep = args.optjstring(4, FILE_SEP);
// 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
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()));
}
return varargsOf(NIL, valueOf(sb.toString()));
}
LuaValue searcher_Java( 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 );
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 );
}
}
}