Move static variables used by libraries into explicit Globals object for better thread safety.
This commit is contained in:
93
src/core/org/luaj/vm2/Globals.java
Normal file
93
src/core/org/luaj/vm2/Globals.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 ) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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"), } );
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 ) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user