Move static variables used by libraries into explicit Globals object for better thread safety.

This commit is contained in:
James Roseborough
2012-09-14 04:12:50 +00:00
parent 9f3aef6403
commit f786802bf1
30 changed files with 739 additions and 1000 deletions

View File

@@ -0,0 +1,93 @@
/*******************************************************************************
* Copyright (c) 2012 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
package org.luaj.vm2;
import java.io.InputStream;
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.ResourceFinder;
import org.luaj.vm2.lib.jme.JmePlatform;
import org.luaj.vm2.lib.jse.JsePlatform;
/**
* Global environment used by luaj.
* <p>
* Contains the global variables referenced by lua libraries such as stdin and stdout,
* the resrouce finder which is used tolook up files in a platform independent way,
* the installed lua compiler, the math library in use, debugging calls stack, and so on.
* <p>
* In a multithreded server environment, each server thread should create one Globals instance,
* which will be logically distance and not interfere with each other, but share certain
* static immutable resources such as class data and string data.
* <p>
* Typically, this is constructed indirectly by a call to
* {@link JsePlatform.standardGlobasl()} or {@link JmePlatform.standardGlobals()},
* and then used to load lua scripts for execution as in the following example.
* <pre> {@code
* Globals _G = JsePlatform.standardGlobals();
* _G.compiler.load( new ByteArrayInputStream("print 'hello'".getBytes()), "main.lua", _G ).call();
* } </pre>
* @see LuaCompiler
* @see JsePlatform
* @see JmePlatform
* @see LuaValue
*
*/
public class Globals extends LuaTable {
public InputStream STDIN = null;
public PrintStream STDOUT = System.out;
public PrintStream STDERR = System.err;
public ResourceFinder FINDER;
public LuaCompiler compiler = null;
public LuaThread.CallStack callstack = new LuaThread.CallStack();
public BaseLib baselib;
public LuaValue errorfunc;
public LuaThread running_thread = new LuaThread(this);
public DebugLib debuglib;
public Globals checkglobals() {
return this;
}
public Varargs loadFile(String filename) {
return baselib.loadFile(filename, "bt", this);
}
public Varargs yield(Varargs args) {
if (running_thread == null || running_thread.isMainThread())
throw new LuaError("cannot yield main thread");
final LuaThread.State s = running_thread.state;
return s.lua_yield(args);
}
}

View File

@@ -21,8 +21,6 @@
******************************************************************************/
package org.luaj.vm2;
import org.luaj.vm2.LoadState.LuaCompiler;
import org.luaj.vm2.compiler.LuaC;
import org.luaj.vm2.lib.DebugLib;
/**
@@ -92,14 +90,7 @@ public class LuaClosure extends LuaFunction {
public UpValue[] upValues;
/** Create a closure around a Prototype with the default global 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) {
this(p, LuaValue._G);
}
final Globals globals;
/** Create a closure around a Prototype with a specific environment.
* If the prototype has upvalues, the environment will be written into the first upvalue.
@@ -114,6 +105,7 @@ public class LuaClosure extends LuaFunction {
this.upValues = new UpValue[p.upvalues.length];
this.upValues[0] = new UpValue(new LuaValue[] {env}, 0);
}
globals = env instanceof Globals? (Globals) env: null;
}
public boolean isclosure() {
@@ -184,7 +176,6 @@ public class LuaClosure extends LuaFunction {
return execute(stack,p.is_vararg!=0? varargs.subargs(p.numparams+1): NONE);
}
protected Varargs execute( LuaValue[] stack, Varargs varargs ) {
// loop through instructions
int i,a,b,c,pc=0,top=0;
@@ -194,18 +185,17 @@ public class LuaClosure extends LuaFunction {
LuaValue[] k = p.k;
// upvalues are only possible when closures create closures
UpValue[] openups = p.p.length>0? new UpValue[stack.length]: null;
UpValue[] openups = p.p.length>0? new UpValue[p.p.length]: null;
// debug wants args to this function
if (DebugLib.DEBUG_ENABLED)
DebugLib.debugSetupCall(varargs, stack);
if (globals != null)
globals.callstack.onCall( this, varargs, stack );
// process instructions
LuaThread.CallStack cs = LuaThread.onCall( this );
try {
while ( true ) {
if (DebugLib.DEBUG_ENABLED)
DebugLib.debugBytecode(pc, v, top);
if (DebugLib.DEBUG_ENABLED && globals != null)
globals.callstack.onInstruction( pc, v, top );
// pull out instruction
i = code[pc++];
@@ -473,7 +463,7 @@ public class LuaClosure extends LuaFunction {
case Lua.OP_CLOSURE: /* A Bx R(A):= closure(KPROTO[Bx]) */
{
Prototype newp = p.p[i>>>14];
LuaClosure ncl = new LuaClosure(newp, null);
LuaClosure ncl = new LuaClosure(newp, globals);
Upvaldesc[] uv = newp.upvalues;
for ( int j=0, nup=uv.length; j<nup; ++j ) {
if (uv[j].instack) /* upvalue refes to local variable? */
@@ -504,11 +494,16 @@ public class LuaClosure extends LuaFunction {
}
}
} catch ( LuaError le ) {
if (le.traceback == null)
processErrorHooks(le, p, pc);
throw le;
} catch ( Exception e ) {
throw new LuaError(e);
LuaError le = new LuaError(e);
processErrorHooks(le, p, pc);
throw le;
} finally {
cs.onReturn();
if (globals != null)
globals.callstack.onReturn();
if ( openups != null )
for ( int u=openups.length; --u>=0; )
if ( openups[u] != null )
@@ -516,6 +511,32 @@ public class LuaClosure extends LuaFunction {
}
}
/**
* Run the error hook if there is one
* @param msg the message to use in error hook processing.
* */
String errorHook(String msg) {
if (globals == null || globals.errorfunc == null)
return msg;
LuaValue errfunc = globals.errorfunc;
globals.errorfunc = null;
try {
return errfunc.call( LuaValue.valueOf(msg) ).tojstring();
} catch ( Throwable t ) {
return "error in error handling";
} finally {
globals.errorfunc = errfunc;
}
}
private void processErrorHooks(LuaError le, Prototype p, int pc) {
le.fileline = (p.source != null? p.source.tojstring(): "?") + ":"
+ (p.lineinfo != null && pc >= 0 && pc < p.lineinfo.length? String.valueOf(p.lineinfo[pc]): "?");
le.traceback = errorHook(le.getMessage());
if (DebugLib.DEBUG_ENABLED && globals != null && globals.debuglib != null)
le.traceback += globals.callstack.traceback(le.level);
}
private UpValue findupval(LuaValue[] stack, short idx, UpValue[] openups) {
final int n = openups.length;
for (int i = 0; i < n; ++i)
@@ -535,4 +556,22 @@ public class LuaClosure extends LuaFunction {
protected void setUpvalue(int i, LuaValue v) {
upValues[i].setValue(v);
}
/**
* Add file and line info to a message at a particular level
* @param message the String message to use
* @param level where to supply line info from in call stack
* */
private String getFileLineMessage( Exception e, int pc ) {
String msg = e.getMessage();
if ( msg == null ) return null;
if ( globals == null ) return msg;
LuaFunction f = globals.callstack.getFunction(1);
if ( ! (f instanceof LuaClosure) ) return msg;
LuaClosure c = (LuaClosure) f;
LuaString file = c.p.source != null ? c.p.source: valueOf("?");
String line = c.p.lineinfo != null && pc < c.p.lineinfo.length? String.valueOf(c.p.lineinfo[pc]): "?";
return file.tojstring() + ": " + line;
}
}

View File

@@ -38,29 +38,18 @@ import org.luaj.vm2.lib.DebugLib;
public class LuaError extends RuntimeException {
private static final long serialVersionUID = 1L;
private String traceback;
protected int level;
/**
* Run the error hook if there is one
* @param msg the message to use in error hook processing.
* */
private static String errorHook(String msg) {
LuaThread thread = LuaThread.getRunning();
if ( thread.err != null ) {
LuaValue errfunc = thread.err;
thread.err = null;
try {
return errfunc.call( LuaValue.valueOf(msg) ).tojstring();
} catch ( Throwable t ) {
return "error in error handling";
} finally {
thread.err = errfunc;
}
}
return msg;
}
protected String fileline;
private Throwable cause;
protected String traceback;
protected Throwable cause;
public String getMessage() {
return (fileline != null? fileline + " ": "")
+ (traceback != null? traceback: super.getMessage());
}
/** Construct LuaError when a program exception occurs.
* <p>
@@ -68,9 +57,9 @@ public class LuaError extends RuntimeException {
* @param cause the Throwable that caused the error, if known.
*/
public LuaError(Throwable cause) {
super( errorHook( addFileLine( "vm error: "+cause ) ) );
super( "vm error: "+cause );
this.cause = cause;
this.traceback = DebugLib.traceback(1);
this.level = 1;
}
/**
@@ -79,8 +68,8 @@ public class LuaError extends RuntimeException {
* @param message message to supply
*/
public LuaError(String message) {
super( errorHook( addFileLine( message ) ) );
this.traceback = DebugLib.traceback(1);
super( message );
this.level = 1;
}
/**
@@ -89,37 +78,10 @@ public class LuaError extends RuntimeException {
* @param level where to supply line info from in call stack
*/
public LuaError(String message, int level) {
super( errorHook( addFileLine( message, level ) ) );
this.traceback = DebugLib.traceback(1);
super( message );
this.level = level;
}
/**
* Add file and line info to a message at a particular level
* @param message the String message to use
* @param level where to supply line info from in call stack
* */
private static String addFileLine( String message, int level ) {
if ( message == null ) return null;
if ( level == 0 ) return message;
String fileline = DebugLib.fileline(level-1);
return fileline!=null? fileline+": "+message: message;
}
/** Add file and line info for the nearest enclosing closure
* @param message the String message to use
* */
private static String addFileLine( String message ) {
if ( message == null ) return null;
String fileline = DebugLib.fileline();
return fileline!=null? fileline+": "+message: message;
}
/** Print the message and stack trace */
public void printStackTrace() {
System.out.println( toString() );
if ( traceback != null )
System.out.println( traceback );
}
/**
* Get the cause, if any.

View File

@@ -24,6 +24,7 @@ package org.luaj.vm2;
import java.lang.ref.WeakReference;
import org.luaj.vm2.LuaThread.CallFrame;
import org.luaj.vm2.lib.DebugLib;
/**
@@ -84,37 +85,39 @@ public class LuaThread extends LuaValue {
public final State state;
/** Field to hold state of error condition during debug hook function calls. */
public LuaValue err;
final CallStack callstack = new CallStack();
public static final int MAX_CALLSTACK = 256;
private static final LuaThread main_thread = new LuaThread();
// state of running thread including call stack
private static LuaThread running_thread = main_thread;
/** Interval to check for LuaThread dereferencing. */
public static int GC_INTERVAL = 30000;
/** Thread-local used by DebugLib to store debugging state. */
public Object debugState;
public LuaValue hookfunc;
public boolean hookline;
public boolean hookcall;
public boolean hookrtrn;
public int hookcount;
public final Globals globals;
/** Private constructor for main thread only */
private LuaThread() {
state = new State(this, null);
public LuaThread(Globals globals) {
state = new State(globals, this, null);
state.status = STATUS_RUNNING;
this.globals = globals;
}
/**
* Create a LuaThread around a function and environment
* @param func The function to execute
*/
public LuaThread(LuaValue func) {
public LuaThread(Globals globals, LuaValue func) {
LuaValue.assert_(func != null, "function cannot be null");
state = new State(this, func);
state = new State(globals, this, func);
this.globals = globals;
}
public int type() {
@@ -145,71 +148,20 @@ public class LuaThread extends LuaValue {
return STATUS_NAMES[state.status];
}
/**
* Get the currently running thread.
* @return {@link LuaThread} that is currenly running
*/
public static LuaThread getRunning() {
return running_thread;
public boolean isMainThread() {
return this.state.function == null;
}
/**
* Callback used at the beginning of a call to prepare for possible getfenv/setfenv calls
* @param function Function being called
* @return CallStack which is used to signal the return or a tail-call recursion
* @see DebugLib
*/
public static final CallStack onCall(LuaFunction function) {
CallStack cs = running_thread.callstack;
cs.onCall(function);
return cs;
}
/**
* 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) {
return running_thread.callstack.getFunction(level);
}
/**
* Replace the error function of the currently running thread.
* @param errfunc the new error function to use.
* @return the previous error function.
*/
public static LuaValue setErrorFunc(LuaValue errfunc) {
LuaValue prev = running_thread.err;
running_thread.err = errfunc;
return prev;
}
/** Yield the current thread with arguments
*
* @param args The arguments to send as return values to {@link #resume(Varargs)}
* @return {@link Varargs} provided as arguments to {@link #resume(Varargs)}
*/
public static Varargs yield(Varargs args) {
State s = running_thread.state;
if (s.function == null)
throw new LuaError("cannot yield main thread");
return s.lua_yield(args);
}
/** Start or resume this thread
*
* @param args The arguments to send as return values to {@link #yield(Varargs)}
* @return {@link Varargs} provided as arguments to {@link #yield(Varargs)}
*/
public Varargs resume(Varargs args) {
if (this.state.status > STATUS_SUSPENDED)
final LuaThread.State s = this.state;
if (s.status > LuaThread.STATUS_SUSPENDED)
return LuaValue.varargsOf(LuaValue.FALSE,
LuaValue.valueOf("cannot resume "+LuaThread.STATUS_NAMES[this.state.status]+" coroutine"));
return state.lua_resume(this, args);
LuaValue.valueOf("cannot resume "+(s.status==LuaThread.STATUS_DEAD? "dead": "non-suspended")+" coroutine"));
return s.lua_resume(this, args);
}
public static class State implements Runnable {
private final Globals globals;
final WeakReference lua_thread;
public final LuaValue function;
Varargs args = LuaValue.NONE;
@@ -217,7 +169,8 @@ public class LuaThread extends LuaValue {
String error = null;
public int status = LuaThread.STATUS_INITIAL;
State(LuaThread lua_thread, LuaValue function) {
State(Globals globals, LuaThread lua_thread, LuaValue function) {
this.globals = globals;
this.lua_thread = new WeakReference(lua_thread);
this.function = function;
}
@@ -236,9 +189,9 @@ public class LuaThread extends LuaValue {
}
public synchronized Varargs lua_resume(LuaThread new_thread, Varargs args) {
LuaThread previous_thread = LuaThread.running_thread;
LuaThread previous_thread = globals.running_thread;
try {
LuaThread.running_thread = new_thread;
globals.running_thread = new_thread;
this.args = args;
if (this.status == STATUS_INITIAL) {
this.status = STATUS_RUNNING;
@@ -246,6 +199,7 @@ public class LuaThread extends LuaValue {
} else {
this.notify();
}
if (previous_thread != null)
previous_thread.state.status = STATUS_NORMAL;
this.status = STATUS_RUNNING;
this.wait();
@@ -255,11 +209,12 @@ public class LuaThread extends LuaValue {
} catch (InterruptedException ie) {
throw new OrphanedThread();
} finally {
running_thread = previous_thread;
running_thread.state.status =STATUS_RUNNING;
this.args = LuaValue.NONE;
this.result = LuaValue.NONE;
this.error = null;
globals.running_thread = previous_thread;
if (previous_thread != null)
globals.running_thread.state.status =STATUS_RUNNING;
}
}
@@ -287,17 +242,30 @@ public class LuaThread extends LuaValue {
}
public static class CallStack {
final LuaFunction[] functions = new LuaFunction[MAX_CALLSTACK];
final CallFrame[] frame = new CallFrame[MAX_CALLSTACK];
int calls = 0;
CallStack() {
for (int i = 0; i < MAX_CALLSTACK; ++i)
frame[i] = new CallFrame();
}
/**
* Method to indicate the start of a call
* @param stack
* @param varargs
* @see DebugLib
*/
final void onCall(LuaFunction function) {
functions[calls++] = function;
if (DebugLib.DEBUG_ENABLED)
DebugLib.debugOnCall(running_thread, calls, function);
public final void onCall(LuaFunction function) {
frame[calls++].set(function);
// if (DebugLib.DEBUG_ENABLED)
// DebugLib.debugOnCall(globals.running_thread, calls, function);
}
public final void onCall(LuaClosure function, Varargs varargs, LuaValue[] stack) {
frame[calls++].set(function, varargs, stack);
// if (DebugLib.DEBUG_ENABLED)
// DebugLib.debugOnCall(globals.running_thread, calls, function);
}
/**
@@ -305,9 +273,13 @@ public class LuaThread extends LuaValue {
* @see DebugLib
*/
public final void onReturn() {
functions[--calls] = null;
if (DebugLib.DEBUG_ENABLED)
DebugLib.debugOnReturn(running_thread, calls);
frame[--calls].reset();
// if (DebugLib.DEBUG_ENABLED)
// DebugLib.debugOnReturn(running_thread, calls);
}
public final void onInstruction(int pc, Varargs v, int top) {
frame[calls-1].instr(pc, v, top);
}
/**
@@ -324,12 +296,103 @@ public class LuaThread extends LuaValue {
* @param level # of levels back from the top of the stack.
* @return LuaFunction, or null if beyond the stack limits.
*/
LuaFunction getFunction(int level) {
return level>0 && level<=calls? functions[calls-level]: null;
public LuaFunction getFunction(int level) {
return level>0 && level<=calls? frame[calls-level].f: null;
}
/**
* Get the traceback starting at a specific level.
* @param level
* @return String containing the traceback.
*/
public String traceback(int level) {
StringBuffer sb = new StringBuffer();
sb.append( "stack traceback:" );
for (LuaFunction f = null; (f = getFunction(level)) != null; ++level) {
sb.append( "\n\t" );
sb.append( f.tostring() );
sb.append( "main chunk" );
}
return sb.toString();
}
public CallFrame getCallFrame(int level) {
if (level < 1 || level >= calls)
return null;
return frame[calls-level];
}
public CallFrame findCallFrame(LuaValue func) {
for (int i = 1; i <= calls; ++i)
if (frame[calls-i].f == func)
return frame[i];
return null;
}
}
public static class CallFrame {
public LuaFunction f;
int pc, top;
Varargs v;
LuaValue[] stack;
public void set(LuaClosure function, Varargs varargs, LuaValue[] stack) {
this.f = function;
this.v = varargs;
this.stack = stack;
}
public void print() {
// TODO Auto-generated method stub
}
public void set(LuaFunction function) {
this.f = function;
}
public void reset() {
this.f = null;
this.v = null;
this.stack = null;
}
public void instr(int pc, Varargs v, int top) {
this.pc = pc;
this.v = v;
this.top = top;
if (DebugLib.DEBUG_ENABLED && DebugLib.TRACE & f.isclosure())
Print.printState(f.checkclosure(), pc, stack, top, v);
}
public int getLine() {
if (!f.isclosure())
return 0;
LuaClosure c = (LuaClosure) f;
Prototype p = c.p;
if (p.lineinfo == null || pc < 0 || pc >= p.lineinfo[pc])
return 0;
return p.lineinfo[pc];
}
public Varargs getLocal(int i) {
if (!f.isclosure())
return NONE;
LuaClosure c = (LuaClosure) f;
Prototype p = c.p;
if (i < 1 || i > stack.length)
if (p.locvars != null && p.locvars.length >= i)
return varargsOf(stack[i-1], p.locvars[i-1].varname);
else
return stack[i-1];
return NONE;
}
public Varargs setLocal(int i, LuaValue value) {
if (!f.isclosure())
return NONE;
LuaClosure c = (LuaClosure) f;
Prototype p = c.p;
if (i < 1 || i > stack.length)
return NONE;
stack[i] = value;
if (p.locvars != null && p.locvars.length >= i)
return p.locvars[i-1].varname;
return NONE;
}
}
public boolean isMainThread() {
return this.state.function == null;
}
}

View File

@@ -24,7 +24,7 @@ package org.luaj.vm2;
public class LuaUserdata extends LuaValue {
public final Object m_instance;
public Object m_instance;
public LuaValue m_metatable;
public LuaUserdata(Object obj) {

View File

@@ -109,11 +109,6 @@ package org.luaj.vm2;
*/
abstract
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 */
public static final int TINT = (-2);
@@ -878,6 +873,15 @@ public class LuaValue extends Varargs {
*/
public LuaValue checkfunction() { argerror("function"); return null; }
/** Check that the value is a Globals instance, or throw {@link LuaError} if not
* <p>
* {@link Globals} are a special {@link LuaTable} that establish the default global environment.
* @return {@code this} if if an instance fof {@Globals}
* @throws LuaError if not a {@link Globals} instance.
*/
public Globals checkglobals() { argerror("globals"); return null; }
/** Check that the value is numeric, and convert and cast value to int, or throw {@link LuaError} if not numeric
* <p>
* Values that are {@link LuaNumber} will be cast to int and may lose precision.
@@ -1354,13 +1358,14 @@ public class LuaValue extends Varargs {
public Varargs inext(LuaValue index) { return typerror("table"); }
/**
* Load a library instance by setting its environment to the global environment {@code LuaValue._G}
* Load a library instance by setting its environment to the calling object,
* and calling it, which should iniitalize the library instance and
* install itself into this instance.
* install itself into this instance. The calling object should be the
* {@link Globals} environment to associate wtih the library.
* @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); }
public LuaValue load(LuaValue library) { return load(library, this); }
/**
* Load a library instance by setting its environment to {@code env}

View File

@@ -25,6 +25,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import org.luaj.vm2.Globals;
import org.luaj.vm2.LoadState;
import org.luaj.vm2.Lua;
import org.luaj.vm2.LuaError;
@@ -73,36 +74,21 @@ import org.luaj.vm2.Varargs;
*/
public class BaseLib extends OneArgFunction implements ResourceFinder {
public static BaseLib instance;
public InputStream STDIN = null;
public PrintStream STDOUT = System.out;
public PrintStream STDERR = System.err;
/**
* Singleton file opener for this Java ClassLoader realm.
*
* Unless set or changed elsewhere, will be set by the BaseLib that is created.
*/
public static ResourceFinder FINDER;
/**
* Construct a base libarary instance.
*/
public BaseLib() {
instance = this;
}
Globals globals;
public LuaValue call(LuaValue env) {
globals = env.checkglobals();
globals.FINDER = this;
globals.baselib = this;
env.set( "_G", env );
env.set( "_VERSION", Lua._VERSION );
env.set("assert", new _assert());
env.set("collectgarbage", new collectgarbage());
env.set("dofile", new dofile(this));
env.set("dofile", new dofile());
env.set("error", new error());
env.set("getmetatable", new getmetatable());
env.set("load", new load());
env.set("loadfile", new loadfile(this));
env.set("loadfile", new loadfile());
env.set("pcall", new pcall());
env.set("print", new print(this));
env.set("rawequal", new rawequal());
@@ -121,9 +107,6 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
env.set("pairs", new pairs(next));
env.set("ipairs", new ipairs());
// set the default resource finder if not set already
if ( FINDER == null )
FINDER = this;
return env;
}
@@ -132,8 +115,7 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
* Tries to open the file as a resource, which can work for JSE and JME.
*/
public InputStream findResource(String filename) {
Class c = getClass();
return c.getResourceAsStream(filename.startsWith("/")? filename: "/"+filename);
return getClass().getResourceAsStream(filename.startsWith("/")? filename: "/"+filename);
}
@@ -168,17 +150,13 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
}
// "dofile", // ( filename ) -> result1, ...
static final class dofile extends VarArgFunction {
final BaseLib baselib;
dofile(BaseLib baselib) {
this.baselib = baselib;
}
final class dofile extends VarArgFunction {
public Varargs invoke(Varargs args) {
args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil");
String filename = args.isstring(1)? args.tojstring(1): null;
Varargs v = filename == null?
BaseLib.loadStream( baselib.STDIN, "=stdin", "bt",LuaValue._G ):
BaseLib.loadFile( args.checkjstring(1), "bt",LuaValue._G );
loadStream( globals.STDIN, "=stdin", "bt", globals ):
loadFile( args.checkjstring(1), "bt", globals );
return v.isnil(1)? error(v.tojstring(2)): v.arg1().invoke();
}
}
@@ -201,63 +179,59 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
}
}
// "load", // ( ld [, source [, mode [, env]]] ) -> chunk | nil, msg
static final class load extends VarArgFunction {
final class load extends VarArgFunction {
public Varargs invoke(Varargs args) {
LuaValue ld = args.arg1();
args.argcheck(ld.isstring() || ld.isfunction(), 1, "ld must be string or function");
String source = args.optjstring(2, ld.isstring()? ld.tojstring(): "=(load)");
String mode = args.optjstring(3, "bt");
LuaValue env = args.optvalue(4,LuaValue._G);
return BaseLib.loadStream(ld.isstring()? ld.strvalue().toInputStream():
LuaValue env = args.optvalue(4, globals);
return loadStream(ld.isstring()? ld.strvalue().toInputStream():
new StringInputStream(ld.checkfunction()), source, mode, env);
}
}
// "loadfile", // ( [filename [, mode [, env]]] ) -> chunk | nil, msg
static final class loadfile extends VarArgFunction {
final BaseLib baselib;
loadfile(BaseLib baselib) {
this.baselib = baselib;
}
final class loadfile extends VarArgFunction {
public Varargs invoke(Varargs args) {
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 mode = args.optjstring(2, "bt");
LuaValue env = args.optvalue(3,LuaValue._G);
LuaValue env = args.optvalue(3, globals);
return filename == null?
BaseLib.loadStream( baselib.STDIN, "=stdin", mode, env ):
BaseLib.loadFile( filename, mode, env );
loadStream( globals.STDIN, "=stdin", mode, env ):
loadFile( filename, mode, env );
}
}
// "pcall", // (f, arg1, ...) -> status, result1, ...
static final class pcall extends VarArgFunction {
final class pcall extends VarArgFunction {
public Varargs invoke(Varargs args) {
LuaValue func = args.checkvalue(1);
LuaThread.CallStack cs = LuaThread.onCall(this);
globals.callstack.onCall(this);
try {
return pcall(func,args.subargs(2),null);
} finally {
cs.onReturn();
globals.callstack.onReturn();
}
}
}
// "print", // (...) -> void
static final class print extends VarArgFunction {
final class print extends VarArgFunction {
final BaseLib baselib;
print(BaseLib baselib) {
this.baselib = baselib;
}
public Varargs invoke(Varargs args) {
LuaValue tostring =LuaValue._G.get("tostring");
LuaValue tostring = globals.get("tostring");
for ( int i=1, n=args.narg(); i<=n; i++ ) {
if ( i>1 ) baselib.STDOUT.write( '\t' );
if ( i>1 ) globals.STDOUT.write( '\t' );
LuaString s = tostring.call( args.arg(i) ).strvalue();
int z = s.indexOf((byte)0, 0);
baselib.STDOUT.write( s.m_bytes, s.m_offset, z>=0? z: s.m_length );
globals.STDOUT.write( s.m_bytes, s.m_offset, z>=0? z: s.m_length );
}
baselib.STDOUT.println();
globals.STDOUT.println();
return NONE;
}
}
@@ -374,13 +348,13 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
}
// "xpcall", // (f, err) -> result1, ...
static final class xpcall extends VarArgFunction {
final class xpcall extends VarArgFunction {
public Varargs invoke(Varargs args) {
LuaThread.CallStack cs = LuaThread.onCall(this);
globals.callstack.onCall(this);
try {
return pcall(args.arg1(),NONE,args.checkvalue(2));
} finally {
cs.onReturn();
globals.callstack.onReturn();
}
}
}
@@ -418,18 +392,19 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
}
}
public static Varargs pcall(LuaValue func, Varargs args, LuaValue errfunc) {
LuaValue olderr = LuaThread.setErrorFunc(errfunc);
public Varargs pcall(LuaValue func, Varargs args, LuaValue errorfunc) {
try {
Varargs result = varargsOf(LuaValue.TRUE, func.invoke(args));
LuaThread.setErrorFunc(olderr);
return result;
LuaValue olderr = globals.errorfunc;
globals.errorfunc = errorfunc;
try {
return varargsOf(LuaValue.TRUE, func.invoke(args));
} finally {
globals.errorfunc = olderr;
}
} catch ( LuaError le ) {
LuaThread.setErrorFunc(olderr);
String m = le.getMessage();
return varargsOf(FALSE, m!=null? valueOf(m): NIL);
} catch ( Exception e ) {
LuaThread.setErrorFunc(olderr);
String m = e.getMessage();
return varargsOf(FALSE, valueOf(m!=null? m: e.toString()));
}
@@ -441,8 +416,8 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
* @param mode
* @return Varargs containing chunk, or NIL,error-text on error
*/
public static Varargs loadFile(String filename, String mode, LuaValue env) {
InputStream is = FINDER.findResource(filename);
public Varargs loadFile(String filename, String mode, LuaValue env) {
InputStream is = globals.FINDER.findResource(filename);
if ( is == null )
return varargsOf(NIL, valueOf("cannot open "+filename+": No such file or directory"));
try {
@@ -456,7 +431,7 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
}
}
public static Varargs loadStream(InputStream is, String chunkname, String mode, LuaValue env) {
public Varargs loadStream(InputStream is, String chunkname, String mode, LuaValue env) {
try {
if ( is == null )
return varargsOf(NIL, valueOf("not found: "+chunkname));

View File

@@ -42,7 +42,7 @@ public class Bit32Lib extends OneArgFunction {
"arshift", "lrotate", "lshift", "rrotate", "rshift"
});
env.set("bit32", t);
PackageLib.instance.LOADED.set("bit32", t);
env.get("package").get("loaded").set("bit32", t);
return t;
}

View File

@@ -21,6 +21,7 @@
******************************************************************************/
package org.luaj.vm2.lib;
import org.luaj.vm2.Globals;
import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaThread;
@@ -61,7 +62,10 @@ public class CoroutineLib extends OneArgFunction {
static int coroutine_count = 0;
Globals globals;
public LuaValue call(LuaValue env) {
globals = env.checkglobals();
LuaTable coroutine = new LuaTable();
coroutine.set("create", new create());
coroutine.set("resume", new resume());
@@ -70,27 +74,26 @@ public class CoroutineLib extends OneArgFunction {
coroutine.set("yield", new yield());
coroutine.set("wrap", new wrap());
env.set("coroutine", coroutine);
env.get("package").get("loaded").set("coroutine", TRUE);
env.get("package").get("loaded").set("coroutine", coroutine);
return coroutine;
}
final class create extends LibFunction {
public LuaValue call(LuaValue f) {
return new LuaThread(f.checkfunction());
return new LuaThread(globals, f.checkfunction());
}
}
final class resume extends VarArgFunction {
public Varargs invoke(Varargs args) {
if (!(args.arg1() instanceof LuaThread)) argerror(1, "thread");
final LuaThread t = (LuaThread) args.arg1();
return resume( t, args.subargs(2) );
final LuaThread t = args.checkthread(1);
return t.resume( args.subargs(2) );
}
}
final class running extends VarArgFunction {
public Varargs invoke(Varargs args) {
final LuaThread r = LuaThread.getRunning();
final LuaThread r = globals.running_thread;
return varargsOf(r, valueOf(r.isMainThread()));
}
}
@@ -104,14 +107,14 @@ public class CoroutineLib extends OneArgFunction {
final class yield extends VarArgFunction {
public Varargs invoke(Varargs args) {
return yield( args );
return globals.yield( args );
}
}
final class wrap extends LibFunction {
public LuaValue call(LuaValue f) {
final LuaValue func = f.checkfunction();
final LuaThread thread = new LuaThread(func);
final LuaThread thread = new LuaThread(globals, func);
return new wrapper(thread);
}
}
@@ -122,7 +125,7 @@ public class CoroutineLib extends OneArgFunction {
this.luathread = luathread;
}
public Varargs invoke(Varargs args) {
final Varargs result = resume(luathread, args);
final Varargs result = luathread.resume(args);
if ( result.arg1().toboolean() ) {
return result.subargs(2);
} else {
@@ -130,19 +133,4 @@ public class CoroutineLib extends OneArgFunction {
}
}
}
Varargs yield(Varargs args) {
final LuaThread.State s = LuaThread.getRunning().state;
if (s.function == null)
throw new LuaError("cannot yield main thread");
return s.lua_yield(args);
}
Varargs resume(LuaThread t, Varargs args) {
final LuaThread.State s = t.state;
if (s.status > LuaThread.STATUS_SUSPENDED)
return LuaValue.varargsOf(LuaValue.FALSE,
LuaValue.valueOf("cannot resume "+(s.status==LuaThread.STATUS_DEAD? "dead": "non-suspended")+" coroutine"));
return s.lua_resume(t, args);
}
}

View File

@@ -23,6 +23,7 @@ package org.luaj.vm2.lib;
import java.lang.ref.WeakReference;
import org.luaj.vm2.Globals;
import org.luaj.vm2.Lua;
import org.luaj.vm2.LuaBoolean;
import org.luaj.vm2.LuaClosure;
@@ -33,6 +34,7 @@ import org.luaj.vm2.LuaNumber;
import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaThread;
import org.luaj.vm2.LuaUserdata;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Print;
import org.luaj.vm2.Prototype;
@@ -66,7 +68,7 @@ import org.luaj.vm2.Varargs;
* @see JmePlatform
* @see <a href="http://www.lua.org/manual/5.1/manual.html#5.9">http://www.lua.org/manual/5.1/manual.html#5.9</a>
*/
public class DebugLib extends VarArgFunction {
public class DebugLib extends OneArgFunction {
public static final boolean CALLS = (null != System.getProperty("CALLS"));
public static final boolean TRACE = (null != System.getProperty("TRACE"));
@@ -74,38 +76,6 @@ public class DebugLib extends VarArgFunction {
// remove it in production builds
public static boolean DEBUG_ENABLED;
static final String[] NAMES = {
"debug",
"gethook",
"getinfo",
"getlocal",
"getmetatable",
"getregistry",
"getupvalue",
"sethook",
"setlocal",
"setmetatable",
"setupvalue",
"traceback",
};
private static final int INIT = 0;
private static final int DEBUG = 1;
private static final int GETHOOK = 2;
private static final int GETINFO = 3;
private static final int GETLOCAL = 4;
private static final int GETMETATABLE = 5;
private static final int GETREGISTRY = 6;
private static final int GETUPVALUE = 7;
private static final int SETHOOK = 8;
private static final int SETLOCAL = 9;
private static final int SETMETATABLE = 10;
private static final int SETUPVALUE = 11;
private static final int TRACEBACK = 12;
/* maximum stack for a Lua function */
private static final int MAXSTACK = 250;
private static final LuaString LUA = valueOf("Lua");
private static final LuaString JAVA = valueOf("Java");
private static final LuaString QMARK = valueOf("?");
@@ -133,291 +103,104 @@ public class DebugLib extends VarArgFunction {
private static final LuaString CURRENTLINE = valueOf("currentline");
private static final LuaString ACTIVELINES = valueOf("activelines");
public DebugLib() {
}
Globals globals;
private LuaTable init(LuaValue env) {
public LuaTable call(LuaValue env) {
globals = env.checkglobals();
globals.debuglib = this;
DEBUG_ENABLED = true;
LuaTable t = new LuaTable();
bind(t, DebugLib.class, NAMES, DEBUG);
env.set("debug", t);
PackageLib.instance.LOADED.set("debug", t);
return t;
LuaTable debug = new LuaTable();
env.set("debug", new debug());
env.set("gethook", new gethook());
env.set("sethook", new sethook());
env.get("package").get("loaded").set("debug", debug);
return debug;
}
public Varargs invoke(Varargs args) {
switch ( opcode ) {
case INIT: return init(args.arg1());
case DEBUG: return _debug(args);
case GETHOOK: return _gethook(args);
case GETINFO: return _getinfo(args,this);
case GETLOCAL: return _getlocal(args);
case GETMETATABLE: return _getmetatable(args);
case GETREGISTRY: return _getregistry(args);
case GETUPVALUE: return _getupvalue(args);
case SETHOOK: return _sethook(args);
case SETLOCAL: return _setlocal(args);
case SETMETATABLE: return _setmetatable(args);
case SETUPVALUE: return _setupvalue(args);
case TRACEBACK: return _traceback(args);
default: return NONE;
}
}
// ------------------------ Debug Info management --------------------------
//
// when DEBUG_ENABLED is set to true, these functions will be called
// by Closure instances as they process bytecodes.
//
// Each thread will get a DebugState attached to it by the debug library
// which will track function calls, hook functions, etc.
//
static class DebugInfo {
LuaValue func;
LuaClosure closure;
LuaValue[] stack;
Varargs varargs, extras;
int pc, top;
private DebugInfo() {
func = NIL;
}
private DebugInfo(LuaValue func) {
pc = -1;
setfunction( func );
}
void setargs(Varargs varargs, LuaValue[] stack) {
this.varargs = varargs;
this.stack = stack;
}
void setfunction( LuaValue func ) {
this.func = func;
this.closure = (func instanceof LuaClosure? (LuaClosure) func: null);
}
void clear() {
func = NIL;
closure = null;
stack = null;
varargs = extras = null;
pc = top = 0;
}
public void bytecode(int pc, Varargs extras, int top) {
this.pc = pc;
this.top = top;
this.extras = extras;
}
public int currentline() {
if ( closure == null ) return -1;
int[] li = closure.p.lineinfo;
return li==null || pc<0 || pc>=li.length? -1: li[pc];
}
public LuaString[] getfunckind() {
if ( closure == null || pc<0 ) return null;
int stackpos = (closure.p.code[pc] >> 6) & 0xff;
return getobjname(this, pc, stackpos);
}
public String sourceline() {
if ( closure == null ) return func.tojstring();
String s = closure.p.source.tojstring();
int line = currentline();
return (s.startsWith("@")||s.startsWith("=")? s.substring(1): s) + ":" + line;
}
public String tracename() {
// if ( func != null )
// return func.tojstring();
LuaString[] kind = getfunckind();
if ( kind == null )
return "function ?";
return "function "+kind[0].tojstring();
}
public LuaString getlocalname(int index) {
if ( closure == null ) return null;
return closure.p.getlocalname(index, pc);
}
public String tojstring() {
return tracename()+" "+sourceline();
}
}
/** DebugState is associated with a Thread */
static class DebugState {
private final WeakReference thread_ref;
private int debugCalls = 0;
private DebugInfo[] debugInfo = new DebugInfo[LuaThread.MAX_CALLSTACK+1];
private LuaValue hookfunc;
private boolean hookcall,hookline,hookrtrn,inhook;
private int hookcount,hookcodes;
private int line;
DebugState(LuaThread thread) {
this.thread_ref = new WeakReference(thread);
}
public DebugInfo nextInfo() {
DebugInfo di = debugInfo[debugCalls];
if ( di == null )
debugInfo[debugCalls] = di = new DebugInfo();
return di;
}
public DebugInfo pushInfo( int calls ) {
while ( debugCalls < calls ) {
nextInfo();
++debugCalls;
}
return debugInfo[debugCalls-1];
}
public void popInfo(int calls) {
while ( debugCalls > calls )
debugInfo[--debugCalls].clear();
}
void callHookFunc(DebugState ds, LuaString type, LuaValue arg) {
if ( inhook || hookfunc == null )
return;
inhook = true;
try {
int n = debugCalls;
ds.nextInfo().setargs( arg, null );
ds.pushInfo(n+1).setfunction(hookfunc);
try {
hookfunc.call(type,arg);
} finally {
ds.popInfo(n);
}
} catch ( Exception e ) {
e.printStackTrace();
} finally {
inhook = false;
}
}
public void sethook(LuaValue func, boolean call, boolean line, boolean rtrn, int count) {
this.hookcount = count;
this.hookcall = call;
this.hookline = line;
this.hookrtrn = rtrn;
this.hookfunc = func;
}
DebugInfo getDebugInfo() {
try {
return debugInfo[debugCalls-1];
} catch ( Exception e ) {
if ( debugCalls <= 0 )
return debugInfo[debugCalls++] = new DebugInfo();
return null;
}
}
DebugInfo getDebugInfo(int level) {
return level < 0 || level >= debugCalls? null: debugInfo[debugCalls-level-1];
}
public DebugInfo findDebugInfo(LuaValue func) {
for ( int i=debugCalls; --i>=0; ) {
if ( debugInfo[i].func == func ) {
return debugInfo[i];
}
}
return new DebugInfo(func);
}
public String tojstring() {
LuaThread thread = (LuaThread) thread_ref.get();
return thread != null? DebugLib.traceback(thread, 0): "orphaned thread";
}
}
static DebugState getDebugState( LuaThread thread ) {
if ( thread.debugState == null )
thread.debugState = new DebugState(thread);
return (DebugState) thread.debugState;
}
static DebugState getDebugState() {
return getDebugState( LuaThread.getRunning() );
}
/** Called by Closures to set up stack and arguments to next call */
public static void debugSetupCall(Varargs args, LuaValue[] stack) {
DebugState ds = getDebugState();
if ( ds.inhook )
return;
ds.nextInfo().setargs( args, stack );
}
/** Called by Closures and recursing java functions on entry
* @param thread the thread for the call
* @param calls the number of calls in the call stack
* @param func the function called
*/
public static void debugOnCall(LuaThread thread, int calls, LuaFunction func) {
DebugState ds = getDebugState();
if ( ds.inhook )
return;
DebugInfo di = ds.pushInfo(calls);
di.setfunction( func );
if(CALLS)System.out.println("calling "+func);
if ( ds.hookcall )
ds.callHookFunc( ds, CALL, LuaValue.NIL );
}
/** Called by Closures and recursing java functions on return
* @param thread the thread for the call
* @param calls the number of calls in the call stack
*/
public static void debugOnReturn(LuaThread thread, int calls) {
DebugState ds = getDebugState(thread);
if ( ds.inhook )
return;
if(CALLS)System.out.println("returning");
try {
if ( ds.hookrtrn )
ds.callHookFunc( ds, RETURN, LuaValue.NIL );
} finally {
getDebugState().popInfo(calls);
}
}
/** Called by Closures on bytecode execution */
public static void debugBytecode( int pc, Varargs extras, int top ) {
DebugState ds = getDebugState();
if ( ds.inhook )
return;
DebugInfo di = ds.getDebugInfo();
if(TRACE)Print.printState(di.closure, pc, di.stack, top, di.varargs);
di.bytecode( pc, extras, top );
if ( ds.hookcount > 0 ) {
if ( ++ds.hookcodes >= ds.hookcount ) {
ds.hookcodes = 0;
ds.callHookFunc( ds, COUNT, LuaValue.NIL );
}
}
if ( ds.hookline ) {
int newline = di.currentline();
if ( newline != ds.line ) {
int c = di.closure.p.code[pc];
if ( (c&0x3f) != Lua.OP_JMP || ((c>>>14)-0x1ffff) >= 0 ) {
ds.line = newline;
ds.callHookFunc( ds, LINE, LuaValue.valueOf(newline) );
}
}
}
}
// ------------------- library function implementations -----------------
// j2se subclass may wish to override and provide actual console here.
// j2me platform has not System.in to provide console.
static Varargs _debug(Varargs args) {
// debug.debug()
static final class debug extends ZeroArgFunction {
public LuaValue call() {
return NONE;
}
static Varargs _gethook(Varargs args) {
int a=1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
DebugState ds = getDebugState(thread);
return varargsOf(
ds.hookfunc,
valueOf((ds.hookcall?"c":"")+(ds.hookline?"l":"")+(ds.hookrtrn?"r":"")),
valueOf(ds.hookcount));
}
static Varargs _sethook(Varargs args) {
// debug.gethook ([thread])
final class gethook extends VarArgFunction {
public Varargs invoke(Varargs args) {
LuaThread t = args.optthread(1, globals.running_thread);
return varargsOf(
t.hookfunc,
valueOf((t.hookcall?"c":"")+(t.hookline?"l":"")+(t.hookrtrn?"r":"")),
valueOf(t.hookcount));
}
}
// debug.getinfo ([thread,] f [, what])
final class getinfo extends VarArgFunction {
public Varargs invoke(Varargs args) {
int a=1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running_thread;
LuaValue func = args.optfunction(a++, null);
String what = args.optjstring(a++,"");
return NONE;
}
}
// debug.getlocal ([thread,] f, local)
final class getlocal extends VarArgFunction {
public Varargs invoke(Varargs args) {
int a=1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running_thread;
LuaValue func = args.optfunction(a++, null);
LuaValue local = args.checkvalue(a++);
return thread.globals.callstack.findCallFrame(func).getLocal(local.toint());
}
}
// debug.getmetatable (value)
final class getmetatable extends LibFunction {
public LuaValue call(LuaValue v) {
LuaValue mt = v.getmetatable();
return mt != null? mt: NIL;
}
}
// debug.getregistry ()
final class getregistry extends ZeroArgFunction {
public LuaValue call() {
return globals;
}
}
// debug.getupvalue (f, up)
static final class getupvalue extends VarArgFunction {
public Varargs invoke(Varargs args) {
LuaValue func = args.checkfunction(1);
int up = args.checkint(2);
if ( func instanceof LuaClosure ) {
LuaClosure c = (LuaClosure) func;
LuaString name = findupvalue(c, up);
if ( name != null ) {
return varargsOf(name, c.upValues[up-1].getValue() );
}
}
return NIL;
}
}
// debug.getuservalue (u)
static final class getuservalue extends LibFunction {
public LuaValue call(LuaValue u) {
return u.isuserdata()? u: NIL;
}
}
// debug.sethook ([thread,] hook, mask [, count])
final class sethook extends VarArgFunction {
public Varargs call(Varargs args) {
int a=1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running_thread;
LuaValue func = args.optfunction(a++, null);
String str = args.optjstring(a++,"");
int count = args.optint(a++,0);
@@ -428,139 +211,30 @@ public class DebugLib extends VarArgFunction {
case 'l': line=true; break;
case 'r': rtrn=true; break;
}
getDebugState(thread).sethook(func, call, line, rtrn, count);
thread.hookfunc = func;
thread.hookcall = call;
thread.hookline = line;
thread.hookcount = count;
thread.hookrtrn = rtrn;
return NONE;
}
}
protected static Varargs _getinfo(Varargs args, LuaValue level0func) {
// debug.setlocal ([thread,] level, local, value)
final class setlocal extends VarArgFunction {
public Varargs invoke(Varargs args) {
int a=1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
LuaValue func = args.arg(a++);
String what = args.optjstring(a++, "nSluf");
// find the stack info
DebugState ds = getDebugState( thread );
DebugInfo di = null;
if ( func.isnumber() ) {
int level = func.checkint();
di = level>0?
ds.getDebugInfo(level-1):
new DebugInfo( level0func );
} else {
di = ds.findDebugInfo( func.checkfunction() );
}
if ( di == null )
return NIL;
// start a table
LuaTable info = new LuaTable();
LuaClosure c = di.closure;
for (int i = 0, j = what.length(); i < j; i++) {
switch (what.charAt(i)) {
case 'S': {
if ( c != null ) {
Prototype p = c.p;
info.set(WHAT, LUA);
info.set(SOURCE, p.source);
info.set(SHORT_SRC, valueOf(sourceshort(p)));
info.set(LINEDEFINED, valueOf(p.linedefined));
info.set(LASTLINEDEFINED, valueOf(p.lastlinedefined));
} else {
String shortName = di.func.tojstring();
LuaString name = LuaString.valueOf("[Java] "+shortName);
info.set(WHAT, JAVA);
info.set(SOURCE, name);
info.set(SHORT_SRC, valueOf(shortName));
info.set(LINEDEFINED, LuaValue.MINUSONE);
info.set(LASTLINEDEFINED, LuaValue.MINUSONE);
}
break;
}
case 'l': {
int line = di.currentline();
info.set( CURRENTLINE, valueOf(line) );
break;
}
case 'u': {
info.set(NUPS, valueOf(c!=null? c.p.upvalues.length: 0));
break;
}
case 'n': {
LuaString[] kind = di.getfunckind();
info.set(NAME, kind!=null? kind[0]: QMARK);
info.set(NAMEWHAT, kind!=null? kind[1]: EMPTYSTRING);
break;
}
case 'f': {
info.set( FUNC, di.func );
break;
}
case 'L': {
LuaTable lines = new LuaTable();
info.set(ACTIVELINES, lines);
// if ( di.luainfo != null ) {
// int line = di.luainfo.currentline();
// if ( line >= 0 )
// lines.set(1, IntValue.valueOf(line));
// }
break;
}
}
}
return info;
}
public static String sourceshort(Prototype p) {
String name = p.source.tojstring();
if ( name.startsWith("@") || name.startsWith("=") )
name = name.substring(1);
else if ( name.startsWith("\033") )
name = "binary string";
return name;
}
static Varargs _getlocal(Varargs args) {
int a=1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
int level = args.checkint(a++);
int local = args.checkint(a++);
DebugState ds = getDebugState(thread);
DebugInfo di = ds.getDebugInfo(level-1);
LuaString name = (di!=null? di.getlocalname(local): null);
if ( name != null ) {
LuaValue value = di.stack[local-1];
return varargsOf( name, value );
} else {
return NIL;
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running_thread;
LuaValue func = args.optfunction(a++, null);
LuaValue local = args.checkvalue(a++);
LuaValue value = args.checkvalue(a++);
return thread.globals.callstack.findCallFrame(func).setLocal(local.toint(), value);
}
}
static Varargs _setlocal(Varargs args) {
int a=1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
int level = args.checkint(a++);
int local = args.checkint(a++);
LuaValue value = args.arg(a++);
DebugState ds = getDebugState(thread);
DebugInfo di = ds.getDebugInfo(level-1);
LuaString name = (di!=null? di.getlocalname(local): null);
if ( name != null ) {
di.stack[local-1] = value;
return name;
} else {
return NIL;
}
}
static LuaValue _getmetatable(Varargs args) {
LuaValue object = args.arg(1);
LuaValue mt = object.getmetatable();
return mt!=null? mt: NIL;
}
static Varargs _setmetatable(Varargs args) {
// debug.setmetatable (value, table)
final class setmetatable extends VarArgFunction {
public Varargs invoke(Varargs args) {
LuaValue object = args.arg(1);
try {
LuaValue mt = args.opttable(2, null);
@@ -578,35 +252,11 @@ public class DebugLib extends VarArgFunction {
return varargsOf(FALSE, valueOf(e.toString()));
}
}
static Varargs _getregistry(Varargs args) {
return new LuaTable();
}
static LuaString findupvalue(LuaClosure c, int up) {
if ( c.upValues != null && up > 0 && up <= c.upValues.length ) {
if ( c.p.upvalues != null && up <= c.p.upvalues.length )
return c.p.upvalues[up-1].name;
else
return LuaString.valueOf( "."+up );
}
return null;
}
static Varargs _getupvalue(Varargs args) {
LuaValue func = args.checkfunction(1);
int up = args.checkint(2);
if ( func instanceof LuaClosure ) {
LuaClosure c = (LuaClosure) func;
LuaString name = findupvalue(c, up);
if ( name != null ) {
return varargsOf(name, c.upValues[up-1].getValue() );
}
}
return NIL;
}
static LuaValue _setupvalue(Varargs args) {
// debug.setupvalue (f, up, value)
final class setupvalue extends VarArgFunction {
public Varargs invoke(Varargs args) {
LuaValue func = args.checkfunction(1);
int up = args.checkint(2);
LuaValue value = args.arg(3);
@@ -620,78 +270,155 @@ public class DebugLib extends VarArgFunction {
}
return NIL;
}
}
static LuaValue _traceback(Varargs args) {
// debug.setuservalue (udata, value)
final class setuservalue extends VarArgFunction {
public Varargs invoke(Varargs args) {
Object o = args.checkuserdata(1);
LuaValue v = args.checkvalue(2);
LuaUserdata u = (LuaUserdata)args.arg1();
u.m_instance = v.checkuserdata();
u.m_metatable = v.getmetatable();
return NONE;
}
}
// debug.traceback ([thread,] [message [, level]])
final class traceback extends VarArgFunction {
public Varargs invoke(Varargs args) {
int a=1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running_thread;
String message = args.optjstring(a++, null);
int level = args.optint(a++,1);
String tb = DebugLib.traceback(thread, level-1);
String tb = globals.callstack.traceback(level-1);
return valueOf(message!=null? message+"\n"+tb: tb);
}
}
// =================== public utilities ====================
// debug.upvalueid (f, n)
final class upvalueid extends VarArgFunction {
public Varargs invoke(Varargs args) {
LuaValue func = args.checkfunction(1);
int up = args.checkint(2);
if ( func instanceof LuaClosure ) {
LuaClosure c = (LuaClosure) func;
if ( c.upValues != null && up > 0 && up <= c.upValues.length ) {
return userdataOf(c.upValues[up-1].hashCode());
}
}
return NIL;
}
}
/**
* Get a traceback as a string for the current thread
// debug.upvaluejoin (f1, n1, f2, n2)
final class upvaluejoin extends VarArgFunction {
public Varargs invoke(Varargs args) {
LuaValue f1 = args.checkfunction(1);
int n1 = args.checkint(2);
LuaValue f2 = args.checkfunction(3);
int n2 = args.checkint(4);
return NONE;
}
}
static LuaString findupvalue(LuaClosure c, int up) {
if ( c.upValues != null && up > 0 && up <= c.upValues.length ) {
if ( c.p.upvalues != null && up <= c.p.upvalues.length )
return c.p.upvalues[up-1].name;
else
return LuaString.valueOf( "."+up );
}
return null;
}
// ------------------- library function implementations -----------------
protected Varargs _getinfo(Varargs args, LuaValue level0func) {
int a=1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running_thread;
LuaValue func = args.arg(a++);
String what = args.optjstring(a++, "nSluf");
LuaThread.CallStack callstack = thread.globals.callstack;
// find the stack info
LuaThread.CallFrame frame;
if ( func.isnumber() ) {
frame = callstack.getCallFrame(func.toint());
} else {
frame = callstack.findCallFrame(func);
}
if (frame == null)
return NIL;
// start a table
LuaTable info = new LuaTable();
LuaClosure c = frame.f.isclosure()? (LuaClosure) frame.f: null;
for (int i = 0, j = what.length(); i < j; i++) {
switch (what.charAt(i)) {
case 'S': {
if ( c != null ) {
Prototype p = c.p;
info.set(WHAT, LUA);
info.set(SOURCE, p.source);
info.set(SHORT_SRC, valueOf(sourceshort(p)));
info.set(LINEDEFINED, valueOf(p.linedefined));
info.set(LASTLINEDEFINED, valueOf(p.lastlinedefined));
} else {
String shortName = frame.f.tojstring();
LuaString name = LuaString.valueOf("[Java] "+shortName);
info.set(WHAT, JAVA);
info.set(SOURCE, name);
info.set(SHORT_SRC, valueOf(shortName));
info.set(LINEDEFINED, LuaValue.MINUSONE);
info.set(LASTLINEDEFINED, LuaValue.MINUSONE);
}
break;
}
case 'l': {
int line = frame.getLine();
info.set( CURRENTLINE, valueOf(line) );
break;
}
case 'u': {
info.set(NUPS, valueOf(c!=null? c.p.upvalues.length: 0));
break;
}
case 'n': {
LuaString[] kind = getfunckind(frame.f);
info.set(NAME, kind!=null? kind[0]: QMARK);
info.set(NAMEWHAT, kind!=null? kind[1]: EMPTYSTRING);
break;
}
case 'f': {
info.set( FUNC, frame.f );
break;
}
/*
case 'L': {
LuaTable lines = new LuaTable();
info.set(ACTIVELINES, lines);
if ( c !+ null && c.luainfo != null ) {
int line = c.luainfo.currentline();
if ( line >= 0 )
lines.set(1, IntValue.valueOf(line));
}
break;
}
*/
public static String traceback(int level) {
return traceback(LuaThread.getRunning(), level);
}
/**
* Get a traceback for a particular thread.
* @param thread LuaThread to provide stack trace for
* @param level 0-based level to start reporting on
* @return String containing the stack trace.
*/
public static String traceback(LuaThread thread, int level) {
StringBuffer sb = new StringBuffer();
DebugState ds = getDebugState(thread);
sb.append( "stack traceback:" );
DebugInfo di = ds.getDebugInfo(level);
if ( di != null ) {
sb.append( "\n\t" );
sb.append( di.sourceline() );
sb.append( " in " );
while ( (di = ds.getDebugInfo(++level)) != null ) {
sb.append( di.tracename() );
sb.append( "\n\t" );
sb.append( di.sourceline() );
sb.append( " in " );
}
sb.append( "main chunk" );
}
return sb.toString();
return info;
}
/**
* Get file and line for the nearest calling closure.
* @return String identifying the file and line of the nearest lua closure,
* or the function name of the Java call if no closure is being called.
*/
public static String fileline() {
DebugState ds = getDebugState(LuaThread.getRunning());
DebugInfo di;
for ( int i=0, n=ds.debugCalls; i<n; i++ ) {
di = ds.getDebugInfo(i);
if ( di != null && di.func.isclosure() )
return di.sourceline();
}
return fileline(0);
}
/**
* Get file and line for a particular level, even if it is a java function.
*
* @param level 0-based index of level to get
* @return String containing file and line info if available
*/
public static String fileline(int level) {
DebugState ds = getDebugState(LuaThread.getRunning());
DebugInfo di = ds.getDebugInfo(level);
return di!=null? di.sourceline(): null;
public static String sourceshort(Prototype p) {
String name = p.source.tojstring();
if ( name.startsWith("@") || name.startsWith("=") )
name = name.substring(1);
else if ( name.startsWith("\033") )
name = "binary string";
return name;
}
// =======================================================
@@ -700,114 +427,10 @@ public class DebugLib extends VarArgFunction {
if (!x) throw new RuntimeException("lua_assert failed");
}
// return StrValue[] { name, namewhat } if found, null if not
static LuaString[] getobjname(DebugInfo di, int lastpc, int reg) {
if (di.closure == null)
return null; /* Not a Lua function? */
Prototype p = di.closure.p;
int pc = di.pc; // currentpc(L, ci);
LuaString name = p.getlocalname(reg + 1, pc);
if (name != null) /* is a local? */
return new LuaString[] { name, LOCAL };
/* else try symbolic execution */
pc = findsetreg(p, lastpc, reg);
if (pc != -1) { /* could find instruction? */
int i = p.code[pc];
switch (Lua.GET_OPCODE(i)) {
case Lua.OP_MOVE: {
int a = Lua.GETARG_A(i);
int b = Lua.GETARG_B(i); /* move from `b' to `a' */
if (b < a)
return getobjname(di, pc, b); /* get name for `b' */
break;
}
case Lua.OP_GETTABUP:
case Lua.OP_GETTABLE: {
int k = Lua.GETARG_C(i); /* key index */
int t = Lua.GETARG_Bx(i); /* table index */
LuaString vn = (Lua.GET_OPCODE(i) == Lua.OP_GETTABLE) /* name of indexed variable */
? p.getlocalname(t + 1, pc)
: (t < p.upvalues.length ? p.upvalues[t].name : QMARK);
name = kname(p, k);
return new LuaString[] { name, vn.eq_b(ENV)? GLOBAL: FIELD };
}
case Lua.OP_GETUPVAL: {
int u = Lua.GETARG_B(i); /* upvalue index */
name = u < p.upvalues.length ? p.upvalues[u].name : QMARK;
return new LuaString[] { name, UPVALUE };
}
case Lua.OP_LOADK:
case Lua.OP_LOADKX: {
int b = (Lua.GET_OPCODE(i) == Lua.OP_LOADK) ? Lua.GETARG_Bx(i)
: Lua.GETARG_Ax(p.code[pc + 1]);
if (p.k[b].isstring()) {
name = p.k[b].strvalue();
return new LuaString[] { name, CONSTANT };
}
break;
}
case Lua.OP_SELF: {
int k = Lua.GETARG_C(i); /* key index */
name = kname(p, k);
return new LuaString[] { name, METHOD };
}
default:
break;
}
}
return null; /* no useful name found */
private LuaString[] getfunckind(LuaFunction f) {
return null;
}
static LuaString kname(Prototype p, int c) {
if (Lua.ISK(c) && p.k[Lua.INDEXK(c)].isstring())
return p.k[Lua.INDEXK(c)].strvalue();
else
return QMARK;
}
static boolean checkreg(Prototype pt,int reg) {
return (reg < pt.maxstacksize);
}
static boolean precheck(Prototype pt) {
if (!(pt.maxstacksize <= MAXSTACK)) return false;
lua_assert(pt.numparams <= pt.maxstacksize);
// if (!(pt.upvalues.length <= pt.nups)) return false;
if (!(pt.lineinfo.length == pt.code.length || pt.lineinfo.length == 0)) return false;
if (!(Lua.GET_OPCODE(pt.code[pt.code.length - 1]) == Lua.OP_RETURN)) return false;
return true;
}
static boolean checkopenop(Prototype pt,int pc) {
int i = pt.code[(pc)+1];
switch (Lua.GET_OPCODE(i)) {
case Lua.OP_CALL:
case Lua.OP_TAILCALL:
case Lua.OP_RETURN:
case Lua.OP_SETLIST: {
if (!(Lua.GETARG_B(i) == 0)) return false;
return true;
}
default:
return false; /* invalid instruction after an open call */
}
}
//static int checkArgMode (Prototype pt, int r, enum OpArgMask mode) {
static boolean checkArgMode (Prototype pt, int r, int mode) {
switch (mode) {
case Lua.OpArgN: if (!(r == 0)) return false; break;
case Lua.OpArgU: break;
case Lua.OpArgR: checkreg(pt, r); break;
case Lua.OpArgK:
if (!(Lua.ISK(r) ? Lua.INDEXK(r) < pt.k.length : r < pt.maxstacksize)) return false;
break;
}
return true;
}
/*
** try to find last instruction before 'lastpc' that modified register 'reg'
@@ -856,4 +479,5 @@ public class DebugLib extends VarArgFunction {
return setreg;
}
}

View File

@@ -25,6 +25,7 @@ import java.io.ByteArrayOutputStream;
import java.io.EOFException;
import java.io.IOException;
import org.luaj.vm2.Globals;
import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
@@ -212,10 +213,10 @@ public class IoLib extends OneArgFunction {
LuaTable filemethods;
public IoLib() {
}
protected Globals globals;
public LuaValue call(LuaValue env) {
globals = env.checkglobals();
// io lib functions
LuaTable t = new LuaTable();
@@ -237,7 +238,7 @@ public class IoLib extends OneArgFunction {
// return the table
env.set("io", t);
PackageLib.instance.LOADED.set("io", t);
env.get("package").get("loaded").set("io", t);
return t;
}

View File

@@ -106,7 +106,7 @@ public class MathLib extends OneArgFunction {
math.set("sqrt", new sqrt());
math.set("tan", new tan());
env.set("math", math);
PackageLib.instance.LOADED.set("math", math);
env.get("package").get("loaded").set("math", math);
return math;
}

View File

@@ -116,7 +116,7 @@ public class OsLib extends VarArgFunction {
LuaTable t = new LuaTable();
bind(t, this.getClass(), NAMES, CLOCK);
env.set("os", t);
PackageLib.instance.LOADED.set("os", t);
env.get("package").get("loaded").set("os", t);
return t;
}

View File

@@ -22,12 +22,10 @@
package org.luaj.vm2.lib;
import java.io.InputStream;
import java.io.PrintStream;
import org.luaj.vm2.LuaFunction;
import org.luaj.vm2.Globals;
import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaThread;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
@@ -67,14 +65,11 @@ public class PackageLib extends OneArgFunction {
public static String DEFAULT_LUA_PATH = "?.lua";
public InputStream STDIN = null;
public PrintStream STDOUT = System.out;
Globals globals;
public LuaTable LOADED;
public LuaTable PACKAGE;
/** Most recent instance of PackageLib */
public static PackageLib instance;
/** Loader that loads from preload table if found there */
public LuaValue preload_searcher;
@@ -101,11 +96,10 @@ public class PackageLib extends OneArgFunction {
private static final String FILE_SEP = System.getProperty("file.separator");
public PackageLib() {
instance = this;
}
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(),
@@ -284,7 +278,7 @@ public class PackageLib extends OneArgFunction {
LuaString filename = v.arg1().strvalue();
// Try to load the file.
v = BaseLib.loadFile(filename.tojstring(), "bt", LuaValue._G);
v = globals.loadFile(filename.tojstring());
if ( v.arg1().isfunction() )
return LuaValue.varargsOf(v.arg1(), filename);
@@ -316,7 +310,7 @@ public class PackageLib extends OneArgFunction {
}
// try opening the file
InputStream is = BaseLib.FINDER.findResource(filename);
InputStream is = globals.FINDER.findResource(filename);
if (is != null) {
try { is.close(); } catch ( java.io.IOException ioe ) {}
return valueOf(filename);

View File

@@ -78,7 +78,7 @@ public class StringLib extends OneArgFunction {
instance = t;
if ( LuaString.s_metatable == null )
LuaString.s_metatable = tableOf( new LuaValue[] { INDEX, t } );
PackageLib.instance.LOADED.set("string", t);
env.get("package").get("loaded").set("string", t);
return t;
}

View File

@@ -67,16 +67,12 @@ import org.luaj.vm2.lib.LibFunction;
*/
public class JmeIoLib extends IoLib {
public JmeIoLib() {
super();
}
protected File wrapStdin() throws IOException {
return new FileImpl(BaseLib.instance.STDIN);
return new FileImpl(globals.STDIN);
}
protected File wrapStdout() throws IOException {
return new FileImpl(BaseLib.instance.STDOUT);
return new FileImpl(globals.STDOUT);
}
protected File openFile( String filename, boolean readMode, boolean appendMode, boolean updateMode, boolean binaryMode ) throws IOException {

View File

@@ -22,6 +22,7 @@
package org.luaj.vm2.lib.jme;
import org.luaj.vm2.compiler.LuaC;
import org.luaj.vm2.Globals;
import org.luaj.vm2.LoadState;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaThread;
@@ -53,7 +54,7 @@ import org.luaj.vm2.lib.TableLib;
* <p>
* A simple example of initializing globals and using them from Java is:
* <pre> {@code
* LuaValue _G = JmePlatform.standardGlobals();
* Globals _G = JmePlatform.standardGlobals();
* _G.get("print").call(LuaValue.valueOf("hello, world"));
* } </pre>
* <p>
@@ -71,6 +72,7 @@ import org.luaj.vm2.lib.TableLib;
* <p>
* The standard globals will contain all standard libraries in their JME flavors:
* <ul>
* <li>{@link Globals}</li>
* <li>{@link BaseLib}</li>
* <li>{@link PackageLib}</li>
* <li>{@link Bit32Lib}</li>
@@ -101,9 +103,8 @@ public class JmePlatform {
* @see JsePlatform
* @see JmePlatform
*/
public static LuaTable standardGlobals() {
LuaTable _G = new LuaTable();
LuaValue._G = _G;
public static Globals standardGlobals() {
Globals _G = new Globals();
_G.load(new BaseLib());
_G.load(new PackageLib());
_G.load(new Bit32Lib());
@@ -114,6 +115,7 @@ public class JmePlatform {
_G.load(new CoroutineLib());
_G.load(new JmeIoLib());
LuaC.install();
_G.compiler = LuaC.instance;
return _G;
}
@@ -125,8 +127,8 @@ public class JmePlatform {
* @see JmePlatform
* @see DebugLib
*/
public static LuaTable debugGlobals() {
LuaTable _G = standardGlobals();
public static Globals debugGlobals() {
Globals _G = standardGlobals();
_G.load(new DebugLib());
return _G;
}

View File

@@ -67,11 +67,14 @@ import org.luaj.vm2.lib.ResourceFinder;
public class JseBaseLib extends org.luaj.vm2.lib.BaseLib {
/** Construct a JSE base library instance */
public JseBaseLib() {
STDIN = System.in;
/** Extend the library loading to set the default value for {@link Globals.STDIN} */
public LuaValue call(LuaValue env) {
super.call(env);
env.checkglobals().STDIN = System.in;
return env;
}
/**
* Try to open a file in the current working directory,
* or fall back to base opener if not found.

View File

@@ -67,16 +67,12 @@ import org.luaj.vm2.lib.LibFunction;
*/
public class JseIoLib extends IoLib {
public JseIoLib() {
super();
}
protected File wrapStdin() throws IOException {
return new FileImpl(BaseLib.instance.STDIN);
return new FileImpl(globals.STDIN);
}
protected File wrapStdout() throws IOException {
return new FileImpl(BaseLib.instance.STDOUT);
return new FileImpl(globals.STDOUT);
}
protected File openFile( String filename, boolean readMode, boolean appendMode, boolean updateMode, boolean binaryMode ) throws IOException {

View File

@@ -21,14 +21,16 @@
******************************************************************************/
package org.luaj.vm2.lib.jse;
import org.luaj.vm2.compiler.LuaC;
import org.luaj.vm2.Globals;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaThread;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.compiler.LuaC;
import org.luaj.vm2.lib.Bit32Lib;
import org.luaj.vm2.lib.CoroutineLib;
import org.luaj.vm2.lib.DebugLib;
import org.luaj.vm2.lib.PackageLib;
import org.luaj.vm2.lib.ResourceFinder;
import org.luaj.vm2.lib.StringLib;
import org.luaj.vm2.lib.TableLib;
@@ -40,13 +42,13 @@ import org.luaj.vm2.lib.TableLib;
* <p>
* A simple example of initializing globals and using them from Java is:
* <pre> {@code
* LuaValue _G = JsePlatform.standardGlobals();
* Globals _G = JsePlatform.standardGlobals();
* _G.get("print").call(LuaValue.valueOf("hello, world"));
* } </pre>
* <p>
* Once globals are created, a simple way to load and run a script is:
* <pre> {@code
* LoadState.load( new FileInputStream("main.lua"), "main.lua", _G ).call();
* _G.load( new FileInputStream("main.lua"), "main.lua" ).call();
* } </pre>
* <p>
* although {@code require} could also be used:
@@ -58,6 +60,7 @@ import org.luaj.vm2.lib.TableLib;
* <p>
* The standard globals will contain all standard libraries plus {@code luajava}:
* <ul>
* <li>{@link Globals}</li>
* <li>{@link JseBaseLib}</li>
* <li>{@link PackageLib}</li>
* <li>{@link Bit32Lib}</li>
@@ -87,9 +90,8 @@ public class JsePlatform {
* @see JsePlatform
* @see JmePlatform
*/
public static LuaTable standardGlobals() {
LuaTable _G = new LuaTable();
LuaValue._G = _G;
public static Globals standardGlobals() {
Globals _G = new Globals();
_G.load(new JseBaseLib());
_G.load(new PackageLib());
_G.load(new Bit32Lib());
@@ -101,6 +103,7 @@ public class JsePlatform {
_G.load(new JseOsLib());
_G.load(new LuajavaLib());
LuaC.install();
_G.compiler = LuaC.instance;
return _G;
}
@@ -112,8 +115,8 @@ public class JsePlatform {
* @see JmePlatform
* @see DebugLib
*/
public static LuaTable debugGlobals() {
LuaTable _G = standardGlobals();
public static Globals debugGlobals() {
Globals _G = standardGlobals();
_G.load(new DebugLib());
return _G;
}

View File

@@ -102,7 +102,7 @@ public class LuajavaLib extends VarArgFunction {
LuaTable t = new LuaTable();
bind( t, LuajavaLib.class, NAMES, BINDCLASS );
env.set("luajava", t);
PackageLib.instance.LOADED.set("luajava", t);
env.get("package").get("loaded").set("luajava", t);
return t;
}
case BINDCLASS: {

View File

@@ -35,18 +35,14 @@ public class JavaLoader extends ClassLoader {
public JavaLoader() {
}
public LuaFunction load( Prototype p, String classname, String filename ) {
public LuaFunction load( Prototype p, String classname, String filename, LuaValue env ) {
JavaGen jg = new JavaGen( p, classname, filename );
return load( jg );
return load( jg, env );
}
public LuaFunction load( JavaGen jg ) {
public LuaFunction load( JavaGen jg, LuaValue env ) {
include( jg );
return load( jg.classname );
}
public LuaFunction load(String classname) {
return load(classname, LuaValue._G);
return load( jg.classname, env );
}
public LuaFunction load(String classname, LuaValue env) {

View File

@@ -100,7 +100,7 @@ public class LuaJC implements LuaCompiler {
String classname = toStandardJavaClassName( name );
String luaname = toStandardLuaFileName( name );
JavaLoader loader = new JavaLoader();
return loader.load(p, classname, luaname);
return loader.load(p, classname, luaname, env);
}
private static String toStandardJavaClassName( String luachunkname ) {

View File

@@ -24,9 +24,6 @@ package org.luaj.vm2;
import java.io.IOException;
import java.io.InputStream;
import org.luaj.vm2.compiler.LuaC;
import org.luaj.vm2.lib.BaseLib;
/**
* Test argument type check errors
@@ -47,7 +44,7 @@ public class ErrorsTest extends ScriptDrivenTest {
}
public void testBaseLibArgs() {
BaseLib.instance.STDIN = new InputStream() {
globals.STDIN = new InputStream() {
public int read() throws IOException {
return -1;
}

View File

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

View File

@@ -56,7 +56,7 @@ public class LuaOperationsTest extends TestCase {
private final LuaValue stringdouble = LuaValue.valueOf(samplestringdouble);
private final LuaTable table = LuaValue.listOf( new LuaValue[] { LuaValue.valueOf("aaa"), LuaValue.valueOf("bbb") } );
private final LuaValue somefunc = new ZeroArgFunction() { public LuaValue call() { return NONE;}};
private final LuaThread thread = new LuaThread(somefunc);
private final LuaThread thread = new LuaThread(new Globals(), somefunc);
private final Prototype proto = new Prototype(1);
private final LuaClosure someclosure = new LuaClosure(proto,table);
private final LuaUserdata userdataobj = LuaValue.userdataOf(sampleobject);
@@ -146,7 +146,7 @@ public class LuaOperationsTest extends TestCase {
// set up suitable environments for execution
LuaValue aaa = LuaValue.valueOf("aaa");
LuaValue eee = LuaValue.valueOf("eee");
LuaTable _G = org.luaj.vm2.lib.jse.JsePlatform.standardGlobals();
final Globals _G = org.luaj.vm2.lib.jse.JsePlatform.standardGlobals();
LuaTable newenv = LuaValue.tableOf( new LuaValue[] {
LuaValue.valueOf("a"), LuaValue.valueOf("aaa"),
LuaValue.valueOf("b"), LuaValue.valueOf("bbb"), } );

View File

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

View File

@@ -36,6 +36,7 @@ import org.luaj.vm2.lib.jse.JsePlatform;
public class OrphanedThreadTest extends TestCase {
Globals globals;
LuaThread luathread;
WeakReference luathr_ref;
LuaValue function;
@@ -113,7 +114,8 @@ public class OrphanedThreadTest extends TestCase {
}
private void doTest(LuaValue status2, LuaValue value2) throws Exception {
luathread = new LuaThread(function);
globals = JsePlatform.standardGlobals();
luathread = new LuaThread(globals, function);
luathr_ref = new WeakReference(luathread);
func_ref = new WeakReference(function);
assertNotNull(luathr_ref.get());
@@ -142,40 +144,40 @@ public class OrphanedThreadTest extends TestCase {
}
static class NormalFunction extends OneArgFunction {
class NormalFunction extends OneArgFunction {
public LuaValue call(LuaValue arg) {
System.out.println("in normal.1, arg is "+arg);
arg = LuaThread.yield(ONE).arg1();
arg = globals.yield(ONE).arg1();
System.out.println("in normal.2, arg is "+arg);
arg = LuaThread.yield(ZERO).arg1();
arg = globals.yield(ZERO).arg1();
System.out.println("in normal.3, arg is "+arg);
return NONE;
}
}
static class EarlyCompletionFunction extends OneArgFunction {
class EarlyCompletionFunction extends OneArgFunction {
public LuaValue call(LuaValue arg) {
System.out.println("in early.1, arg is "+arg);
arg = LuaThread.yield(ONE).arg1();
arg = globals.yield(ONE).arg1();
System.out.println("in early.2, arg is "+arg);
return ZERO;
}
}
static class AbnormalFunction extends OneArgFunction {
class AbnormalFunction extends OneArgFunction {
public LuaValue call(LuaValue arg) {
System.out.println("in abnormal.1, arg is "+arg);
arg = LuaThread.yield(ONE).arg1();
arg = globals.yield(ONE).arg1();
System.out.println("in abnormal.2, arg is "+arg);
error("abnormal condition");
return ZERO;
}
}
static class ClosureFunction extends OneArgFunction {
class ClosureFunction extends OneArgFunction {
public LuaValue call(LuaValue arg) {
System.out.println("in abnormal.1, arg is "+arg);
arg = LuaThread.yield(ONE).arg1();
arg = globals.yield(ONE).arg1();
System.out.println("in abnormal.2, arg is "+arg);
error("abnormal condition");
return ZERO;

View File

@@ -47,7 +47,7 @@ public class ScriptDrivenTest extends TestCase implements ResourceFinder {
private final PlatformType platform;
private final String subdir;
private LuaTable _G;
protected Globals globals;
static final String zipdir = "test/lua/";
static final String zipfile = "luaj3.0-tests.zip";
@@ -63,10 +63,10 @@ public class ScriptDrivenTest extends TestCase implements ResourceFinder {
default:
case JSE:
case LUAJIT:
_G = org.luaj.vm2.lib.jse.JsePlatform.debugGlobals();
globals = org.luaj.vm2.lib.jse.JsePlatform.standardGlobals();
break;
case JME:
_G = org.luaj.vm2.lib.jme.JmePlatform.debugGlobals();
globals = org.luaj.vm2.lib.jme.JmePlatform.standardGlobals();
break;
}
}
@@ -75,7 +75,7 @@ public class ScriptDrivenTest extends TestCase implements ResourceFinder {
protected void setUp() throws Exception {
super.setUp();
initGlobals();
BaseLib.FINDER = this;
globals.FINDER = this;
}
// ResourceFinder implementation.
@@ -147,13 +147,13 @@ public class ScriptDrivenTest extends TestCase implements ResourceFinder {
try {
// override print()
final ByteArrayOutputStream output = new ByteArrayOutputStream();
final PrintStream oldps = BaseLib.instance.STDOUT;
final PrintStream oldps = globals.STDOUT;
final PrintStream ps = new PrintStream( output );
BaseLib.instance.STDOUT = ps;
globals.STDOUT = ps;
// run the script
try {
LuaValue chunk = loadScript(testName, _G);
LuaValue chunk = loadScript(testName, globals);
chunk.call(LuaValue.valueOf(platform.toString()));
ps.flush();
@@ -164,7 +164,7 @@ public class ScriptDrivenTest extends TestCase implements ResourceFinder {
assertEquals(expectedOutput, actualOutput);
} finally {
BaseLib.instance.STDOUT = oldps;
globals.STDOUT = oldps;
ps.close();
}
} catch ( IOException ioe ) {

View File

@@ -56,8 +56,8 @@ public class TypeTest extends TestCase {
private final LuaValue stringdouble = LuaValue.valueOf(samplestringdouble);
private final LuaTable table = LuaValue.tableOf();
private final LuaFunction somefunc = new ZeroArgFunction() { public LuaValue call() { return NONE;}};
private final LuaThread thread = new LuaThread(somefunc);
private final LuaClosure someclosure = new LuaClosure(new Prototype());
private final LuaThread thread = new LuaThread(new Globals(), somefunc);
private final LuaClosure someclosure = new LuaClosure(new Prototype(), new LuaTable());
private final LuaUserdata userdataobj = LuaValue.userdataOf(sampleobject);
private final LuaUserdata userdatacls = LuaValue.userdataOf(sampledata);