Remove env from LuaFunction, replace with upValiue array, and remove most occurances of setfenv and getfenv.

This commit is contained in:
James Roseborough
2012-09-07 04:36:50 +00:00
parent 244a964af5
commit 3bacea878e
36 changed files with 130 additions and 265 deletions

View File

@@ -67,7 +67,6 @@ import org.luaj.vm2.lib.DebugLib;
* Since a {@link LuaClosure} is a {@link LuaFunction} which is a {@link LuaValue}, * Since a {@link LuaClosure} is a {@link LuaFunction} which is a {@link LuaValue},
* all the value operations can be used directly such as: * all the value operations can be used directly such as:
* <ul> * <ul>
* <li>{@link LuaValue#setfenv(LuaValue)}</li>
* <li>{@link LuaValue#call()}</li> * <li>{@link LuaValue#call()}</li>
* <li>{@link LuaValue#call(LuaValue)}</li> * <li>{@link LuaValue#call(LuaValue)}</li>
* <li>{@link LuaValue#invoke()}</li> * <li>{@link LuaValue#invoke()}</li>
@@ -90,24 +89,28 @@ public class LuaClosure extends LuaFunction {
private static final UpValue[] NOUPVALUES = new UpValue[0]; private static final UpValue[] NOUPVALUES = new UpValue[0];
public final Prototype p; public final Prototype p;
public final UpValue[] upValues;
LuaClosure() { /** Create a closure around a Prototype with the default global environment.
p = null; * If the prototype has upvalues, the environment will be written into the first upvalue.
upValues = null; * @param p the Prototype to construct this Closure for.
* @param env the environment to associate with the closure.
*/
public LuaClosure(Prototype p) {
this(p, LuaValue._G);
} }
/** Supply the initial environment */
/** Create a closure around a Prototype with a specific environment.
* If the prototype has upvalues, the environment will be written into the first upvalue.
* @param p the Prototype to construct this Closure for.
* @param env the environment to associate with the closure.
*/
public LuaClosure(Prototype p, LuaValue env) { public LuaClosure(Prototype p, LuaValue env) {
this(p, p.upvalues.length, env);
}
protected LuaClosure(Prototype p, int nupvalues, LuaValue env) {
super( env );
this.p = p; this.p = p;
switch (nupvalues) { if (p.upvalues == null || p.upvalues.length == 0)
case 0: this.upValues = NOUPVALUES; break; this.upValues = NOUPVALUES;
case 1: this.upValues = new UpValue[] { new UpValue(new LuaValue[1], 0) }; this.upValues[0].setValue(env); break; else {
default: this.upValues = new UpValue[nupvalues]; break; this.upValues = new UpValue[p.upvalues.length];
this.upValues[0] = new UpValue(new LuaValue[] {env}, 0);
} }
} }
@@ -463,7 +466,7 @@ public class LuaClosure extends LuaFunction {
case Lua.OP_CLOSURE: /* A Bx R(A):= closure(KPROTO[Bx]) */ case Lua.OP_CLOSURE: /* A Bx R(A):= closure(KPROTO[Bx]) */
{ {
Prototype newp = p.p[i>>>14]; Prototype newp = p.p[i>>>14];
LuaClosure ncl = new LuaClosure(newp, env); LuaClosure ncl = new LuaClosure(newp);
Upvaldesc[] uv = newp.upvalues; Upvaldesc[] uv = newp.upvalues;
for ( int j=0, nup=uv.length; j<nup; ++j ) { for ( int j=0, nup=uv.length; j<nup; ++j ) {
if (uv[j].instack) /* upvalue refes to local variable? */ if (uv[j].instack) /* upvalue refes to local variable? */

View File

@@ -38,15 +38,7 @@ public class LuaFunction extends LuaValue {
/** Shared static metatable for all functions and closures. */ /** Shared static metatable for all functions and closures. */
public static LuaValue s_metatable; public static LuaValue s_metatable;
protected LuaValue env; public UpValue[] upValues;
public LuaFunction() {
this.env = NIL;
}
public LuaFunction(LuaValue env) {
this.env = env;
}
public int type() { public int type() {
return TFUNCTION; return TFUNCTION;
@@ -72,11 +64,8 @@ public class LuaFunction extends LuaValue {
return s_metatable; return s_metatable;
} }
public LuaValue getfenv() { public void initupvalue1(LuaValue env) {
return env; if (upValues != null && upValues.length > 0)
} upValues[0] = new UpValue(new LuaValue[] {env}, 0);
public void setfenv(LuaValue env) {
this.env = env!=null? env: NIL;
} }
} }

View File

@@ -82,7 +82,6 @@ public class LuaThread extends LuaValue {
"normal", "normal",
"dead",}; "dead",};
private LuaValue env;
private final State state; private final State state;
/** Field to hold state of error condition during debug hook function calls. */ /** Field to hold state of error condition during debug hook function calls. */
@@ -112,11 +111,9 @@ public class LuaThread extends LuaValue {
/** /**
* Create a LuaThread around a function and environment * Create a LuaThread around a function and environment
* @param func The function to execute * @param func The function to execute
* @param env The environment to apply to the thread
*/ */
public LuaThread(LuaValue func, LuaValue env) { public LuaThread(LuaValue func) {
LuaValue.assert_(func != null, "function cannot be null"); LuaValue.assert_(func != null, "function cannot be null");
this.env = env;
state = new State(this, func); state = new State(this, func);
} }
@@ -144,14 +141,6 @@ public class LuaThread extends LuaValue {
return s_metatable; return s_metatable;
} }
public LuaValue getfenv() {
return env;
}
public void setfenv(LuaValue env) {
this.env = env;
}
public String getStatus() { public String getStatus() {
return STATUS_NAMES[state.status]; return STATUS_NAMES[state.status];
} }
@@ -172,24 +161,6 @@ public class LuaThread extends LuaValue {
return r == main_thread; return r == main_thread;
} }
/**
* Set the globals of the current thread.
* <p>
* This must be done once before any other code executes.
* @param globals The global variables for the main ghread.
*/
public static void setGlobals(LuaValue globals) {
running_thread.env = globals;
}
/** Get the current thread's environment
* @return {@link LuaValue} containing the global variables of the current thread.
*/
public static LuaValue getGlobals() {
LuaValue e = running_thread.env;
return e!=null? e: LuaValue.error("LuaThread.setGlobals() not initialized");
}
/** /**
* Callback used at the beginning of a call to prepare for possible getfenv/setfenv calls * Callback used at the beginning of a call to prepare for possible getfenv/setfenv calls
* @param function Function being called * @param function Function being called

View File

@@ -109,7 +109,11 @@ package org.luaj.vm2;
*/ */
abstract abstract
public class LuaValue extends Varargs { public class LuaValue extends Varargs {
/** The default global environment. This must be set before lua can be used.
* Typically, it is set as a side effect of calling one of
* JsePlatform.standardGlobals() or similar functions.
*/
public static LuaValue _G;
/** Type enumeration constant for lua numbers that are ints, for compatibility with lua 5.1 number patch only */ /** Type enumeration constant for lua numbers that are ints, for compatibility with lua 5.1 number patch only */
public static final int TINT = (-2); public static final int TINT = (-2);
@@ -1351,13 +1355,23 @@ public class LuaValue extends Varargs {
public Varargs inext(LuaValue index) { return typerror("table"); } public Varargs inext(LuaValue index) { return typerror("table"); }
/** /**
* Load a library instance by setting its environment to {@code this} * Load a library instance by setting its environment to the global environment {@code LuaValue._G}
* and calling it, which should iniitalize the library instance and * and calling it, which should iniitalize the library instance and
* install itself into this instance. * install itself into this instance.
* @param library The callable {@link LuaValue} to load into {@code this} * @param library The callable {@link LuaValue} to load into {@code this}
* @return {@link LuaValue._G} containing the result of the initialization call.
*/
public LuaValue load(LuaValue library) { return load(library, _G); }
/**
* Load a library instance by setting its environment to {@code env}
* and calling it, which should iniitalize the library instance and
* install itself into this instance.
* @param library The callable {@link LuaValue} to load into {@code this}
* @param env The {@link LuaValue} to use as the environment for the library.
* @return {@link LuaValue} containing the result of the initialization call. * @return {@link LuaValue} containing the result of the initialization call.
*/ */
public LuaValue load(LuaValue library) { library.setfenv(this); return library.call(); } public LuaValue load(LuaValue library, LuaValue env) { return library.call(env); }
// varargs references // varargs references
public LuaValue arg(int index) { return index==1? this: NIL; } public LuaValue arg(int index) { return index==1? this: NIL; }
@@ -1394,25 +1408,6 @@ public class LuaValue extends Varargs {
*/ */
public LuaValue setmetatable(LuaValue metatable) { return argerror("table"); } public LuaValue setmetatable(LuaValue metatable) { return argerror("table"); }
/**
* Get the environemnt for an instance.
* @return {@link LuaValue} currently set as the instances environent.
*/
public LuaValue getfenv() { typerror("function or thread"); return null; }
/**
* Set the environment on an object.
* <p>
* Typically the environment is created once per application via a platform
* helper method such as {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
* However, any object can serve as an environment if it contains suitable metatag
* values to implement {@link #get(LuaValue)} to provide the environment values.
* @param env {@link LuaValue} (typically a {@link LuaTable}) containing the environment.
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see org.luaj.vm2.lib.jse.JsePlatform
*/
public void setfenv(LuaValue env) { typerror("function or thread"); }
/** Call {@link this} with 0 arguments, including metatag processing, /** Call {@link this} with 0 arguments, including metatag processing,
* and return only the first return value. * and return only the first return value.
* <p> * <p>

View File

@@ -52,6 +52,12 @@ public class Prototype {
public int maxstacksize; public int maxstacksize;
public Prototype() {}
public Prototype(int n_upvalues) {
upvalues = new Upvaldesc[n_upvalues];
}
public String toString() { public String toString() {
return source + ":" + linedefined+"-"+lastlinedefined; return source + ":" + linedefined+"-"+lastlinedefined;
} }

View File

@@ -126,7 +126,7 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
instance = this; instance = this;
} }
public LuaValue call(LuaValue arg) { public LuaValue call(LuaValue env) {
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, BaseLib1.class, LIB1_KEYS );
@@ -230,8 +230,8 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or 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 filename = args.isstring(1)? args.tojstring(1): null;
Varargs v = filename == null? Varargs v = filename == null?
BaseLib.loadStream( baselib.STDIN, "=stdin", "bt", LuaThread.getGlobals() ): BaseLib.loadStream( baselib.STDIN, "=stdin", "bt",LuaValue._G ):
BaseLib.loadFile( args.checkjstring(1), "bt", LuaThread.getGlobals() ); BaseLib.loadFile( args.checkjstring(1), "bt",LuaValue._G );
return v.isnil(1)? error(v.tojstring(2)): v.arg1().invoke(); return v.isnil(1)? error(v.tojstring(2)): v.arg1().invoke();
} }
case 2: // "load", // ( ld [, source [, mode [, env]]] ) -> chunk | nil, msg case 2: // "load", // ( ld [, source [, mode [, env]]] ) -> chunk | nil, msg
@@ -240,7 +240,7 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
args.argcheck(ld.isstring() || ld.isfunction(), 1, "ld must be string or function"); args.argcheck(ld.isstring() || ld.isfunction(), 1, "ld must be string or function");
String source = args.optjstring(2, ld.isstring()? ld.tojstring(): "=(load)"); String source = args.optjstring(2, ld.isstring()? ld.tojstring(): "=(load)");
String mode = args.optjstring(3, "bt"); String mode = args.optjstring(3, "bt");
LuaValue env = args.optvalue(4, LuaThread.getGlobals()); LuaValue env = args.optvalue(4,LuaValue._G);
return BaseLib.loadStream(ld.isstring()? ld.strvalue().toInputStream(): return BaseLib.loadStream(ld.isstring()? ld.strvalue().toInputStream():
new StringInputStream(ld.checkfunction()), source, mode, env); new StringInputStream(ld.checkfunction()), source, mode, env);
} }
@@ -249,7 +249,7 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or 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 filename = args.isstring(1)? args.tojstring(1): null;
String mode = args.optjstring(2, "bt"); String mode = args.optjstring(2, "bt");
LuaValue env = args.optvalue(3, LuaThread.getGlobals()); LuaValue env = args.optvalue(3,LuaValue._G);
return filename == null? return filename == null?
BaseLib.loadStream( baselib.STDIN, "=stdin", mode, env ): BaseLib.loadStream( baselib.STDIN, "=stdin", mode, env ):
BaseLib.loadFile( filename, mode, env ); BaseLib.loadFile( filename, mode, env );
@@ -275,7 +275,7 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
} }
case 6: // "print", // (...) -> void case 6: // "print", // (...) -> void
{ {
LuaValue tostring = LuaThread.getGlobals().get("tostring"); LuaValue tostring =LuaValue._G.get("tostring");
for ( int i=1, n=args.narg(); i<=n; i++ ) { for ( int i=1, n=args.narg(); i<=n; i++ ) {
if ( i>1 ) baselib.STDOUT.write( '\t' ); if ( i>1 ) baselib.STDOUT.write( '\t' );
LuaString s = tostring.call( args.arg(i) ).strvalue(); LuaString s = tostring.call( args.arg(i) ).strvalue();

View File

@@ -65,10 +65,16 @@ public class CoroutineLib extends VarArgFunction {
private static final int WRAP = 6; private static final int WRAP = 6;
private static final int WRAPPED = 7; private static final int WRAPPED = 7;
private LuaThread t;
public CoroutineLib() { public CoroutineLib() {
} }
private LuaTable init() { private CoroutineLib(LuaThread t) {
this.t = t;
}
private LuaTable init(LuaValue env) {
LuaTable t = new LuaTable(); LuaTable t = new LuaTable();
bind(t, CoroutineLib.class, new String[] { bind(t, CoroutineLib.class, new String[] {
"create", "resume", "running", "status", "yield", "wrap" }, "create", "resume", "running", "status", "yield", "wrap" },
@@ -81,11 +87,11 @@ public class CoroutineLib extends VarArgFunction {
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
switch ( opcode ) { switch ( opcode ) {
case INIT: { case INIT: {
return init(); return init(args.arg1());
} }
case CREATE: { case CREATE: {
final LuaValue func = args.checkfunction(1); final LuaValue func = args.checkfunction(1);
return new LuaThread(func, LuaThread.getGlobals() ); return new LuaThread(func);
} }
case RESUME: { case RESUME: {
final LuaThread t = args.checkthread(1); final LuaThread t = args.checkthread(1);
@@ -103,15 +109,13 @@ public class CoroutineLib extends VarArgFunction {
} }
case WRAP: { case WRAP: {
final LuaValue func = args.checkfunction(1); final LuaValue func = args.checkfunction(1);
final LuaThread thread = new LuaThread(func, func.getfenv()); final LuaThread thread = new LuaThread(func);
CoroutineLib cl = new CoroutineLib(); CoroutineLib cl = new CoroutineLib(thread);
cl.setfenv(thread);
cl.name = "wrapped"; cl.name = "wrapped";
cl.opcode = WRAPPED; cl.opcode = WRAPPED;
return cl; return cl;
} }
case WRAPPED: { case WRAPPED: {
final LuaThread t = (LuaThread) env;
final Varargs result = t.resume( args ); final Varargs result = t.resume( args );
if ( result.arg1().toboolean() ) { if ( result.arg1().toboolean() ) {
return result.subargs(2); return result.subargs(2);

View File

@@ -136,7 +136,7 @@ public class DebugLib extends VarArgFunction {
public DebugLib() { public DebugLib() {
} }
private LuaTable init() { private LuaTable init(LuaValue env) {
DEBUG_ENABLED = true; DEBUG_ENABLED = true;
LuaTable t = new LuaTable(); LuaTable t = new LuaTable();
bind(t, DebugLib.class, NAMES, DEBUG); bind(t, DebugLib.class, NAMES, DEBUG);
@@ -147,7 +147,7 @@ public class DebugLib extends VarArgFunction {
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
switch ( opcode ) { switch ( opcode ) {
case INIT: return init(); case INIT: return init(args.arg1());
case DEBUG: return _debug(args); case DEBUG: return _debug(args);
case GETHOOK: return _gethook(args); case GETHOOK: return _gethook(args);
case GETINFO: return _getinfo(args,this); case GETINFO: return _getinfo(args,this);

View File

@@ -215,7 +215,7 @@ public class IoLib extends OneArgFunction {
public IoLib() { public IoLib() {
} }
public LuaValue call(LuaValue arg) { public LuaValue call(LuaValue env) {
// io lib functions // io lib functions
LuaTable t = new LuaTable(); LuaTable t = new LuaTable();
@@ -248,12 +248,13 @@ public class IoLib extends OneArgFunction {
} }
static final class IoLibV extends VarArgFunction { static final class IoLibV extends VarArgFunction {
private File f;
public IoLib iolib; public IoLib iolib;
public IoLibV() { public IoLibV() {
} }
public IoLibV(LuaValue env, String name, int opcode, IoLib iolib) { public IoLibV(File f, String name, int opcode, IoLib iolib) {
super(); super();
this.env = env; this.f = f;
this.name = name; this.name = name;
this.opcode = opcode; this.opcode = opcode;
this.iolib = iolib; this.iolib = iolib;
@@ -283,7 +284,7 @@ public class IoLib extends OneArgFunction {
case FILE_WRITE: return iolib._file_write(args.arg1(),args.subargs(2)); case FILE_WRITE: return iolib._file_write(args.arg1(),args.subargs(2));
case IO_INDEX: return iolib._io_index(args.arg(2)); case IO_INDEX: return iolib._io_index(args.arg(2));
case LINES_ITER: return iolib._lines_iter(env); case LINES_ITER: return iolib._lines_iter(f);
} }
} catch ( IOException ioe ) { } catch ( IOException ioe ) {
return errorresult(ioe); return errorresult(ioe);

View File

@@ -169,7 +169,6 @@ abstract public class LibFunction extends LuaFunction {
LibFunction f = (LibFunction) factory.newInstance(); LibFunction f = (LibFunction) factory.newInstance();
f.opcode = firstopcode + i; f.opcode = firstopcode + i;
f.name = names[i]; f.name = names[i];
f.env = env;
env.set(f.name, f); env.set(f.name, f);
} }
} catch ( Exception e ) { } catch ( Exception e ) {

View File

@@ -83,7 +83,7 @@ public class MathLib extends OneArgFunction {
MATHLIB = this; MATHLIB = this;
} }
public LuaValue call(LuaValue arg) { public LuaValue call(LuaValue env) {
LuaTable t = new LuaTable(0,30); LuaTable t = new LuaTable(0,30);
t.set( "pi", Math.PI ); t.set( "pi", Math.PI );
t.set( "huge", LuaDouble.POSINF ); t.set( "huge", LuaDouble.POSINF );

View File

@@ -58,7 +58,7 @@ abstract public class OneArgFunction extends LibFunction {
* @param env The environment to apply during constructon. * @param env The environment to apply during constructon.
*/ */
public OneArgFunction( LuaValue env ) { public OneArgFunction( LuaValue env ) {
this.env = env; throw new UnsupportedOperationException("Cannot supply env to constructor");
} }
public final LuaValue call() { public final LuaValue call() {

View File

@@ -112,7 +112,7 @@ public class OsLib extends VarArgFunction {
public OsLib() { public OsLib() {
} }
public LuaValue init() { public LuaValue init(LuaValue env) {
LuaTable t = new LuaTable(); LuaTable t = new LuaTable();
bind(t, this.getClass(), NAMES, CLOCK); bind(t, this.getClass(), NAMES, CLOCK);
env.set("os", t); env.set("os", t);
@@ -124,7 +124,7 @@ public class OsLib extends VarArgFunction {
try { try {
switch ( opcode ) { switch ( opcode ) {
case INIT: case INIT:
return init(); return init(args.arg1());
case CLOCK: case CLOCK:
return valueOf(clock()); return valueOf(clock());
case DATE: { case DATE: {

View File

@@ -105,18 +105,18 @@ public class PackageLib extends OneArgFunction {
instance = this; instance = this;
} }
public LuaValue call(LuaValue arg) { public LuaValue call(LuaValue env) {
env.set("require", new PkgLib1(env,"require",OP_REQUIRE,this)); env.set("require", new PkgLib1("require",OP_REQUIRE,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("loadlib",OP_LOADLIB,this),
_SEARCHPATH, new PkgLibV(env,"searchpath",OP_SEARCHPATH,this), _SEARCHPATH, new PkgLibV("searchpath",OP_SEARCHPATH,this),
_SEARCHERS, listOf(new LuaValue[] { _SEARCHERS, listOf(new LuaValue[] {
preload_searcher = new PkgLibV(env,"preload_searcher", OP_PRELOAD_SEARCHER,this), preload_searcher = new PkgLibV("preload_searcher",OP_PRELOAD_SEARCHER, this),
lua_searcher = new PkgLibV(env,"lua_searcher", OP_LUA_SEARCHER,this), lua_searcher = new PkgLibV("lua_searcher",OP_LUA_SEARCHER, this),
java_searcher = new PkgLibV(env,"java_searcher", OP_JAVA_SEARCHER,this), java_searcher = new PkgLibV("java_searcher",OP_JAVA_SEARCHER, this),
}) }) ); }) }) );
LOADED.set("package", PACKAGE); LOADED.set("package", PACKAGE);
return env; return env;
@@ -124,8 +124,7 @@ public class PackageLib extends OneArgFunction {
static final class PkgLib1 extends OneArgFunction { static final class PkgLib1 extends OneArgFunction {
PackageLib lib; PackageLib lib;
public PkgLib1(LuaValue env,String name, int opcode, PackageLib lib) { public PkgLib1(String name, int opcode, PackageLib lib) {
this.env = env;
this.name = name; this.name = name;
this.opcode = opcode; this.opcode = opcode;
this.lib = lib; this.lib = lib;
@@ -141,8 +140,7 @@ public class PackageLib extends OneArgFunction {
static final class PkgLibV extends VarArgFunction { static final class PkgLibV extends VarArgFunction {
PackageLib lib; PackageLib lib;
public PkgLibV(LuaValue env,String name, int opcode, PackageLib lib) { public PkgLibV(String name,int opcode, PackageLib lib) {
this.env = env;
this.name = name; this.name = name;
this.opcode = opcode; this.opcode = opcode;
this.lib = lib; this.lib = lib;
@@ -286,7 +284,7 @@ public class PackageLib extends OneArgFunction {
LuaString filename = v.arg1().strvalue(); LuaString filename = v.arg1().strvalue();
// Try to load the file. // Try to load the file.
v = BaseLib.loadFile(filename.tojstring(), "bt", LuaThread.getGlobals()); v = BaseLib.loadFile(filename.tojstring(), "bt", LuaValue._G);
if ( v.arg1().isfunction() ) if ( v.arg1().isfunction() )
return LuaValue.varargsOf(v.arg1(), filename); return LuaValue.varargsOf(v.arg1(), filename);
@@ -340,7 +338,6 @@ public class PackageLib extends OneArgFunction {
try { try {
c = Class.forName(classname); c = Class.forName(classname);
v = (LuaValue) c.newInstance(); v = (LuaValue) c.newInstance();
v.setfenv(env);
return v; return v;
} catch ( ClassNotFoundException cnfe ) { } catch ( ClassNotFoundException cnfe ) {
return valueOf("\n\tno class '"+classname+"'" ); return valueOf("\n\tno class '"+classname+"'" );

View File

@@ -66,7 +66,7 @@ public class StringLib extends OneArgFunction {
public StringLib() { public StringLib() {
} }
public LuaValue call(LuaValue arg) { public LuaValue call(LuaValue env) {
LuaTable t = new LuaTable(); LuaTable t = new LuaTable();
bind(t, StringLib1.class, new String[] { bind(t, StringLib1.class, new String[] {
"dump", "len", "lower", "reverse", "upper", } ); "dump", "len", "lower", "reverse", "upper", } );

View File

@@ -61,7 +61,7 @@ public class TableLib extends OneArgFunction {
public TableLib() { public TableLib() {
} }
private LuaTable init() { private LuaTable init(LuaValue env) {
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[] {
@@ -74,7 +74,7 @@ public class TableLib extends OneArgFunction {
public LuaValue call(LuaValue arg) { public LuaValue call(LuaValue arg) {
switch ( opcode ) { switch ( opcode ) {
case 0: // init library case 0: // init library
return init(); return init(arg);
case 1: // "getn" (table) -> number case 1: // "getn" (table) -> number
return arg.checktable().getn(); return arg.checktable().getn();
case 2: // "maxn" (table) -> number case 2: // "maxn" (table) -> number

View File

@@ -58,7 +58,7 @@ abstract public class ThreeArgFunction extends LibFunction {
* @param env The environment to apply during constructon. * @param env The environment to apply during constructon.
*/ */
public ThreeArgFunction( LuaValue env ) { public ThreeArgFunction( LuaValue env ) {
this.env = env; throw new UnsupportedOperationException("Cannot supply env to constructor");
} }
public final LuaValue call() { public final LuaValue call() {

View File

@@ -58,7 +58,7 @@ abstract public class TwoArgFunction extends LibFunction {
* @param env The environment to apply during constructon. * @param env The environment to apply during constructon.
*/ */
public TwoArgFunction( LuaValue env ) { public TwoArgFunction( LuaValue env ) {
this.env = env; throw new UnsupportedOperationException("Cannot supply env to constructor");
} }
public final LuaValue call() { public final LuaValue call() {

View File

@@ -51,7 +51,7 @@ abstract public class VarArgFunction extends LibFunction {
} }
public VarArgFunction( LuaValue env ) { public VarArgFunction( LuaValue env ) {
this.env = env; throw new UnsupportedOperationException("Cannot supply env to constructor");
} }
public LuaValue call() { public LuaValue call() {
@@ -71,30 +71,12 @@ abstract public class VarArgFunction extends LibFunction {
} }
/** /**
* Override and implement for the best performance. * Subclass responsibility.
* May not have expected behavior for tail calls. * May not have expected behavior for tail calls.
* Should not be used if either: * Should not be used if:
* - function needs to be used as a module
* - function has a possibility of returning a TailcallVarargs * - function has a possibility of returning a TailcallVarargs
* @param args the arguments to the function call. * @param args the arguments to the function call.
*/ */
public Varargs invoke(Varargs args) { abstract public Varargs invoke(Varargs args);
LuaThread.CallStack cs = LuaThread.onCall(this);
try {
return this.onInvoke(args).eval();
} finally {
cs.onReturn();
}
}
/**
* Override to provide a call implementation that runs in an environment
* that can participate in setfenv, and behaves as expected
* when returning TailcallVarargs.
* @param args the arguments to the function call.
*/
public Varargs onInvoke(Varargs args) {
return invoke(args);
}
} }

View File

@@ -56,7 +56,7 @@ abstract public class ZeroArgFunction extends LibFunction {
* @param env The environment to apply during constructon. * @param env The environment to apply during constructon.
*/ */
public ZeroArgFunction( LuaValue env ) { public ZeroArgFunction( LuaValue env ) {
this.env = env; throw new UnsupportedOperationException("Cannot supply env to constructor");
} }
public LuaValue call(LuaValue arg) { public LuaValue call(LuaValue arg) {

View File

@@ -101,6 +101,7 @@ public class JmePlatform {
*/ */
public static LuaTable standardGlobals() { public static LuaTable standardGlobals() {
LuaTable _G = new LuaTable(); LuaTable _G = new LuaTable();
LuaValue._G = _G;
_G.load(new BaseLib()); _G.load(new BaseLib());
_G.load(new PackageLib()); _G.load(new PackageLib());
_G.load(new OsLib()); _G.load(new OsLib());
@@ -109,7 +110,6 @@ public class JmePlatform {
_G.load(new StringLib()); _G.load(new StringLib());
_G.load(new CoroutineLib()); _G.load(new CoroutineLib());
_G.load(new JmeIoLib()); _G.load(new JmeIoLib());
LuaThread.setGlobals(_G);
LuaC.install(); LuaC.install();
return _G; return _G;
} }

View File

@@ -186,7 +186,6 @@ public class lua {
try { try {
// load as java class // load as java class
LuaValue v = (LuaValue) Class.forName(libname).newInstance(); LuaValue v = (LuaValue) Class.forName(libname).newInstance();
v.setfenv(_G);
v.call(slibname, _G); v.call(slibname, _G);
} catch ( Exception f ) { } catch ( Exception f ) {
throw new IOException("loadLibrary("+libname+") failed: "+e+","+f ); throw new IOException("loadLibrary("+libname+") failed: "+e+","+f );

View File

@@ -87,6 +87,7 @@ public class JsePlatform {
*/ */
public static LuaTable standardGlobals() { public static LuaTable standardGlobals() {
LuaTable _G = new LuaTable(); LuaTable _G = new LuaTable();
LuaValue._G = _G;
_G.load(new JseBaseLib()); _G.load(new JseBaseLib());
_G.load(new PackageLib()); _G.load(new PackageLib());
_G.load(new TableLib()); _G.load(new TableLib());
@@ -96,7 +97,6 @@ public class JsePlatform {
_G.load(new JseIoLib()); _G.load(new JseIoLib());
_G.load(new JseOsLib()); _G.load(new JseOsLib());
_G.load(new LuajavaLib()); _G.load(new LuajavaLib());
LuaThread.setGlobals(_G);
LuaC.install(); LuaC.install();
return _G; return _G;
} }

View File

@@ -98,6 +98,7 @@ public class LuajavaLib extends VarArgFunction {
try { try {
switch ( opcode ) { switch ( opcode ) {
case INIT: { case INIT: {
LuaValue env = args.arg1();
LuaTable t = new LuaTable(); LuaTable t = new LuaTable();
bind( t, LuajavaLib.class, NAMES, BINDCLASS ); bind( t, LuajavaLib.class, NAMES, BINDCLASS );
env.set("luajava", t); env.set("luajava", t);

View File

@@ -112,7 +112,6 @@ public class Lua2Java implements LuaCompiler {
Class clazz = cl.loadClass(className); Class clazz = cl.loadClass(className);
Object instance = clazz.newInstance(); Object instance = clazz.newInstance();
LuaFunction value = (LuaFunction) instance; LuaFunction value = (LuaFunction) instance;
value.setfenv( env );
return value; return value;
} else { } else {
} }

View File

@@ -30,12 +30,9 @@ import org.luaj.vm2.Prototype;
******************************************************************************/ ******************************************************************************/
public class JavaLoader extends ClassLoader { public class JavaLoader extends ClassLoader {
private final LuaValue env;
private Map<String,byte[]> unloaded = new HashMap<String,byte[]>(); private Map<String,byte[]> unloaded = new HashMap<String,byte[]>();
public JavaLoader( LuaValue env ) { public JavaLoader() {
this.env = env;
} }
public LuaFunction load( Prototype p, String classname, String filename ) { public LuaFunction load( Prototype p, String classname, String filename ) {
@@ -49,10 +46,14 @@ public class JavaLoader extends ClassLoader {
} }
public LuaFunction load(String classname) { public LuaFunction load(String classname) {
return load(classname, LuaValue._G);
}
public LuaFunction load(String classname, LuaValue env) {
try { try {
Class c = loadClass( classname ); Class c = loadClass( classname );
LuaFunction v = (LuaFunction) c.newInstance(); LuaFunction v = (LuaFunction) c.newInstance();
v.setfenv(env); v.initupvalue1(env);
return v; return v;
} catch ( Exception e ) { } catch ( Exception e ) {
e.printStackTrace(); e.printStackTrace();

View File

@@ -99,7 +99,7 @@ public class LuaJC implements LuaCompiler {
Prototype p = LuaC.instance.compile(stream, name); Prototype p = LuaC.instance.compile(stream, name);
String classname = toStandardJavaClassName( name ); String classname = toStandardJavaClassName( name );
String luaname = toStandardLuaFileName( name ); String luaname = toStandardLuaFileName( name );
JavaLoader loader = new JavaLoader(env); JavaLoader loader = new JavaLoader();
return loader.load(p, classname, luaname); return loader.load(p, classname, luaname);
} }

View File

@@ -203,7 +203,7 @@ public class LuaScriptEngine implements ScriptEngine, Compilable {
Bindings b = context.getBindings(ScriptContext.ENGINE_SCOPE); Bindings b = context.getBindings(ScriptContext.ENGINE_SCOPE);
LuaFunction f = newFunctionInstance(); LuaFunction f = newFunctionInstance();
ClientBindings cb = new ClientBindings(b); ClientBindings cb = new ClientBindings(b);
f.setfenv(cb.env); f.initupvalue1(cb.env);
Varargs result = f.invoke(LuaValue.NONE); Varargs result = f.invoke(LuaValue.NONE);
cb.copyGlobalsToBindings(); cb.copyGlobalsToBindings();
return result; return result;

View File

@@ -60,7 +60,7 @@ public class TestLuaJC {
} else { } else {
chunk = (LuaValue) Class.forName("script").newInstance(); chunk = (LuaValue) Class.forName("script").newInstance();
} }
chunk.setfenv(_G); //chunk.setfenv(_G); // TODO: convert to setupvalue()?
// call with arguments // call with arguments
LuaValue[] vargs = new LuaValue[args.length]; LuaValue[] vargs = new LuaValue[args.length];

View File

@@ -71,18 +71,18 @@ public class FragmentsTest extends TestSuite {
public void runFragment( Varargs expected, String script ) { public void runFragment( Varargs expected, String script ) {
try { try {
String name = getName(); String name = getName();
LuaTable _G = org.luaj.vm2.lib.jse.JsePlatform.debugGlobals(); org.luaj.vm2.lib.jse.JsePlatform.debugGlobals();
InputStream is = new ByteArrayInputStream(script.getBytes("UTF-8")); InputStream is = new ByteArrayInputStream(script.getBytes("UTF-8"));
LuaValue chunk ; LuaValue chunk ;
switch ( TEST_TYPE ) { switch ( TEST_TYPE ) {
case TEST_TYPE_LUA2JAVA: case TEST_TYPE_LUA2JAVA:
chunk = Lua2Java.instance.load(is,name,_G); chunk = Lua2Java.instance.load(is,name,LuaValue._G);
break; break;
case TEST_TYPE_LUAJC: case TEST_TYPE_LUAJC:
chunk = LuaJC.getInstance().load(is,name,_G); chunk = LuaJC.getInstance().load(is,name,LuaValue._G);
break; break;
default: default:
chunk = LuaC.instance.load( is, name, _G ); chunk = LuaC.instance.load( is, name, LuaValue._G );
Print.print(((LuaClosure)chunk).p); Print.print(((LuaClosure)chunk).p);
break; break;
} }

View File

@@ -55,9 +55,9 @@ public class LuaOperationsTest extends TestCase {
private final LuaValue stringlong = LuaValue.valueOf(samplestringlong); private final LuaValue stringlong = LuaValue.valueOf(samplestringlong);
private final LuaValue stringdouble = LuaValue.valueOf(samplestringdouble); private final LuaValue stringdouble = LuaValue.valueOf(samplestringdouble);
private final LuaTable table = LuaValue.listOf( new LuaValue[] { LuaValue.valueOf("aaa"), LuaValue.valueOf("bbb") } ); private final LuaTable table = LuaValue.listOf( new LuaValue[] { LuaValue.valueOf("aaa"), LuaValue.valueOf("bbb") } );
private final LuaValue somefunc = new ZeroArgFunction(table) { public LuaValue call() { return NONE;}}; private final LuaValue somefunc = new ZeroArgFunction() { public LuaValue call() { return NONE;}};
private final LuaThread thread = new LuaThread(somefunc,table); private final LuaThread thread = new LuaThread(somefunc);
private final Prototype proto = new Prototype(); private final Prototype proto = new Prototype(1);
private final LuaClosure someclosure = new LuaClosure(proto,table); private final LuaClosure someclosure = new LuaClosure(proto,table);
private final LuaUserdata userdataobj = LuaValue.userdataOf(sampleobject); private final LuaUserdata userdataobj = LuaValue.userdataOf(sampleobject);
private final LuaUserdata userdatacls = LuaValue.userdataOf(sampledata); private final LuaUserdata userdatacls = LuaValue.userdataOf(sampledata);
@@ -128,55 +128,6 @@ public class LuaOperationsTest extends TestCase {
throwsLuaError( "length", userdatacls ); throwsLuaError( "length", userdatacls );
} }
public void testGetfenv() {
throwsLuaError( "getfenv", somenil );
throwsLuaError( "getfenv", sometrue );
throwsLuaError( "getfenv", somefalse );
throwsLuaError( "getfenv", zero );
throwsLuaError( "getfenv", intint );
throwsLuaError( "getfenv", longdouble );
throwsLuaError( "getfenv", doubledouble );
throwsLuaError( "getfenv", stringstring );
throwsLuaError( "getfenv", stringint );
throwsLuaError( "getfenv", stringlong );
throwsLuaError( "getfenv", stringdouble );
throwsLuaError( "getfenv", table );
assertTrue( table == thread.getfenv() );
assertTrue( table == someclosure.getfenv() );
assertTrue( table == somefunc.getfenv() );
throwsLuaError( "getfenv", userdataobj );
throwsLuaError( "getfenv", userdatacls );
}
public void testSetfenv() {
LuaTable table2 = LuaValue.listOf( new LuaValue[] {
LuaValue.valueOf("ccc"),
LuaValue.valueOf("ddd") } );
throwsLuaError( "setfenv", somenil, table2 );
throwsLuaError( "setfenv", sometrue, table2 );
throwsLuaError( "setfenv", somefalse, table2 );
throwsLuaError( "setfenv", zero, table2 );
throwsLuaError( "setfenv", intint, table2 );
throwsLuaError( "setfenv", longdouble, table2 );
throwsLuaError( "setfenv", doubledouble, table2 );
throwsLuaError( "setfenv", stringstring, table2 );
throwsLuaError( "setfenv", stringint, table2 );
throwsLuaError( "setfenv", stringlong, table2 );
throwsLuaError( "setfenv", stringdouble, table2 );
throwsLuaError( "setfenv", table, table2 );
thread.setfenv(table2);
assertTrue( table2 == thread.getfenv() );
assertTrue( table == someclosure.getfenv() );
assertTrue( table == somefunc.getfenv() );
someclosure.setfenv(table2);
assertTrue( table2 == someclosure.getfenv() );
assertTrue( table == somefunc.getfenv() );
somefunc.setfenv(table2);
assertTrue( table2 == somefunc.getfenv() );
throwsLuaError( "setfenv", userdataobj, table2 );
throwsLuaError( "setfenv", userdatacls, table2 );
}
public Prototype createPrototype( String script, String name ) { public Prototype createPrototype( String script, String name ) {
try { try {
LuaTable _G = org.luaj.vm2.lib.jse.JsePlatform.standardGlobals(); LuaTable _G = org.luaj.vm2.lib.jse.JsePlatform.standardGlobals();
@@ -206,56 +157,20 @@ public class LuaOperationsTest extends TestCase {
// function tests // function tests
{ {
LuaFunction f = new ZeroArgFunction(_G) { public LuaValue call() { return env.get("a");}}; LuaFunction f = new ZeroArgFunction() { public LuaValue call() { return _G.get("a");}};
assertEquals( aaa, f.call() ); assertEquals( aaa, f.call() );
f.setfenv(newenv);
assertEquals( newenv, f.getfenv() );
assertEquals( eee, f.call() );
} }
// closure tests // closure tests
{ {
Prototype p = createPrototype( "return a\n", "closuretester" ); Prototype p = createPrototype( "return a\n", "closuretester" );
LuaClosure c = new LuaClosure(p, _G); LuaClosure c = new LuaClosure(p, _G);
assertEquals( aaa, c.call() );
c.setfenv(newenv);
assertEquals( newenv, c.getfenv() );
assertEquals( eee, c.call() );
}
// thread tests, functions created in threads inherit the thread's environment initially // Test that a clusure with a custom enviroment uses that environment.
// those closures created not in any other function get the thread's enviroment assertEquals( aaa, c.call() );
Prototype p2 = createPrototype( "return loadstring('return a')", "threadtester" ); c = new LuaClosure(p, newenv);
{ assertEquals( newenv, c.upValues[0].getValue() );
LuaThread t = new LuaThread(new LuaClosure(p2,_G), _G); assertEquals( eee, c.call() );
Varargs v = t.resume(LuaValue.NONE);
assertEquals(LuaValue.TRUE, v.arg(1) );
LuaValue f = v.arg(2);
assertEquals( LuaValue.TFUNCTION, f.type() );
assertEquals( aaa, f.call() );
assertEquals( _G, f.getfenv() );
}
{
// change the thread environment after creation!
LuaThread t = new LuaThread(new LuaClosure(p2,_G), _G);
t.setfenv(newenv);
Varargs v = t.resume(LuaValue.NONE);
assertEquals(LuaValue.TRUE, v.arg(1) );
LuaValue f = v.arg(2);
assertEquals( LuaValue.TFUNCTION, f.type() );
assertEquals( eee, f.call() );
assertEquals( newenv, f.getfenv() );
}
{
// let the closure have a different environment from the thread
Prototype p3 = createPrototype( "return function() return a end", "envtester" );
LuaThread t = new LuaThread(new LuaClosure(p3,newenv), _G);
Varargs v = t.resume(LuaValue.NONE);
assertEquals(LuaValue.TRUE, v.arg(1) );
LuaValue f = v.arg(2);
assertEquals( LuaValue.TFUNCTION, f.type() );
assertEquals( eee, f.call() );
assertEquals( newenv, f.getfenv() );
} }
} }
} }

View File

@@ -38,8 +38,8 @@ public class MetatableTest extends TestCase {
private final LuaValue string = LuaValue.valueOf(samplestring); private final LuaValue string = LuaValue.valueOf(samplestring);
private final LuaTable table = LuaValue.tableOf(); private final LuaTable table = LuaValue.tableOf();
private final LuaFunction function = new ZeroArgFunction() { public LuaValue call() { return NONE;}}; private final LuaFunction function = new ZeroArgFunction() { public LuaValue call() { return NONE;}};
private final LuaThread thread = new LuaThread(function,table); private final LuaThread thread = new LuaThread(function);
private final LuaClosure closure = new LuaClosure(); private final LuaClosure closure = new LuaClosure(new Prototype());
private final LuaUserdata userdata = LuaValue.userdataOf(sampleobject); private final LuaUserdata userdata = LuaValue.userdataOf(sampleobject);
private final LuaUserdata userdatamt = LuaValue.userdataOf(sampledata,table); private final LuaUserdata userdatamt = LuaValue.userdataOf(sampledata,table);

View File

@@ -113,7 +113,7 @@ public class OrphanedThreadTest extends TestCase {
} }
private void doTest(LuaValue status2, LuaValue value2) throws Exception { private void doTest(LuaValue status2, LuaValue value2) throws Exception {
luathread = new LuaThread(function, env); luathread = new LuaThread(function);
luathr_ref = new WeakReference(luathread); luathr_ref = new WeakReference(luathread);
func_ref = new WeakReference(function); func_ref = new WeakReference(function);
assertNotNull(luathr_ref.get()); assertNotNull(luathr_ref.get());

View File

@@ -119,7 +119,6 @@ public class ScriptDrivenTest extends TestCase {
case LUAJIT: case LUAJIT:
if ( nocompile ) { if ( nocompile ) {
LuaValue c = (LuaValue) Class.forName(name).newInstance(); LuaValue c = (LuaValue) Class.forName(name).newInstance();
c.setfenv(_G);
return c; return c;
} else { } else {
script = new FileInputStream(file); script = new FileInputStream(file);

View File

@@ -26,8 +26,12 @@ import java.lang.reflect.InvocationTargetException;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.luaj.vm2.lib.ZeroArgFunction; import org.luaj.vm2.lib.ZeroArgFunction;
import org.luaj.vm2.lib.jse.JsePlatform;
public class TypeTest extends TestCase { public class TypeTest extends TestCase {
static {
JsePlatform.debugGlobals();
}
private final int sampleint = 77; private final int sampleint = 77;
private final long samplelong = 123400000000L; private final long samplelong = 123400000000L;
@@ -52,8 +56,8 @@ public class TypeTest extends TestCase {
private final LuaValue stringdouble = LuaValue.valueOf(samplestringdouble); private final LuaValue stringdouble = LuaValue.valueOf(samplestringdouble);
private final LuaTable table = LuaValue.tableOf(); private final LuaTable table = LuaValue.tableOf();
private final LuaFunction somefunc = new ZeroArgFunction() { public LuaValue call() { return NONE;}}; private final LuaFunction somefunc = new ZeroArgFunction() { public LuaValue call() { return NONE;}};
private final LuaThread thread = new LuaThread(somefunc,table); private final LuaThread thread = new LuaThread(somefunc);
private final LuaClosure someclosure = new LuaClosure(); private final LuaClosure someclosure = new LuaClosure(new Prototype());
private final LuaUserdata userdataobj = LuaValue.userdataOf(sampleobject); private final LuaUserdata userdataobj = LuaValue.userdataOf(sampleobject);
private final LuaUserdata userdatacls = LuaValue.userdataOf(sampledata); private final LuaUserdata userdatacls = LuaValue.userdataOf(sampledata);