Make error message handler in xpcall per-thread instead of per-globals.

This commit is contained in:
James Roseborough
2013-12-31 00:44:55 +00:00
parent b0d52fe118
commit 03985ec7ee
5 changed files with 40 additions and 36 deletions

View File

@@ -910,6 +910,7 @@ Files are no longer hosted at LuaForge.
<li>Implement formatting with os.date(), and table argument for os.time().</li> <li>Implement formatting with os.date(), and table argument for os.time().</li>
<li>Refactor APIs related to compiling and loading scripts.</li> <li>Refactor APIs related to compiling and loading scripts.</li>
<li>Let errors thrown in debug hooks bubble up to the running coroutine.</li> <li>Let errors thrown in debug hooks bubble up to the running coroutine.</li>
<li>Make error function in xpcall per-thread instead of per-globals.</li>
</ul></td></tr> </ul></td></tr>
</table></td></tr></table> </table></td></tr></table>

View File

@@ -136,9 +136,6 @@ public class Globals extends LuaTable {
/** The DebugLib instance loaded into this Globals, or null if debugging is not enabled */ /** The DebugLib instance loaded into this Globals, or null if debugging is not enabled */
public DebugLib debuglib; public DebugLib debuglib;
/** The current error handler for this Globals */
public LuaValue errorfunc;
/** Interface for module that converts a Prototype into a LuaFunction with an environment. */ /** Interface for module that converts a Prototype into a LuaFunction with an environment. */
public interface Loader { public interface Loader {
/** Convert the prototype into a LuaFunction with the supplied environment. */ /** Convert the prototype into a LuaFunction with the supplied environment. */

View File

@@ -519,16 +519,18 @@ public class LuaClosure extends LuaFunction {
* @param msg the message to use in error hook processing. * @param msg the message to use in error hook processing.
* */ * */
String errorHook(String msg) { String errorHook(String msg) {
if (globals == null || globals.errorfunc == null) if (globals == null ) return msg;
return msg; final LuaThread running = globals.running;
LuaValue errfunc = globals.errorfunc; if (running == null) return msg;
globals.errorfunc = null; final LuaValue errfunc = running.errorfunc;
if (errfunc == null) return msg;
running.errorfunc = null;
try { try {
return errfunc.call( LuaValue.valueOf(msg) ).tojstring(); return errfunc.call( LuaValue.valueOf(msg) ).tojstring();
} catch ( Throwable t ) { } catch ( Throwable t ) {
return "error in error handling"; return "error in error handling";
} finally { } finally {
globals.errorfunc = errfunc; running.errorfunc = errfunc;
} }
} }
@@ -536,8 +538,6 @@ public class LuaClosure extends LuaFunction {
le.fileline = (p.source != null? p.source.tojstring(): "?") + ":" le.fileline = (p.source != null? p.source.tojstring(): "?") + ":"
+ (p.lineinfo != null && pc >= 0 && pc < p.lineinfo.length? String.valueOf(p.lineinfo[pc]): "?"); + (p.lineinfo != null && pc >= 0 && pc < p.lineinfo.length? String.valueOf(p.lineinfo[pc]): "?");
le.traceback = errorHook(le.getMessage()); le.traceback = errorHook(le.getMessage());
if (globals != null && globals.debuglib != null)
le.traceback = le.traceback + "\n" + globals.debuglib.traceback(le.level);
} }
private UpValue findupval(LuaValue[] stack, short idx, UpValue[] openups) { private UpValue findupval(LuaValue[] stack, short idx, UpValue[] openups) {
@@ -548,7 +548,7 @@ public class LuaClosure extends LuaFunction {
for (int i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
if (openups[i] == null) if (openups[i] == null)
return openups[i] = new UpValue(stack, idx); return openups[i] = new UpValue(stack, idx);
this.error("No space for upvalue"); error("No space for upvalue");
return null; return null;
} }

View File

@@ -93,8 +93,12 @@ public class LuaThread extends LuaValue {
public final Globals globals; public final Globals globals;
// Hook function control state used by debug lib. /** Hook function control state used by debug lib. */
public LuaValue hookfunc; public LuaValue hookfunc;
/** Error message handler for this thread, if any. */
public LuaValue errorfunc;
public boolean hookline; public boolean hookline;
public boolean hookcall; public boolean hookcall;
public boolean hookrtrn; public boolean hookrtrn;

View File

@@ -29,6 +29,7 @@ import org.luaj.vm2.Lua;
import org.luaj.vm2.LuaError; import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaString; import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaTable; import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaThread;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs; import org.luaj.vm2.Varargs;
@@ -213,7 +214,13 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
if (globals != null && globals.debuglib != null) if (globals != null && globals.debuglib != null)
globals.debuglib.onCall(this); globals.debuglib.onCall(this);
try { try {
return pcall(func,args.subargs(2),null); return varargsOf(TRUE, func.invoke(args.subargs(2)));
} catch ( LuaError le ) {
final String m = le.getMessage();
return varargsOf(FALSE, m!=null? valueOf(m): NIL);
} catch ( Exception e ) {
final String m = e.getMessage();
return varargsOf(FALSE, valueOf(m!=null? m: e.toString()));
} finally { } finally {
if (globals != null && globals.debuglib != null) if (globals != null && globals.debuglib != null)
globals.debuglib.onReturn(); globals.debuglib.onReturn();
@@ -353,13 +360,26 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
// "xpcall", // (f, err) -> result1, ... // "xpcall", // (f, err) -> result1, ...
final class xpcall extends VarArgFunction { final class xpcall extends VarArgFunction {
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
if (globals != null && globals.debuglib != null) final LuaThread t = globals.running;
globals.debuglib.onCall(this); final LuaValue preverror = t.errorfunc;
t.errorfunc = args.checkvalue(2);
try { try {
return pcall(args.arg1(),args.subargs(3),args.checkvalue(2));
} finally {
if (globals != null && globals.debuglib != null) if (globals != null && globals.debuglib != null)
globals.debuglib.onReturn(); globals.debuglib.onCall(this);
try {
return varargsOf(TRUE, args.arg1().invoke(args.subargs(3)));
} catch ( LuaError le ) {
final String m = le.getMessage();
return varargsOf(FALSE, m!=null? valueOf(m): NIL);
} catch ( Exception e ) {
final String m = e.getMessage();
return varargsOf(FALSE, valueOf(m!=null? m: e.toString()));
} finally {
if (globals != null && globals.debuglib != null)
globals.debuglib.onReturn();
}
} finally {
t.errorfunc = preverror;
} }
} }
} }
@@ -396,24 +416,6 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
return args.checktable(1).inext(args.arg(2)); return args.checktable(1).inext(args.arg(2));
} }
} }
public Varargs pcall(LuaValue func, Varargs args, LuaValue errorfunc) {
try {
LuaValue olderr = globals.errorfunc;
globals.errorfunc = errorfunc;
try {
return varargsOf(LuaValue.TRUE, func.invoke(args));
} finally {
globals.errorfunc = olderr;
}
} catch ( LuaError le ) {
String m = le.getMessage();
return varargsOf(FALSE, m!=null? valueOf(m): NIL);
} catch ( Exception e ) {
String m = e.getMessage();
return varargsOf(FALSE, valueOf(m!=null? m: e.toString()));
}
}
/** /**
* Load from a named file, returning the chunk or nil,error of can't load * Load from a named file, returning the chunk or nil,error of can't load