diff options
| author | Stefan Monnier | 2013-07-26 03:38:18 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2013-07-26 03:38:18 -0400 |
| commit | 56ea72917a7a700e29cf6c115fd1cd75ad782e9e (patch) | |
| tree | 1a9220717c6333b376d45ebc044ad8ed71cfda37 /src/eval.c | |
| parent | f6b1502430653fac080f76a08edd2eb690f92146 (diff) | |
| download | emacs-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.c | 169 |
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 | ||
| 141 | static void | ||
| 142 | set_specpdl_old_value (union specbinding *pdl, Lisp_Object val) | ||
| 143 | { | ||
| 144 | eassert (pdl->kind >= SPECPDL_LET); | ||
| 145 | pdl->let.old_value = val; | ||
| 146 | } | ||
| 147 | |||
| 141 | static Lisp_Object | 148 | static Lisp_Object |
| 142 | specpdl_where (union specbinding *pdl) | 149 | specpdl_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 | ||
| 3425 | DEFUN ("backtrace-frame", Fbacktrace_frame, Sbacktrace_frame, 1, 1, NULL, | 3427 | union specbinding * |
| 3428 | get_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 | |||
| 3450 | DEFUN ("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. |
| 3427 | If that frame has not evaluated the arguments yet (or is a special form), | 3452 | If that frame has not evaluated the arguments yet (or is a special form), |
| 3428 | the value is (nil FUNCTION ARG-FORMS...). | 3453 | the value is (nil FUNCTION ARG-FORMS...). |
| @@ -3431,17 +3456,12 @@ the value is (t FUNCTION ARG-VALUES...). | |||
| 3431 | A &rest arg is represented as the tail of the list ARG-VALUES. | 3456 | A &rest arg is represented as the tail of the list ARG-VALUES. |
| 3432 | FUNCTION is whatever was supplied as car of evaluated list, | 3457 | FUNCTION is whatever was supplied as car of evaluated list, |
| 3433 | or a lambda expression for macro calls. | 3458 | or a lambda expression for macro calls. |
| 3434 | If NFRAMES is more than the number of frames, the value is nil. */) | 3459 | If NFRAMES is more than the number of frames, the value is nil. |
| 3435 | (Lisp_Object nframes) | 3460 | If BASE is non-nil, it should be a function and NFRAMES counts from its |
| 3461 | nearest 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. */ | ||
| 3486 | void | ||
| 3487 | backtrace_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 | |||
| 3560 | DEFUN ("backtrace-eval", Fbacktrace_eval, Sbacktrace_eval, 2, 3, NULL, | ||
| 3561 | doc: /* Evaluate EXP in the context of some activation frame. | ||
| 3562 | NFRAMES 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 | ||
| 3460 | void | 3582 | void |
| 3461 | mark_specpdl (void) | 3583 | mark_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 | } |