This JVMTI doesn't know Clojure source code from parsnip soup, I expect, so can't it be fooled into "thinking" that the bytecode it's interpreting came from a source with many more, shorter lines? So
(defn x [y z] (a (b (c)) ((d) e (f g)))) could be passed off to it as if it were (defn x [y z] (a (b (c)) ((d) e (f g)))) with breakpoints on (defn ...), (a ...), a, (b (c)), or b being passed to JVMTI as breakpoints on the first line of the latter formatting of the code; breakpoints on (c) or c the second line; breakpoints on (d) or d the third line; and breakpoints on e, (f g), f, or g the fourth line. Execution would halt at the breakpoint with the correct amount of evaluation done. (The bare letters are presumed to be self-evaluating literals or var lookups here, and the operators, other than defn, to be functions.) Breakpoints on a macro sexp would need to halt on the first evaluation of any of the expansion, and breakpoints on a macro argument would need to be carried through into the expansion. The special forms are mostly fairly obvious -- break on an if or its condition, for example, breaks before evaluating the condition; break on the then clause breaks after evaluating the condition, before evaluating the then clause, only if the condition was true; etc. Combined, those rules mean a breakpoint on a particular (cond ...) condition X would only trip if all the previous conditions were false, before evaluating condition X, and a breakpoint on the corresponding then clause only if all the preceding conditions were false but condition X was true, after evaluating X but before evaluating X's then clause, because it would end up attached to X's corresponding conditional or then clause (respectively) in the macro-expanded if-tree (>(sexp)< indicates breakpoint target): (cond (thing1) (dothis) (thing2) (dothat) >(thing3)< (dosomethingelse) :else (default)) should macroexpand to (if (thing1) (dothis) (if (thing2) (dothat) (if >(thing3)< (dosomethingelse) (if :else (default) (throw ( ... no matching clause blah blah ... [never actually executes in this case])))))) so the "(if >(thing3)<" line would be what JVMTI "thinks" is the breakpointed line in this case. The real issue I can foresee here would be if there's no way to make the "lines" seen by the breakpoint/debugging stuff be different from the "lines" used for error reporting (e.g. in stacktraces), as then *either* the "line" granularity for breakpoints is whole lines of your actual source code *or* stacktrace line numbers won't always correspond to what your editor shows for the problem line in your source code, for example if (default) threw a ClassCastException because "default" did not implement IFn in the above the stacktrace might point to line 8 when it was really line 5 of your (cond ...) expression (but line 8 of the (if ...) it macroexpanded to, and which was vertically spread out to put each distinct (as to what nontrivial evaluation has happened yet) sexp-based breakpoint position on its own line to please JVMTI). On Fri, Nov 8, 2013 at 12:53 AM, Colin Fleming <colin.mailingl...@gmail.com>wrote: > Right, sadly I believe this is impossible using JVMTI, although I'm far > from an expert. > > > On 8 November 2013 18:51, Cedric Greevey <cgree...@gmail.com> wrote: > >> Ideally, in a Lisp I'd think the unit of breakpoints would not be a line >> but instead an s-expression, tripping before evaluating the body of the >> expression. >> >> >> On Fri, Nov 8, 2013 at 12:24 AM, Colin Fleming < >> colin.mailingl...@gmail.com> wrote: >> >>> I'm slightly late to the discussion, sorry - currently moving cities. >>> Cursive does indeed have a stepping debugger which works well with Clojure, >>> although it's quite slow (I haven't been able to figure out why, yet - I >>> suspect Clojure adds a lot of line information to the bytecode). There have >>> also been some fairly annoying bugs with it which will be fixed in the next >>> drop. Here's more or less what it can do: >>> >>> 1. Standard stepping - step into, step over. Step out is flaky for >>> non-Java languages for some reason, I believe this is fixed in the new >>> version of IntelliJ (13, currently in beta, due to be released soon). >>> 2. Place breakpoints on any line. This generally works well but is >>> occasionally frustrating with Clojure since you can pack a lot on a line. >>> I've found chained sequence operations to be particularly difficult to >>> debug. This is really a JVM limitation since JVMTI is line-oriented. >>> 3. Breakpoints can be configured in various ways. Instead of >>> stopping you can configure them to print the value of an expression, or >>> to >>> stop only the current thread, or to stop all threads. >>> 4. Drop frame to go back in time, as long as you're not mutating any >>> global state. You're not, right? >>> 5. Look at locals up and down the stack, as long as you have locals >>> clearing disabled. >>> 6. For the next drop I'm going to add the ability to toggle locals >>> clearing in debug REPLs with a button in the REPL tool window. >>> 7. You can evaluate arbitrary Clojure expressions at any point in >>> the call stack. >>> 8. You can set a breakpoint on an arbitrary exception, and it will >>> pause *at the time the exception is thrown* and you can inspect locals >>> etc. >>> >>> I'm pretty sure all of this works, and I use most of it regularly. >>> Expression evaluation has been broken until the current dev build so I need >>> to test that things that depend on it work before promising them, but I'm >>> pretty sure they will. They include: >>> >>> 1. Watches. >>> 2. Being able to configure breakpoints to only stop when a >>> particular expression is true. >>> >>> For the next drop I'm planning to work a lot on the debugger and >>> document it all properly including some pretty animations, so I'll post to >>> the list when that is done. >>> >>> >>> On 8 November 2013 13:14, intronic <m...@pheasant.co.nz> wrote: >>> >>>> Why would a break function in clojure the language not be considered, >>>> a-la common-lisp? >>>> >>>> >>>> >>>> On Friday, 8 November 2013 09:31:55 UTC+10, Lee wrote: >>>>> >>>>> >>>>> On Nov 7, 2013, at 5:48 PM, Alex Miller wrote: >>>>> >>>>> > When you say "hit an error", I'm assuming you mean "clojure throws >>>>> an exception" and not "hit a breakpoint in a debugger" or something else. >>>>> >>>>> Yes -- I mean "clojure throws an exception." >>>>> >>>>> > >>>>> > I don't think there is one place where we could generically attach >>>>> locals info to a thrown exception. The JVM debugging interface (JVMTI - >>>>> http://docs.oracle.com/javase/7/docs/technotes/guides/jvmti/index.html) >>>>> can do an awful lot of things (including arbitrary class bytecode >>>>> transformation) so I would guess it's possible to build a java agent that >>>>> could do this (or to modify the Compiler to inject the right code at >>>>> compile time). Sounds like a fun project, but probably non-trivial. >>>>> >>>>> Too bad... unless someone wants to have that fun and then share it >>>>> with the rest of us :-). It still strikes me as really odd that such basic >>>>> and clearly desirable functionality, available forever in other >>>>> environments, should be so hard to come by. >>>>> >>>>> -Lee >>>> >>>> -- >>>> -- >>>> You received this message because you are subscribed to the Google >>>> Groups "Clojure" group. >>>> To post to this group, send email to clojure@googlegroups.com >>>> Note that posts from new members are moderated - please be patient with >>>> your first post. >>>> To unsubscribe from this group, send email to >>>> clojure+unsubscr...@googlegroups.com >>>> For more options, visit this group at >>>> http://groups.google.com/group/clojure?hl=en >>>> --- >>>> You received this message because you are subscribed to the Google >>>> Groups "Clojure" group. >>>> To unsubscribe from this group and stop receiving emails from it, send >>>> an email to clojure+unsubscr...@googlegroups.com. >>>> For more options, visit https://groups.google.com/groups/opt_out. >>>> >>> >>> -- >>> -- >>> You received this message because you are subscribed to the Google >>> Groups "Clojure" group. >>> To post to this group, send email to clojure@googlegroups.com >>> Note that posts from new members are moderated - please be patient with >>> your first post. >>> To unsubscribe from this group, send email to >>> clojure+unsubscr...@googlegroups.com >>> For more options, visit this group at >>> http://groups.google.com/group/clojure?hl=en >>> --- >>> You received this message because you are subscribed to the Google >>> Groups "Clojure" group. >>> To unsubscribe from this group and stop receiving emails from it, send >>> an email to clojure+unsubscr...@googlegroups.com. >>> For more options, visit https://groups.google.com/groups/opt_out. >>> >> >> -- >> -- >> You received this message because you are subscribed to the Google >> Groups "Clojure" group. >> To post to this group, send email to clojure@googlegroups.com >> Note that posts from new members are moderated - please be patient with >> your first post. >> To unsubscribe from this group, send email to >> clojure+unsubscr...@googlegroups.com >> For more options, visit this group at >> http://groups.google.com/group/clojure?hl=en >> --- >> You received this message because you are subscribed to the Google Groups >> "Clojure" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to clojure+unsubscr...@googlegroups.com. >> For more options, visit https://groups.google.com/groups/opt_out. >> > > -- > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with > your first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/groups/opt_out. > -- -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.