Improve stack traces.

This commit is contained in:
James Roseborough
2012-09-20 14:39:11 +00:00
parent 9ae6767f76
commit 9666f40ad7

View File

@@ -184,7 +184,7 @@ public class DebugLib extends OneArgFunction {
Prototype p = c.p; Prototype p = c.p;
info.set(WHAT, LUA); info.set(WHAT, LUA);
info.set(SOURCE, p.source); info.set(SOURCE, p.source);
info.set(SHORT_SRC, valueOf(sourceshort(p))); info.set(SHORT_SRC, valueOf(shortsource(p)));
info.set(LINEDEFINED, valueOf(p.linedefined)); info.set(LINEDEFINED, valueOf(p.linedefined));
info.set(LASTLINEDEFINED, valueOf(p.lastlinedefined)); info.set(LASTLINEDEFINED, valueOf(p.lastlinedefined));
} else { } else {
@@ -470,6 +470,22 @@ public class DebugLib extends OneArgFunction {
return (CallStack) t.callstack; return (CallStack) t.callstack;
} }
static class DebugInfo {
String name; /* (n) */
String namewhat; /* (n) 'global', 'local', 'field', 'method' */
String what; /* (S) 'Lua', 'C', 'main', 'tail' */
String source; /* (S) */
int currentline; /* (l) */
int linedefined; /* (S) */
int lastlinedefined; /* (S) */
short nups; /* (u) number of upvalues */
short nparams;/* (u) number of parameters */
boolean isvararg; /* (u) */
boolean istailcall; /* (t) */
String short_src; /* (S) */
CallFrame cf; /* active function */
}
public static class CallStack { public static class CallStack {
final static CallFrame[] EMPTY = {}; final static CallFrame[] EMPTY = {};
CallFrame[] frame = EMPTY; CallFrame[] frame = EMPTY;
@@ -518,18 +534,18 @@ public class DebugLib extends OneArgFunction {
String traceback(int level) { String traceback(int level) {
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
sb.append( "stack traceback:" ); sb.append( "stack traceback:" );
DebugLib.CallFrame c = getCallFrame(level); for (DebugLib.CallFrame c, prev = null; (c = getCallFrame(level++)) != null; prev = c ) {
if (c != null) { DebugInfo ar = c.getinfo("Slnt", prev);
prev = c;
sb.append("\n\t"); sb.append("\n\t");
sb.append( c.sourceline() ); sb.append( c.shortsource() );
sb.append( ':' );
if (c.currentline() > 0)
sb.append( c.currentline()+":" );
sb.append( " in " ); sb.append( " in " );
while ( (c = getCallFrame(++level)) != null ) { sb.append( c.tracename() );
sb.append( c.tracename() ); if (c.istailcall())
sb.append( "\n\t" ); sb.append("\n\t(...tail calls...)");
sb.append( c.sourceline() );
sb.append( " in " );
}
sb.append( "main chunk" );
} }
return sb.toString(); return sb.toString();
} }
@@ -545,8 +561,7 @@ public class DebugLib extends OneArgFunction {
if (frame[calls-i].f == func) if (frame[calls-i].f == func)
return frame[i]; return frame[i];
return null; return null;
} }
} }
static class CallFrame { static class CallFrame {
@@ -562,6 +577,9 @@ public class DebugLib extends OneArgFunction {
this.stack = stack; this.stack = stack;
this.tail = false; this.tail = false;
} }
public String shortsource() {
return f.isclosure()? DebugLib.shortsource(f.checkclosure().p): "[Java]";
}
void set(LuaFunction function) { void set(LuaFunction function) {
this.f = function; this.f = function;
} }
@@ -608,9 +626,17 @@ public class DebugLib extends OneArgFunction {
} }
String tracename() { String tracename() {
LuaString[] kind = getfuncname(this); LuaString[] kind = getfuncname(this);
if ( kind == null ) if (kind[0] == null)
return "function ?"; return "function "+kind[1].tojstring();
return "function "+kind[0].tojstring(); // if (kind[0] == M)
// return "main chunk";
if (kind[0] == JAVA)
return "function "+kind[1].tojstring();
return "function <"+shortsource()+":"+linedefined()+">";
}
private int linedefined() {
return f.isclosure()? f.checkclosure().p.linedefined: -1;
} }
LuaString getlocalname(int index) { LuaString getlocalname(int index) {
if ( !f.isclosure() ) return null; if ( !f.isclosure() ) return null;
@@ -622,7 +648,81 @@ public class DebugLib extends OneArgFunction {
boolean istailcall() { boolean istailcall() {
return tail; return tail;
} }
DebugInfo getinfo(String what, CallFrame previous) {
DebugInfo ar = new DebugInfo();
for (int i = 0, n = what.length(); i < n; ++i) {
switch (what.charAt(i)) {
case 'S':
if (f.isclosure()) {
Prototype p = f.checkclosure().p;
ar.source = p.source != null ? p.source.tojstring() : "=?";
ar.linedefined = p.linedefined;
ar.lastlinedefined = p.lastlinedefined;
ar.what = (ar.linedefined == 0) ? "main" : "Lua";
} else {
ar.source = "=[Java]";
ar.linedefined = -1;
ar.lastlinedefined = -1;
ar.what = "Java";
}
ar.short_src = chunkid(ar.source);
break;
case 'l':
ar.currentline = currentline();
break;
case 'u':
if (f.isclosure()) {
Prototype p = f.checkclosure().p;
ar.nups = (short) p.upvalues.length;
ar.nparams = (short) p.numparams;
ar.isvararg = p.is_vararg != 0;
} else {
ar.isvararg = true;
ar.nups = 0;
ar.nparams = 0;
}
break;
case 't':
ar.istailcall = this.tail;
break;
case 'n': {
/* calling function is a known Lua function? */
if (!tail && (previous != null && previous.f.isclosure())) {
LuaString[] kind = getfuncname(previous);
ar.name = String.valueOf(kind[0]);
ar.namewhat = String.valueOf(kind[1]);
}
else
ar.namewhat = null;
if (ar.namewhat == null) {
ar.namewhat = ""; /* not found */
ar.name = null;
}
break;
}
default:
break;
}
}
return null;
}
}
static String chunkid( String source ) {
if ( source.startsWith("=") )
return source.substring(1);
String end = "";
if ( source.startsWith("@") ) {
source = source.substring(1);
} else {
source = "[string \""+source;
end = "\"]";
}
int n = source.length() + end.length();
if ( n > 50 )
source = source.substring(0,50-end.length()-3) + "...";
return source + end;
} }
static LuaString findupvalue(LuaClosure c, int up) { static LuaString findupvalue(LuaClosure c, int up) {
@@ -635,7 +735,7 @@ public class DebugLib extends OneArgFunction {
return null; return null;
} }
public static String sourceshort(Prototype p) { public static String shortsource(Prototype p) {
String name = p.source.tojstring(); String name = p.source.tojstring();
if ( name.startsWith("@") || name.startsWith("=") ) if ( name.startsWith("@") || name.startsWith("=") )
name = name.substring(1); name = name.substring(1);