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
<[email protected]>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 <[email protected]> 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 <
>> [email protected]> 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 <[email protected]> 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 [email protected]
>>>> Note that posts from new members are moderated - please be patient with
>>>> your first post.
>>>> To unsubscribe from this group, send email to
>>>> [email protected]
>>>> 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 [email protected].
>>>> 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 [email protected]
>>> Note that posts from new members are moderated - please be patient with
>>> your first post.
>>> To unsubscribe from this group, send email to
>>> [email protected]
>>> 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 [email protected].
>>> 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 [email protected]
>> Note that posts from new members are moderated - please be patient with
>> your first post.
>> To unsubscribe from this group, send email to
>> [email protected]
>> 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 [email protected].
>> 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 [email protected]
> Note that posts from new members are moderated - please be patient with
> your first post.
> To unsubscribe from this group, send email to
> [email protected]
> 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 [email protected].
> 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 [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
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 [email protected].
For more options, visit https://groups.google.com/groups/opt_out.