aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGemini Lasswell2018-07-20 21:54:00 -0700
committerGemini Lasswell2018-08-01 13:59:49 -0700
commitdf7371b84e9cfbb6e62c3196c2bc588eb934b835 (patch)
tree9321571f27ac46fc4a45856fa4564c6bccc36bac
parent22d463ed5ca262e1d8893b115c3f1237485fc7e0 (diff)
downloademacs-df7371b84e9cfbb6e62c3196c2bc588eb934b835.tar.gz
emacs-df7371b84e9cfbb6e62c3196c2bc588eb934b835.zip
Fix Edebug spec for cl-macrolet (bug#29919)
Add an Edebug matching function for cl-macrolet which keeps track of its bindings and treats them as macros without Edebug specs when found in the body of the expression. * lisp/emacs-lisp/edebug.el (edebug--cl-macrolet-defs): New variable. (edebug-list-form-args): Use it. (edebug--current-cl-macrolet-defs): New variable. (edebug-match-cl-macrolet-expr, edebug-match-cl-macrolet-name) (edebug-match-cl-macrolet-body): New functions. * lisp/emacs-lisp/cl-macs.el (cl-macrolet): Use cl-macrolet-expr for Edebug spec. * test/lisp/emacs-lisp/edebug-tests.el (edebug-tests-cl-macrolet): New test. * test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el (edebug-test-code-use-cl-macrolet): New function.
-rw-r--r--lisp/emacs-lisp/cl-macs.el5
-rw-r--r--lisp/emacs-lisp/edebug.el47
-rw-r--r--test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el7
-rw-r--r--test/lisp/emacs-lisp/edebug-tests.el11
4 files changed, 66 insertions, 4 deletions
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el
index 011965acb54..d0d1c3b156a 100644
--- a/lisp/emacs-lisp/cl-macs.el
+++ b/lisp/emacs-lisp/cl-macs.el
@@ -2083,10 +2083,7 @@ This is like `cl-flet', but for macros instead of functions.
2083 2083
2084\(fn ((NAME ARGLIST BODY...) ...) FORM...)" 2084\(fn ((NAME ARGLIST BODY...) ...) FORM...)"
2085 (declare (indent 1) 2085 (declare (indent 1)
2086 (debug 2086 (debug (cl-macrolet-expr)))
2087 ((&rest (&define name (&rest arg) cl-declarations-or-string
2088 def-body))
2089 cl-declarations body)))
2090 (if (cdr bindings) 2087 (if (cdr bindings)
2091 `(cl-macrolet (,(car bindings)) (cl-macrolet ,(cdr bindings) ,@body)) 2088 `(cl-macrolet (,(car bindings)) (cl-macrolet ,(cdr bindings) ,@body))
2092 (if (null bindings) (macroexp-progn body) 2089 (if (null bindings) (macroexp-progn body)
diff --git a/lisp/emacs-lisp/edebug.el b/lisp/emacs-lisp/edebug.el
index e759c5b5b24..f0c0db182ed 100644
--- a/lisp/emacs-lisp/edebug.el
+++ b/lisp/emacs-lisp/edebug.el
@@ -1198,6 +1198,8 @@ purpose by adding an entry to this alist, and setting
1198(defvar edebug-inside-func) ;; whether code is inside function context. 1198(defvar edebug-inside-func) ;; whether code is inside function context.
1199;; Currently def-form sets this to nil; def-body sets it to t. 1199;; Currently def-form sets this to nil; def-body sets it to t.
1200 1200
1201(defvar edebug--cl-macrolet-defs) ;; Fully defined below.
1202
1201(defun edebug-interactive-p-name () 1203(defun edebug-interactive-p-name ()
1202 ;; Return a unique symbol for the variable used to store the 1204 ;; Return a unique symbol for the variable used to store the
1203 ;; status of interactive-p for this function. 1205 ;; status of interactive-p for this function.
@@ -1463,6 +1465,11 @@ expressions; a `progn' form will be returned enclosing these forms."
1463 ;; Helper for edebug-list-form 1465 ;; Helper for edebug-list-form
1464 (let ((spec (get-edebug-spec head))) 1466 (let ((spec (get-edebug-spec head)))
1465 (cond 1467 (cond
1468 ;; Treat cl-macrolet bindings like macros with no spec.
1469 ((member head edebug--cl-macrolet-defs)
1470 (if edebug-eval-macro-args
1471 (edebug-forms cursor)
1472 (edebug-sexps cursor)))
1466 (spec 1473 (spec
1467 (cond 1474 (cond
1468 ((consp spec) 1475 ((consp spec)
@@ -1651,6 +1658,9 @@ expressions; a `progn' form will be returned enclosing these forms."
1651 ;; (function . edebug-match-function) 1658 ;; (function . edebug-match-function)
1652 (lambda-expr . edebug-match-lambda-expr) 1659 (lambda-expr . edebug-match-lambda-expr)
1653 (cl-generic-method-args . edebug-match-cl-generic-method-args) 1660 (cl-generic-method-args . edebug-match-cl-generic-method-args)
1661 (cl-macrolet-expr . edebug-match-cl-macrolet-expr)
1662 (cl-macrolet-name . edebug-match-cl-macrolet-name)
1663 (cl-macrolet-body . edebug-match-cl-macrolet-body)
1654 (&not . edebug-match-&not) 1664 (&not . edebug-match-&not)
1655 (&key . edebug-match-&key) 1665 (&key . edebug-match-&key)
1656 (place . edebug-match-place) 1666 (place . edebug-match-place)
@@ -1954,6 +1964,43 @@ expressions; a `progn' form will be returned enclosing these forms."
1954 (edebug-move-cursor cursor) 1964 (edebug-move-cursor cursor)
1955 (list args))) 1965 (list args)))
1956 1966
1967(defvar edebug--cl-macrolet-defs nil
1968 "List of symbols found within the bindings of enclosing `cl-macrolet' forms.")
1969(defvar edebug--current-cl-macrolet-defs nil
1970 "List of symbols found within the bindings of the current `cl-macrolet' form.")
1971
1972(defun edebug-match-cl-macrolet-expr (cursor)
1973 "Match a `cl-macrolet' form at CURSOR."
1974 (let (edebug--current-cl-macrolet-defs)
1975 (edebug-match cursor
1976 '((&rest (&define cl-macrolet-name cl-macro-list
1977 cl-declarations-or-string
1978 def-body))
1979 cl-declarations cl-macrolet-body))))
1980
1981(defun edebug-match-cl-macrolet-name (cursor)
1982 "Match the name in a `cl-macrolet' binding at CURSOR.
1983Collect the names in `edebug--cl-macrolet-defs' where they
1984will be checked by `edebug-list-form-args' and treated as
1985macros without a spec."
1986 (let ((name (edebug-top-element-required cursor "Expected name")))
1987 (when (not (symbolp name))
1988 (edebug-no-match cursor "Bad name:" name))
1989 ;; Change edebug-def-name to avoid conflicts with
1990 ;; names at global scope.
1991 (setq edebug-def-name (gensym "edebug-anon"))
1992 (edebug-move-cursor cursor)
1993 (push name edebug--current-cl-macrolet-defs)
1994 (list name)))
1995
1996(defun edebug-match-cl-macrolet-body (cursor)
1997 "Match the body of a `cl-macrolet' expression at CURSOR.
1998Put the definitions collected in `edebug--current-cl-macrolet-defs'
1999into `edebug--cl-macrolet-defs' which is checked in `edebug-list-form-args'."
2000 (let ((edebug--cl-macrolet-defs (nconc edebug--current-cl-macrolet-defs
2001 edebug--cl-macrolet-defs)))
2002 (edebug-match-body cursor)))
2003
1957(defun edebug-match-arg (cursor) 2004(defun edebug-match-arg (cursor)
1958 ;; set the def-args bound in edebug-defining-form 2005 ;; set the def-args bound in edebug-defining-form
1959 (let ((edebug-arg (edebug-top-element-required cursor "Expected arg"))) 2006 (let ((edebug-arg (edebug-top-element-required cursor "Expected arg")))
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 e86c2f1c1e7..f3fc78d4e12 100644
--- a/test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el
+++ b/test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el
@@ -130,5 +130,12 @@
130 (let ((two 2) (three 3)) 130 (let ((two 2) (three 3))
131 (cl-destructuring-bind (x . y) (cons two three) (+ x!x! y!y!)))) 131 (cl-destructuring-bind (x . y) (cons two three) (+ x!x! y!y!))))
132 132
133(defun edebug-test-code-use-cl-macrolet (x)
134 (cl-macrolet ((wrap (func &rest args)
135 `(format "The result of applying %s to %s is %S"
136 ',func!func! ',args
137 ,(cons func args))))
138 (wrap + 1 x)))
139
133(provide 'edebug-test-code) 140(provide 'edebug-test-code)
134;;; edebug-test-code.el ends here 141;;; 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 85f6bd47db2..7d780edf285 100644
--- a/test/lisp/emacs-lisp/edebug-tests.el
+++ b/test/lisp/emacs-lisp/edebug-tests.el
@@ -913,5 +913,16 @@ test and possibly others should be updated."
913 "g" 913 "g"
914 (should (equal edebug-tests-@-result 5))))) 914 (should (equal edebug-tests-@-result 5)))))
915 915
916(ert-deftest edebug-tests-cl-macrolet ()
917 "Edebug can instrument `cl-macrolet' expressions. (Bug#29919)"
918 (edebug-tests-with-normal-env
919 (edebug-tests-setup-@ "use-cl-macrolet" '(10) t)
920 (edebug-tests-run-kbd-macro
921 "@ SPC SPC"
922 (edebug-tests-should-be-at "use-cl-macrolet" "func")
923 (edebug-tests-should-match-result-in-messages "+")
924 "g"
925 (should (equal edebug-tests-@-result "The result of applying + to (1 x) is 11")))))
926
916(provide 'edebug-tests) 927(provide 'edebug-tests)
917;;; edebug-tests.el ends here 928;;; edebug-tests.el ends here