]> git.eshelyaron.com Git - emacs.git/commitdiff
* lisp/emacs-lisp/edebug.el (edebug--handle-&-spec-op <&name>): New method
authorStefan Monnier <monnier@iro.umontreal.ca>
Sat, 13 Feb 2021 21:21:53 +0000 (16:21 -0500)
committerStefan Monnier <monnier@iro.umontreal.ca>
Sat, 13 Feb 2021 21:21:53 +0000 (16:21 -0500)
(edebug--concat-name): New function.
(edebug-match-name, edebug-match-cl-generic-method-qualifier)
(edebug-match-cl-generic-method-args): Delete functions.

* doc/lispref/edebug.texi (Specification List): Document it.

* lisp/emacs-lisp/cl-generic.el (cl-defgeneric): Use `&name`.
(cl-generic--method-qualifier-p): New predicate.
(cl-defmethod): Use it and `&name`.
* lisp/emacs-lisp/cl-macs.el (cl-defun, cl-iter-defun, cl-flet):
* lisp/emacs-lisp/eieio-compat.el (defmethod):
* lisp/emacs-lisp/gv.el (gv-define-setter):
* lisp/emacs-lisp/ert.el (ert-deftest): Use `&name`.
* lisp/erc/erc-backend.el (define-erc-response-handler): Use `declare`
and `&name`.

doc/lispref/edebug.texi
etc/NEWS
lisp/emacs-lisp/cl-generic.el
lisp/emacs-lisp/cl-macs.el
lisp/emacs-lisp/edebug.el
lisp/emacs-lisp/eieio-compat.el
lisp/emacs-lisp/ert.el
lisp/emacs-lisp/gv.el
lisp/erc/erc-backend.el

index 99d55c7ab95cad6753d016ec667d20fcfaa56302..2412e844b70468cd1e5bbeacd21f2e2ae3aa9f25 100644 (file)
@@ -1444,29 +1444,23 @@ Here is a list of additional specifications that may appear only after
 @code{&define}.  See the @code{defun} example.
 
 @table @code
+@item &name
+Extracts the name of the current defining form from the code.
+It takes the form @code{&name [@var{prestring}] @var{spec}
+[@var{poststring}] @var{fun} @var{args...}} and means that Edebug will
+match @var{spec} against the code and then call @var{fun} with the
+concatenation of the current name, @var{args...}, @var{prestring},
+the code that matched @code{spec}, and @var{poststring}.  If @var{fun}
+is absent, it defaults to a function that concatenates the arguments
+(with an @code{@} between the previous name and the new).
+
 @item name
 The argument, a symbol, is the name of the defining form.
+Shorthand for @code{[&name symbolp]}.
 
 A defining form is not required to have a name field; and it may have
 multiple name fields.
 
-@item :name
-This construct does not actually match an argument.  The element
-following @code{:name} should be a symbol; it is used as an additional
-name component for the definition.  You can use this to add a unique,
-static component to the name of the definition.  It may be used more
-than once.
-
-@item :unique
-This construct is like @code{:name}, but generates unique names.  It
-does not match an argument.  The element following @code{:unique}
-should be a string; it is used as the prefix for an additional name
-component for the definition.  You can use this to add a unique,
-dynamic component to the name of the definition.  This is useful for
-macros that can define the same symbol multiple times in different
-scopes, such as @code{cl-flet}; @ref{Function Bindings,,,cl}.  It may
-be used more than once.
-
 @item arg
 The argument, a symbol, is the name of an argument of the defining form.
 However, lambda-list keywords (symbols starting with @samp{&})
index aead8c6f78179d42a5fd96c977d75d1a8bfdaf84..de26c0172b140915688c4c018a5ef5695a70c35d 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -936,7 +936,11 @@ To customize obsolete user options, use 'customize-option' or
 ** Edebug
 
 ---
-*** 'get-edebug-spec' is obsolete, replaced by 'edebug-get-spec'.
+*** Obsoletions
+**** 'get-edebug-spec' is obsolete, replaced by 'edebug-get-spec'.
+
++++
+**** The Edebug spec operator ':name NAME' is obsolete.
 
 +++
 *** New function 'def-edebug-elem-spec' to define Edebug spec elements.
@@ -954,8 +958,7 @@ declared obsolete.
 **** '&error MSG' unconditionally aborts the current edebug instrumentation.
 
 +++
-**** ':unique STRING' appends STRING to the Edebug name of the current
-definition to (hopefully) make it more unique.
+**** '&name SPEC FUN' extracts the current name from the code matching SPEC.
 
 ** ElDoc
 
index 8e36dbe4a36400b922a657e013dc51a8e7458241..229608395ebbc22d41dbd7e780beac7f22271942 100644 (file)
@@ -206,22 +206,29 @@ 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)
            (debug
-            (&define [&or name ("setf" name :name setf)] listp
-                     lambda-doc
+            (&define [&name sexp] ;Allow (setf ...) additionally to symbols.
+                     listp lambda-doc
                      [&rest [&or
                              ("declare" &rest sexp)
                              (":argument-precedence-order" &rest sexp)
                              (&define ":method"
-                                      ;; FIXME: The `:unique'
+                                      ;; FIXME: The `gensym'
                                       ;; construct works around
                                       ;; Bug#42672.  We'd rather want
                                       ;; names like those generated by
                                       ;; `cl-defmethod', but that
                                       ;; requires larger changes to
                                       ;; Edebug.
-                                      :unique "cl-generic-:method@"
-                                      [&rest cl-generic-method-qualifier]
-                                      cl-generic-method-args lambda-doc
+                                      [&name "cl-generic-:method@" []]
+                                      [&name [] gensym] ;Make it unique!
+                                      [&name
+                                       [[&rest cl-generic--method-qualifier-p]
+                                        ;; FIXME: We don't actually want the
+                                        ;; argument's names to be considered
+                                        ;; part of the name of the defined
+                                        ;; function.
+                                        listp]] ;Formal args
+                                      lambda-doc
                                       def-body)]]
                      def-body)))
   (let* ((doc (if (stringp (car-safe options-and-methods))
@@ -398,6 +405,9 @@ the specializer used will be the one returned by BODY."
       (let ((combined-doc (buffer-string)))
         (if ud (help-add-fundoc-usage combined-doc (car ud)) combined-doc)))))
 
+(defun cl-generic--method-qualifier-p (x)
+  (not (listp x)))
+
 ;;;###autoload
 (defmacro cl-defmethod (name args &rest body)
   "Define a new method for generic function NAME.
@@ -440,15 +450,17 @@ The set of acceptable TYPEs (also called \"specializers\") is defined
   (declare (doc-string 3) (indent defun)
            (debug
             (&define                    ; this means we are defining something
-             [&or name ("setf" name :name setf)]
-             ;; ^^ This is the methods symbol
-             [ &rest cl-generic-method-qualifier ]
-             ;; Multiple qualifiers are allowed.
-             cl-generic-method-args     ; arguments
+             [&name [sexp   ;Allow (setf ...) additionally to symbols.
+                     ;; Multiple qualifiers are allowed.
+                     [&rest cl-generic--method-qualifier-p]
+                     ;; FIXME: We don't actually want the argument's names
+                     ;; to be considered part of the name of the
+                     ;; defined function.
+                     listp]]     ; arguments
              lambda-doc                 ; documentation string
              def-body)))                ; part to be debugged
   (let ((qualifiers nil))
-    (while (not (listp args))
+    (while (cl-generic--method-qualifier-p args)
       (push args qualifiers)
       (setq args (pop body)))
     (when (eq 'setf (car-safe name))
index 5967e0d084fa98149b08f418f59b958f43565be1..e2faf6df53444fa43f382d2f09fae9a34c138dc0 100644 (file)
@@ -358,7 +358,7 @@ more details.
 \(fn NAME ARGLIST [DOCSTRING] BODY...)"
   (declare (debug
             ;; Same as defun but use cl-lambda-list.
-            (&define [&or name ("setf" :name setf name)]
+            (&define [&name sexp]   ;Allow (setf ...) additionally to symbols.
                      cl-lambda-list
                      cl-declarations-or-string
                      [&optional ("interactive" interactive)]
@@ -376,7 +376,7 @@ and BODY is implicitly surrounded by (cl-block NAME ...).
 \(fn NAME ARGLIST [DOCSTRING] BODY...)"
   (declare (debug
             ;; Same as iter-defun but use cl-lambda-list.
-            (&define [&or name ("setf" :name setf name)]
+            (&define [&name sexp]   ;Allow (setf ...) additionally to symbols.
                      cl-lambda-list
                      cl-declarations-or-string
                      [&optional ("interactive" interactive)]
@@ -2016,8 +2016,9 @@ info node `(cl) Function Bindings' for details.
 
 \(fn ((FUNC ARGLIST BODY...) ...) FORM...)"
   (declare (indent 1)
-           (debug ((&rest [&or (&define name :unique "cl-flet@" form)
-                               (&define name :unique "cl-flet@"
+           (debug ((&rest [&or (symbolp form)
+                               (&define [&name symbolp "@cl-flet@"]
+                                        [&name [] gensym] ;Make it unique!
                                         cl-lambda-list
                                         cl-declarations-or-string
                                         [&optional ("interactive" interactive)]
index cbf2d171a96970113ea80497fc2f45a544e6316d..867161e02806256b8d58859ce8ebffe817a08334 100644 (file)
@@ -1748,16 +1748,12 @@ contains a circular object."
 (dolist (pair '((form . edebug-match-form)
                (sexp . edebug-match-sexp)
                (body . edebug-match-body)
-               (name . edebug-match-name)
                (arg . edebug-match-arg)
                (def-body . edebug-match-def-body)
                (def-form . edebug-match-def-form)
                ;; Less frequently used:
                ;; (function . edebug-match-function)
                (lambda-expr . edebug-match-lambda-expr)
-                (cl-generic-method-qualifier
-                 . edebug-match-cl-generic-method-qualifier)
-                (cl-generic-method-args . edebug-match-cl-generic-method-args)
                 (cl-macrolet-expr . edebug-match-cl-macrolet-expr)
                 (cl-macrolet-name . edebug-match-cl-macrolet-name)
                 (cl-macrolet-body . edebug-match-cl-macrolet-body)
@@ -2056,19 +2052,61 @@ and then matches the rest against the output of (FUN ARGS... HEAD)."
       )))
 
 
-(defun edebug-match-name (cursor)
-  ;; Set the edebug-def-name bound in edebug-defining-form.
-  (let ((name (edebug-top-element-required cursor "Expected name")))
-    ;; Maybe strings and numbers could be used.
-    (if (not (symbolp name))
-       (edebug-no-match cursor "Symbol expected for name of definition"))
-    (setq edebug-def-name
-         (if edebug-def-name
-             ;; Construct a new name by appending to previous name.
-             (intern (format "%s@%s" edebug-def-name name))
-           name))
-    (edebug-move-cursor cursor)
-    (list name)))
+(cl-defmethod edebug--handle-&-spec-op ((_ (eql &name)) cursor specs)
+  "Compute the name for `&name SPEC FUN` spec operator.
+
+The full syntax of that operator is:
+    &name [PRESTRING] SPEC [POSTSTRING] FUN ARGS...
+
+Extracts the head of the data by matching it against SPEC,
+and then get the new name to use by calling
+  (FUN ARGS... OLDNAME [PRESTRING] HEAD [POSTSTRING])
+FUN should return either a string or a symbol.
+FUN can be missing in which case it defaults to concatenating
+the new name to the end of the old with an \"@\" char between the two.
+PRESTRING and POSTSTRING are optional strings that get prepended
+or appended to the actual name."
+  (pcase-let*
+      ((`(,spec ,fun . ,args) specs)
+       (prestrings (when (stringp spec)
+                     (prog1 (list spec) (setq spec fun fun (pop args)))))
+       (poststrings (when (stringp fun)
+                      (prog1 (list fun) (setq fun (pop args)))))
+       (exps (edebug-cursor-expressions cursor))
+       (instrumented (edebug-match-one-spec cursor spec))
+       (consumed (- (length exps)
+                    (length (edebug-cursor-expressions cursor))))
+       (newname (apply (or fun #'edebug--concat-name)
+                       `(,@args ,edebug-def-name
+                                ,@prestrings
+                                ,@(seq-subseq exps 0 consumed)
+                                ,@poststrings))))
+    (cl-assert (eq (edebug-cursor-expressions cursor) (nthcdr consumed exps)))
+    (setq edebug-def-name (if (stringp newname) (intern newname) newname))
+    instrumented))
+
+(defun edebug--concat-name (oldname &rest newnames)
+  (let ((newname (if (null (cdr newnames))
+                     (car newnames)
+                   ;; Put spaces between each name, but not for the
+                   ;; leading and trailing strings, if any.
+                   (let (beg mid end)
+                     (dolist (name newnames)
+                       (if (stringp name)
+                           (push name (if mid end beg))
+                         (when end (setq mid (nconc end mid) end nil))
+                         (push name mid)))
+                     (apply #'concat `(,@(nreverse beg)
+                                       ,(mapconcat (lambda (x) (format "%s" x))
+                                                   (nreverse mid) " ")
+                                       ,@(nreverse end)))))))
+    (if (null oldname)
+        (if (or (stringp newname) (symbolp newname))
+            newname
+          (format "%s" newname))
+      (format "%s@%s" edebug-def-name newname))))
+
+(def-edebug-elem-spec 'name '(&name symbolp))
 
 (cl-defgeneric edebug--handle-:-spec-op (op cursor spec)
   "Handle :foo spec operators.
@@ -2094,26 +2132,6 @@ SPEC is the symbol name prefix for `gensym'."
            suffix)))
   nil)
 
-(defun edebug-match-cl-generic-method-qualifier (cursor)
-  "Match a QUALIFIER for `cl-defmethod' at CURSOR."
-  (let ((args (edebug-top-element-required cursor "Expected qualifier")))
-    ;; Like in CLOS spec, we support any non-list values.
-    (unless (atom args) (edebug-no-match cursor "Atom expected"))
-    ;; Append the arguments to `edebug-def-name' (Bug#42671).
-    (setq edebug-def-name (intern (format "%s %s" edebug-def-name args)))
-    (edebug-move-cursor cursor)
-    (list args)))
-
-(defun edebug-match-cl-generic-method-args (cursor)
-  (let ((args (edebug-top-element-required cursor "Expected arguments")))
-    (if (not (consp args))
-        (edebug-no-match cursor "List expected"))
-    ;; Append the arguments to edebug-def-name.
-    (setq edebug-def-name
-          (intern (format "%s %s" edebug-def-name args)))
-    (edebug-move-cursor cursor)
-    (list args)))
-
 (defvar edebug--cl-macrolet-defs nil
   "List of symbols found within the bindings of enclosing `cl-macrolet' forms.")
 (defvar edebug--current-cl-macrolet-defs nil
index db97d4ca4e80d38ff8e92d064335fed0fe22b786..6d84839c341443a5ad8395fb61ab96d19176a16c 100644 (file)
@@ -105,7 +105,7 @@ Summary:
   (declare (doc-string 3) (obsolete cl-defmethod "25.1")
            (debug
             (&define                    ; this means we are defining something
-             [&or name ("setf" name :name setf)]
+             [&name sexp]   ;Allow (setf ...) additionally to symbols.
              ;; ^^ This is the methods symbol
              [ &optional symbolp ]                ; this is key :before etc
              cl-generic-method-args               ; arguments
index fdbf95319ff50951843724c794c2378914d63f08..e08fa7ac7b30d4337315863d9a0bf4b7f54e6a44 100644 (file)
@@ -196,8 +196,8 @@ it has to be wrapped in `(eval (quote ...))'.
 
 \(fn NAME () [DOCSTRING] [:expected-result RESULT-TYPE] \
 [:tags \\='(TAG...)] BODY...)"
-  (declare (debug (&define :name test
-                           name sexp [&optional stringp]
+  (declare (debug (&define [&name "test@" symbolp]
+                          sexp [&optional stringp]
                           [&rest keywordp sexp] def-body))
            (doc-string 3)
            (indent 2))
index edacdf7f0c833585d635339cf1a0b15fca434f96..3200b1c3494f5f80a51fd84531d0b5f5c0f0fb2f 100644 (file)
@@ -229,7 +229,8 @@ The first arg in ARGLIST (the one that receives VAL) receives an expression
 which can do arbitrary things, whereas the other arguments are all guaranteed
 to be pure and copyable.  Example use:
   (gv-define-setter aref (v a i) \\=`(aset ,a ,i ,v))"
-  (declare (indent 2) (debug (&define name :name gv-setter sexp def-body)))
+  (declare (indent 2)
+           (debug (&define [&name symbolp "@gv-setter"] sexp def-body)))
   `(gv-define-expander ,name
      (lambda (do &rest args)
        (declare-function
index 6f1193cbb2bb09762c987aa029302ace3bcac9ef..73c2b56b02e231c428dc324c73f3d8d04ee99cb1 100644 (file)
@@ -1079,14 +1079,12 @@ Finds hooks by looking in the `erc-server-responses' hash table."
     (erc-display-message parsed 'notice proc line)))
 
 
-(put 'define-erc-response-handler 'edebug-form-spec
-     '(&define :name erc-response-handler
-               (name &rest name)
-               &optional sexp sexp def-body))
-
 (cl-defmacro define-erc-response-handler ((name &rest aliases)
-                                        &optional extra-fn-doc extra-var-doc
-                                        &rest fn-body)
+                                          &optional extra-fn-doc extra-var-doc
+                                          &rest fn-body)
+  (declare (debug (&define [&name "erc-response-handler@"
+                                  (symbolp &rest symbolp)]
+                           &optional sexp sexp def-body)))
   "Define an ERC handler hook/function pair.
 NAME is the response name as sent by the server (see the IRC RFC for
 meanings).