diff options
| author | Stefan Monnier | 2012-08-06 15:53:45 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2012-08-06 15:53:45 -0400 |
| commit | ea3768613f759f3802a9dd9826b238c46b46ce67 (patch) | |
| tree | 3be13bfa91ec4a15037adad263bca7ec4ed98739 | |
| parent | 2b90362b19f920bb7a64f7cf3039457a9b750d63 (diff) | |
| download | emacs-ea3768613f759f3802a9dd9826b238c46b46ce67.tar.gz emacs-ea3768613f759f3802a9dd9826b238c46b46ce67.zip | |
* lisp/emacs-lisp/cl-macs.el (cl--sm-macroexpand): Fix handling of
re-binding a symbol that has a symbol-macro.
Fixes: debbugs:12119
| -rw-r--r-- | lisp/ChangeLog | 5 | ||||
| -rw-r--r-- | lisp/emacs-lisp/cl-macs.el | 93 |
2 files changed, 79 insertions, 19 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 72b6db71cfa..23f8b3ec831 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,8 @@ | |||
| 1 | 2012-08-06 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | * emacs-lisp/cl-macs.el (cl--sm-macroexpand): Fix handling of | ||
| 4 | re-binding a symbol that has a symbol-macro (bug#12119). | ||
| 5 | |||
| 1 | 2012-08-06 Mohsen BANAN <libre@mohsen.1.banan.byname.net> | 6 | 2012-08-06 Mohsen BANAN <libre@mohsen.1.banan.byname.net> |
| 2 | 7 | ||
| 3 | * language/persian.el: New file. (Bug#11812) | 8 | * language/persian.el: New file. (Bug#11812) |
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el index 00ba6b9e0d0..95aa1f18a0c 100644 --- a/lisp/emacs-lisp/cl-macs.el +++ b/lisp/emacs-lisp/cl-macs.el | |||
| @@ -1668,31 +1668,86 @@ This is like `cl-flet', but for macros instead of functions. | |||
| 1668 | cl--old-macroexpand | 1668 | cl--old-macroexpand |
| 1669 | (symbol-function 'macroexpand))) | 1669 | (symbol-function 'macroexpand))) |
| 1670 | 1670 | ||
| 1671 | (defun cl--sm-macroexpand (cl-macro &optional cl-env) | 1671 | (defun cl--sm-macroexpand (exp &optional env) |
| 1672 | "Special macro expander used inside `cl-symbol-macrolet'. | 1672 | "Special macro expander used inside `cl-symbol-macrolet'. |
| 1673 | This function replaces `macroexpand' during macro expansion | 1673 | This function replaces `macroexpand' during macro expansion |
| 1674 | of `cl-symbol-macrolet', and does the same thing as `macroexpand' | 1674 | of `cl-symbol-macrolet', and does the same thing as `macroexpand' |
| 1675 | except that it additionally expands symbol macros." | 1675 | except that it additionally expands symbol macros." |
| 1676 | (let ((macroexpand-all-environment cl-env)) | 1676 | (let ((macroexpand-all-environment env)) |
| 1677 | (while | 1677 | (while |
| 1678 | (progn | 1678 | (progn |
| 1679 | (setq cl-macro (funcall cl--old-macroexpand cl-macro cl-env)) | 1679 | (setq exp (funcall cl--old-macroexpand exp env)) |
| 1680 | (cond | 1680 | (pcase exp |
| 1681 | ((symbolp cl-macro) | 1681 | ((pred symbolp) |
| 1682 | ;; Perform symbol-macro expansion. | 1682 | ;; Perform symbol-macro expansion. |
| 1683 | (when (cdr (assq (symbol-name cl-macro) cl-env)) | 1683 | (when (cdr (assq (symbol-name exp) env)) |
| 1684 | (setq cl-macro (cadr (assq (symbol-name cl-macro) cl-env))))) | 1684 | (setq exp (cadr (assq (symbol-name exp) env))))) |
| 1685 | ((eq 'setq (car-safe cl-macro)) | 1685 | (`(setq . ,_) |
| 1686 | ;; Convert setq to setf if required by symbol-macro expansion. | 1686 | ;; Convert setq to setf if required by symbol-macro expansion. |
| 1687 | (let* ((args (mapcar (lambda (f) (cl--sm-macroexpand f cl-env)) | 1687 | (let* ((args (mapcar (lambda (f) (cl--sm-macroexpand f env)) |
| 1688 | (cdr cl-macro))) | 1688 | (cdr exp))) |
| 1689 | (p args)) | 1689 | (p args)) |
| 1690 | (while (and p (symbolp (car p))) (setq p (cddr p))) | 1690 | (while (and p (symbolp (car p))) (setq p (cddr p))) |
| 1691 | (if p (setq cl-macro (cons 'setf args)) | 1691 | (if p (setq exp (cons 'setf args)) |
| 1692 | (setq cl-macro (cons 'setq args)) | 1692 | (setq exp (cons 'setq args)) |
| 1693 | ;; Don't loop further. | 1693 | ;; Don't loop further. |
| 1694 | nil)))))) | 1694 | nil))) |
| 1695 | cl-macro)) | 1695 | (`(,(or `let `let*) . ,(or `(,bindings . ,body) dontcare)) |
| 1696 | ;; CL's symbol-macrolet treats re-bindings as candidates for | ||
| 1697 | ;; expansion (turning the let into a letf if needed), contrary to | ||
| 1698 | ;; Common-Lisp where such re-bindings hide the symbol-macro. | ||
| 1699 | (let ((letf nil) (found nil) (nbs ())) | ||
| 1700 | (dolist (binding bindings) | ||
| 1701 | (let* ((var (if (symbolp binding) binding (car binding))) | ||
| 1702 | (sm (assq (symbol-name var) env))) | ||
| 1703 | (push (if (not (cdr sm)) | ||
| 1704 | binding | ||
| 1705 | (let ((nexp (cadr sm))) | ||
| 1706 | (setq found t) | ||
| 1707 | (unless (symbolp nexp) (setq letf t)) | ||
| 1708 | (cons nexp (cdr-safe binding)))) | ||
| 1709 | nbs))) | ||
| 1710 | (when found | ||
| 1711 | (setq exp `(,(if letf | ||
| 1712 | (if (eq (car exp) 'let) 'cl-letf 'cl-letf*) | ||
| 1713 | (car exp)) | ||
| 1714 | ,(nreverse nbs) | ||
| 1715 | ,@body))))) | ||
| 1716 | ;; FIXME: The behavior of CL made sense in a dynamically scoped | ||
| 1717 | ;; language, but for lexical scoping, Common-Lisp's behavior might | ||
| 1718 | ;; make more sense (and indeed, CL behaves like Common-Lisp w.r.t | ||
| 1719 | ;; lexical-let), so maybe we should adjust the behavior based on | ||
| 1720 | ;; the use of lexical-binding. | ||
| 1721 | ;; (`(,(or `let `let*) . ,(or `(,bindings . ,body) dontcare)) | ||
| 1722 | ;; (let ((nbs ()) (found nil)) | ||
| 1723 | ;; (dolist (binding bindings) | ||
| 1724 | ;; (let* ((var (if (symbolp binding) binding (car binding))) | ||
| 1725 | ;; (name (symbol-name var)) | ||
| 1726 | ;; (val (and found (consp binding) (eq 'let* (car exp)) | ||
| 1727 | ;; (list (macroexpand-all (cadr binding) | ||
| 1728 | ;; env))))) | ||
| 1729 | ;; (push (if (assq name env) | ||
| 1730 | ;; ;; This binding should hide its symbol-macro, | ||
| 1731 | ;; ;; but given the way macroexpand-all works, we | ||
| 1732 | ;; ;; can't prevent application of `env' to the | ||
| 1733 | ;; ;; sub-expressions, so we need to α-rename this | ||
| 1734 | ;; ;; variable instead. | ||
| 1735 | ;; (let ((nvar (make-symbol | ||
| 1736 | ;; (copy-sequence name)))) | ||
| 1737 | ;; (setq found t) | ||
| 1738 | ;; (push (list name nvar) env) | ||
| 1739 | ;; (cons nvar (or val (cdr-safe binding)))) | ||
| 1740 | ;; (if val (cons var val) binding)) | ||
| 1741 | ;; nbs))) | ||
| 1742 | ;; (when found | ||
| 1743 | ;; (setq exp `(,(car exp) | ||
| 1744 | ;; ,(nreverse nbs) | ||
| 1745 | ;; ,@(macroexp-unprogn | ||
| 1746 | ;; (macroexpand-all (macroexp-progn body) | ||
| 1747 | ;; env))))) | ||
| 1748 | ;; nil)) | ||
| 1749 | ))) | ||
| 1750 | exp)) | ||
| 1696 | 1751 | ||
| 1697 | ;;;###autoload | 1752 | ;;;###autoload |
| 1698 | (defmacro cl-symbol-macrolet (bindings &rest body) | 1753 | (defmacro cl-symbol-macrolet (bindings &rest body) |