Merge from emacs-24; up to 2012-05-02T11:38:01Z!lekktu@gmail.com
[bpt/emacs.git] / lisp / emacs-lisp / edebug.el
index e828842..bbf0757 100644 (file)
@@ -1,8 +1,6 @@
 ;;; edebug.el --- a source-level debugger for Emacs Lisp
 
-;; Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1997, 1999,
-;;   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
-;;   Free Software Foundation, Inc.
+;; Copyright (C) 1988-1995, 1997, 1999-2012 Free Software Foundation, Inc.
 
 ;; Author: Daniel LaLiberte <liberte@holonexus.org>
 ;; Maintainer: FSF
@@ -53,6 +51,8 @@
 
 ;;; Code:
 
+(require 'macroexp)
+
 ;;; Bug reporting
 
 (defalias 'edebug-submit-bug-report 'report-emacs-bug)
@@ -193,6 +193,7 @@ Use this with caution since it is not debugged."
 
 (defcustom edebug-unwrap-results nil
   "Non-nil if Edebug should unwrap results of expressions.
+That is, Edebug will try to remove its own instrumentation from the result.
 This is useful when debugging macros where the results of expressions
 are instrumented expressions.  But don't do this when results might be
 circular or an infinite loop will result."
@@ -241,10 +242,13 @@ If the result is non-nil, then break.  Errors are ignored."
 
 (defun get-edebug-spec (symbol)
   ;; Get the spec of symbol resolving all indirection.
-  (let ((edebug-form-spec (get symbol 'edebug-form-spec))
-       indirect)
-    (while (and (symbolp edebug-form-spec)
-               (setq indirect (get edebug-form-spec 'edebug-form-spec)))
+  (let ((edebug-form-spec nil)
+       (indirect symbol))
+    (while
+        (progn
+          (and (symbolp indirect)
+               (setq indirect
+                     (function-get indirect 'edebug-form-spec 'autoload))))
       ;; (edebug-trace "indirection: %s" edebug-form-spec)
       (setq edebug-form-spec indirect))
     edebug-form-spec
@@ -262,7 +266,7 @@ An extant spec symbol is a symbol that is not a function and has a
             (setq spec (cdr spec)))
           t))
        ((symbolp spec)
-        (unless (functionp spec) (get spec 'edebug-form-spec)))))
+        (unless (functionp spec) (function-get spec 'edebug-form-spec)))))
 
 ;;; Utilities
 
@@ -521,12 +525,14 @@ the minibuffer."
          ((and (eq (car form) 'defcustom)
                (default-boundp (nth 1 form)))
           ;; Force variable to be bound.
-          (set-default (nth 1 form) (eval (nth 2 form))))
+           ;; FIXME: Shouldn't this use the :setter or :initializer?
+          (set-default (nth 1 form) (eval (nth 2 form) lexical-binding)))
           ((eq (car form) 'defface)
            ;; Reset the face.
            (setq face-new-frame-defaults
                  (assq-delete-all (nth 1 form) face-new-frame-defaults))
            (put (nth 1 form) 'face-defface-spec nil)
+           (put (nth 1 form) 'face-documentation (nth 3 form))
           ;; See comments in `eval-defun-1' for purpose of code below
           (setq form (prog1 `(prog1 ,form
                                (put ',(nth 1 form) 'saved-face
@@ -534,7 +540,7 @@ the minibuffer."
                                (put ',(nth 1 form) 'customized-face
                                     ,(nth 2 form)))
                        (put (nth 1 form) 'saved-face nil)))))
-    (setq edebug-result (eval form))
+    (setq edebug-result (eval (eval-sexp-add-defvars form) lexical-binding))
     (if (not edebugging)
        (princ edebug-result)
       edebug-result)))
@@ -567,7 +573,8 @@ already is one.)"
    ;; but this causes problems while edebugging edebug.
    (let ((edebug-all-forms t)
         (edebug-all-defs t))
-     (edebug-read-top-level-form))))
+     (eval-sexp-add-defvars
+      (edebug-read-top-level-form)))))
 
 
 (defun edebug-read-top-level-form ()
@@ -885,17 +892,12 @@ already is one.)"
    (edebug-storing-offsets (1- (point)) 'quote)
    (edebug-read-storing-offsets stream)))
 
-(defvar edebug-read-backquote-level 0
-  "If non-zero, we're in a new-style backquote.
-It should never be negative.  This controls how we read comma constructs.")
-
 (defun edebug-read-backquote (stream)
   ;; Turn `thing into (\` thing)
   (forward-char 1)
   (list
    (edebug-storing-offsets (1- (point)) '\`)
-   (let ((edebug-read-backquote-level (1+ edebug-read-backquote-level)))
-     (edebug-read-storing-offsets stream))))
+   (edebug-read-storing-offsets stream)))
 
 (defun edebug-read-comma (stream)
   ;; Turn ,thing into (\, thing).  Handle ,@ and ,. also.
@@ -910,12 +912,9 @@ It should never be negative.  This controls how we read comma constructs.")
             (forward-char 1)))
       ;; Generate the same structure of offsets we would have
       ;; if the resulting list appeared verbatim in the input text.
-      (if (zerop edebug-read-backquote-level)
-         (edebug-storing-offsets opoint symbol)
-       (list
-        (edebug-storing-offsets opoint symbol)
-        (let ((edebug-read-backquote-level (1- edebug-read-backquote-level)))
-          (edebug-read-storing-offsets stream)))))))
+      (list
+       (edebug-storing-offsets opoint symbol)
+       (edebug-read-storing-offsets stream)))))
 
 (defun edebug-read-function (stream)
   ;; Turn #'thing into (function thing)
@@ -923,8 +922,7 @@ It should never be negative.  This controls how we read comma constructs.")
   (cond ((eq ?\' (following-char))
         (forward-char 1)
         (list
-         (edebug-storing-offsets (- (point) 2)
-           (if (featurep 'cl) 'function* 'function))
+         (edebug-storing-offsets (- (point) 2) 'function)
          (edebug-read-storing-offsets stream)))
        ((memq (following-char) '(?: ?B ?O ?X ?b ?o ?x ?1 ?2 ?3 ?4 ?5 ?6
                                  ?7 ?8 ?9 ?0))
@@ -937,17 +935,7 @@ It should never be negative.  This controls how we read comma constructs.")
   (prog1
       (let ((elements))
        (while (not (memq (edebug-next-token-class) '(rparen dot)))
-         (if (and (eq (edebug-next-token-class) 'backquote)
-                  (null elements)
-                  (zerop edebug-read-backquote-level))
-             (progn
-               ;; Old style backquote.
-               (forward-char 1)        ; Skip backquote.
-               ;; Call edebug-storing-offsets here so that we
-               ;; produce the same offsets we would have had
-               ;; if the backquote were an ordinary symbol.
-               (push (edebug-storing-offsets (1- (point)) '\`) elements))
-           (push (edebug-read-storing-offsets stream) elements)))
+          (push (edebug-read-storing-offsets stream) elements))
        (setq elements (nreverse elements))
        (if (eq 'dot (edebug-next-token-class))
            (let (dotted-form)
@@ -1267,10 +1255,7 @@ expressions; a `progn' form will be returned enclosing these forms."
        ((eq 'edebug-after (car sexp))
        (nth 3 sexp))
        ((eq 'edebug-enter (car sexp))
-       (let ((forms (nthcdr 2 (nth 1 (nth 3 sexp)))))
-         (if (> (length forms) 1)
-             (cons 'progn forms)  ;; could return (values forms) instead.
-           (car forms))))
+        (macroexp-progn (nthcdr 2 (nth 1 (nth 3 sexp)))))
        (t sexp);; otherwise it is not wrapped, so just return it.
        )
     sexp))
@@ -1303,7 +1288,7 @@ expressions; a `progn' form will be returned enclosing these forms."
   ;; Wrap a form, usually a defining form, but any evaluated one.
   ;; If speclist is non-nil, this is being called by edebug-defining-form.
   ;; Otherwise it is being called from edebug-read-and-maybe-wrap-form1.
-  ;; This is a hack, but I havent figured out a simpler way yet.
+  ;; This is a hack, but I haven't figured out a simpler way yet.
   (let* ((form-data-entry (edebug-get-form-data-entry form-begin form-end))
         ;; Set this marker before parsing.
         (edebug-form-begin-marker
@@ -1575,7 +1560,7 @@ expressions; a `progn' form will be returned enclosing these forms."
   ;; The first spec is handled and the remainder-handler handles the rest.
   (let ((edebug-matching-depth
         (if (> edebug-matching-depth edebug-max-depth)
-            (error "too deep - perhaps infinite loop in spec?")
+            (error "Too deep - perhaps infinite loop in spec?")
           (1+ edebug-matching-depth))))
     (cond
      ((null specs) nil)
@@ -1955,7 +1940,6 @@ expressions; a `progn' form will be returned enclosing these forms."
 
 ;;;; Edebug Form Specs
 ;;; ==========================================================
-;;; See cl-specs.el for common lisp specs.
 
 ;;;;* Spec for def-edebug-spec
 ;;; Out of date.
@@ -2028,12 +2012,6 @@ expressions; a `progn' form will be returned enclosing these forms."
 ;; A macro is allowed by Emacs.
 (def-edebug-spec function (&or symbolp lambda-expr))
 
-;; lambda is a macro in emacs 19.
-(def-edebug-spec lambda (&define lambda-list
-                                [&optional stringp]
-                                [&optional ("interactive" interactive)]
-                                def-body))
-
 ;; A macro expression is a lambda expression with "macro" prepended.
 (def-edebug-spec macro (&define "lambda" lambda-list def-body))
 
@@ -2046,7 +2024,10 @@ expressions; a `progn' form will be returned enclosing these forms."
 (def-edebug-spec apply (function-form &rest form))
 (def-edebug-spec funcall (function-form &rest form))
 
-;; FIXME? The manual has a gate here.
+;; FIXME?  The manual uses this form (maybe that's just for illustration?):
+;; (def-edebug-spec let
+;;   ((&rest &or symbolp (gate symbolp &optional form))
+;;    body))
 (def-edebug-spec let
   ((&rest &or (symbolp &optional form) symbolp)
    body))
@@ -2149,8 +2130,6 @@ expressions; a `progn' form will be returned enclosing these forms."
 
 (def-edebug-spec with-custom-print body)
 
-(def-edebug-spec sregexq (&rest sexp))
-(def-edebug-spec rx (&rest sexp))
 
 ;;; The debugger itself
 
@@ -2484,6 +2463,7 @@ MSG is printed after `::::} '."
            (if edebug-global-break-condition
                (condition-case nil
                    (setq edebug-global-break-result
+                          ;; FIXME: lexbind.
                          (eval edebug-global-break-condition))
                  (error nil))))
           (edebug-break))
@@ -2495,6 +2475,7 @@ MSG is printed after `::::} '."
                (and edebug-break-data
                     (or (not edebug-break-condition)
                         (setq edebug-break-result
+                               ;; FIXME: lexbind.
                               (eval edebug-break-condition))))))
       (if (and edebug-break
               (nth 2 edebug-break-data)) ; is it temporary?
@@ -3009,7 +2990,7 @@ MSG is printed after `::::} '."
   ;; Set up the overlay arrow at beginning-of-line in current buffer.
   ;; The arrow string is derived from edebug-arrow-alist and
   ;; edebug-execution-mode.
-  (let ((pos (save-excursion (beginning-of-line) (point))))
+  (let ((pos (line-beginning-position)))
     (setq overlay-arrow-string
          (cdr (assq edebug-execution-mode edebug-arrow-alist)))
     (setq overlay-arrow-position (make-marker))
@@ -3076,7 +3057,6 @@ Otherwise, toggle for all windows."
       (edebug-toggle-save-selected-window)
     (edebug-toggle-save-all-windows)))
 
-
 (defun edebug-where ()
   "Show the debug windows and where we stopped in the program."
   (interactive)
@@ -3219,7 +3199,7 @@ before returning.  The default is one second."
   "Modify the breakpoint for the form at point or after it.
 Set it if FLAG is non-nil, clear it otherwise.  Then move to that point.
 If CONDITION or TEMPORARY are non-nil, add those attributes to
-the breakpoint.  "
+the breakpoint."
   (let ((edebug-stop-point (edebug-find-stop-point)))
     (if edebug-stop-point
        (let* ((edebug-def-name (car edebug-stop-point))
@@ -3416,7 +3396,7 @@ go to the end of the last sexp, or if that is the same point, then step."
   ;; Return the function symbol, or nil if not instrumented.
   (let ((func-marker (get func 'edebug)))
     (cond
-     ((markerp func-marker)
+     ((and (markerp func-marker) (marker-buffer func-marker))
       ;; It is uninstrumented, so instrument it.
       (with-current-buffer (marker-buffer func-marker)
        (goto-char func-marker)
@@ -3426,7 +3406,7 @@ go to the end of the last sexp, or if that is the same point, then step."
       (message "%s is already instrumented." func)
       func)
      (t
-      (let ((loc (find-function-noselect func)))
+      (let ((loc (find-function-noselect func t)))
        (unless (cdr loc)
          (error "Could not find the definition in its file"))
        (with-current-buffer (car loc)
@@ -3466,7 +3446,7 @@ instrumented.  Then it does `edebug-on-entry' and switches to `go' mode."
 (defun edebug-on-entry (function &optional flag)
   "Cause Edebug to stop when FUNCTION is called.
 With prefix argument, make this temporary so it is automatically
-cancelled the first time the function is entered."
+canceled the first time the function is entered."
   (interactive "aEdebug on entry to: \nP")
   ;; Could store this in the edebug data instead.
   (put function 'edebug-on-entry (if flag 'temp t)))
@@ -3655,9 +3635,10 @@ Return the result of the last expression."
 
 (defun edebug-eval (edebug-expr)
   ;; Are there cl lexical variables active?
-  (if (bound-and-true-p cl-debug-env)
-      (eval (cl-macroexpand-all edebug-expr cl-debug-env))
-    (eval edebug-expr)))
+  (eval (if (bound-and-true-p cl-debug-env)
+            (cl-macroexpand-all edebug-expr cl-debug-env)
+          edebug-expr)
+        lexical-binding))
 
 (defun edebug-safe-eval (edebug-expr)
   ;; Evaluate EXPR safely.
@@ -3755,12 +3736,16 @@ This prints the value into current buffer."
 
 ;;; Edebug Minor Mode
 
-;; FIXME eh?
-(defvar gud-inhibit-global-bindings
-  "*Non-nil means don't do global rebindings of C-x C-a subcommands.")
+(defvar edebug-inhibit-emacs-lisp-mode-bindings nil
+  "If non-nil, inhibit Edebug bindings on the C-x C-a key.
+By default, loading the `edebug' library causes these bindings to
+be installed in `emacs-lisp-mode-map'.")
+
+(define-obsolete-variable-alias 'gud-inhibit-global-bindings
+  'edebug-inhibit-emacs-lisp-mode-bindings "24.2")
 
 ;; Global GUD bindings for all emacs-lisp-mode buffers.
-(unless gud-inhibit-global-bindings
+(unless edebug-inhibit-emacs-lisp-mode-bindings
   (define-key emacs-lisp-mode-map "\C-x\C-a\C-s" 'edebug-step-mode)
   (define-key emacs-lisp-mode-map "\C-x\C-a\C-n" 'edebug-next-mode)
   (define-key emacs-lisp-mode-map "\C-x\C-a\C-c" 'edebug-go-mode)
@@ -3896,24 +3881,23 @@ Global commands prefixed by `global-edebug-prefix':
 \\{global-edebug-map}
 
 Options:
-edebug-setup-hook
-edebug-all-defs
-edebug-all-forms
-edebug-save-windows
-edebug-save-displayed-buffer-points
-edebug-initial-mode
-edebug-trace
-edebug-test-coverage
-edebug-continue-kbd-macro
-edebug-print-length
-edebug-print-level
-edebug-print-circle
-edebug-on-error
-edebug-on-quit
-edebug-on-signal
-edebug-unwrap-results
-edebug-global-break-condition
-"
+`edebug-setup-hook'
+`edebug-all-defs'
+`edebug-all-forms'
+`edebug-save-windows'
+`edebug-save-displayed-buffer-points'
+`edebug-initial-mode'
+`edebug-trace'
+`edebug-test-coverage'
+`edebug-continue-kbd-macro'
+`edebug-print-length'
+`edebug-print-level'
+`edebug-print-circle'
+`edebug-on-error'
+`edebug-on-quit'
+`edebug-on-signal'
+`edebug-unwrap-results'
+`edebug-global-break-condition'"
   ;; If the user kills the buffer in which edebug is currently active,
   ;; exit to top level, because the edebug command loop can't usefully
   ;; continue running in such a case.
@@ -4029,18 +4013,16 @@ May only be called from within `edebug-recursive-edit'."
 
 
 
-(defvar edebug-eval-mode-map nil
-  "Keymap for Edebug Eval mode.  Superset of Lisp Interaction mode.")
-
-(unless edebug-eval-mode-map
-  (setq edebug-eval-mode-map (make-sparse-keymap))
-  (set-keymap-parent edebug-eval-mode-map lisp-interaction-mode-map)
-
-  (define-key edebug-eval-mode-map "\C-c\C-w" 'edebug-where)
-  (define-key edebug-eval-mode-map "\C-c\C-d" 'edebug-delete-eval-item)
-  (define-key edebug-eval-mode-map "\C-c\C-u" 'edebug-update-eval-list)
-  (define-key edebug-eval-mode-map "\C-x\C-e" 'edebug-eval-last-sexp)
-  (define-key edebug-eval-mode-map "\C-j" 'edebug-eval-print-last-sexp))
+(defvar edebug-eval-mode-map
+  (let ((map (make-sparse-keymap)))
+    (set-keymap-parent map lisp-interaction-mode-map)
+    (define-key map "\C-c\C-w" 'edebug-where)
+    (define-key map "\C-c\C-d" 'edebug-delete-eval-item)
+    (define-key map "\C-c\C-u" 'edebug-update-eval-list)
+    (define-key map "\C-x\C-e" 'edebug-eval-last-sexp)
+    (define-key map "\C-j" 'edebug-eval-print-last-sexp)
+  map)
+"Keymap for Edebug Eval mode.  Superset of Lisp Interaction mode.")
 
 (put 'edebug-eval-mode 'mode-class 'special)
 
@@ -4177,6 +4159,8 @@ You must include newlines in FMT to break lines, but one newline is appended."
 ;;; Frequency count and coverage
 
 ;; FIXME should this use overlays instead?
+;; Definitely, IMO.  The current business with undo in
+;; edebug-temp-display-freq-count is horrid.
 (defun edebug-display-freq-count ()
   "Display the frequency count data for each line of the current definition.
 The frequency counts are inserted as comment lines after each line,
@@ -4246,6 +4230,8 @@ reinstrument it."
        (insert "\n")
        (setq i first-index)))))
 
+;; FIXME this does not work very well.  Eg if you press an arrow key,
+;; or make a mouse-click, it fails with "Non-character input-event".
 (defun edebug-temp-display-freq-count ()
   "Temporarily display the frequency count data for the current definition.
 It is removed when you hit any char."
@@ -4255,14 +4241,15 @@ It is removed when you hit any char."
     (undo-boundary)
     (edebug-display-freq-count)
     (setq unread-command-char (read-char))
+    ;; Yuck!  This doesn't seem to work at all for me.
     (undo)))
 
 \f
 ;;; Menus
 
 (defun edebug-toggle (variable)
-  (set variable (not (eval variable)))
-  (message "%s: %s" variable (eval variable)))
+  (set variable (not (symbol-value variable)))
+  (message "%s: %s" variable (symbol-value variable)))
 
 ;; We have to require easymenu (even for Emacs 18) just so
 ;; the easy-menu-define macro call is compiled correctly.
@@ -4448,14 +4435,7 @@ With prefix argument, make it a temporary breakpoint."
 \f
 ;;; Autoloading of Edebug accessories
 
-(if (featurep 'cl)
-    (add-hook 'edebug-setup-hook
-             (function (lambda () (require 'cl-specs))))
-  ;; The following causes cl-specs to be loaded if you load cl.el.
-  (add-hook 'cl-load-hook
-           (function (lambda () (require 'cl-specs)))))
-
-;;; edebug-cl-read and cl-read are available from liberte@cs.uiuc.edu
+;; edebug-cl-read and cl-read are available from liberte@cs.uiuc.edu
 (if (featurep 'cl-read)
     (add-hook 'edebug-setup-hook
              (function (lambda () (require 'edebug-cl-read))))
@@ -4466,13 +4446,12 @@ With prefix argument, make it a temporary breakpoint."
 \f
 ;;; Finalize Loading
 
-;;; Finally, hook edebug into the rest of Emacs.
-;;; There are probably some other things that could go here.
+;; Finally, hook edebug into the rest of Emacs.
+;; There are probably some other things that could go here.
 
 ;; Install edebug read and eval functions.
 (edebug-install-read-eval-functions)
 
 (provide 'edebug)
 
-;; arch-tag: 19c8d05c-4554-426e-ac72-e0fa1fcb0808
 ;;; edebug.el ends here