emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master d1be48f: Edebug: Overload `edebug-form-spec` even less


From: Stefan Monnier
Subject: master d1be48f: Edebug: Overload `edebug-form-spec` even less
Date: Fri, 12 Feb 2021 19:28:35 -0500 (EST)

branch: master
commit d1be48fdedabb451d5c6cf315fd5f09a632e771f
Author: Stefan Monnier <monnier@iro.umontreal.ca>
Commit: Stefan Monnier <monnier@iro.umontreal.ca>

    Edebug: Overload `edebug-form-spec` even less
    
    The `edebug-form-spec` symbol property was used both to map forms's
    head symbol to the corresponding spec, and to map spec element names
    to their expansion.
    
    This lead to name conflicts which break instrumentation of examples such as
    
        (cl-flet ((gate (x) x)) (gate 4))
    
    because of the Edebug spec element `gate`.
    So introduce a new symbol property `edebug-elem-spec`.
    
    * lisp/subr.el (def-edebug-elem-spec): New function.
    
    * lisp/emacs-lisp/edebug.el (edebug--get-elem-spec): New function.
    (edebug-match-symbol): Use it.
    (Core Edebug elems): Put them on `edebug-elem-spec` instead of
    `edebug-form-spec`.
    (ELisp special forms): Set their `edebug-form-spec` via dolist.
    (Other non-core Edebug elems): Use `def-edebug-elem-spec`.
    (edebug-\`): Use `declare`.
    
    * lisp/emacs-lisp/pcase.el (pcase-PAT, pcase-FUN, pcase-QPAT):
    * lisp/skeleton.el (skeleton-edebug-spec):
    * lisp/emacs-lisp/cl-macs.el: Use `def-edebug-elem-spec`.
    
    * test/lisp/emacs-lisp/edebug-tests.el
    (edebug-tests--conflicting-internal-names): New test.
    * test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el
    (edebug-test-code-cl-flet1): New test case.
    
    * doc/lispref/edebug.texi (Specification List): Add `def-edebug-elem-spec`.
    (Specification Examples): Use it.
    
    * doc/lispref/loading.texi (Hooks for Loading): Avoid the use of
    `def-edebug-spec` in example (better use `debug` declaration).
---
 doc/lispref/edebug.texi                            |  41 ++--
 doc/lispref/loading.texi                           |   2 +-
 etc/NEWS                                           |   7 +
 lisp/emacs-lisp/cl-macs.el                         | 170 ++++++++--------
 lisp/emacs-lisp/edebug.el                          | 224 ++++++++++-----------
 lisp/emacs-lisp/pcase.el                           |  27 ++-
 lisp/skeleton.el                                   |   8 +-
 lisp/subr.el                                       |  17 +-
 .../edebug-resources/edebug-test-code.el           |  10 +
 test/lisp/emacs-lisp/edebug-tests.el               |   5 +
 10 files changed, 273 insertions(+), 238 deletions(-)

diff --git a/doc/lispref/edebug.texi b/doc/lispref/edebug.texi
index 693d0e0..99d55c7 100644
--- a/doc/lispref/edebug.texi
+++ b/doc/lispref/edebug.texi
@@ -1203,7 +1203,7 @@ define Edebug specifications for special forms 
implemented in C.
 
 @defmac def-edebug-spec macro specification
 Specify which expressions of a call to macro @var{macro} are forms to be
-evaluated.  @var{specification} should be the edebug specification.
+evaluated.  @var{specification} should be the Edebug specification.
 Neither argument is evaluated.
 
 The @var{macro} argument can actually be any symbol, not just a macro
@@ -1389,8 +1389,13 @@ indirect specification.
 If the symbol has an Edebug specification, this @dfn{indirect
 specification} should be either a list specification that is used in
 place of the symbol, or a function that is called to process the
-arguments.  The specification may be defined with @code{def-edebug-spec}
-just as for macros.  See the @code{defun} example.
+arguments.  The specification may be defined with
+@code{def-edebug-elem-spec}:
+
+@defun def-edebug-elem-spec element specification
+Define the @var{specification} to use in place of the symbol @var{element}.
+@var{specification} has to be a list.
+@end defun
 
 Otherwise, the symbol should be a predicate.  The predicate is called
 with the argument, and if the predicate returns @code{nil}, the
@@ -1568,14 +1573,14 @@ specification for @code{defmacro} is very similar to 
that for
            [&optional ("interactive" interactive)]
            def-body))
 
-(def-edebug-spec lambda-list
-  (([&rest arg]
-    [&optional ["&optional" arg &rest arg]]
-    &optional ["&rest" arg]
-    )))
+(def-edebug-elem-spec 'lambda-list
+  '(([&rest arg]
+     [&optional ["&optional" arg &rest arg]]
+     &optional ["&rest" arg]
+     )))
 
-(def-edebug-spec interactive
-  (&optional &or stringp def-form))    ; @r{Notice: @code{def-form}}
+(def-edebug-elem-spec 'interactive
+  '(&optional &or stringp def-form))    ; @r{Notice: @code{def-form}}
 @end smallexample
 
 The specification for backquote below illustrates how to match
@@ -1588,11 +1593,11 @@ could fail.)
 @smallexample
 (def-edebug-spec \` (backquote-form))   ; @r{Alias just for clarity.}
 
-(def-edebug-spec backquote-form
-  (&or ([&or "," ",@@"] &or ("quote" backquote-form) form)
-       (backquote-form . [&or nil backquote-form])
-       (vector &rest backquote-form)
-       sexp))
+(def-edebug-elem-spec 'backquote-form
+  '(&or ([&or "," ",@@"] &or ("quote" backquote-form) form)
+        (backquote-form . [&or nil backquote-form])
+        (vector &rest backquote-form)
+        sexp))
 @end smallexample
 
 
@@ -1635,10 +1640,10 @@ option.  @xref{Instrumenting}.
 
 @defopt edebug-eval-macro-args
 When this is non-@code{nil}, all macro arguments will be instrumented
-in the generated code.  For any macro, an @code{edebug-form-spec}
+in the generated code.  For any macro, the @code{debug} declaration
 overrides this option.  So to specify exceptions for macros that have
-some arguments evaluated and some not, use @code{def-edebug-spec} to
-specify an @code{edebug-form-spec}.
+some arguments evaluated and some not, use the @code{debug} declaration
+specify an Edebug form specification.
 @end defopt
 
 @defopt edebug-save-windows
diff --git a/doc/lispref/loading.texi b/doc/lispref/loading.texi
index 22f0dde..33f3733 100644
--- a/doc/lispref/loading.texi
+++ b/doc/lispref/loading.texi
@@ -1125,7 +1125,7 @@ You don't need to give a directory or extension in the 
file name
 @var{library}.  Normally, you just give a bare file name, like this:
 
 @example
-(with-eval-after-load "edebug" (def-edebug-spec c-point t))
+(with-eval-after-load "js" (define-key js-mode-map "\C-c\C-c" 'js-eval))
 @end example
 
 To restrict which files can trigger the evaluation, include a
diff --git a/etc/NEWS b/etc/NEWS
index fe626fe..464b955 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -938,6 +938,13 @@ To customize obsolete user options, use 'customize-option' 
or
 ---
 *** 'get-edebug-spec' is obsolete, replaced by 'edebug-get-spec'.
 
++++
+*** New function 'def-edebug-elem-spec' to define Edebug spec elements.
+These used to be defined with 'def-edebug-spec' thus conflating the
+two name spaces, which lead to name collisions.
+The use of 'def-edebug-spec' to define Edebug spec elements is
+declared obsolete.
+
 *** Edebug specification lists can use some new keywords:
 
 +++
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el
index c312afe..5967e0d 100644
--- a/lisp/emacs-lisp/cl-macs.el
+++ b/lisp/emacs-lisp/cl-macs.el
@@ -186,14 +186,14 @@ The name is made by appending a number to PREFIX, default 
\"T\"."
 
 ;;; Program structure.
 
-(def-edebug-spec cl-declarations
-  (&rest ("cl-declare" &rest sexp)))
+(def-edebug-elem-spec 'cl-declarations
+  '(&rest ("cl-declare" &rest sexp)))
 
-(def-edebug-spec cl-declarations-or-string
-  (&or lambda-doc cl-declarations))
+(def-edebug-elem-spec 'cl-declarations-or-string
+  '(&or lambda-doc cl-declarations))
 
-(def-edebug-spec cl-lambda-list
-  (([&rest cl-lambda-arg]
+(def-edebug-elem-spec 'cl-lambda-list
+  '(([&rest cl-lambda-arg]
     [&optional ["&optional" cl-&optional-arg &rest cl-&optional-arg]]
     [&optional ["&rest" cl-lambda-arg]]
     [&optional ["&key" [cl-&key-arg &rest cl-&key-arg]
@@ -202,27 +202,27 @@ The name is made by appending a number to PREFIX, default 
\"T\"."
                &or (cl-lambda-arg &optional def-form) arg]]
     . [&or arg nil])))
 
-(def-edebug-spec cl-&optional-arg
-  (&or (cl-lambda-arg &optional def-form arg) arg))
+(def-edebug-elem-spec 'cl-&optional-arg
+  '(&or (cl-lambda-arg &optional def-form arg) arg))
 
-(def-edebug-spec cl-&key-arg
-  (&or ([&or (symbolp cl-lambda-arg) arg] &optional def-form arg) arg))
+(def-edebug-elem-spec 'cl-&key-arg
+  '(&or ([&or (symbolp cl-lambda-arg) arg] &optional def-form arg) arg))
 
-(def-edebug-spec cl-lambda-arg
-  (&or arg cl-lambda-list1))
+(def-edebug-elem-spec 'cl-lambda-arg
+  '(&or arg cl-lambda-list1))
 
-(def-edebug-spec cl-lambda-list1
-  (([&optional ["&whole" arg]]  ;; only allowed at lower levels
-    [&rest cl-lambda-arg]
-    [&optional ["&optional" cl-&optional-arg &rest cl-&optional-arg]]
-    [&optional ["&rest" cl-lambda-arg]]
-    [&optional ["&key" cl-&key-arg &rest cl-&key-arg
-                &optional "&allow-other-keys"]]
-    [&optional ["&aux" &rest
-                &or (cl-lambda-arg &optional def-form) arg]]
-    . [&or arg nil])))
+(def-edebug-elem-spec 'cl-lambda-list1
+  '(([&optional ["&whole" arg]] ;; only allowed at lower levels
+     [&rest cl-lambda-arg]
+     [&optional ["&optional" cl-&optional-arg &rest cl-&optional-arg]]
+     [&optional ["&rest" cl-lambda-arg]]
+     [&optional ["&key" cl-&key-arg &rest cl-&key-arg
+                 &optional "&allow-other-keys"]]
+     [&optional ["&aux" &rest
+                 &or (cl-lambda-arg &optional def-form) arg]]
+     . [&or arg nil])))
 
-(def-edebug-spec cl-type-spec sexp)
+(def-edebug-elem-spec 'cl-type-spec '(sexp))
 
 (defconst cl--lambda-list-keywords
   '(&optional &rest &key &allow-other-keys &aux &whole &body &environment))
@@ -390,39 +390,39 @@ and BODY is implicitly surrounded by (cl-block NAME ...).
 ;; Note that &environment is only allowed as first or last items in the
 ;; top level list.
 
-(def-edebug-spec cl-macro-list
-  (([&optional "&environment" arg]
-    [&rest cl-macro-arg]
-    [&optional ["&optional" &rest
-               &or (cl-macro-arg &optional def-form cl-macro-arg) arg]]
-    [&optional [[&or "&rest" "&body"] cl-macro-arg]]
-    [&optional ["&key" [&rest
-                       [&or ([&or (symbolp cl-macro-arg) arg]
-                             &optional def-form cl-macro-arg)
-                            arg]]
-               &optional "&allow-other-keys"]]
-    [&optional ["&aux" &rest
-               &or (cl-macro-arg &optional def-form) arg]]
-    [&optional "&environment" arg]
-    )))
-
-(def-edebug-spec cl-macro-arg
-  (&or arg cl-macro-list1))
-
-(def-edebug-spec cl-macro-list1
-  (([&optional "&whole" arg]  ;; only allowed at lower levels
-    [&rest cl-macro-arg]
-    [&optional ["&optional" &rest
-               &or (cl-macro-arg &optional def-form cl-macro-arg) arg]]
-    [&optional [[&or "&rest" "&body"] cl-macro-arg]]
-    [&optional ["&key" [&rest
-                       [&or ([&or (symbolp cl-macro-arg) arg]
-                             &optional def-form cl-macro-arg)
-                            arg]]
-               &optional "&allow-other-keys"]]
-    [&optional ["&aux" &rest
-               &or (cl-macro-arg &optional def-form) arg]]
-    . [&or arg nil])))
+(def-edebug-elem-spec 'cl-macro-list
+  '(([&optional "&environment" arg]
+     [&rest cl-macro-arg]
+     [&optional ["&optional" &rest
+                &or (cl-macro-arg &optional def-form cl-macro-arg) arg]]
+     [&optional [[&or "&rest" "&body"] cl-macro-arg]]
+     [&optional ["&key" [&rest
+                        [&or ([&or (symbolp cl-macro-arg) arg]
+                              &optional def-form cl-macro-arg)
+                             arg]]
+                &optional "&allow-other-keys"]]
+     [&optional ["&aux" &rest
+                &or (cl-macro-arg &optional def-form) arg]]
+     [&optional "&environment" arg]
+     )))
+
+(def-edebug-elem-spec 'cl-macro-arg
+  '(&or arg cl-macro-list1))
+
+(def-edebug-elem-spec 'cl-macro-list1
+  '(([&optional "&whole" arg] ;; only allowed at lower levels
+     [&rest cl-macro-arg]
+     [&optional ["&optional" &rest
+                &or (cl-macro-arg &optional def-form cl-macro-arg) arg]]
+     [&optional [[&or "&rest" "&body"] cl-macro-arg]]
+     [&optional ["&key" [&rest
+                        [&or ([&or (symbolp cl-macro-arg) arg]
+                              &optional def-form cl-macro-arg)
+                             arg]]
+                &optional "&allow-other-keys"]]
+     [&optional ["&aux" &rest
+                &or (cl-macro-arg &optional def-form) arg]]
+     . [&or arg nil])))
 
 ;;;###autoload
 (defmacro cl-defmacro (name args &rest body)
@@ -452,19 +452,19 @@ more details.
            (indent 2))
   `(defmacro ,name ,@(cl--transform-lambda (cons args body) name)))
 
-(def-edebug-spec cl-lambda-expr
-  (&define ("lambda" cl-lambda-list
-           cl-declarations-or-string
-           [&optional ("interactive" interactive)]
-           def-body)))
+(def-edebug-elem-spec 'cl-lambda-expr
+  '(&define ("lambda" cl-lambda-list
+            cl-declarations-or-string
+            [&optional ("interactive" interactive)]
+            def-body)))
 
 ;; Redefine function-form to also match cl-function
-(def-edebug-spec function-form
+(def-edebug-elem-spec 'function-form
   ;; form at the end could also handle "function",
   ;; but recognize it specially to avoid wrapping function forms.
-  (&or ([&or "quote" "function"] &or symbolp lambda-expr)
-       ("cl-function" cl-function)
-       form))
+  '(&or ([&or "quote" "function"] &or symbolp lambda-expr)
+        ("cl-function" cl-function)
+        form))
 
 ;;;###autoload
 (defmacro cl-function (func)
@@ -1051,20 +1051,20 @@ For more details, see Info node `(cl)Loop Facility'.
 ;;    [&rest loop-clause]
 ;;    ))
 
-;; (def-edebug-spec loop-with
-;;   ("with" loop-var
+;; (def-edebug-elem-spec 'loop-with
+;;  '("with" loop-var
 ;;    loop-type-spec
 ;;    [&optional ["=" form]]
 ;;    &rest ["and" loop-var
 ;;       loop-type-spec
 ;;       [&optional ["=" form]]]))
 
-;; (def-edebug-spec loop-for-as
-;;   ([&or "for" "as"] loop-for-as-subclause
+;; (def-edebug-elem-spec 'loop-for-as
+;;  '([&or "for" "as"] loop-for-as-subclause
 ;;    &rest ["and" loop-for-as-subclause]))
 
-;; (def-edebug-spec loop-for-as-subclause
-;;   (loop-var
+;; (def-edebug-elem-spec 'loop-for-as-subclause
+;;  '(loop-var
 ;;    loop-type-spec
 ;;    &or
 ;;    [[&or "in" "on" "in-ref" "across-ref"]
@@ -1124,19 +1124,19 @@ For more details, see Info node `(cl)Loop Facility'.
 ;;     [&optional ["by" form]]
 ;;     ]))
 
-;; (def-edebug-spec loop-initial-final
-;;   (&or ["initially"
+;; (def-edebug-elem-spec 'loop-initial-final
+;;  '(&or ["initially"
 ;;     ;; [&optional &or "do" "doing"]  ;; CLtL2 doesn't allow this.
 ;;     &rest loop-non-atomic-expr]
 ;;        ["finally" &or
 ;;     [[&optional &or "do" "doing"] &rest loop-non-atomic-expr]
 ;;     ["return" form]]))
 
-;; (def-edebug-spec loop-and-clause
-;;   (loop-clause &rest ["and" loop-clause]))
+;; (def-edebug-elem-spec 'loop-and-clause
+;;   '(loop-clause &rest ["and" loop-clause]))
 
-;; (def-edebug-spec loop-clause
-;;   (&or
+;; (def-edebug-elem-spec 'loop-clause
+;;  '(&or
 ;;    [[&or "while" "until" "always" "never" "thereis"] form]
 
 ;;    [[&or "collect" "collecting"
@@ -1163,10 +1163,10 @@ For more details, see Info node `(cl)Loop Facility'.
 ;;    loop-initial-final
 ;;    ))
 
-;; (def-edebug-spec loop-non-atomic-expr
-;;   ([&not atom] form))
+;; (def-edebug-elem-spec 'loop-non-atomic-expr
+;;   '([&not atom] form))
 
-;; (def-edebug-spec loop-var
+;; (def-edebug-elem-spec 'loop-var
 ;;   ;; The symbolp must be last alternative to recognize e.g. (a b . c)
 ;;   ;; loop-var =>
 ;;   ;; (loop-var . [&or nil loop-var])
@@ -1175,13 +1175,13 @@ For more details, see Info node `(cl)Loop Facility'.
 ;;   ;; (symbolp . (symbolp . [&or nil loop-var]))
 ;;   ;; (symbolp . (symbolp . loop-var))
 ;;   ;; (symbolp . (symbolp . symbolp)) == (symbolp symbolp . symbolp)
-;;   (&or (loop-var . [&or nil loop-var]) [gate symbolp]))
+;;   '(&or (loop-var . [&or nil loop-var]) [gate symbolp]))
 
-;; (def-edebug-spec loop-type-spec
-;;   (&optional ["of-type" loop-d-type-spec]))
+;; (def-edebug-elem-spec 'loop-type-spec
+;;   '(&optional ["of-type" loop-d-type-spec]))
 
-;; (def-edebug-spec loop-d-type-spec
-;;   (&or (loop-d-type-spec . [&or nil loop-d-type-spec]) cl-type-spec))
+;; (def-edebug-elem-spec 'loop-d-type-spec
+;;   '(&or (loop-d-type-spec . [&or nil loop-d-type-spec]) cl-type-spec))
 
 (defun cl--parse-loop-clause ()                ; uses loop-*
   (let ((word (pop cl--loop-args))
diff --git a/lisp/emacs-lisp/edebug.el b/lisp/emacs-lisp/edebug.el
index 7822994..47b4561 100644
--- a/lisp/emacs-lisp/edebug.el
+++ b/lisp/emacs-lisp/edebug.el
@@ -261,6 +261,14 @@ The argument is usually a symbol, but it doesn't have to 
be."
 
 (define-obsolete-function-alias 'get-edebug-spec #'edebug-get-spec "28.1")
 
+(defun edebug--get-elem-spec (elem)
+  "Return the specs of the Edebug element ELEM, if any.
+ELEM has to be a symbol."
+  (or (get elem 'edebug-elem-spec)
+      ;; For backward compatibility, we also allow the use of
+      ;; a form's name as a shorthand to refer to its spec.
+      (edebug-get-spec elem)))
+
 ;;;###autoload
 (defun edebug-basic-spec (spec)
   "Return t if SPEC uses only extant spec symbols.
@@ -1757,16 +1765,11 @@ contains a circular object."
                (gate . edebug-match-gate)
                ;;   (nil . edebug-match-nil)  not this one - special case it.
                ))
-  ;; FIXME: We abuse `edebug-form-spec' here.  It's normally used to store the
-  ;; specs for a given sexp's head, but here we use it to keep the
-  ;; function implementing of a given "core spec".
-  (put (car pair) 'edebug-form-spec (cdr pair)))
+  (put (car pair) 'edebug-elem-spec (cdr pair)))
 
 (defun edebug-match-symbol (cursor symbol)
   ;; Match a symbol spec.
-  ;; FIXME: We abuse `edebug-get-spec' here, passing it a *spec* rather than
-  ;; the head element of a source sexp.
-  (let* ((spec (edebug-get-spec symbol)))
+  (let* ((spec (edebug--get-elem-spec symbol)))
     (cond
      (spec
       (if (consp spec)
@@ -2184,112 +2187,114 @@ into `edebug--cl-macrolet-defs' which is checked in 
`edebug-list-form-args'."
 
 ;;;* Emacs special forms and some functions.
 
-;; quote expects only one argument, although it allows any number.
-(def-edebug-spec quote sexp)
-
-;; The standard defining forms.
-(def-edebug-spec defconst defvar)
-(def-edebug-spec defvar (symbolp &optional form stringp))
-
-(def-edebug-spec defun
-  (&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 lambda-doc
-           [&optional ("declare" &rest sexp)] def-body))
-
-(def-edebug-spec arglist lambda-list)  ;; deprecated - use lambda-list.
+(pcase-dolist
+    (`(,name ,spec)
+
+     '((quote (sexp)) ;quote expects only one arg, tho it allows any number.
+
+       ;; The standard defining forms.
+       (defvar (symbolp &optional form stringp))
+       (defconst defvar)
+
+       ;; Contrary to macros, special forms default to assuming that all args
+       ;; are normal forms, so we don't need to do anything about those
+       ;; special forms:
+       ;;(save-current-buffer t)
+       ;;(save-excursion t)
+       ;;...
+       ;;(progn t)
+
+       ;; `defun' and `defmacro' are not special forms (any more), but it's
+       ;; more convenient to define their Edebug spec here.
+       (defun ( &define name lambda-list lambda-doc
+               [&optional ("declare" &rest sexp)]
+               [&optional ("interactive" &optional &or stringp def-form)]
+               def-body))
+
+       ;; FIXME: Improve `declare' so we can Edebug gv-expander and
+       ;; gv-setter declarations.
+       (defmacro ( &define name lambda-list lambda-doc
+                   [&optional ("declare" &rest sexp)]
+                   def-body))
+
+       ;; function expects a symbol or a lambda or macro expression
+       ;; A macro is allowed by Emacs.
+       (function (&or symbolp lambda-expr))
+
+       ;; FIXME?  The manual uses this form (maybe that's just
+       ;; for illustration purposes?):
+       ;; (let ((&rest &or symbolp (gate symbolp &optional form)) body))
+       (let ((&rest &or (symbolp &optional form) symbolp) body))
+       (let* let)
+
+       (setq (&rest symbolp form))
+       (cond (&rest (&rest form)))
+
+       (condition-case ( symbolp form
+                         &rest ([&or symbolp (&rest symbolp)] body)))
+
+       (\` (backquote-form))
+
+       ;; Assume immediate quote in unquotes mean backquote at next
+       ;;  higher level.
+       (\, (&or ("quote" edebug-\`) def-form))
+       (\,@ (&define  ;; so (,@ form) is never wrapped.
+            &or ("quote" edebug-\`) def-form))
+       ))
+    (put name 'edebug-form-spec spec))
 
-(def-edebug-spec lambda-list
-  (([&rest arg]
-    [&optional ["&optional" arg &rest arg]]
-    &optional ["&rest" arg]
-    )))
+(def-edebug-elem-spec 'lambda-list
+  '(([&rest arg]
+     [&optional ["&optional" arg &rest arg]]
+     &optional ["&rest" arg]
+     )))
 
-(def-edebug-spec lambda-doc
-  (&optional [&or stringp
-                  (&define ":documentation" def-form)]))
+(def-edebug-elem-spec 'arglist '(lambda-list))  ;; deprecated - use 
lambda-list.
 
-(def-edebug-spec interactive
-  (&optional &or stringp def-form))
+(def-edebug-elem-spec 'lambda-doc
+  '(&optional [&or stringp
+                   (&define ":documentation" def-form)]))
 
 ;; A function-form is for an argument that may be a function or a form.
 ;; This specially recognizes anonymous functions quoted with quote.
-(def-edebug-spec function-form
+(def-edebug-elem-spec 'function-form          ;Deprecated, use `form'!
   ;; form at the end could also handle "function",
   ;; but recognize it specially to avoid wrapping function forms.
-  (&or ([&or "quote" "function"] &or symbolp lambda-expr) form))
-
-;; function expects a symbol or a lambda or macro expression
-;; A macro is allowed by Emacs.
-(def-edebug-spec function (&or symbolp lambda-expr))
-
-;; A macro expression is a lambda expression with "macro" prepended.
-(def-edebug-spec macro (&define "lambda" lambda-list def-body))
-
-;; (def-edebug-spec anonymous-form ((&or ["lambda" lambda] ["macro" macro])))
-
-;; Standard functions that take function-forms arguments.
-
-;; 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))
-
-(def-edebug-spec let* let)
-
-(def-edebug-spec setq (&rest symbolp form))
-
-(def-edebug-spec cond (&rest (&rest form)))
-
-(def-edebug-spec condition-case
-  (symbolp
-   form
-   &rest ([&or symbolp (&rest symbolp)] body)))
-
-
-(def-edebug-spec \` (backquote-form))
+  '(&or ([&or "quote" "function"] &or symbolp lambda-expr) form))
 
 ;; Supports quotes inside backquotes,
 ;; but only at the top level inside unquotes.
-(def-edebug-spec backquote-form
-  (&or
-   ;; Disallow instrumentation of , and ,@ inside a nested backquote, since
-   ;; these are likely to be forms generated by a macro being debugged.
-   ("`" nested-backquote-form)
-   ([&or "," ",@"] &or ("quote" backquote-form) form)
-   ;; The simple version:
-   ;;   (backquote-form &rest backquote-form)
-   ;; doesn't handle (a . ,b).  The straightforward fix:
-   ;;   (backquote-form . [&or nil backquote-form])
-   ;; uses up too much stack space.
-   ;; Note that `(foo . ,@bar) is not valid, so we don't need to handle it.
-   (backquote-form [&rest [&not ","] backquote-form]
-                  . [&or nil backquote-form])
-   ;; If you use dotted forms in backquotes, replace the previous line
-   ;; with the following.  This takes quite a bit more stack space, however.
-   ;; (backquote-form . [&or nil backquote-form])
-   (vector &rest backquote-form)
-   sexp))
-
-(def-edebug-spec nested-backquote-form
-  (&or
-   ("`" &error "Triply nested backquotes (without commas \"between\" them) \
+(def-edebug-elem-spec 'backquote-form
+  '(&or
+    ;; Disallow instrumentation of , and ,@ inside a nested backquote, since
+    ;; these are likely to be forms generated by a macro being debugged.
+    ("`" nested-backquote-form)
+    ([&or "," ",@"] &or ("quote" backquote-form) form)
+    ;; The simple version:
+    ;;   (backquote-form &rest backquote-form)
+    ;; doesn't handle (a . ,b).  The straightforward fix:
+    ;;   (backquote-form . [&or nil backquote-form])
+    ;; uses up too much stack space.
+    ;; Note that `(foo . ,@bar) is not valid, so we don't need to handle it.
+    (backquote-form [&rest [&not ","] backquote-form]
+                   . [&or nil backquote-form])
+    ;; If you use dotted forms in backquotes, replace the previous line
+    ;; with the following.  This takes quite a bit more stack space, however.
+    ;; (backquote-form . [&or nil backquote-form])
+    (vector &rest backquote-form)
+    sexp))
+
+(def-edebug-elem-spec 'nested-backquote-form
+  '(&or
+    ("`" &error "Triply nested backquotes (without commas \"between\" them) \
 are too difficult to instrument")
-   ;; Allow instrumentation of any , or ,@ contained within the (\, ...) or
-   ;; (\,@ ...) matched on the next line.
-   ([&or "," ",@"] backquote-form)
-   (nested-backquote-form [&rest [&not "," ",@"] nested-backquote-form]
-                          . [&or nil nested-backquote-form])
-   (vector &rest nested-backquote-form)
-   sexp))
+    ;; Allow instrumentation of any , or ,@ contained within the (\, ...) or
+    ;; (\,@ ...) matched on the next line.
+    ([&or "," ",@"] backquote-form)
+    (nested-backquote-form [&rest [&not "," ",@"] nested-backquote-form]
+                           . [&or nil nested-backquote-form])
+    (vector &rest nested-backquote-form)
+    sexp))
 
 ;; Special version of backquote that instruments backquoted forms
 ;; destined to be evaluated, usually as the result of a
@@ -2304,20 +2309,9 @@ are too difficult to instrument")
 
 ;; ,@ might have some problems.
 
-(defalias 'edebug-\` '\`)  ;; same macro as regular backquote.
-(def-edebug-spec edebug-\` (def-form))
-
-;; Assume immediate quote in unquotes mean backquote at next higher level.
-(def-edebug-spec \, (&or ("quote" edebug-\`) def-form))
-(def-edebug-spec \,@ (&define  ;; so (,@ form) is never wrapped.
-                    &or ("quote" edebug-\`) def-form))
-
-;; New byte compiler.
-
-(def-edebug-spec save-selected-window t)
-(def-edebug-spec save-current-buffer t)
-
-;; Anything else?
+(defmacro edebug-\` (exp)
+  (declare (debug (def-form)))
+  (list '\` exp))
 
 ;;; The debugger itself
 
diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el
index d6c96c1..5d428ac 100644
--- a/lisp/emacs-lisp/pcase.el
+++ b/lisp/emacs-lisp/pcase.el
@@ -62,15 +62,14 @@
 
 (defvar pcase--dontwarn-upats '(pcase--dontcare))
 
-(def-edebug-spec pcase-PAT
-  (&or (&lookup symbolp pcase--get-edebug-spec)
-       sexp))
+(def-edebug-elem-spec 'pcase-PAT
+  '(&or (&lookup symbolp pcase--get-edebug-spec) sexp))
 
-(def-edebug-spec pcase-FUN
-  (&or lambda-expr
-       ;; Punt on macros/special forms.
-       (functionp &rest form)
-       sexp))
+(def-edebug-elem-spec 'pcase-FUN
+  '(&or lambda-expr
+        ;; Punt on macros/special forms.
+        (functionp &rest form)
+        sexp))
 
 ;; Only called from edebug.
 (declare-function edebug-get-spec "edebug" (symbol))
@@ -925,13 +924,13 @@ Otherwise, it defers to REST which is a list of branches 
of the form
        (t (error "Unknown pattern `%S'" upat)))))
    (t (error "Incorrect MATCH %S" (car matches)))))
 
-(def-edebug-spec pcase-QPAT
+(def-edebug-elem-spec 'pcase-QPAT
   ;; Cf. edebug spec for `backquote-form' in edebug.el.
-  (&or ("," pcase-PAT)
-       (pcase-QPAT [&rest [&not ","] pcase-QPAT]
-                  . [&or nil pcase-QPAT])
-       (vector &rest pcase-QPAT)
-       sexp))
+  '(&or ("," pcase-PAT)
+        (pcase-QPAT [&rest [&not ","] pcase-QPAT]
+                   . [&or nil pcase-QPAT])
+       (vector &rest pcase-QPAT)
+       sexp))
 
 (pcase-defmacro \` (qpat)
   "Backquote-style pcase patterns: \\=`QPAT
diff --git a/lisp/skeleton.el b/lisp/skeleton.el
index 48491e4..8a50fbe 100644
--- a/lisp/skeleton.el
+++ b/lisp/skeleton.el
@@ -104,10 +104,10 @@ are integer buffer positions in the reverse order of the 
insertion order.")
 (defvar skeleton-point)
 (defvar skeleton-regions)
 
-(def-edebug-spec skeleton-edebug-spec
-  ([&or null stringp (stringp &rest stringp) [[&not atom] sexp]]
-   &rest &or "n" "_" "-" ">" "@" "&" "!" "|" "resume:"
-   ("quote" def-form) skeleton-edebug-spec def-form))
+(def-edebug-elem-spec 'skeleton-edebug-spec
+  '([&or null stringp (stringp &rest stringp) [[&not atom] sexp]]
+    &rest &or "n" "_" "-" ">" "@" "&" "!" "|" "resume:"
+    ("quote" def-form) skeleton-edebug-spec def-form))
 ;;;###autoload
 (defmacro define-skeleton (command documentation &rest skeleton)
   "Define a user-configurable COMMAND that enters a statement skeleton.
diff --git a/lisp/subr.el b/lisp/subr.el
index 454ea54..70ee281 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -82,7 +82,7 @@ Testcover will raise an error."
   form)
 
 (defmacro def-edebug-spec (symbol spec)
-  "Set the `edebug-form-spec' property of SYMBOL according to SPEC.
+  "Set the Edebug SPEC to use for sexps which have SYMBOL as head.
 Both SYMBOL and SPEC are unevaluated.  The SPEC can be:
 0 (instrument no arguments); t (instrument all arguments);
 a symbol (naming a function with an Edebug specification); or a list.
@@ -91,6 +91,21 @@ Info node `(elisp)Specification List' for details."
   (declare (indent 1))
   `(put (quote ,symbol) 'edebug-form-spec (quote ,spec)))
 
+(defun def-edebug-elem-spec (name spec)
+  "Define a new Edebug spec element NAME as shorthand for SPEC.
+The SPEC has to be a list or a symbol.
+The elements of the list describe the argument types; see
+Info node `(elisp)Specification List' for details.
+If SPEC is a symbol it should name another pre-existing Edebug element."
+  (declare (indent 1))
+  (when (string-match "\\`[&:]" (symbol-name name))
+    ;; & and : have special meaning in spec element names.
+    (error "Edebug spec name cannot start with '&' or ':'"))
+  (unless (consp spec)
+    (error "Edebug spec has to be a list: %S" spec))
+  (put name 'edebug-elem-spec spec))
+
+
 (defmacro lambda (&rest cdr)
   "Return an anonymous function.
 Under dynamic binding, a call of the form (lambda ARGS DOCSTRING
diff --git a/test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el 
b/test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el
index f8ca39c..d77df3c 100644
--- a/test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el
+++ b/test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el
@@ -137,5 +137,15 @@
                                ,(cons func args))))
     (wrap + 1 x)))
 
+(defun edebug-test-code-cl-flet1 ()
+  (cl-flet
+      ;; This `&rest' sexp head should not collide with
+      ;; the Edebug spec elem of the same name.
+      ((f (&rest x) x)
+       (gate (x) (+ x 5)))
+    ;; This call to `gate' shouldn't collide with the Edebug spec elem
+    ;; of the same name.
+    (message "Hi %s" (gate 7))))
+
 (provide 'edebug-test-code)
 ;;; edebug-test-code.el ends here
diff --git a/test/lisp/emacs-lisp/edebug-tests.el 
b/test/lisp/emacs-lisp/edebug-tests.el
index 6a6080d..c11bfcf 100644
--- a/test/lisp/emacs-lisp/edebug-tests.el
+++ b/test/lisp/emacs-lisp/edebug-tests.el
@@ -954,6 +954,11 @@ primary ones (Bug#42671)."
         (list (intern "edebug-cl-defmethod-qualifier :around ((_ number))")
               (intern "edebug-cl-defmethod-qualifier ((_ number))")))))))
 
+(ert-deftest edebug-tests--conflicting-internal-names ()
+  "Check conflicts between form's head symbols and Edebug spec elements."
+  (edebug-tests-with-normal-env
+   (edebug-tests-setup-@ "cl-flet1" '(10) t)))
+
 (ert-deftest edebug-tests-cl-flet ()
   "Check that Edebug can instrument `cl-flet' forms without name
 clashes (Bug#41853)."



reply via email to

[Prev in Thread] Current Thread [Next in Thread]