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 | |
| 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.
| -rw-r--r-- | etc/NEWS | 4 | ||||
| -rw-r--r-- | lisp/ChangeLog | 16 | ||||
| -rw-r--r-- | lisp/emacs-lisp/debug.el | 145 | ||||
| -rw-r--r-- | lisp/emacs-lisp/edebug.el | 2 | ||||
| -rw-r--r-- | lisp/subr.el | 18 | ||||
| -rw-r--r-- | src/ChangeLog | 10 | ||||
| -rw-r--r-- | src/eval.c | 169 | ||||
| -rw-r--r-- | src/xterm.c | 15 |
8 files changed, 212 insertions, 167 deletions
| @@ -158,6 +158,10 @@ You can pick the name of the function and the variables with `C-x 4 a'. | |||
| 158 | 158 | ||
| 159 | * Changes in Specialized Modes and Packages in Emacs 24.4 | 159 | * Changes in Specialized Modes and Packages in Emacs 24.4 |
| 160 | 160 | ||
| 161 | ** The debugger's `e' command evaluates the code in the context at point. | ||
| 162 | This includes using the lexical environment at point, which means that | ||
| 163 | `e' now lets you access lexical variables as well. | ||
| 164 | |||
| 161 | ** `eshell' now supports visual subcommands and options | 165 | ** `eshell' now supports visual subcommands and options |
| 162 | Eshell has been able to handle "visual" commands (interactive, | 166 | Eshell has been able to handle "visual" commands (interactive, |
| 163 | non-line oriented commands such as top that require display | 167 | non-line oriented commands such as top that require display |
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 79582ea560a..84919e634be 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,19 @@ | |||
| 1 | 2013-07-26 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | Add support for lexical variables to the debugger's `e' command. | ||
| 4 | * emacs-lisp/debug.el (debug): Don't let-bind the debugger-outer-* | ||
| 5 | vars, except for debugger-outer-match-data. | ||
| 6 | (debugger-frame-number): Move check for "on a function call" from | ||
| 7 | callers into it. Add `skip-base' argument. | ||
| 8 | (debugger-frame, debugger-frame-clear): Simplify accordingly. | ||
| 9 | (debugger-env-macro): Only reset the state stored in non-variables, | ||
| 10 | i.e. current-buffer and match-data. | ||
| 11 | (debugger-eval-expression): Rewrite using backtrace-eval. | ||
| 12 | * subr.el (internal--called-interactively-p--get-frame): Remove. | ||
| 13 | (called-interactively-p): | ||
| 14 | * emacs-lisp/edebug.el (edebug--called-interactively-skip): Use the new | ||
| 15 | `base' arg of backtrace-frame instead. | ||
| 16 | |||
| 1 | 2013-07-26 Glenn Morris <rgm@gnu.org> | 17 | 2013-07-26 Glenn Morris <rgm@gnu.org> |
| 2 | 18 | ||
| 3 | * align.el (align-regexp): Doc fix. (Bug#14857) | 19 | * align.el (align-regexp): Doc fix. (Bug#14857) |
diff --git a/lisp/emacs-lisp/debug.el b/lisp/emacs-lisp/debug.el index 0728e86d072..aee48eef668 100644 --- a/lisp/emacs-lisp/debug.el +++ b/lisp/emacs-lisp/debug.el | |||
| @@ -102,22 +102,6 @@ The value used here is passed to `quit-restore-window'." | |||
| 102 | This is to optimize `debugger-make-xrefs'.") | 102 | This is to optimize `debugger-make-xrefs'.") |
| 103 | 103 | ||
| 104 | (defvar debugger-outer-match-data) | 104 | (defvar debugger-outer-match-data) |
| 105 | (defvar debugger-outer-load-read-function) | ||
| 106 | (defvar debugger-outer-overriding-local-map) | ||
| 107 | (defvar debugger-outer-overriding-terminal-local-map) | ||
| 108 | (defvar debugger-outer-track-mouse) | ||
| 109 | (defvar debugger-outer-last-command) | ||
| 110 | (defvar debugger-outer-this-command) | ||
| 111 | (defvar debugger-outer-unread-command-events) | ||
| 112 | (defvar debugger-outer-unread-post-input-method-events) | ||
| 113 | (defvar debugger-outer-last-input-event) | ||
| 114 | (defvar debugger-outer-last-command-event) | ||
| 115 | (defvar debugger-outer-last-nonmenu-event) | ||
| 116 | (defvar debugger-outer-last-event-frame) | ||
| 117 | (defvar debugger-outer-standard-input) | ||
| 118 | (defvar debugger-outer-standard-output) | ||
| 119 | (defvar debugger-outer-inhibit-redisplay) | ||
| 120 | (defvar debugger-outer-cursor-in-echo-area) | ||
| 121 | (defvar debugger-will-be-back nil | 105 | (defvar debugger-will-be-back nil |
| 122 | "Non-nil if we expect to get back in the debugger soon.") | 106 | "Non-nil if we expect to get back in the debugger soon.") |
| 123 | 107 | ||
| @@ -174,24 +158,6 @@ first will be printed into the backtrace buffer." | |||
| 174 | ;; Save the outer values of these vars for the `e' command | 158 | ;; Save the outer values of these vars for the `e' command |
| 175 | ;; before we replace the values. | 159 | ;; before we replace the values. |
| 176 | (debugger-outer-match-data (match-data)) | 160 | (debugger-outer-match-data (match-data)) |
| 177 | (debugger-outer-load-read-function load-read-function) | ||
| 178 | (debugger-outer-overriding-local-map overriding-local-map) | ||
| 179 | (debugger-outer-overriding-terminal-local-map | ||
| 180 | overriding-terminal-local-map) | ||
| 181 | (debugger-outer-track-mouse track-mouse) | ||
| 182 | (debugger-outer-last-command last-command) | ||
| 183 | (debugger-outer-this-command this-command) | ||
| 184 | (debugger-outer-unread-command-events unread-command-events) | ||
| 185 | (debugger-outer-unread-post-input-method-events | ||
| 186 | unread-post-input-method-events) | ||
| 187 | (debugger-outer-last-input-event last-input-event) | ||
| 188 | (debugger-outer-last-command-event last-command-event) | ||
| 189 | (debugger-outer-last-nonmenu-event last-nonmenu-event) | ||
| 190 | (debugger-outer-last-event-frame last-event-frame) | ||
| 191 | (debugger-outer-standard-input standard-input) | ||
| 192 | (debugger-outer-standard-output standard-output) | ||
| 193 | (debugger-outer-inhibit-redisplay inhibit-redisplay) | ||
| 194 | (debugger-outer-cursor-in-echo-area cursor-in-echo-area) | ||
| 195 | (debugger-with-timeout-suspend (with-timeout-suspend))) | 161 | (debugger-with-timeout-suspend (with-timeout-suspend))) |
| 196 | ;; Set this instead of binding it, so that `q' | 162 | ;; Set this instead of binding it, so that `q' |
| 197 | ;; will not restore it. | 163 | ;; will not restore it. |
| @@ -294,26 +260,6 @@ first will be printed into the backtrace buffer." | |||
| 294 | (funcall (nth 0 debugger-previous-state)))))) | 260 | (funcall (nth 0 debugger-previous-state)))))) |
| 295 | (with-timeout-unsuspend debugger-with-timeout-suspend) | 261 | (with-timeout-unsuspend debugger-with-timeout-suspend) |
| 296 | (set-match-data debugger-outer-match-data))) | 262 | (set-match-data debugger-outer-match-data))) |
| 297 | ;; Put into effect the modified values of these variables | ||
| 298 | ;; in case the user set them with the `e' command. | ||
| 299 | (setq load-read-function debugger-outer-load-read-function) | ||
| 300 | (setq overriding-local-map debugger-outer-overriding-local-map) | ||
| 301 | (setq overriding-terminal-local-map | ||
| 302 | debugger-outer-overriding-terminal-local-map) | ||
| 303 | (setq track-mouse debugger-outer-track-mouse) | ||
| 304 | (setq last-command debugger-outer-last-command) | ||
| 305 | (setq this-command debugger-outer-this-command) | ||
| 306 | (setq unread-command-events debugger-outer-unread-command-events) | ||
| 307 | (setq unread-post-input-method-events | ||
| 308 | debugger-outer-unread-post-input-method-events) | ||
| 309 | (setq last-input-event debugger-outer-last-input-event) | ||
| 310 | (setq last-command-event debugger-outer-last-command-event) | ||
| 311 | (setq last-nonmenu-event debugger-outer-last-nonmenu-event) | ||
| 312 | (setq last-event-frame debugger-outer-last-event-frame) | ||
| 313 | (setq standard-input debugger-outer-standard-input) | ||
| 314 | (setq standard-output debugger-outer-standard-output) | ||
| 315 | (setq inhibit-redisplay debugger-outer-inhibit-redisplay) | ||
| 316 | (setq cursor-in-echo-area debugger-outer-cursor-in-echo-area) | ||
| 317 | (setq debug-on-next-call debugger-step-after-exit) | 263 | (setq debug-on-next-call debugger-step-after-exit) |
| 318 | debugger-value))) | 264 | debugger-value))) |
| 319 | 265 | ||
| @@ -518,18 +464,21 @@ removes itself from that hook." | |||
| 518 | (setq debugger-jumping-flag nil) | 464 | (setq debugger-jumping-flag nil) |
| 519 | (remove-hook 'post-command-hook 'debugger-reenable)) | 465 | (remove-hook 'post-command-hook 'debugger-reenable)) |
| 520 | 466 | ||
| 521 | (defun debugger-frame-number () | 467 | (defun debugger-frame-number (&optional skip-base) |
| 522 | "Return number of frames in backtrace before the one point points at." | 468 | "Return number of frames in backtrace before the one point points at." |
| 523 | (save-excursion | 469 | (save-excursion |
| 524 | (beginning-of-line) | 470 | (beginning-of-line) |
| 471 | (if (looking-at " *;;;\\|[a-z]") | ||
| 472 | (error "This line is not a function call")) | ||
| 525 | (let ((opoint (point)) | 473 | (let ((opoint (point)) |
| 526 | (count 0)) | 474 | (count 0)) |
| 527 | (while (not (eq (cadr (backtrace-frame count)) 'debug)) | 475 | (unless skip-base |
| 528 | (setq count (1+ count))) | 476 | (while (not (eq (cadr (backtrace-frame count)) 'debug)) |
| 529 | ;; Skip debug--implement-debug-on-entry frame. | 477 | (setq count (1+ count))) |
| 530 | (when (eq 'debug--implement-debug-on-entry | 478 | ;; Skip debug--implement-debug-on-entry frame. |
| 531 | (cadr (backtrace-frame (1+ count)))) | 479 | (when (eq 'debug--implement-debug-on-entry |
| 532 | (setq count (+ 2 count))) | 480 | (cadr (backtrace-frame (1+ count)))) |
| 481 | (setq count (+ 2 count)))) | ||
| 533 | (goto-char (point-min)) | 482 | (goto-char (point-min)) |
| 534 | (when (looking-at "Debugger entered--\\(Lisp error\\|returning value\\):") | 483 | (when (looking-at "Debugger entered--\\(Lisp error\\|returning value\\):") |
| 535 | (goto-char (match-end 0)) | 484 | (goto-char (match-end 0)) |
| @@ -551,12 +500,8 @@ removes itself from that hook." | |||
| 551 | "Request entry to debugger when this frame exits. | 500 | "Request entry to debugger when this frame exits. |
| 552 | Applies to the frame whose line point is on in the backtrace." | 501 | Applies to the frame whose line point is on in the backtrace." |
| 553 | (interactive) | 502 | (interactive) |
| 554 | (save-excursion | ||
| 555 | (beginning-of-line) | ||
| 556 | (if (looking-at " *;;;\\|[a-z]") | ||
| 557 | (error "This line is not a function call"))) | ||
| 558 | (beginning-of-line) | ||
| 559 | (backtrace-debug (debugger-frame-number) t) | 503 | (backtrace-debug (debugger-frame-number) t) |
| 504 | (beginning-of-line) | ||
| 560 | (if (= (following-char) ? ) | 505 | (if (= (following-char) ? ) |
| 561 | (let ((inhibit-read-only t)) | 506 | (let ((inhibit-read-only t)) |
| 562 | (delete-char 1) | 507 | (delete-char 1) |
| @@ -567,12 +512,8 @@ Applies to the frame whose line point is on in the backtrace." | |||
| 567 | "Do not enter debugger when this frame exits. | 512 | "Do not enter debugger when this frame exits. |
| 568 | Applies to the frame whose line point is on in the backtrace." | 513 | Applies to the frame whose line point is on in the backtrace." |
| 569 | (interactive) | 514 | (interactive) |
| 570 | (save-excursion | ||
| 571 | (beginning-of-line) | ||
| 572 | (if (looking-at " *;;;\\|[a-z]") | ||
| 573 | (error "This line is not a function call"))) | ||
| 574 | (beginning-of-line) | ||
| 575 | (backtrace-debug (debugger-frame-number) nil) | 515 | (backtrace-debug (debugger-frame-number) nil) |
| 516 | (beginning-of-line) | ||
| 576 | (if (= (following-char) ?*) | 517 | (if (= (following-char) ?*) |
| 577 | (let ((inhibit-read-only t)) | 518 | (let ((inhibit-read-only t)) |
| 578 | (delete-char 1) | 519 | (delete-char 1) |
| @@ -583,59 +524,33 @@ Applies to the frame whose line point is on in the backtrace." | |||
| 583 | "Run BODY in original environment." | 524 | "Run BODY in original environment." |
| 584 | (declare (indent 0)) | 525 | (declare (indent 0)) |
| 585 | `(save-excursion | 526 | `(save-excursion |
| 586 | (if (null (buffer-name debugger-old-buffer)) | 527 | (if (null (buffer-live-p debugger-old-buffer)) |
| 587 | ;; old buffer deleted | 528 | ;; old buffer deleted |
| 588 | (setq debugger-old-buffer (current-buffer))) | 529 | (setq debugger-old-buffer (current-buffer))) |
| 589 | (set-buffer debugger-old-buffer) | 530 | (set-buffer debugger-old-buffer) |
| 590 | (let ((load-read-function debugger-outer-load-read-function) | 531 | (set-match-data debugger-outer-match-data) |
| 591 | (overriding-terminal-local-map | 532 | (prog1 |
| 592 | debugger-outer-overriding-terminal-local-map) | 533 | (progn ,@body) |
| 593 | (overriding-local-map debugger-outer-overriding-local-map) | 534 | (setq debugger-outer-match-data (match-data))))) |
| 594 | (track-mouse debugger-outer-track-mouse) | ||
| 595 | (last-command debugger-outer-last-command) | ||
| 596 | (this-command debugger-outer-this-command) | ||
| 597 | (unread-command-events debugger-outer-unread-command-events) | ||
| 598 | (unread-post-input-method-events | ||
| 599 | debugger-outer-unread-post-input-method-events) | ||
| 600 | (last-input-event debugger-outer-last-input-event) | ||
| 601 | (last-command-event debugger-outer-last-command-event) | ||
| 602 | (last-nonmenu-event debugger-outer-last-nonmenu-event) | ||
| 603 | (last-event-frame debugger-outer-last-event-frame) | ||
| 604 | (standard-input debugger-outer-standard-input) | ||
| 605 | (standard-output debugger-outer-standard-output) | ||
| 606 | (inhibit-redisplay debugger-outer-inhibit-redisplay) | ||
| 607 | (cursor-in-echo-area debugger-outer-cursor-in-echo-area)) | ||
| 608 | (set-match-data debugger-outer-match-data) | ||
| 609 | (prog1 | ||
| 610 | (progn ,@body) | ||
| 611 | (setq debugger-outer-match-data (match-data)) | ||
| 612 | (setq debugger-outer-load-read-function load-read-function) | ||
| 613 | (setq debugger-outer-overriding-terminal-local-map | ||
| 614 | overriding-terminal-local-map) | ||
| 615 | (setq debugger-outer-overriding-local-map overriding-local-map) | ||
| 616 | (setq debugger-outer-track-mouse track-mouse) | ||
| 617 | (setq debugger-outer-last-command last-command) | ||
| 618 | (setq debugger-outer-this-command this-command) | ||
| 619 | (setq debugger-outer-unread-command-events unread-command-events) | ||
| 620 | (setq debugger-outer-unread-post-input-method-events | ||
| 621 | unread-post-input-method-events) | ||
| 622 | (setq debugger-outer-last-input-event last-input-event) | ||
| 623 | (setq debugger-outer-last-command-event last-command-event) | ||
| 624 | (setq debugger-outer-last-nonmenu-event last-nonmenu-event) | ||
| 625 | (setq debugger-outer-last-event-frame last-event-frame) | ||
| 626 | (setq debugger-outer-standard-input standard-input) | ||
| 627 | (setq debugger-outer-standard-output standard-output) | ||
| 628 | (setq debugger-outer-inhibit-redisplay inhibit-redisplay) | ||
| 629 | (setq debugger-outer-cursor-in-echo-area cursor-in-echo-area) | ||
| 630 | )))) | ||
| 631 | 535 | ||
| 632 | (defun debugger-eval-expression (exp) | 536 | (defun debugger-eval-expression (exp) |
| 633 | "Eval an expression, in an environment like that outside the debugger." | 537 | "Eval an expression, in an environment like that outside the debugger. |
| 538 | The environment used is the one when entering the activation frame at point." | ||
| 634 | (interactive | 539 | (interactive |
| 635 | (list (read-from-minibuffer "Eval: " | 540 | (list (read-from-minibuffer "Eval: " |
| 636 | nil read-expression-map t | 541 | nil read-expression-map t |
| 637 | 'read-expression-history))) | 542 | 'read-expression-history))) |
| 638 | (debugger-env-macro (eval-expression exp))) | 543 | (let ((nframe (condition-case nil (1+ (debugger-frame-number 'skip-base)) |
| 544 | (error 0))) ;; If on first line. | ||
| 545 | (base (if (eq 'debug--implement-debug-on-entry | ||
| 546 | (cadr (backtrace-frame 1 'debug))) | ||
| 547 | 'debug--implement-debug-on-entry 'debug))) | ||
| 548 | (debugger-env-macro | ||
| 549 | (let ((val (backtrace-eval exp nframe base))) | ||
| 550 | (prog1 | ||
| 551 | (prin1 val t) | ||
| 552 | (let ((str (eval-expression-print-format val))) | ||
| 553 | (if str (princ str t)))))))) | ||
| 639 | 554 | ||
| 640 | (defvar debugger-mode-map | 555 | (defvar debugger-mode-map |
| 641 | (let ((map (make-keymap)) | 556 | (let ((map (make-keymap)) |
diff --git a/lisp/emacs-lisp/edebug.el b/lisp/emacs-lisp/edebug.el index 36c72f3a3bd..7771c3adaa4 100644 --- a/lisp/emacs-lisp/edebug.el +++ b/lisp/emacs-lisp/edebug.el | |||
| @@ -4268,7 +4268,7 @@ With prefix argument, make it a temporary breakpoint." | |||
| 4268 | (eq (nth 1 (nth 1 frame1)) '()) | 4268 | (eq (nth 1 (nth 1 frame1)) '()) |
| 4269 | (eq (nth 1 frame2) 'edebug-enter)) | 4269 | (eq (nth 1 frame2) 'edebug-enter)) |
| 4270 | ;; `edebug-enter' calls itself on its first invocation. | 4270 | ;; `edebug-enter' calls itself on its first invocation. |
| 4271 | (if (eq (nth 1 (internal--called-interactively-p--get-frame i)) | 4271 | (if (eq (nth 1 (backtrace-frame i 'called-interactively-p)) |
| 4272 | 'edebug-enter) | 4272 | 'edebug-enter) |
| 4273 | 2 1))) | 4273 | 2 1))) |
| 4274 | 4274 | ||
diff --git a/lisp/subr.el b/lisp/subr.el index 7130639dbe5..3b85a9bedb0 100644 --- a/lisp/subr.el +++ b/lisp/subr.el | |||
| @@ -4191,22 +4191,6 @@ I is the index of the frame after FRAME2. It should return nil | |||
| 4191 | if those frames don't seem special and otherwise, it should return | 4191 | if those frames don't seem special and otherwise, it should return |
| 4192 | the number of frames to skip (minus 1).") | 4192 | the number of frames to skip (minus 1).") |
| 4193 | 4193 | ||
| 4194 | (defmacro internal--called-interactively-p--get-frame (n) | ||
| 4195 | ;; `sym' will hold a global variable, which will be used kind of like C's | ||
| 4196 | ;; "static" variables. | ||
| 4197 | (let ((sym (make-symbol "base-index"))) | ||
| 4198 | `(progn | ||
| 4199 | (defvar ,sym) | ||
| 4200 | (unless (boundp ',sym) | ||
| 4201 | (let ((i 1)) | ||
| 4202 | (while (not (eq (indirect-function (nth 1 (backtrace-frame i)) t) | ||
| 4203 | (indirect-function 'called-interactively-p))) | ||
| 4204 | (setq i (1+ i))) | ||
| 4205 | (setq ,sym i))) | ||
| 4206 | ;; (unless (eq (nth 1 (backtrace-frame ,sym)) 'called-interactively-p) | ||
| 4207 | ;; (error "called-interactively-p: %s is out-of-sync!" ,sym)) | ||
| 4208 | (backtrace-frame (+ ,sym ,n))))) | ||
| 4209 | |||
| 4210 | (defun called-interactively-p (&optional kind) | 4194 | (defun called-interactively-p (&optional kind) |
| 4211 | "Return t if the containing function was called by `call-interactively'. | 4195 | "Return t if the containing function was called by `call-interactively'. |
| 4212 | If KIND is `interactive', then only return t if the call was made | 4196 | If KIND is `interactive', then only return t if the call was made |
| @@ -4241,7 +4225,7 @@ command is called from a keyboard macro?" | |||
| 4241 | (get-next-frame | 4225 | (get-next-frame |
| 4242 | (lambda () | 4226 | (lambda () |
| 4243 | (setq frame nextframe) | 4227 | (setq frame nextframe) |
| 4244 | (setq nextframe (internal--called-interactively-p--get-frame i)) | 4228 | (setq nextframe (backtrace-frame i 'called-interactively-p)) |
| 4245 | ;; (message "Frame %d = %S" i nextframe) | 4229 | ;; (message "Frame %d = %S" i nextframe) |
| 4246 | (setq i (1+ i))))) | 4230 | (setq i (1+ i))))) |
| 4247 | (funcall get-next-frame) ;; Get the first frame. | 4231 | (funcall get-next-frame) ;; Get the first frame. |
diff --git a/src/ChangeLog b/src/ChangeLog index 56fe20fda98..6542703adbb 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,13 @@ | |||
| 1 | 2013-07-26 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | * eval.c (set_specpdl_old_value): New function. | ||
| 4 | (unbind_to): Minor simplification. | ||
| 5 | (get_backtrace_frame): New function. | ||
| 6 | (Fbacktrace_frame): Use it. Add `base' argument. | ||
| 7 | (backtrace_eval_unrewind, Fbacktrace_eval): New functions. | ||
| 8 | (syms_of_eval): Export backtrace-eval. | ||
| 9 | * xterm.c (x_focus_changed): Simplify. | ||
| 10 | |||
| 1 | 2013-07-25 Paul Eggert <eggert@cs.ucla.edu> | 11 | 2013-07-25 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 12 | ||
| 3 | * fileio.c (Finsert_file_contents): Avoid double-close (Bug#14936). | 13 | * fileio.c (Finsert_file_contents): Avoid double-close (Bug#14936). |
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 | } |
diff --git a/src/xterm.c b/src/xterm.c index 74e495e5645..b3534871da9 100644 --- a/src/xterm.c +++ b/src/xterm.c | |||
| @@ -3435,17 +3435,10 @@ x_focus_changed (int type, int state, struct x_display_info *dpyinfo, struct fra | |||
| 3435 | /* Don't stop displaying the initial startup message | 3435 | /* Don't stop displaying the initial startup message |
| 3436 | for a switch-frame event we don't need. */ | 3436 | for a switch-frame event we don't need. */ |
| 3437 | /* When run as a daemon, Vterminal_frame is always NIL. */ | 3437 | /* When run as a daemon, Vterminal_frame is always NIL. */ |
| 3438 | if ((NILP (Vterminal_frame) || EQ (Fdaemonp(), Qt)) | 3438 | bufp->arg = (((NILP (Vterminal_frame) || EQ (Fdaemonp (), Qt)) |
| 3439 | && CONSP (Vframe_list) | 3439 | && CONSP (Vframe_list) |
| 3440 | && !NILP (XCDR (Vframe_list))) | 3440 | && !NILP (XCDR (Vframe_list))) |
| 3441 | { | 3441 | ? Qt : Qnil); |
| 3442 | bufp->arg = Qt; | ||
| 3443 | } | ||
| 3444 | else | ||
| 3445 | { | ||
| 3446 | bufp->arg = Qnil; | ||
| 3447 | } | ||
| 3448 | |||
| 3449 | bufp->kind = FOCUS_IN_EVENT; | 3442 | bufp->kind = FOCUS_IN_EVENT; |
| 3450 | XSETFRAME (bufp->frame_or_window, frame); | 3443 | XSETFRAME (bufp->frame_or_window, frame); |
| 3451 | } | 3444 | } |