aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2012-11-12 22:00:09 -0500
committerStefan Monnier2012-11-12 22:00:09 -0500
commit413d4689c0c3f616856615ac7b8bb047c5f2febd (patch)
tree3f2ca64880fb237665d78b4d19d1fe4ab400fb6a
parentf78ee6afc094cdfd6162bfd645836e84875dcddf (diff)
downloademacs-413d4689c0c3f616856615ac7b8bb047c5f2febd.tar.gz
emacs-413d4689c0c3f616856615ac7b8bb047c5f2febd.zip
* lisp/emacs-lisp/cl.el (dolist, dotimes, declare): Use advice-add to
override the default. * lisp/emacs-lisp/cl-macs.el (cl-dolist, cl-dotimes): Rewrite without using cl--dotimes/dolist. * lisp/subr.el (dolist, dotimes, declare): Redefine them normally, even when `cl' is loaded. * lisp/emacs-lisp/nadvice.el (advice--normalize): New function, extracted from add-advice. (advice--strip-macro): New function. (advice--defalias-fset): Use them to handle macros. (advice-add): Use them. (advice-member-p): Correctly handle macros.
-rw-r--r--lisp/ChangeLog16
-rw-r--r--lisp/emacs-lisp/cl-loaddefs.el2
-rw-r--r--lisp/emacs-lisp/cl-macs.el12
-rw-r--r--lisp/emacs-lisp/cl.el20
-rw-r--r--lisp/emacs-lisp/nadvice.el87
-rw-r--r--lisp/subr.el6
-rw-r--r--test/automated/advice-tests.el7
7 files changed, 91 insertions, 59 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 6ab2880f09f..92f3343db64 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,5 +1,21 @@
12012-11-13 Stefan Monnier <monnier@iro.umontreal.ca> 12012-11-13 Stefan Monnier <monnier@iro.umontreal.ca>
2 2
3 * emacs-lisp/cl.el (dolist, dotimes, declare): Use advice-add to
4 override the default.
5 * emacs-lisp/cl-macs.el (cl-dolist, cl-dotimes): Rewrite without using
6 cl--dotimes/dolist.
7 * subr.el (dolist, dotimes, declare): Redefine them normally, even when
8 `cl' is loaded.
9
10 * emacs-lisp/nadvice.el (advice--normalize): New function, extracted
11 from add-advice.
12 (advice--strip-macro): New function.
13 (advice--defalias-fset): Use them to handle macros.
14 (advice-add): Use them.
15 (advice-member-p): Correctly handle macros.
16
172012-11-13 Stefan Monnier <monnier@iro.umontreal.ca>
18
3 * emacs-lisp/gv.el (gv-define-simple-setter): One more fix (bug#12871). 19 * emacs-lisp/gv.el (gv-define-simple-setter): One more fix (bug#12871).
4 20
52012-11-13 Wolfgang Jenkner <wjenkner@inode.at> 212012-11-13 Wolfgang Jenkner <wjenkner@inode.at>
diff --git a/lisp/emacs-lisp/cl-loaddefs.el b/lisp/emacs-lisp/cl-loaddefs.el
index bf99af2f7e6..eb58d17c02e 100644
--- a/lisp/emacs-lisp/cl-loaddefs.el
+++ b/lisp/emacs-lisp/cl-loaddefs.el
@@ -267,7 +267,7 @@ including `cl-block' and `cl-eval-when'.
267;;;;;; cl-typecase cl-ecase cl-case cl-load-time-value cl-eval-when 267;;;;;; cl-typecase cl-ecase cl-case cl-load-time-value cl-eval-when
268;;;;;; cl-destructuring-bind cl-function cl-defmacro cl-defun cl-gentemp 268;;;;;; cl-destructuring-bind cl-function cl-defmacro cl-defun cl-gentemp
269;;;;;; cl-gensym cl--compiler-macro-cXXr cl--compiler-macro-list*) 269;;;;;; cl-gensym cl--compiler-macro-cXXr cl--compiler-macro-list*)
270;;;;;; "cl-macs" "cl-macs.el" "a7228877484d2b39e1c2bee40b011734") 270;;;;;; "cl-macs" "cl-macs.el" "c7ad09a74a1d2969406e7e2aaf3812fc")
271;;; Generated autoloads from cl-macs.el 271;;; Generated autoloads from cl-macs.el
272 272
273(autoload 'cl--compiler-macro-list* "cl-macs" "\ 273(autoload 'cl--compiler-macro-list* "cl-macs" "\
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el
index b28f8f7f9e9..3c46c40242d 100644
--- a/lisp/emacs-lisp/cl-macs.el
+++ b/lisp/emacs-lisp/cl-macs.el
@@ -1547,9 +1547,9 @@ An implicit nil block is established around the loop.
1547\(fn (VAR LIST [RESULT]) BODY...)" 1547\(fn (VAR LIST [RESULT]) BODY...)"
1548 (declare (debug ((symbolp form &optional form) cl-declarations body)) 1548 (declare (debug ((symbolp form &optional form) cl-declarations body))
1549 (indent 1)) 1549 (indent 1))
1550 `(cl-block nil 1550 (let ((loop `(dolist ,spec ,@body)))
1551 (,(if (eq 'cl-dolist (symbol-function 'dolist)) 'cl--dolist 'dolist) 1551 (if (advice-member-p #'cl--wrap-in-nil-block 'dolist)
1552 ,spec ,@body))) 1552 loop `(cl-block nil ,loop))))
1553 1553
1554;;;###autoload 1554;;;###autoload
1555(defmacro cl-dotimes (spec &rest body) 1555(defmacro cl-dotimes (spec &rest body)
@@ -1560,9 +1560,9 @@ nil.
1560 1560
1561\(fn (VAR COUNT [RESULT]) BODY...)" 1561\(fn (VAR COUNT [RESULT]) BODY...)"
1562 (declare (debug cl-dolist) (indent 1)) 1562 (declare (debug cl-dolist) (indent 1))
1563 `(cl-block nil 1563 (let ((loop `(dotimes ,spec ,@body)))
1564 (,(if (eq 'cl-dotimes (symbol-function 'dotimes)) 'cl--dotimes 'dotimes) 1564 (if (advice-member-p #'cl--wrap-in-nil-block 'dotimes)
1565 ,spec ,@body))) 1565 loop `(cl-block nil ,loop))))
1566 1566
1567;;;###autoload 1567;;;###autoload
1568(defmacro cl-do-symbols (spec &rest body) 1568(defmacro cl-do-symbols (spec &rest body)
diff --git a/lisp/emacs-lisp/cl.el b/lisp/emacs-lisp/cl.el
index 016967bc713..40d12358b17 100644
--- a/lisp/emacs-lisp/cl.el
+++ b/lisp/emacs-lisp/cl.el
@@ -107,14 +107,6 @@
107 )) 107 ))
108 (defvaralias var (intern (format "cl-%s" var)))) 108 (defvaralias var (intern (format "cl-%s" var))))
109 109
110;; Before overwriting subr.el's `dotimes' and `dolist', let's remember
111;; them under a different name, so we can use them in our implementation
112;; of `dotimes' and `dolist'.
113(unless (fboundp 'cl--dotimes)
114 (defalias 'cl--dotimes (symbol-function 'dotimes) "The non-CL `dotimes'."))
115(unless (fboundp 'cl--dolist)
116 (defalias 'cl--dolist (symbol-function 'dolist) "The non-CL `dolist'."))
117
118(dolist (fun '( 110(dolist (fun '(
119 (get* . cl-get) 111 (get* . cl-get)
120 (random* . cl-random) 112 (random* . cl-random)
@@ -228,7 +220,6 @@
228 remf 220 remf
229 psetf 221 psetf
230 (define-setf-method . define-setf-expander) 222 (define-setf-method . define-setf-expander)
231 declare
232 the 223 the
233 locally 224 locally
234 multiple-value-setq 225 multiple-value-setq
@@ -239,8 +230,6 @@
239 psetq 230 psetq
240 do-all-symbols 231 do-all-symbols
241 do-symbols 232 do-symbols
242 dotimes
243 dolist
244 do* 233 do*
245 do 234 do
246 loop 235 loop
@@ -322,6 +311,15 @@
322 (intern (format "cl-%s" fun))))) 311 (intern (format "cl-%s" fun)))))
323 (defalias fun new))) 312 (defalias fun new)))
324 313
314(defun cl--wrap-in-nil-block (fun &rest args)
315 `(cl-block nil ,(apply fun args)))
316(advice-add 'dolist :around #'cl--wrap-in-nil-block)
317(advice-add 'dotimes :around #'cl--wrap-in-nil-block)
318
319(defun cl--pass-args-to-cl-declare (&rest specs)
320 (macroexpand `(cl-declare ,@specs)))
321(advice-add 'declare :after #'cl--pass-args-to-cl-declare)
322
325;;; Features provided a bit differently in Elisp. 323;;; Features provided a bit differently in Elisp.
326 324
327;; First, the old lexical-let is now better served by `lexical-binding', tho 325;; First, the old lexical-let is now better served by `lexical-binding', tho
diff --git a/lisp/emacs-lisp/nadvice.el b/lisp/emacs-lisp/nadvice.el
index 020a2f89bdb..ca1ebf3cad2 100644
--- a/lisp/emacs-lisp/nadvice.el
+++ b/lisp/emacs-lisp/nadvice.el
@@ -230,23 +230,49 @@ of the piece of advice."
230 (advice--make-1 (aref old 1) (aref old 3) 230 (advice--make-1 (aref old 1) (aref old 3)
231 first nrest props))))) 231 first nrest props)))))
232 232
233(defun advice--normalize (symbol def)
234 (cond
235 ((special-form-p def)
236 ;; Not worth the trouble trying to handle this, I think.
237 (error "add-advice failure: %S is a special form" symbol))
238 ((and (symbolp def)
239 (eq 'macro (car-safe (ignore-errors (indirect-function def)))))
240 (let ((newval (cons 'macro (cdr (indirect-function def)))))
241 (put symbol 'advice--saved-rewrite (cons def newval))
242 newval))
243 ;; `f' might be a pure (hence read-only) cons!
244 ((and (eq 'macro (car-safe def))
245 (not (ignore-errors (setcdr def (cdr def)) t)))
246 (cons 'macro (cdr def)))
247 (t def)))
248
249(defsubst advice--strip-macro (x)
250 (if (eq 'macro (car-safe x)) (cdr x) x))
251
233(defun advice--defalias-fset (fsetfun symbol newdef) 252(defun advice--defalias-fset (fsetfun symbol newdef)
234 (let* ((olddef (if (fboundp symbol) (symbol-function symbol))) 253 (when (get symbol 'advice--saved-rewrite)
254 (put symbol 'advice--saved-rewrite nil))
255 (setq newdef (advice--normalize symbol newdef))
256 (let* ((olddef (advice--strip-macro
257 (if (fboundp symbol) (symbol-function symbol))))
235 (oldadv 258 (oldadv
236 (cond 259 (cond
237 ((null (get symbol 'advice--pending)) 260 ((null (get symbol 'advice--pending))
238 (or olddef 261 (or olddef
239 (progn 262 (progn
240 (message "Delayed advice activation failed for %s: no data" 263 (message "Delayed advice activation failed for %s: no data"
241 symbol) 264 symbol)
242 nil))) 265 nil)))
243 ((or (not olddef) (autoloadp olddef)) 266 ((or (not olddef) (autoloadp olddef))
244 (prog1 (get symbol 'advice--pending) 267 (prog1 (get symbol 'advice--pending)
245 (put symbol 'advice--pending nil))) 268 (put symbol 'advice--pending nil)))
246 (t (message "Dropping left-over advice--pending for %s" symbol) 269 (t (message "Dropping left-over advice--pending for %s" symbol)
247 (put symbol 'advice--pending nil) 270 (put symbol 'advice--pending nil)
248 olddef)))) 271 olddef))))
249 (funcall (or fsetfun #'fset) symbol (advice--subst-main oldadv newdef)))) 272 (let* ((snewdef (advice--strip-macro newdef))
273 (snewadv (advice--subst-main oldadv snewdef)))
274 (funcall (or fsetfun #'fset) symbol
275 (if (eq snewdef newdef) snewadv (cons 'macro snewadv))))))
250 276
251 277
252;;;###autoload 278;;;###autoload
@@ -269,29 +295,18 @@ is defined as a macro, alias, command, ..."
269 ;; simplest way is to make advice.el build one ad-Advice-foo function for 295 ;; simplest way is to make advice.el build one ad-Advice-foo function for
270 ;; each advised function which is advice-added/removed whenever ad-activate 296 ;; each advised function which is advice-added/removed whenever ad-activate
271 ;; ad-deactivate is called. 297 ;; ad-deactivate is called.
272 (let ((f (and (fboundp symbol) (symbol-function symbol)))) 298 (let* ((f (and (fboundp symbol) (symbol-function symbol)))
273 (cond 299 (nf (advice--normalize symbol f)))
274 ((special-form-p f) 300 (unless (eq f nf) ;; Most importantly, if nf == nil!
275 ;; Not worth the trouble trying to handle this, I think. 301 (fset symbol nf))
276 (error "add-advice failure: %S is a special form" symbol))
277 ((and (symbolp f)
278 (eq 'macro (car-safe (ignore-errors (indirect-function f)))))
279 (let ((newval (cons 'macro (cdr (indirect-function f)))))
280 (put symbol 'advice--saved-rewrite (cons f newval))
281 (fset symbol newval)))
282 ;; `f' might be a pure (hence read-only) cons!
283 ((and (eq 'macro (car-safe f)) (not (ignore-errors (setcdr f (cdr f)) t)))
284 (fset symbol (cons 'macro (cdr f))))
285 ))
286 (let ((f (and (fboundp symbol) (symbol-function symbol))))
287 (add-function where (cond 302 (add-function where (cond
288 ((eq (car-safe f) 'macro) (cdr f)) 303 ((eq (car-safe nf) 'macro) (cdr nf))
289 ;; If the function is not yet defined, we can't yet 304 ;; If the function is not yet defined, we can't yet
290 ;; install the advice. 305 ;; install the advice.
291 ;; FIXME: If it's an autoloaded command, we also 306 ;; FIXME: If it's an autoloaded command, we also
292 ;; have a problem because we need to load the 307 ;; have a problem because we need to load the
293 ;; command to build the interactive-form. 308 ;; command to build the interactive-form.
294 ((or (not f) (and (autoloadp f))) ;; (commandp f) 309 ((or (not nf) (and (autoloadp nf))) ;; (commandp nf)
295 (get symbol 'advice--pending)) 310 (get symbol 'advice--pending))
296 (t (symbol-function symbol))) 311 (t (symbol-function symbol)))
297 function props) 312 function props)
@@ -316,7 +331,7 @@ of the piece of advice."
316 function) 331 function)
317 (unless (advice--p 332 (unless (advice--p
318 (if (eq (car-safe f) 'macro) (cdr f) (symbol-function symbol))) 333 (if (eq (car-safe f) 'macro) (cdr f) (symbol-function symbol)))
319 ;; Not adviced any more. 334 ;; Not advised any more.
320 (remove-function (get symbol 'defalias-fset-function) 335 (remove-function (get symbol 'defalias-fset-function)
321 #'advice--defalias-fset) 336 #'advice--defalias-fset)
322 (if (eq (symbol-function symbol) 337 (if (eq (symbol-function symbol)
@@ -335,13 +350,15 @@ of the piece of advice."
335;; (setq def (advice--cdr def))))) 350;; (setq def (advice--cdr def)))))
336 351
337;;;###autoload 352;;;###autoload
338(defun advice-member-p (function symbol) 353(defun advice-member-p (advice function-name)
339 "Return non-nil if advice FUNCTION has been added to function SYMBOL. 354 "Return non-nil if ADVICE has been added to FUNCTION-NAME.
340Instead of FUNCTION being the actual function, it can also be the `name' 355Instead of ADVICE being the actual function, it can also be the `name'
341of the piece of advice." 356of the piece of advice."
342 (advice--member-p function 357 (advice--member-p advice
343 (or (get symbol 'advice--pending) 358 (or (get function-name 'advice--pending)
344 (if (fboundp symbol) (symbol-function symbol))))) 359 (advice--strip-macro
360 (if (fboundp function-name)
361 (symbol-function function-name))))))
345 362
346 363
347(provide 'nadvice) 364(provide 'nadvice)
diff --git a/lisp/subr.el b/lisp/subr.el
index ebfcfbc0930..b0ac2dd2106 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -195,11 +195,6 @@ value of last one, or nil if there are none.
195 (declare (indent 1) (debug t)) 195 (declare (indent 1) (debug t))
196 (cons 'if (cons cond (cons nil body)))) 196 (cons 'if (cons cond (cons nil body))))
197 197
198(if (null (featurep 'cl))
199 (progn
200 ;; If we reload subr.el after having loaded CL, be careful not to
201 ;; overwrite CL's extended definition of `dolist', `dotimes', `declare'.
202
203(defmacro dolist (spec &rest body) 198(defmacro dolist (spec &rest body)
204 "Loop over a list. 199 "Loop over a list.
205Evaluate BODY with VAR bound to each car from LIST, in turn. 200Evaluate BODY with VAR bound to each car from LIST, in turn.
@@ -279,7 +274,6 @@ The possible values of SPECS are specified by
279`defun-declarations-alist' and `macro-declarations-alist'." 274`defun-declarations-alist' and `macro-declarations-alist'."
280 ;; FIXME: edebug spec should pay attention to defun-declarations-alist. 275 ;; FIXME: edebug spec should pay attention to defun-declarations-alist.
281 nil) 276 nil)
282))
283 277
284(defmacro ignore-errors (&rest body) 278(defmacro ignore-errors (&rest body)
285 "Execute BODY; if an error occurs, return nil. 279 "Execute BODY; if an error occurs, return nil.
diff --git a/test/automated/advice-tests.el b/test/automated/advice-tests.el
index cac10e9602f..9f9719fdcfc 100644
--- a/test/automated/advice-tests.el
+++ b/test/automated/advice-tests.el
@@ -50,6 +50,13 @@
50 ((ad-activate 'sm-test2) 50 ((ad-activate 'sm-test2)
51 (sm-test2 6) 20) 51 (sm-test2 6) 20)
52 ((null (get 'sm-test2 'defalias-fset-function)) t) 52 ((null (get 'sm-test2 'defalias-fset-function)) t)
53
54 ((advice-add 'sm-test3 :around
55 (lambda (f &rest args) `(toto ,(apply f args)))
56 '((name . wrap-with-toto)))
57 (defmacro sm-test3 (x) `(call-test3 ,x))
58 (macroexpand '(sm-test3 56)) (toto (call-test3 56)))
59
53 )) 60 ))
54 61
55(ert-deftest advice-tests () 62(ert-deftest advice-tests ()