From d048fe3f0372011f4aef5cae0a89ccdbe3d59bf8 Mon Sep 17 00:00:00 2001 From: Gemini Lasswell Date: Fri, 29 Sep 2017 14:58:20 -0700 Subject: [PATCH] Create new Edebug spec for docstrings and use it in closures Since (:documentation FORM) can be used to create a docstring when lexical-binding is on, allow for that possibility in Edebug specs (bug#24773). * lisp/emacs-lisp/edebug.el: Define an Edebug spec for docstrings called lambda-doc and modify the Edebug specs for defun and defmacro to use it. (edebug-instrument-function): Check for generic functions first, to fix bug where edebug-step-in didn't work on methods now that cl-defgeneric has an Edebug spec. * lisp/subr.el (lambda): Modify Edebug spec to use lambda-doc. * lisp/emacs-lisp/cl-generic.el (cl-defgeneric): Add Edebug spec (bug#27747). (cl-defmethod): Use lambda-doc in Edebug spec. * lisp/emacs-lisp/cl-macs.el: Modify Edebug spec for cl-declarations-or-string to use lambda-doc, and modify Edebug spec for cl-lambda-expr to use cl-declarations-or-string. * lisp/emacs-lisp/pcase.el (pcase-lambda): Modify Edebug spec to use lambda-doc, as well as &define and def-body which are necessary for using Edebug on code wrapped by lambda. * lisp/emacs-lisp/generator.el (iter-defun, iter-lambda): Add Edebug specs. --- lisp/emacs-lisp/cl-generic.el | 13 +++++++++++-- lisp/emacs-lisp/cl-macs.el | 6 +++--- lisp/emacs-lisp/edebug.el | 27 +++++++++++++++------------ lisp/emacs-lisp/generator.el | 6 ++++-- lisp/emacs-lisp/pcase.el | 2 +- lisp/subr.el | 3 +-- 6 files changed, 35 insertions(+), 22 deletions(-) diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el index b2f76abd88..62befd4742 100644 --- a/lisp/emacs-lisp/cl-generic.el +++ b/lisp/emacs-lisp/cl-generic.el @@ -204,7 +204,16 @@ cl-defgeneric DEFAULT-BODY, if present, is used as the body of a default method. \(fn NAME ARGS [DOC-STRING] [OPTIONS-AND-METHODS...] &rest DEFAULT-BODY)" - (declare (indent 2) (doc-string 3)) + (declare (indent 2) (doc-string 3) + (debug + (&define name cl-lambda-list lambda-doc + [&rest [&or + ("declare" &rest sexp) + (":argument-precedence-order" &rest sexp) + (&define ":method" [&rest atom] + cl-generic-method-args lambda-doc + def-body)]] + def-body))) (let* ((doc (if (stringp (car-safe options-and-methods)) (pop options-and-methods))) (declarations nil) @@ -422,7 +431,7 @@ cl-defmethod ; Like in CLOS spec, we support ; any non-list values. cl-generic-method-args ; arguments - [ &optional stringp ] ; documentation string + lambda-doc ; documentation string def-body))) ; part to be debugged (let ((qualifiers nil)) (while (not (listp args)) diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el index 32ba0ac309..40eda1e0d6 100644 --- a/lisp/emacs-lisp/cl-macs.el +++ b/lisp/emacs-lisp/cl-macs.el @@ -190,7 +190,7 @@ cl-declarations (&rest ("cl-declare" &rest sexp))) (def-edebug-spec cl-declarations-or-string - (&or stringp cl-declarations)) + (&or lambda-doc cl-declarations)) (def-edebug-spec cl-lambda-list (([&rest arg] @@ -447,8 +447,8 @@ cl-defmacro (def-edebug-spec cl-lambda-expr (&define ("lambda" cl-lambda-list - ;;cl-declarations-or-string - ;;[&optional ("interactive" interactive)] + cl-declarations-or-string + [&optional ("interactive" interactive)] def-body))) ;; Redefine function-form to also match cl-function diff --git a/lisp/emacs-lisp/edebug.el b/lisp/emacs-lisp/edebug.el index dbc56e272f..d00b14e803 100644 --- a/lisp/emacs-lisp/edebug.el +++ b/lisp/emacs-lisp/edebug.el @@ -1986,15 +1986,14 @@ defconst (def-edebug-spec defvar (symbolp &optional form stringp)) (def-edebug-spec defun - (&define name lambda-list - [&optional stringp] + (&define name lambda-list lambda-doc [&optional ("declare" &rest sexp)] [&optional ("interactive" interactive)] def-body)) (def-edebug-spec defmacro ;; FIXME: Improve `declare' so we can Edebug gv-expander and ;; gv-setter declarations. - (&define name lambda-list [&optional stringp] + (&define name lambda-list lambda-doc [&optional ("declare" &rest sexp)] def-body)) (def-edebug-spec arglist lambda-list) ;; deprecated - use lambda-list. @@ -2005,6 +2004,10 @@ lambda-list &optional ["&rest" arg] ))) +(def-edebug-spec lambda-doc + (&optional [&or stringp + (&define ":documentation" def-form)])) + (def-edebug-spec interactive (&optional &or stringp def-form)) @@ -3204,15 +3207,6 @@ edebug-instrument-function instrument cannot be found, signal an error." (let ((func-marker (get func 'edebug))) (cond - ((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) - (edebug-eval-top-level-form) - (list func))) - ((consp func-marker) - (message "%s is already instrumented." func) - (list func)) ((cl-generic-p func) (let ((method-defs (cl--generic-method-files func)) symbols) @@ -3227,6 +3221,15 @@ edebug-instrument-function (edebug-eval-top-level-form) (push (edebug-form-data-symbol) symbols)))) symbols)) + ((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) + (edebug-eval-top-level-form) + (list func))) + ((consp func-marker) + (message "%s is already instrumented." func) + (list func)) (t (let ((loc (find-function-noselect func t))) (unless (cdr loc) diff --git a/lisp/emacs-lisp/generator.el b/lisp/emacs-lisp/generator.el index f3597cc387..23af6143a7 100644 --- a/lisp/emacs-lisp/generator.el +++ b/lisp/emacs-lisp/generator.el @@ -681,7 +681,8 @@ iter-defun When called as a function, NAME returns an iterator value that encapsulates the state of a computation that produces a sequence of values. Callers can retrieve each value using `iter-next'." - (declare (indent defun)) + (declare (indent defun) + (debug (&define name lambda-list lambda-doc def-body))) (cl-assert lexical-binding) (let* ((parsed-body (macroexp-parse-body body)) (declarations (car parsed-body)) @@ -693,7 +694,8 @@ iter-defun (defmacro iter-lambda (arglist &rest body) "Return a lambda generator. `iter-lambda' is to `iter-defun' as `lambda' is to `defun'." - (declare (indent defun)) + (declare (indent defun) + (debug (&define lambda-list lambda-doc def-body))) (cl-assert lexical-binding) `(lambda ,arglist ,(cps-generate-evaluator body))) diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el index c703cae445..36af88423c 100644 --- a/lisp/emacs-lisp/pcase.el +++ b/lisp/emacs-lisp/pcase.el @@ -226,7 +226,7 @@ pcase-lambda formal argument can be any pattern accepted by `pcase' (a mere variable name being but a special case of it)." (declare (doc-string 2) (indent defun) - (debug ((&rest pcase-PAT) body))) + (debug (&define (&rest pcase-PAT) lambda-doc def-body))) (let* ((bindings ()) (parsed-body (macroexp-parse-body body)) (args (mapcar (lambda (pat) diff --git a/lisp/subr.el b/lisp/subr.el index cf15ec287f..e0ef3e5885 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -110,8 +110,7 @@ lambda \(fn ARGS [DOCSTRING] [INTERACTIVE] BODY)" (declare (doc-string 2) (indent defun) - (debug (&define lambda-list - [&optional stringp] + (debug (&define lambda-list lambda-doc [&optional ("interactive" interactive)] def-body))) ;; Note that this definition should not use backquotes; subr.el should not -- 2.14.1