Fix setfenv(), getfenv(), let threads inherit environment.

This commit is contained in:
James Roseborough
2010-04-17 13:15:16 +00:00
parent c0a1d002c7
commit 00f8d291f9
6 changed files with 48 additions and 30 deletions

View File

@@ -115,10 +115,16 @@ public class LuaThread extends LuaValue implements Runnable {
public static boolean isMainThread(LuaThread r) { public static boolean isMainThread(LuaThread r) {
return r == mainthread; return r == mainthread;
} }
/** get environment of the running thread, or defval if not defined */ /** Set the globals of the current thread */
public static LuaValue getRunningEnv(LuaValue defval) { public static void setGlobals(LuaValue globals) {
return running_thread.env!=null? running_thread.env: defval; running_thread.env = globals;
}
/** Get the current thread's environment */
public static LuaValue getGlobals() {
LuaValue e = running_thread.env;
return e!=null? e: LuaValue.error("LuaThread.setGlobals() not initialized");
} }
public static final void onCall(LuaFunction function) { public static final void onCall(LuaFunction function) {
@@ -137,9 +143,14 @@ public class LuaThread extends LuaValue implements Runnable {
return running_thread.calls; return running_thread.calls;
} }
/**
* Get the function called as a specific location on the stack.
* @param level 1 for the function calling this one, 2 for the next one.
* @return LuaFunction on the call stack, or null if outside of range of active stack
*/
public static final LuaFunction getCallstackFunction(int level) { public static final LuaFunction getCallstackFunction(int level) {
return level>=0 && level<running_thread.calls? return level>0 && level<=running_thread.calls?
running_thread.callstack[running_thread.calls-level-1]: running_thread.callstack[running_thread.calls-level]:
null; null;
} }
@@ -222,4 +233,5 @@ public class LuaThread extends LuaValue implements Runnable {
} }
} }

View File

@@ -26,6 +26,7 @@ import java.io.PrintStream;
import org.luaj.vm2.LoadState; import org.luaj.vm2.LoadState;
import org.luaj.vm2.LuaError; import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaFunction;
import org.luaj.vm2.LuaString; import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaTable; import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaThread; import org.luaj.vm2.LuaThread;
@@ -131,13 +132,8 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
protected LuaValue oncall1(int opcode, LuaValue arg) { protected LuaValue oncall1(int opcode, LuaValue arg) {
switch ( opcode ) { switch ( opcode ) {
case 0: { // "getfenv", // ( [f] ) -> env case 0: { // "getfenv", // ( [f] ) -> env
if ( ! arg.isfunction() ) { LuaValue f = getfenvobj(arg);
int i = arg.optint(0); LuaValue e = f.getfenv();
arg = (i==0)? (LuaValue) LuaThread.getRunning(): (LuaValue) LuaThread.getCallstackFunction(i-1);
if ( arg == null )
LuaValue.argerror(1, "invalid level");
}
LuaValue e = arg.getfenv();
return e!=null? e: NIL; return e!=null? e: NIL;
} }
case 1: // "getmetatable", // ( object ) -> table case 1: // "getmetatable", // ( object ) -> table
@@ -148,7 +144,7 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
} }
return NIL; return NIL;
} }
protected LuaValue oncall2(int opcode, LuaValue arg1, LuaValue arg2) { protected LuaValue oncall2(int opcode, LuaValue arg1, LuaValue arg2) {
switch ( opcode ) { switch ( opcode ) {
case 0: // "collectgarbage", // ( opt [,arg] ) -> value case 0: // "collectgarbage", // ( opt [,arg] ) -> value
@@ -172,15 +168,10 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
case 2: // "rawequal", // (v1, v2) -> boolean case 2: // "rawequal", // (v1, v2) -> boolean
return valueOf(arg1 == arg2); return valueOf(arg1 == arg2);
case 3: { // "setfenv", // (f, table) -> void case 3: { // "setfenv", // (f, table) -> void
LuaValue f = arg1; LuaTable t = arg2.checktable();
if ( ! f.isfunction() ) { LuaValue f = getfenvobj(arg1);
int i = arg1.checkint(0); f.setfenv(t);
f = (i==0)? (LuaValue) LuaThread.getRunning(): (LuaValue) LuaThread.getCallstackFunction(i-1); return f.isthread()? NONE: f;
if ( f == null )
LuaValue.argerror(1, "invalid level");
}
f.setfenv(arg2);
return f;
} }
case 4: // "tonumber", // (e [,base]) -> value case 4: // "tonumber", // (e [,base]) -> value
final int base = arg2.optint(10); final int base = arg2.optint(10);
@@ -195,6 +186,17 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
} }
return NIL; return NIL;
} }
private LuaValue getfenvobj(LuaValue arg) {
if ( arg.isclosure() )
return arg;
int level = arg.optint(1);
if ( level == 0 )
return LuaThread.getRunning();
LuaValue f = LuaThread.getCallstackFunction(level);
arg.argcheck(f != null, 1, "invalid level");
return f;
}
protected Varargs oncallv(int opcode, Varargs args) { protected Varargs oncallv(int opcode, Varargs args) {
switch ( opcode ) { switch ( opcode ) {
@@ -216,7 +218,7 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
try { try {
LuaValue func = args.checkfunction(1); LuaValue func = args.checkfunction(1);
String chunkname = args.optString(2, "function"); String chunkname = args.optString(2, "function");
return LoadState.load(new StringInputStream(func), chunkname, LuaThread.getRunningEnv(env)); return LoadState.load(new StringInputStream(func), chunkname, LuaThread.getGlobals());
} catch ( Exception e ) { } catch ( Exception e ) {
return varargsOf(NIL, valueOf(e.getMessage())); return varargsOf(NIL, valueOf(e.getMessage()));
} }
@@ -233,7 +235,7 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
try { try {
LuaString script = args.checkstring(1); LuaString script = args.checkstring(1);
String chunkname = args.optString(2, "string"); String chunkname = args.optString(2, "string");
return LoadState.load(script.toInputStream(),chunkname,LuaThread.getRunningEnv(env)); return LoadState.load(script.toInputStream(),chunkname,LuaThread.getGlobals());
} catch ( Exception e ) { } catch ( Exception e ) {
return varargsOf(NIL, valueOf(e.getMessage())); return varargsOf(NIL, valueOf(e.getMessage()));
} }
@@ -279,7 +281,7 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
} }
case 7: // "print", // (...) -> void case 7: // "print", // (...) -> void
{ {
LuaValue tostring = env.get("tostring"); LuaValue tostring = LuaThread.getGlobals().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 ) STDOUT.write( '\t' ); if ( i>1 ) STDOUT.write( '\t' );
LuaString s = tostring.call( args.arg(i) ).strvalue(); LuaString s = tostring.call( args.arg(i) ).strvalue();
@@ -347,7 +349,7 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
if ( is == null ) if ( is == null )
return varargsOf(NIL, valueOf("not found: "+filename)); return varargsOf(NIL, valueOf("not found: "+filename));
try { try {
return LoadState.load(is, filename, LuaThread.getRunningEnv(env)); return LoadState.load(is, filename, LuaThread.getGlobals());
} finally { } finally {
is.close(); is.close();
} }

View File

@@ -51,7 +51,7 @@ public class CoroutineLib extends ZeroArgFunction {
switch ( opcode ) { switch ( opcode ) {
case CREATE: { case CREATE: {
final LuaValue func = args.checkfunction(1); final LuaValue func = args.checkfunction(1);
return new LuaThread(func, func.getfenv() ); return new LuaThread(func, LuaThread.getGlobals() );
} }
case RESUME: { case RESUME: {
final LuaThread t = args.checkthread(1); final LuaThread t = args.checkthread(1);

View File

@@ -25,9 +25,9 @@ import java.io.InputStream;
import java.io.PrintStream; import java.io.PrintStream;
import org.luaj.vm2.LuaFunction; import org.luaj.vm2.LuaFunction;
import org.luaj.vm2.LuaThread;
import org.luaj.vm2.LuaString; import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaTable; import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaThread;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs; import org.luaj.vm2.Varargs;
@@ -91,7 +91,7 @@ public class PackageLib extends OneArgFunction {
LuaValue m = t.getmetatable(); LuaValue m = t.getmetatable();
if ( m == null ) if ( m == null )
t.setmetatable(m=tableOf()); t.setmetatable(m=tableOf());
m.set( INDEX, env ); m.set( INDEX, LuaThread.getGlobals() );
return NONE; return NONE;
} }
} }

View File

@@ -22,6 +22,7 @@
package org.luaj.vm2.lib; package org.luaj.vm2.lib;
import org.luaj.vm2.LuaTable; import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaThread;
import org.luaj.vm2.lib.jme.JmeIoLib; import org.luaj.vm2.lib.jme.JmeIoLib;
public class JmePlatform { public class JmePlatform {
@@ -41,6 +42,7 @@ 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);
return _G; return _G;
} }

View File

@@ -22,6 +22,7 @@
package org.luaj.vm2.lib; package org.luaj.vm2.lib;
import org.luaj.vm2.LuaTable; import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaThread;
import org.luaj.vm2.lib.jse.JseBaseLib; import org.luaj.vm2.lib.jse.JseBaseLib;
import org.luaj.vm2.lib.jse.JseIoLib; import org.luaj.vm2.lib.jse.JseIoLib;
import org.luaj.vm2.lib.jse.JseMathLib; import org.luaj.vm2.lib.jse.JseMathLib;
@@ -47,6 +48,7 @@ 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);
return _G; return _G;
} }
} }