aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2012-08-06 15:53:45 -0400
committerStefan Monnier2012-08-06 15:53:45 -0400
commitea3768613f759f3802a9dd9826b238c46b46ce67 (patch)
tree3be13bfa91ec4a15037adad263bca7ec4ed98739
parent2b90362b19f920bb7a64f7cf3039457a9b750d63 (diff)
downloademacs-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/ChangeLog5
-rw-r--r--lisp/emacs-lisp/cl-macs.el93
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 @@
12012-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
12012-08-06 Mohsen BANAN <libre@mohsen.1.banan.byname.net> 62012-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'.
1673This function replaces `macroexpand' during macro expansion 1673This function replaces `macroexpand' during macro expansion
1674of `cl-symbol-macrolet', and does the same thing as `macroexpand' 1674of `cl-symbol-macrolet', and does the same thing as `macroexpand'
1675except that it additionally expands symbol macros." 1675except 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)