Supply environment as extra argument when loading functions.
This commit is contained in:
@@ -57,40 +57,43 @@ import org.luaj.vm2.Varargs;
|
||||
* <p>
|
||||
* For example, the following code will implement a library called "hyperbolic"
|
||||
* with two functions, "sinh", and "cosh":
|
||||
* <pre> {@code
|
||||
<pre> {@code
|
||||
* import org.luaj.vm2.LuaValue;
|
||||
* public class hyperbolic extends org.luaj.vm2.lib.OneArgFunction {
|
||||
* public hyperbolic() {}
|
||||
* public LuaValue call(LuaValue arg) {
|
||||
* switch ( opcode ) {
|
||||
* case 0: {
|
||||
* LuaValue t = tableOf();
|
||||
* this.bind(t, hyperbolic.class, new String[] { "sinh", "cosh" }, 1 );
|
||||
* env.set("hyperbolic", t);
|
||||
* return t;
|
||||
* }
|
||||
* case 1: return valueOf(Math.sinh(arg.todouble()));
|
||||
* case 2: return valueOf(Math.cosh(arg.todouble()));
|
||||
* default: return error("bad opcode: "+opcode);
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
* The default constructor is both to instantiate the library
|
||||
* in response to {@code require 'hyperbolic'} statement,
|
||||
* provided it is on Javas class path,
|
||||
* and to instantiate copies of the {@code hyperbolic}
|
||||
* class when initializing library instances. .
|
||||
* The instance returned by the default constructor will be invoked
|
||||
* as part of library loading.
|
||||
* In response, it creates two more instances, one for each library function,
|
||||
* in the body of the {@code switch} statement {@code case 0}
|
||||
* via the {@link #bind(LuaValue, Class, String[], int)} utility method.
|
||||
* It also registers the table in the globals via the {@link #env}
|
||||
* local variable, which should be the global environment unless
|
||||
* it has been changed.
|
||||
* {@code case 1} and {@code case 2} will be called when {@code hyperbolic.sinh}
|
||||
* {@code hyperbolic.sinh} and {@code hyperbolic.cosh} are invoked.
|
||||
* import org.luaj.vm2.lib.*;
|
||||
*
|
||||
* public class hyperbolic extends TwoArgFunction {
|
||||
*
|
||||
* public hyperbolic() {}
|
||||
*
|
||||
* public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
* LuaValue library = tableOf();
|
||||
* library.set( "sinh", new sinh() );
|
||||
* library.set( "cosh", new cosh() );
|
||||
* env.set( "hyperbolic", library );
|
||||
* return library;
|
||||
* }
|
||||
*
|
||||
* static class sinh extends OneArgFunction {
|
||||
* public LuaValue call(LuaValue x) {
|
||||
* return LuaValue.valueOf(Math.sinh(x.checkdouble()));
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* static class cosh extends OneArgFunction {
|
||||
* public LuaValue call(LuaValue x) {
|
||||
* return LuaValue.valueOf(Math.cosh(x.checkdouble()));
|
||||
* }
|
||||
* }
|
||||
*}
|
||||
*}</pre>
|
||||
* The default constructor is used to instantiate the library
|
||||
* in response to {@code require 'hyperbolic'} statement,
|
||||
* provided it is on Java"s class path.
|
||||
* This instance is then invoked with 2 arguments: the name supplied to require(),
|
||||
* and the environment for this function. The library may ignore these, or use
|
||||
* them to leave side effects in the global environment, for example.
|
||||
* In the previous example, two functions are created, 'sinh', and 'cosh', and placed
|
||||
* into a global table called 'hyperbolic' using the supplied 'env' argument.
|
||||
* <p>
|
||||
* To test it, a script such as this can be used:
|
||||
* <pre> {@code
|
||||
@@ -108,14 +111,14 @@ import org.luaj.vm2.Varargs;
|
||||
* <pre> {@code
|
||||
* t table: 3dbbd23f
|
||||
* hyperbolic table: 3dbbd23f
|
||||
* k,v cosh cosh
|
||||
* k,v sinh sinh
|
||||
* k,v cosh function: 3dbbd128
|
||||
* k,v sinh function: 3dbbd242
|
||||
* sinh(.5) 0.5210953
|
||||
* cosh(.5) 1.127626
|
||||
* }</pre>
|
||||
* <p>
|
||||
* See the source code in any of the library functions
|
||||
* such as {@link BaseLib} or {@link TableLib} for specific examples.
|
||||
* such as {@link BaseLib} or {@link TableLib} for other examples.
|
||||
*/
|
||||
abstract public class LibFunction extends LuaFunction {
|
||||
|
||||
|
||||
@@ -148,28 +148,29 @@ public class PackageLib extends OneArgFunction {
|
||||
/**
|
||||
* require (modname)
|
||||
*
|
||||
* Loads the given module. The function starts by looking into the package.loaded table to
|
||||
* determine whether modname is already loaded. If it is, then require returns the value
|
||||
* Loads the given module. The function starts by looking into the package.loaded table
|
||||
* to determine whether modname is already loaded. If it is, then require returns the value
|
||||
* stored at package.loaded[modname]. Otherwise, it tries to find a loader for the module.
|
||||
*
|
||||
* To find a loader, require is guided by the package.loaders array. By changing this array,
|
||||
* we can change how require looks for a module. The following explanation is based on the
|
||||
* default configuration for package.loaders.
|
||||
*
|
||||
* To find a loader, require is guided by the package.searchers sequence.
|
||||
* By changing this sequence, we can change how require looks for a module.
|
||||
* The following explanation is based on the default configuration for package.searchers.
|
||||
*
|
||||
* First require queries package.preload[modname]. If it has a value, this value
|
||||
* (which should be a function) is the loader. Otherwise require searches for a Lua loader
|
||||
* using the path stored in package.path. If that also fails, it searches for a C loader
|
||||
* using the path stored in package.cpath. If that also fails, it tries an all-in-one loader
|
||||
* (see package.loaders).
|
||||
* (which should be a function) is the loader. Otherwise require searches for a Lua loader using
|
||||
* the path stored in package.path. If that also fails, it searches for a Java loader using
|
||||
* the classpath, using the public default constructor, and casting the instance to LuaFunction.
|
||||
*
|
||||
* Once a loader is found, require calls the loader with a single argument, modname.
|
||||
* If the loader returns any value, require assigns the returned value to package.loaded[modname].
|
||||
* If the loader returns no value and has not assigned any value to package.loaded[modname],
|
||||
* then require assigns true to this entry. In any case, require returns the final value of
|
||||
* package.loaded[modname].
|
||||
*
|
||||
* 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.
|
||||
* Once a loader is found, require calls the loader with two arguments: modname and an extra value
|
||||
* dependent on how it got the loader. If the loader came from a file, this extra value is the file name.
|
||||
* If the loader is a Java instance of LuaFunction, this extra value is the environment.
|
||||
* If the loader returns any non-nil value, require assigns the returned value to package.loaded[modname].
|
||||
* If the loader does not return a non-nil value and has not assigned any value to package.loaded[modname],
|
||||
* then require assigns true to this entry.
|
||||
* In any case, require returns the final value of package.loaded[modname].
|
||||
*
|
||||
* If there is any error loading or running the module, or if it cannot find any loader for the module,
|
||||
* then require raises an error.
|
||||
*/
|
||||
public class require extends OneArgFunction {
|
||||
public LuaValue call( LuaValue arg ) {
|
||||
@@ -184,24 +185,24 @@ public class PackageLib extends OneArgFunction {
|
||||
/* else must load it; iterate over available loaders */
|
||||
LuaTable tbl = PackageLib.this.searchers.checktable();
|
||||
StringBuffer sb = new StringBuffer();
|
||||
LuaValue chunk = null;
|
||||
Varargs loader = null;
|
||||
for ( int i=1; true; i++ ) {
|
||||
LuaValue loader = tbl.get(i);
|
||||
if ( loader.isnil() ) {
|
||||
LuaValue searcher = tbl.get(i);
|
||||
if ( searcher.isnil() ) {
|
||||
error( "module '"+name+"' not found: "+name+sb );
|
||||
}
|
||||
|
||||
/* call loader with module name as argument */
|
||||
chunk = loader.call(name);
|
||||
if ( chunk.isfunction() )
|
||||
loader = searcher.invoke(name);
|
||||
if ( loader.isfunction(1) )
|
||||
break;
|
||||
if ( chunk.isstring() )
|
||||
sb.append( chunk.tojstring() );
|
||||
if ( loader.isstring(1) )
|
||||
sb.append( loader.tojstring(1) );
|
||||
}
|
||||
|
||||
// load the module using the loader
|
||||
loaded.set(name, _SENTINEL);
|
||||
result = chunk.call(name);
|
||||
result = loader.arg1().call(name, loader.arg(2));
|
||||
if ( ! result.isnil() )
|
||||
loaded.set( name, result );
|
||||
else if ( (result = PackageLib.this.loaded.get(name)) == _SENTINEL )
|
||||
@@ -309,7 +310,7 @@ public class PackageLib extends OneArgFunction {
|
||||
v = (LuaValue) c.newInstance();
|
||||
if (v.isfunction())
|
||||
((LuaFunction)v).initupvalue1(globals);
|
||||
return v;
|
||||
return varargsOf(v, globals);
|
||||
} catch ( ClassNotFoundException cnfe ) {
|
||||
return valueOf("\n\tno class '"+classname+"'" );
|
||||
} catch ( Exception e ) {
|
||||
|
||||
Reference in New Issue
Block a user