emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Edebug & lexical scope


From: egnarts-ms
Subject: Edebug & lexical scope
Date: Fri, 18 May 2012 06:30:00 -0700 (PDT)

Hi,

Currently (Emacs 24.0.97) Edebug cannot evaluate lexical variables when it
is suspended (by "e" or "M-:"). To be more precise: when you have
"lexical-binding" variable set to non-nil in a buffer, and you instrument a
defun from this buffer, and then debug it with Edebug, and you're suspended
at some stop point inside this defun, you cannot see the value of a
(lexical) variable.

Example:

(defun solve-square-equation (a b c)
  (if (= a 0.0)
      (/ (- c) b)
    (let ((D (- (* b b) (* 4 (* a c)))))
      (cond
        ((= D 0.0)
         (/ (- b) (* 2 a)))
        ((< D 0.0)
         nil)
        (t
         (let ((sqD (sqrt D)))
           (list (/ (+ (- b) sqD) (* 2 a))
                 (/ (- (- b) sqD) (* 2 a)))))))))


It is impossible to see the value of D when the program is stopped in any of
the cond's branches.

The reason for that is simple: when you are asking Edebug to evaluate
something, it does so by calling `eval', and the latter just binds
Qinternal_interpreter_environment (internal variable holding the current
lexical environment, or nil in dynamic scoping) to "(t)" (provided that
lexical scoping is on). So the values of all lexical variables are lost.

Nevertheless, when you press "G" or "c", the execution resumes and those
lexical variables are perfectly accessible.  By all evidence, it is just due
to the fact that Qinternal_interpreter_environment gets unbound, and takes
on its previous value (which is what we would also like to access when
evaluating by "M-:").

It seems that I've managed to make M-: evaluate lexical variables. I've
created the following C subroutine; it does the same job as `eval', but
first of all it scans "specpdl" (the stack of bindings of symbols) searching
for the most recent value of Qinternal_interpreter_environment which is not
eq to nil. (That is, we want to find out the most recent lexical environment
to which Qinternal_interpreter_environment was bound by some code upward the
stack.) If that value is found, Qinternal_interpreter_environment gets bound
to it again, and usual `eval_sub' is called. Otherwise, `eval_sub' is called
as well, but this would be in dynamic environment now.

DEFUN ("eval-in-most-recent-lex-env", Seval_in_mo....) (Lisp_Object form)
  {
    struct specbinding* ptr = specpdl_ptr;
    while (ptr != specpdl)
      {
        if (EQ (ptr->symbol, Qinternal_interpreter_environment) &&
            !EQ (ptr->old_value, Qnil))
         {
           break;
         }
       --ptr;
      }
    if (ptr != specpdl)
      {
        int count = SPECPDL_INDEX ();
        specbind (Qinternal_interpreter_environment, ptr->old_value);
        return unbind_to (count, eval_sub (form));
      }
    return eval_sub (form);
  }

The second step is pretty easy: there's a function named `edebug-eval'. One
should just change it to call `eval-in-most-recent-lex-env' rather than
`eval'.

That seems to work fine in Emacs 24.0.97 pretest.

I'd be very glad to hear any critics or comments.



Best regards,
  egnarts-ms.
-- 
View this message in context: 
http://old.nabble.com/Edebug---lexical-scope-tp33870303p33870303.html
Sent from the Emacs - Dev mailing list archive at Nabble.com.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]