aboutsummaryrefslogtreecommitdiffstats
path: root/src/eval.c
diff options
context:
space:
mode:
authorStefan Monnier2013-07-26 03:38:18 -0400
committerStefan Monnier2013-07-26 03:38:18 -0400
commit56ea72917a7a700e29cf6c115fd1cd75ad782e9e (patch)
tree1a9220717c6333b376d45ebc044ad8ed71cfda37 /src/eval.c
parentf6b1502430653fac080f76a08edd2eb690f92146 (diff)
downloademacs-56ea72917a7a700e29cf6c115fd1cd75ad782e9e.tar.gz
emacs-56ea72917a7a700e29cf6c115fd1cd75ad782e9e.zip
Add support for lexical variables to the debugger's `e' command.
* lisp/emacs-lisp/debug.el (debug): Don't let-bind the debugger-outer-* vars, except for debugger-outer-match-data. (debugger-frame-number): Move check for "on a function call" from callers into it. Add `skip-base' argument. (debugger-frame, debugger-frame-clear): Simplify accordingly. (debugger-env-macro): Only reset the state stored in non-variables, i.e. current-buffer and match-data. (debugger-eval-expression): Rewrite using backtrace-eval. * lisp/subr.el (internal--called-interactively-p--get-frame): Remove. (called-interactively-p): * lisp/emacs-lisp/edebug.el (edebug--called-interactively-skip): Use the new `base' arg of backtrace-frame instead. * src/eval.c (set_specpdl_old_value): New function. (unbind_to): Minor simplification. (get_backtrace_frame): New function. (Fbacktrace_frame): Use it. Add `base' argument. (backtrace_eval_unrewind, Fbacktrace_eval): New functions. (syms_of_eval): Export backtrace-eval. * src/xterm.c (x_focus_changed): Simplify.
Diffstat (limited to 'src/eval.c')
-rw-r--r--src/eval.c169
1 files changed, 146 insertions, 23 deletions
diff --git a/src/eval.c b/src/eval.c
index 6cb2b7a92b8..e55a3b259e0 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -138,6 +138,13 @@ specpdl_old_value (union specbinding *pdl)
138 return pdl->let.old_value; 138 return pdl->let.old_value;
139} 139}
140 140
141static void
142set_specpdl_old_value (union specbinding *pdl, Lisp_Object val)
143{
144 eassert (pdl->kind >= SPECPDL_LET);
145 pdl->let.old_value = val;
146}
147
141static Lisp_Object 148static Lisp_Object
142specpdl_where (union specbinding *pdl) 149specpdl_where (union specbinding *pdl)
143{ 150{
@@ -3301,6 +3308,8 @@ unbind_to (ptrdiff_t count, Lisp_Object value)
3301 case SPECPDL_UNWIND_VOID: 3308 case SPECPDL_UNWIND_VOID:
3302 specpdl_ptr->unwind_void.func (); 3309 specpdl_ptr->unwind_void.func ();
3303 break; 3310 break;
3311 case SPECPDL_BACKTRACE:
3312 break;
3304 case SPECPDL_LET: 3313 case SPECPDL_LET:
3305 /* If variable has a trivial value (no forwarding), we can 3314 /* If variable has a trivial value (no forwarding), we can
3306 just set it. No need to check for constant symbols here, 3315 just set it. No need to check for constant symbols here,
@@ -3315,27 +3324,20 @@ unbind_to (ptrdiff_t count, Lisp_Object value)
3315 Fset_default (specpdl_symbol (specpdl_ptr), 3324 Fset_default (specpdl_symbol (specpdl_ptr),
3316 specpdl_old_value (specpdl_ptr)); 3325 specpdl_old_value (specpdl_ptr));
3317 break; 3326 break;
3318 case SPECPDL_BACKTRACE: 3327 case SPECPDL_LET_DEFAULT:
3328 Fset_default (specpdl_symbol (specpdl_ptr),
3329 specpdl_old_value (specpdl_ptr));
3319 break; 3330 break;
3320 case SPECPDL_LET_LOCAL: 3331 case SPECPDL_LET_LOCAL:
3321 case SPECPDL_LET_DEFAULT: 3332 {
3322 { /* If the symbol is a list, it is really (SYMBOL WHERE
3323 . CURRENT-BUFFER) where WHERE is either nil, a buffer, or a
3324 frame. If WHERE is a buffer or frame, this indicates we
3325 bound a variable that had a buffer-local or frame-local
3326 binding. WHERE nil means that the variable had the default
3327 value when it was bound. CURRENT-BUFFER is the buffer that
3328 was current when the variable was bound. */
3329 Lisp_Object symbol = specpdl_symbol (specpdl_ptr); 3333 Lisp_Object symbol = specpdl_symbol (specpdl_ptr);
3330 Lisp_Object where = specpdl_where (specpdl_ptr); 3334 Lisp_Object where = specpdl_where (specpdl_ptr);
3331 Lisp_Object old_value = specpdl_old_value (specpdl_ptr); 3335 Lisp_Object old_value = specpdl_old_value (specpdl_ptr);
3332 eassert (BUFFERP (where)); 3336 eassert (BUFFERP (where));
3333 3337
3334 if (specpdl_ptr->kind == SPECPDL_LET_DEFAULT)
3335 Fset_default (symbol, old_value);
3336 /* If this was a local binding, reset the value in the appropriate 3338 /* If this was a local binding, reset the value in the appropriate
3337 buffer, but only if that buffer's binding still exists. */ 3339 buffer, but only if that buffer's binding still exists. */
3338 else if (!NILP (Flocal_variable_p (symbol, where))) 3340 if (!NILP (Flocal_variable_p (symbol, where)))
3339 set_internal (symbol, old_value, where, 1); 3341 set_internal (symbol, old_value, where, 1);
3340 } 3342 }
3341 break; 3343 break;
@@ -3422,7 +3424,30 @@ Output stream used is value of `standard-output'. */)
3422 return Qnil; 3424 return Qnil;
3423} 3425}
3424 3426
3425DEFUN ("backtrace-frame", Fbacktrace_frame, Sbacktrace_frame, 1, 1, NULL, 3427union specbinding *
3428get_backtrace_frame (Lisp_Object nframes, Lisp_Object base)
3429{
3430 union specbinding *pdl = backtrace_top ();
3431 register EMACS_INT i;
3432
3433 CHECK_NATNUM (nframes);
3434
3435 if (!NILP (base))
3436 { /* Skip up to `base'. */
3437 base = Findirect_function (base, Qt);
3438 while (backtrace_p (pdl)
3439 && !EQ (base, Findirect_function (backtrace_function (pdl), Qt)))
3440 pdl = backtrace_next (pdl);
3441 }
3442
3443 /* Find the frame requested. */
3444 for (i = XFASTINT (nframes); i > 0 && backtrace_p (pdl); i--)
3445 pdl = backtrace_next (pdl);
3446
3447 return pdl;
3448}
3449
3450DEFUN ("backtrace-frame", Fbacktrace_frame, Sbacktrace_frame, 1, 2, NULL,
3426 doc: /* Return the function and arguments NFRAMES up from current execution point. 3451 doc: /* Return the function and arguments NFRAMES up from current execution point.
3427If that frame has not evaluated the arguments yet (or is a special form), 3452If that frame has not evaluated the arguments yet (or is a special form),
3428the value is (nil FUNCTION ARG-FORMS...). 3453the value is (nil FUNCTION ARG-FORMS...).
@@ -3431,17 +3456,12 @@ the value is (t FUNCTION ARG-VALUES...).
3431A &rest arg is represented as the tail of the list ARG-VALUES. 3456A &rest arg is represented as the tail of the list ARG-VALUES.
3432FUNCTION is whatever was supplied as car of evaluated list, 3457FUNCTION is whatever was supplied as car of evaluated list,
3433or a lambda expression for macro calls. 3458or a lambda expression for macro calls.
3434If NFRAMES is more than the number of frames, the value is nil. */) 3459If NFRAMES is more than the number of frames, the value is nil.
3435 (Lisp_Object nframes) 3460If BASE is non-nil, it should be a function and NFRAMES counts from its
3461nearest activation frame. */)
3462 (Lisp_Object nframes, Lisp_Object base)
3436{ 3463{
3437 union specbinding *pdl = backtrace_top (); 3464 union specbinding *pdl = get_backtrace_frame (nframes, base);
3438 register EMACS_INT i;
3439
3440 CHECK_NATNUM (nframes);
3441
3442 /* Find the frame requested. */
3443 for (i = 0; backtrace_p (pdl) && i < XFASTINT (nframes); i++)
3444 pdl = backtrace_next (pdl);
3445 3465
3446 if (!backtrace_p (pdl)) 3466 if (!backtrace_p (pdl))
3447 return Qnil; 3467 return Qnil;
@@ -3456,6 +3476,108 @@ If NFRAMES is more than the number of frames, the value is nil. */)
3456 } 3476 }
3457} 3477}
3458 3478
3479/* For backtrace-eval, we want to temporarily unwind the last few elements of
3480 the specpdl stack, and then rewind them. We store the pre-unwind values
3481 directly in the pre-existing specpdl elements (i.e. we swap the current
3482 value and the old value stored in the specpdl), kind of like the inplace
3483 pointer-reversal trick. As it turns out, the rewind does the same as the
3484 unwind, except it starts from the other end of the spepdl stack, so we use
3485 the same function for both unwind and rewind. */
3486void
3487backtrace_eval_unrewind (int distance)
3488{
3489 union specbinding *tmp = specpdl_ptr;
3490 int step = -1;
3491 if (distance < 0)
3492 { /* It's a rewind rather than unwind. */
3493 tmp += distance - 1;
3494 step = 1;
3495 distance = -distance;
3496 }
3497
3498 for (; distance > 0; distance--)
3499 {
3500 tmp += step;
3501 /* */
3502 switch (tmp->kind)
3503 {
3504 /* FIXME: Ideally we'd like to "temporarily unwind" (some of) those
3505 unwind_protect, but the problem is that we don't know how to
3506 rewind them afterwards. */
3507 case SPECPDL_UNWIND:
3508 case SPECPDL_UNWIND_PTR:
3509 case SPECPDL_UNWIND_INT:
3510 case SPECPDL_UNWIND_VOID:
3511 case SPECPDL_BACKTRACE:
3512 break;
3513 case SPECPDL_LET:
3514 /* If variable has a trivial value (no forwarding), we can
3515 just set it. No need to check for constant symbols here,
3516 since that was already done by specbind. */
3517 if (XSYMBOL (specpdl_symbol (tmp))->redirect
3518 == SYMBOL_PLAINVAL)
3519 {
3520 struct Lisp_Symbol *sym = XSYMBOL (specpdl_symbol (tmp));
3521 Lisp_Object old_value = specpdl_old_value (tmp);
3522 set_specpdl_old_value (tmp, SYMBOL_VAL (sym));
3523 SET_SYMBOL_VAL (sym, old_value);
3524 break;
3525 }
3526 else
3527 /* FALLTHROUGH!
3528 NOTE: we only ever come here if make_local_foo was used for
3529 the first time on this var within this let. */
3530 ;
3531 case SPECPDL_LET_DEFAULT:
3532 {
3533 Lisp_Object sym = specpdl_symbol (tmp);
3534 Lisp_Object old_value = specpdl_old_value (tmp);
3535 set_specpdl_old_value (tmp, Fdefault_value (sym));
3536 Fset_default (sym, old_value);
3537 }
3538 break;
3539 case SPECPDL_LET_LOCAL:
3540 {
3541 Lisp_Object symbol = specpdl_symbol (tmp);
3542 Lisp_Object where = specpdl_where (tmp);
3543 Lisp_Object old_value = specpdl_old_value (tmp);
3544 eassert (BUFFERP (where));
3545
3546 /* If this was a local binding, reset the value in the appropriate
3547 buffer, but only if that buffer's binding still exists. */
3548 if (!NILP (Flocal_variable_p (symbol, where)))
3549 {
3550 set_specpdl_old_value
3551 (tmp, Fbuffer_local_value (symbol, where));
3552 set_internal (symbol, old_value, where, 1);
3553 }
3554 }
3555 break;
3556 }
3557 }
3558}
3559
3560DEFUN ("backtrace-eval", Fbacktrace_eval, Sbacktrace_eval, 2, 3, NULL,
3561 doc: /* Evaluate EXP in the context of some activation frame.
3562NFRAMES and BASE specify the activation frame to use, as in `backtrace-frame'. */)
3563 (Lisp_Object exp, Lisp_Object nframes, Lisp_Object base)
3564{
3565 union specbinding *pdl = get_backtrace_frame (nframes, base);
3566 ptrdiff_t count = SPECPDL_INDEX ();
3567 ptrdiff_t distance = specpdl_ptr - pdl;
3568 eassert (distance >= 0);
3569
3570 if (!backtrace_p (pdl))
3571 error ("Activation frame not found!");
3572
3573 backtrace_eval_unrewind (distance);
3574 record_unwind_protect_int (backtrace_eval_unrewind, -distance);
3575
3576 /* Use eval_sub rather than Feval since the main motivation behind
3577 backtrace-eval is to be able to get/set the value of lexical variables
3578 from the debugger. */
3579 return unbind_to (count, eval_sub (exp));
3580}
3459 3581
3460void 3582void
3461mark_specpdl (void) 3583mark_specpdl (void)
@@ -3701,6 +3823,7 @@ alist of active lexical bindings. */);
3701 defsubr (&Sbacktrace_debug); 3823 defsubr (&Sbacktrace_debug);
3702 defsubr (&Sbacktrace); 3824 defsubr (&Sbacktrace);
3703 defsubr (&Sbacktrace_frame); 3825 defsubr (&Sbacktrace_frame);
3826 defsubr (&Sbacktrace_eval);
3704 defsubr (&Sspecial_variable_p); 3827 defsubr (&Sspecial_variable_p);
3705 defsubr (&Sfunctionp); 3828 defsubr (&Sfunctionp);
3706} 3829}