"place 2" below enters the debugger instead of raising the Java error specified by "place 0". Does anyone know if that's a bug in ABCL, or if I'm doing something wrong?
import org.armedbear.lisp.*; public class TestDebugger { public static void main(String[] args) { Interpreter interp = Interpreter.createInstance(); Symbol.DEBUGGER_HOOK.setSymbolValue( Packages.findPackage("SYSTEM") .findSymbol("%DEBUGGER-HOOK-FUNCTION") //place 0 .getSymbolFunction()); String exp = "(f 1)"; //a non-existent function try { interp.eval(exp); //place 1 } catch (Throwable e) {} interp.eval(exp); //place 2 p("end"); } static void p(Object o) {System.out.println(o);} }
Observations: 1. "place 1" does not enter the debugger, but correctly raises an exception. Why? It's no different from "place 2". 2. If variable "exp" is "(length 1)", then "place2" correctly causes the program to terminate immediately due to an exception. So it's just undefined functions that appear to be problematic, in that they produce the debugger.
Some (unsatisfactory) theories I have:
0. At "place 1", debug.lisp #'run-hook has re-bound *debugger-hook* to NIL. My hook raising an exception causes #'run-hook's progv to not complete. So the *debugger-hook* is left as NIL, causing the debugger to be entered at "place 2". 1. restart.lisp #'undefined-function-called calls "loop", which is a problem. 2. Or maybe it's that it establishes restarts, which is a problem. By comparison, in the "Observation 2" experiment above, there are no active restarts when my *debugger-hook* is called. 3. If I don't call eval directly, but do it through a wrapper such as this: static LispObject eval(String e) { LispThread th = LispThread.currentThread(); SpecialBindingsMark mark = th.markSpecialBindings(); try {return interpreter.eval(e);} finally {th.resetSpecialBindings(mark);} } then "place 2" above will correctly raise an exception instead of entering the debugger. But I don't understand this very well at all, so don't plan to do this.
Also, I'd said before that I suspected that interpreter.eval(...) was handled differently from someSymbol.execute(...) but my tests have shown that not to be the case at all.
It's specifically the second time onwards that you call an undefined function that lands you in the debugger.
Thanks for reading, and I'd love to hear if any of you have dealt with this before.
Vibhu