Improve error and traceback reporting.

This commit is contained in:
James Roseborough
2010-05-08 23:50:51 +00:00
parent 482b6056a1
commit 8d16726e8b
5 changed files with 79 additions and 49 deletions

View File

@@ -431,13 +431,9 @@ public class LuaClosure extends LuaFunction {
} }
} }
} catch ( LuaError le ) { } catch ( LuaError le ) {
if ( p.lineinfo!=null && p.lineinfo.length>=pc )
le.addTracebackLine(p.source+":"+p.lineinfo[pc-1]);
throw le; throw le;
} catch ( Throwable t ) { } catch ( Throwable t ) {
LuaError le = new LuaError(t); LuaError le = new LuaError(t);
if ( p.lineinfo!=null && p.lineinfo.length>=pc )
le.addTracebackLine(p.source+":"+p.lineinfo[pc-1]);
throw le; throw le;
} finally { } finally {
LuaThread.onReturn(); LuaThread.onReturn();

View File

@@ -23,6 +23,8 @@ package org.luaj.vm2;
import java.util.Vector; import java.util.Vector;
import org.luaj.vm2.lib.DebugLib;
/** /**
* RuntimeException that is thrown and caught in response to a lua error. * RuntimeException that is thrown and caught in response to a lua error.
* This error does not indicate any problem with the normal functioning * This error does not indicate any problem with the normal functioning
@@ -34,7 +36,7 @@ public class LuaError extends RuntimeException {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private LuaValue msgvalue = null; private LuaValue msgvalue = null;
private Vector traceback = null; private String traceback;
/** Run the error hook if there is one */ /** Run the error hook if there is one */
private static String errorHook(String msg) { private static String errorHook(String msg) {
@@ -61,9 +63,10 @@ public class LuaError extends RuntimeException {
* *
* All errors generated from lua code should throw LuaError(String) instead. * All errors generated from lua code should throw LuaError(String) instead.
*/ */
public LuaError(Throwable cause) { public LuaError(Throwable cause) {
this( errorHook( "vm error: "+cause ) ); super( errorHook( addFileLine( "vm error: "+cause ) ) );
this.cause = cause; this.cause = cause;
this.traceback = DebugLib.traceback(1);
} }
/** /**
@@ -73,7 +76,8 @@ public class LuaError extends RuntimeException {
* @param message message to supply * @param message message to supply
*/ */
public LuaError(String message) { public LuaError(String message) {
super( errorHook( message ) ); super( errorHook( addFileLine( message ) ) );
this.traceback = DebugLib.traceback(1);
} }
/** /**
@@ -82,38 +86,35 @@ public class LuaError extends RuntimeException {
*/ */
public LuaError(String message, int level) { public LuaError(String message, int level) {
super( errorHook( addFileLine( message, level ) ) ); super( errorHook( addFileLine( message, level ) ) );
this.traceback = DebugLib.traceback(1);
} }
/** Add file and line info to a message */ /** Add file and line info to a message at a particular level */
private static String addFileLine( String message, int level ) { private static String addFileLine( String message, int level ) {
if ( message == null ) return message; if ( message == null ) return null;
LuaFunction f = LuaThread.getCallstackFunction(level); if ( level == 0 ) return message;
return f!=null? f+": "+message: message; String fileline = DebugLib.fileline(level-1);
} return fileline!=null? fileline+": "+message: message;
/** Get the message, including source line info if there is any */
public String getMessage() {
String msg = super.getMessage();
return msg!=null && traceback!=null? traceback.elementAt(0)+": "+msg: msg;
} }
/** Add a line of traceback info */ /** Add file and line info for the nearest enclosing closure */
public void addTracebackLine( String line ) { private static String addFileLine( String message ) {
if ( traceback == null ) { if ( message == null ) return null;
traceback = new Vector(); String fileline = DebugLib.fileline();
} return fileline!=null? fileline+": "+message: message;
traceback.addElement( line );
} }
// /** Get the message, including source line info if there is any */
// public String getMessage() {
// String msg = super.getMessage();
// return msg!=null && traceback!=null? traceback+": "+msg: msg;
// }
/** Print the message and stack trace */ /** Print the message and stack trace */
public void printStackTrace() { public void printStackTrace() {
System.out.println( toString() ); System.out.println( toString() );
if ( traceback != null ) { if ( traceback != null )
for ( int i=0,n=traceback.size(); i<n; i++ ) { System.out.println( traceback );
System.out.print("\t");
System.out.println(traceback.elementAt(i));
}
}
} }
/** /**

View File

@@ -351,7 +351,7 @@ public class LuaValue extends Varargs {
if ((!res.isnil()) || (tm = t.metatag(INDEX)).isnil()) if ((!res.isnil()) || (tm = t.metatag(INDEX)).isnil())
return res; return res;
} else if ((tm = t.metatag(INDEX)).isnil()) } else if ((tm = t.metatag(INDEX)).isnil())
t.typerror("index"); t.typerror("table");
if (tm.isfunction()) if (tm.isfunction())
return tm.call(t, key); return tm.call(t, key);
t = tm; t = tm;

View File

@@ -190,7 +190,7 @@ public class DebugLib extends VarArgFunction {
int stackpos = (closure.p.code[pc] >> 6) & 0xff; int stackpos = (closure.p.code[pc] >> 6) & 0xff;
return getobjname(this, stackpos); return getobjname(this, stackpos);
} }
public Object sourceline() { public String sourceline() {
if ( closure == null ) return func.tojstring(); if ( closure == null ) return func.tojstring();
String s = closure.p.source.tojstring(); String s = closure.p.source.tojstring();
int line = currentline(); int line = currentline();
@@ -209,7 +209,7 @@ public class DebugLib extends VarArgFunction {
return closure.p.getlocalname(index, pc); return closure.p.getlocalname(index, pc);
} }
public String tojstring() { public String tojstring() {
return sourceline()+": in "+tracename(); return tracename()+" "+sourceline();
} }
} }
@@ -605,10 +605,10 @@ public class DebugLib extends VarArgFunction {
static LuaValue _traceback(Varargs args) { static LuaValue _traceback(Varargs args) {
int a=1; int a=1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning(); LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
String message = args.optjstring(a++, "stack traceback:"); String message = args.optjstring(a++, null);
int level = args.optint(a++,1); int level = args.optint(a++,1);
String tb = DebugLib.traceback(thread, level); String tb = DebugLib.traceback(thread, level-1);
return valueOf(message+"\n"+tb); return valueOf(message!=null? message+"\n"+tb: tb);
} }
// =================== public utilities ==================== // =================== public utilities ====================
@@ -622,26 +622,59 @@ public class DebugLib extends VarArgFunction {
/** /**
* Get a traceback for a particular thread. * Get a traceback for a particular thread.
* @param thread * @param thread LuaThread to provide stack trace for
* @param level * @param level 0-based level to start reporting on
* @return * @return String containing the stack trace.
*/ */
public static String traceback(LuaThread thread, int level) { public static String traceback(LuaThread thread, int level) {
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
DebugState ds = getDebugState(thread); DebugState ds = getDebugState(thread);
DebugInfo di; sb.append( "stack traceback:" );
for ( int i=level, n=ds.debugCalls; i<n; i++ ) { DebugInfo di = ds.getDebugInfo(level);
di = ds.getDebugInfo(i); if ( di != null ) {
if ( di != null ) { sb.append( "\n\t" );
sb.append( "\t" ); sb.append( di.sourceline() );
sb.append( di.tojstring() ); sb.append( " in " );
if ( i<n ) while ( (di = ds.getDebugInfo(++level)) != null ) {
sb.append( "\n" ); sb.append( di.tracename() );
sb.append( "\n\t" );
sb.append( di.sourceline() );
sb.append( " in " );
} }
sb.append( "main chunk" );
} }
return sb.toString(); return sb.toString();
} }
/**
* 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
*/
public static String fileline(int level) {
DebugState ds = getDebugState(LuaThread.getRunning());
DebugInfo di = ds.getDebugInfo(level);
return di!=null? di.sourceline(): null;
}
// ======================================================= // =======================================================
static void lua_assert(boolean x) { static void lua_assert(boolean x) {

View File

@@ -64,7 +64,7 @@ public class lua {
public static void main( String[] args ) throws IOException { public static void main( String[] args ) throws IOException {
// new lua state // new lua state
_G = JsePlatform.standardGlobals(); _G = JsePlatform.debugGlobals();
LuaC.install(); LuaC.install();
// process args // process args