diff options
| author | Stefan Monnier | 2018-02-08 21:40:46 -0500 |
|---|---|---|
| committer | Stefan Monnier | 2018-02-08 21:41:21 -0500 |
| commit | 6b183f85e02ae1b8527c1bbfa8c5e2c914d28f7c (patch) | |
| tree | f6797583be0ee794ce1841eab485e36625c11fd8 | |
| parent | d34dbc0b69b288ee5e969208ab05b00a3fcc7638 (diff) | |
| download | emacs-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.el | 78 | ||||
| -rw-r--r-- | test/lisp/emacs-lisp/cl-lib-tests.el | 7 |
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) | 2094 | This function extends `macroexpand' during macro expansion |
| 2095 | #'cl--sm-macroexpand)) | 2095 | of `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'. | ||
| 2101 | This function replaces `macroexpand' during macro expansion | ||
| 2102 | of `cl-symbol-macrolet', and does the same thing as `macroexpand' | ||
| 2103 | except 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. |