aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2018-02-08 21:40:46 -0500
committerStefan Monnier2018-02-08 21:41:21 -0500
commit6b183f85e02ae1b8527c1bbfa8c5e2c914d28f7c (patch)
treef6797583be0ee794ce1841eab485e36625c11fd8
parentd34dbc0b69b288ee5e969208ab05b00a3fcc7638 (diff)
downloademacs-6b183f85e02ae1b8527c1bbfa8c5e2c914d28f7c.tar.gz
emacs-6b183f85e02ae1b8527c1bbfa8c5e2c914d28f7c.zip
* lisp/emacs-lisp/cl-macs.el (cl--sm-macroexpand): Handle lambda!
(cl--old-macroexpand): Remove. (cl--sm-macroexpand): Change its calling convention, so it can use advice-add. Extend re-binding treatment of vars so it applies to all var-introducing forms rather than only to 'let'. (cl-symbol-macrolet): Use advice-add rather than fset.
-rw-r--r--lisp/emacs-lisp/cl-macs.el78
-rw-r--r--test/lisp/emacs-lisp/cl-lib-tests.el7
2 files changed, 59 insertions, 26 deletions
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el
index 4aed1f26624..4d4640cbe0d 100644
--- a/lisp/emacs-lisp/cl-macs.el
+++ b/lisp/emacs-lisp/cl-macs.el
@@ -2089,23 +2089,15 @@ This is like `cl-flet', but for macros instead of functions.
2089 (eval `(cl-function (lambda ,@(cdr res))) t)) 2089 (eval `(cl-function (lambda ,@(cdr res))) t))
2090 macroexpand-all-environment)))))) 2090 macroexpand-all-environment))))))
2091 2091
2092(defconst cl--old-macroexpand 2092(defun cl--sm-macroexpand (orig-fun exp &optional env)
2093 (if (and (boundp 'cl--old-macroexpand) 2093 "Special macro expander advice used inside `cl-symbol-macrolet'.
2094 (eq (symbol-function 'macroexpand) 2094This function extends `macroexpand' during macro expansion
2095 #'cl--sm-macroexpand)) 2095of `cl-symbol-macrolet' to additionally expand symbol macros."
2096 cl--old-macroexpand
2097 (symbol-function 'macroexpand)))
2098
2099(defun cl--sm-macroexpand (exp &optional env)
2100 "Special macro expander used inside `cl-symbol-macrolet'.
2101This function replaces `macroexpand' during macro expansion
2102of `cl-symbol-macrolet', and does the same thing as `macroexpand'
2103except that it additionally expands symbol macros."
2104 (let ((macroexpand-all-environment env) 2096 (let ((macroexpand-all-environment env)
2105 (venv (alist-get :cl-symbol-macros env))) 2097 (venv (alist-get :cl-symbol-macros env)))
2106 (while 2098 (while
2107 (progn 2099 (progn
2108 (setq exp (funcall cl--old-macroexpand exp env)) 2100 (setq exp (funcall orig-fun exp env))
2109 (pcase exp 2101 (pcase exp
2110 ((pred symbolp) 2102 ((pred symbolp)
2111 ;; Perform symbol-macro expansion. 2103 ;; Perform symbol-macro expansion.
@@ -2114,7 +2106,7 @@ except that it additionally expands symbol macros."
2114 (setq exp (cadr symval))))) 2106 (setq exp (cadr symval)))))
2115 (`(setq . ,_) 2107 (`(setq . ,_)
2116 ;; Convert setq to setf if required by symbol-macro expansion. 2108 ;; Convert setq to setf if required by symbol-macro expansion.
2117 (let* ((args (mapcar (lambda (f) (cl--sm-macroexpand f env)) 2109 (let* ((args (mapcar (lambda (f) (macroexpand f env))
2118 (cdr exp))) 2110 (cdr exp)))
2119 (p args)) 2111 (p args))
2120 (while (and p (symbolp (car p))) (setq p (cddr p))) 2112 (while (and p (symbolp (car p))) (setq p (cddr p)))
@@ -2160,10 +2152,10 @@ except that it additionally expands symbol macros."
2160 (list (macroexpand-all (cadr binding) 2152 (list (macroexpand-all (cadr binding)
2161 env))))) 2153 env)))))
2162 (push (if (assq var venv) 2154 (push (if (assq var venv)
2163 ;; This binding should hide its symbol-macro, 2155 ;; This binding should hide "its" surrounding
2164 ;; but given the way macroexpand-all works 2156 ;; symbol-macro, but given the way macroexpand-all
2165 ;; (i.e. the `env' we receive as input will be 2157 ;; works (i.e. the `env' we receive as input will
2166 ;; (re)applied to the code we return), we can't 2158 ;; be (re)applied to the code we return), we can't
2167 ;; prevent application of `env' to the 2159 ;; prevent application of `env' to the
2168 ;; sub-expressions, so we need to α-rename this 2160 ;; sub-expressions, so we need to α-rename this
2169 ;; variable instead. 2161 ;; variable instead.
@@ -2181,6 +2173,43 @@ except that it additionally expands symbol macros."
2181 (macroexpand-all (macroexp-progn body) 2173 (macroexpand-all (macroexp-progn body)
2182 env))))) 2174 env)))))
2183 nil)) 2175 nil))
2176 ;; Do the same as for `let' but for variables introduced
2177 ;; via other means, such as `lambda' and `condition-case'.
2178 (`(function (lambda ,args . ,body))
2179 (let ((nargs ()) (found nil))
2180 (dolist (var args)
2181 (push (cond
2182 ((memq var '(&optional &rest)) var)
2183 ((assq var venv)
2184 (let ((nvar (make-symbol (symbol-name var))))
2185 (setq found t)
2186 (push (list var nvar) venv)
2187 (push (cons :cl-symbol-macros venv) env)
2188 nvar))
2189 (t var))
2190 nargs))
2191 (when found
2192 (setq exp `(function
2193 (lambda ,(nreverse nargs)
2194 . ,(mapcar (lambda (exp)
2195 (macroexpand-all exp env))
2196 body)))))
2197 nil))
2198 ((and `(condition-case ,var ,exp . ,clauses)
2199 (guard (assq var venv)))
2200 (let ((nvar (make-symbol (symbol-name var))))
2201 (push (list var nvar) venv)
2202 (push (cons :cl-symbol-macros venv) env)
2203 (setq exp
2204 `(condition-case ,nvar ,(macroexpand-all exp env)
2205 . ,(mapcar
2206 (lambda (clause)
2207 `(,(car clause)
2208 . ,(mapcar (lambda (exp)
2209 (macroexpand-all exp env))
2210 (cdr clause))))
2211 clauses)))
2212 nil))
2184 ))) 2213 )))
2185 exp)) 2214 exp))
2186 2215
@@ -2192,16 +2221,18 @@ by EXPANSION, and (setq NAME ...) will act like (setf EXPANSION ...).
2192 2221
2193\(fn ((NAME EXPANSION) ...) FORM...)" 2222\(fn ((NAME EXPANSION) ...) FORM...)"
2194 (declare (indent 1) (debug ((&rest (symbolp sexp)) cl-declarations body))) 2223 (declare (indent 1) (debug ((&rest (symbolp sexp)) cl-declarations body)))
2195 (let ((previous-macroexpand (symbol-function 'macroexpand)) 2224 (let ((malformed-bindings nil)
2196 (malformed-bindings nil)) 2225 (advised (advice-member-p #'cl--sm-macroexpand 'macroexpand)))
2197 (dolist (binding bindings) 2226 (dolist (binding bindings)
2198 (unless (and (consp binding) (symbolp (car binding)) 2227 (unless (and (consp binding) (symbolp (car binding))
2199 (consp (cdr binding)) (null (cddr binding))) 2228 (consp (cdr binding)) (null (cddr binding)))
2200 (push binding malformed-bindings))) 2229 (push binding malformed-bindings)))
2201 (unwind-protect 2230 (unwind-protect
2202 (progn 2231 (progn
2203 (fset 'macroexpand #'cl--sm-macroexpand) 2232 (unless advised
2204 (let* ((venv (cdr (assq :cl-symbol-macros macroexpand-all-environment))) 2233 (advice-add 'macroexpand :around #'cl--sm-macroexpand))
2234 (let* ((venv (cdr (assq :cl-symbol-macros
2235 macroexpand-all-environment)))
2205 (expansion 2236 (expansion
2206 (macroexpand-all (macroexp-progn body) 2237 (macroexpand-all (macroexp-progn body)
2207 (cons (cons :cl-symbol-macros 2238 (cons (cons :cl-symbol-macros
@@ -2213,7 +2244,8 @@ by EXPANSION, and (setq NAME ...) will act like (setf EXPANSION ...).
2213 (nreverse malformed-bindings)) 2244 (nreverse malformed-bindings))
2214 expansion) 2245 expansion)
2215 expansion))) 2246 expansion)))
2216 (fset 'macroexpand previous-macroexpand)))) 2247 (unless advised
2248 (advice-remove 'macroexpand #'cl--sm-macroexpand)))))
2217 2249
2218;;; Multiple values. 2250;;; Multiple values.
2219 2251
diff --git a/test/lisp/emacs-lisp/cl-lib-tests.el b/test/lisp/emacs-lisp/cl-lib-tests.el
index 69d0a747105..f100e8c6c5f 100644
--- a/test/lisp/emacs-lisp/cl-lib-tests.el
+++ b/test/lisp/emacs-lisp/cl-lib-tests.el
@@ -518,13 +518,14 @@
518 518
519 519
520(ert-deftest cl-lib-symbol-macrolet-hide () 520(ert-deftest cl-lib-symbol-macrolet-hide ()
521 ;; bug#26325 521 ;; bug#26325, bug#26073
522 (should (equal (let ((y 5)) 522 (should (equal (let ((y 5))
523 (cl-symbol-macrolet ((x y)) 523 (cl-symbol-macrolet ((x y))
524 (list x 524 (list x
525 (let ((x 6)) (list x y)) 525 (let ((x 6)) (list x y))
526 (cl-letf ((x 6)) (list x y))))) 526 (cl-letf ((x 6)) (list x y))
527 '(5 (6 5) (6 6))))) 527 (apply (lambda (x) (+ x 1)) (list 8)))))
528 '(5 (6 5) (6 6) 9))))
528 529
529(defun cl-lib-tests--dummy-function () 530(defun cl-lib-tests--dummy-function ()
530 ;; Dummy function to see if the file is compiled. 531 ;; Dummy function to see if the file is compiled.