aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2015-01-17 22:50:50 -0500
committerStefan Monnier2015-01-17 22:50:50 -0500
commit909126de0f6d2e53aec44c97abccee5b32b25f28 (patch)
tree1cd37b86acf2b8b9b1476e9f7971e3644db2c74f
parent3065125d314a4cb97aa7982e2d06f48759865af7 (diff)
downloademacs-909126de0f6d2e53aec44c97abccee5b32b25f28.tar.gz
emacs-909126de0f6d2e53aec44c97abccee5b32b25f28.zip
* lisp/emacs-lisp/cl-generic.el: Add support for cl-next-method-p.
(cl-defmethod): Add edebug spec. (cl--generic-build-combined-method): Fix call to cl-no-applicable-method. (cl--generic-nnm-sample, cl--generic-cnm-sample): New constant. (cl--generic-isnot-nnm-p): New function. (cl--generic-lambda): Use it to add support for cl-next-method-p. (cl-no-next-method, cl-no-applicable-method): Simplify arg list. (cl-next-method-p): New function.
-rw-r--r--lisp/ChangeLog20
-rw-r--r--lisp/emacs-lisp/cl-generic.el72
-rw-r--r--lisp/emacs-lisp/eieio.el8
3 files changed, 84 insertions, 16 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index cce686b5f1d..ace8d2231a8 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,19 @@
12015-01-18 Stefan Monnier <monnier@iro.umontreal.ca>
2
3 * emacs-lisp/cl-macs.el (cl-defstruct): Minor optimization when include
4 or print is nil.
5 (cl-struct-type-p): New function.
6
7 * emacs-lisp/cl-generic.el: Add support for cl-next-method-p.
8 (cl-defmethod): Add edebug spec.
9 (cl--generic-build-combined-method): Fix call to
10 cl-no-applicable-method.
11 (cl--generic-nnm-sample, cl--generic-cnm-sample): New constant.
12 (cl--generic-isnot-nnm-p): New function.
13 (cl--generic-lambda): Use it to add support for cl-next-method-p.
14 (cl-no-next-method, cl-no-applicable-method): Simplify arg list.
15 (cl-next-method-p): New function.
16
12015-01-17 Ulrich Müller <ulm@gentoo.org> 172015-01-17 Ulrich Müller <ulm@gentoo.org>
2 18
3 * version.el (emacs-repository-get-version): Update docstring. 19 * version.el (emacs-repository-get-version): Update docstring.
@@ -14,8 +30,8 @@
14 in place of the file name while working on non-file buffers, just 30 in place of the file name while working on non-file buffers, just
15 like hack-dir-local-variables already does. (Bug#19140) 31 like hack-dir-local-variables already does. (Bug#19140)
16 32
17 * textmodes/enriched.el (enriched-encode): Use 33 * textmodes/enriched.el (enriched-encode):
18 inhibit-point-motion-hooks in addition to inhibit-read-only. 34 Use inhibit-point-motion-hooks in addition to inhibit-read-only.
19 (Bug#18246) 35 (Bug#18246)
20 36
21 * desktop.el (desktop-read): Do not call desktop-clear when no 37 * desktop.el (desktop-read): Do not call desktop-clear when no
diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el
index ae0f129bb23..819e2e92888 100644
--- a/lisp/emacs-lisp/cl-generic.el
+++ b/lisp/emacs-lisp/cl-generic.el
@@ -26,8 +26,7 @@
26;; The main entry points are: `cl-defgeneric' and `cl-defmethod'. 26;; The main entry points are: `cl-defgeneric' and `cl-defmethod'.
27 27
28;; Missing elements: 28;; Missing elements:
29;; - We don't support next-method-p, make-method, call-method, 29;; - We don't support make-method, call-method, define-method-combination.
30;; define-method-combination.
31;; - Method and generic function objects: CLOS defines methods as objects 30;; - Method and generic function objects: CLOS defines methods as objects
32;; (same for generic functions), whereas we don't offer such an abstraction. 31;; (same for generic functions), whereas we don't offer such an abstraction.
33;; - `no-next-method' should receive the "calling method" object, but since we 32;; - `no-next-method' should receive the "calling method" object, but since we
@@ -133,7 +132,7 @@ They should be sorted from most specific to least specific.")
133 "Create a generic function NAME. 132 "Create a generic function NAME.
134DOC-STRING is the base documentation for this class. A generic 133DOC-STRING is the base documentation for this class. A generic
135function has no body, as its purpose is to decide which method body 134function has no body, as its purpose is to decide which method body
136is appropriate to use. Specific methods are defined with `defmethod'. 135is appropriate to use. Specific methods are defined with `cl-defmethod'.
137With this implementation the ARGS are currently ignored. 136With this implementation the ARGS are currently ignored.
138OPTIONS-AND-METHODS is currently only used to specify the docstring, 137OPTIONS-AND-METHODS is currently only used to specify the docstring,
139via (:documentation DOCSTRING)." 138via (:documentation DOCSTRING)."
@@ -223,8 +222,10 @@ This macro can only be used within the lexical scope of a cl-generic method."
223 (let* ((doc-string (and doc-string (stringp (car body)) 222 (let* ((doc-string (and doc-string (stringp (car body))
224 (pop body))) 223 (pop body)))
225 (cnm (make-symbol "cl--cnm")) 224 (cnm (make-symbol "cl--cnm"))
225 (nmp (make-symbol "cl--nmp"))
226 (nbody (macroexpand-all 226 (nbody (macroexpand-all
227 `(cl-flet ((cl-call-next-method ,cnm)) 227 `(cl-flet ((cl-call-next-method ,cnm)
228 (cl-next-method-p ,nmp))
228 ,@body) 229 ,@body)
229 macroenv)) 230 macroenv))
230 ;; FIXME: Rather than `grep' after the fact, the 231 ;; FIXME: Rather than `grep' after the fact, the
@@ -232,11 +233,15 @@ This macro can only be used within the lexical scope of a cl-generic method."
232 ;; is used. 233 ;; is used.
233 ;; FIXME: Also, optimize the case where call-next-method is 234 ;; FIXME: Also, optimize the case where call-next-method is
234 ;; only called with explicit arguments. 235 ;; only called with explicit arguments.
235 (uses-cnm (cl--generic-fgrep (list cnm) nbody))) 236 (uses-cnm (cl--generic-fgrep (list cnm nmp) nbody)))
236 (cons (not (not uses-cnm)) 237 (cons (not (not uses-cnm))
237 `#'(lambda (,@(if uses-cnm (list cnm)) ,@args) 238 `#'(lambda (,@(if uses-cnm (list cnm)) ,@args)
238 ,@(if doc-string (list doc-string)) 239 ,@(if doc-string (list doc-string))
239 ,nbody)))) 240 ,(if (not (memq nmp uses-cnm))
241 nbody
242 `(let ((,nmp (lambda ()
243 (cl--generic-isnot-nnm-p ,cnm))))
244 ,nbody))))))
240 (f (error "Unexpected macroexpansion result: %S" f)))))))) 245 (f (error "Unexpected macroexpansion result: %S" f))))))))
241 246
242 247
@@ -261,7 +266,15 @@ Other than a type, TYPE can also be of the form `(eql VAL)' in
261which case this method will be invoked when the argument is `eql' to VAL. 266which case this method will be invoked when the argument is `eql' to VAL.
262 267
263\(fn NAME [QUALIFIER] ARGS &rest [DOCSTRING] BODY)" 268\(fn NAME [QUALIFIER] ARGS &rest [DOCSTRING] BODY)"
264 (declare (doc-string 3) (indent 2)) 269 (declare (doc-string 3) (indent 2)
270 (debug
271 (&define ; this means we are defining something
272 [&or name ("setf" :name setf name)]
273 ;; ^^ This is the methods symbol
274 [ &optional keywordp ] ; this is key :before etc
275 list ; arguments
276 [ &optional stringp ] ; documentation string
277 def-body))) ; part to be debugged
265 (let ((qualifiers nil)) 278 (let ((qualifiers nil))
266 (while (keywordp args) 279 (while (keywordp args)
267 (push args qualifiers) 280 (push args qualifiers)
@@ -402,7 +415,8 @@ for all those different tags in the method-cache.")
402 cl--generic-combined-method-memoization) 415 cl--generic-combined-method-memoization)
403 (cond 416 (cond
404 ((null mets-by-qual) (lambda (&rest args) 417 ((null mets-by-qual) (lambda (&rest args)
405 (cl-no-applicable-method generic-name args))) 418 (apply #'cl-no-applicable-method
419 generic-name args)))
406 (t 420 (t
407 (let* ((fun (lambda (&rest args) 421 (let* ((fun (lambda (&rest args)
408 ;; FIXME: CLOS passes as second arg the "calling method". 422 ;; FIXME: CLOS passes as second arg the "calling method".
@@ -428,6 +442,38 @@ for all those different tags in the method-cache.")
428 (apply af args))))))) 442 (apply af args)))))))
429 (cl--generic-nest fun (alist-get :around mets-by-qual)))))))) 443 (cl--generic-nest fun (alist-get :around mets-by-qual))))))))
430 444
445(defconst cl--generic-nnm-sample
446 (cl--generic-build-combined-method nil '(((specializer . :qualifier)))))
447(defconst cl--generic-cnm-sample
448 (funcall (cl--generic-build-combined-method
449 nil `(((specializer . :primary) t . ,#'identity)))))
450
451(defun cl--generic-isnot-nnm-p (cnm)
452 "Return non-nil if CNM is the function that calls `cl-no-next-method'."
453 ;; ¡Big Gross Ugly Hack!
454 ;; `next-method-p' just sucks, we should let it die. But EIEIO did support
455 ;; it, and some packages use it, so we need to support it.
456 (catch 'found
457 (cl-assert (function-equal cnm cl--generic-cnm-sample))
458 (if (byte-code-function-p cnm)
459 (let ((cnm-constants (aref cnm 2))
460 (sample-constants (aref cl--generic-cnm-sample 2)))
461 (dotimes (i (length sample-constants))
462 (when (function-equal (aref sample-constants i)
463 cl--generic-nnm-sample)
464 (throw 'found
465 (not (function-equal (aref cnm-constants i)
466 cl--generic-nnm-sample))))))
467 (cl-assert (eq 'closure (car-safe cl--generic-cnm-sample)))
468 (let ((cnm-env (cadr cnm)))
469 (dolist (vb (cadr cl--generic-cnm-sample))
470 (when (function-equal (cdr vb) cl--generic-nnm-sample)
471 (throw 'found
472 (not (function-equal (cdar cnm-env)
473 cl--generic-nnm-sample))))
474 (setq cnm-env (cdr cnm-env)))))
475 (error "Haven't found no-next-method-sample in cnm-sample")))
476
431(defun cl--generic-cache-miss (generic dispatch-arg dispatches-left tags) 477(defun cl--generic-cache-miss (generic dispatch-arg dispatches-left tags)
432 (let ((types (apply #'append (mapcar cl-generic-tag-types-function tags))) 478 (let ((types (apply #'append (mapcar cl-generic-tag-types-function tags)))
433 (methods '())) 479 (methods '()))
@@ -452,12 +498,12 @@ for all those different tags in the method-cache.")
452 498
453(cl-defgeneric cl-no-next-method (generic method &rest args) 499(cl-defgeneric cl-no-next-method (generic method &rest args)
454 "Function called when `cl-call-next-method' finds no next method.") 500 "Function called when `cl-call-next-method' finds no next method.")
455(cl-defmethod cl-no-next-method ((generic t) method &rest args) 501(cl-defmethod cl-no-next-method (generic method &rest args)
456 (signal 'cl-no-next-method `(,generic ,method ,@args))) 502 (signal 'cl-no-next-method `(,generic ,method ,@args)))
457 503
458(cl-defgeneric cl-no-applicable-method (generic &rest args) 504(cl-defgeneric cl-no-applicable-method (generic &rest args)
459 "Function called when a method call finds no applicable method.") 505 "Function called when a method call finds no applicable method.")
460(cl-defmethod cl-no-applicable-method ((generic t) &rest args) 506(cl-defmethod cl-no-applicable-method (generic &rest args)
461 (signal 'cl-no-applicable-method `(,generic ,@args))) 507 (signal 'cl-no-applicable-method `(,generic ,@args)))
462 508
463(defun cl-call-next-method (&rest _args) 509(defun cl-call-next-method (&rest _args)
@@ -465,6 +511,12 @@ for all those different tags in the method-cache.")
465Can only be used from within the lexical body of a primary or around method." 511Can only be used from within the lexical body of a primary or around method."
466 (error "cl-call-next-method only allowed inside primary and around methods")) 512 (error "cl-call-next-method only allowed inside primary and around methods"))
467 513
514(defun cl-next-method-p ()
515 "Return non-nil if there is a next method.
516Can only be used from within the lexical body of a primary or around method."
517 (declare (obsolete "make sure there's always a next method, or catch `cl-no-next-method' instead" "25.1"))
518 (error "cl-next-method-p only allowed inside primary and around methods"))
519
468;;; Add support for describe-function 520;;; Add support for describe-function
469 521
470(defun cl--generic-search-method (met-name) 522(defun cl--generic-search-method (met-name)
diff --git a/lisp/emacs-lisp/eieio.el b/lisp/emacs-lisp/eieio.el
index cda0c97a64f..c5597b83170 100644
--- a/lisp/emacs-lisp/eieio.el
+++ b/lisp/emacs-lisp/eieio.el
@@ -36,12 +36,12 @@
36;; Retrieved from: 36;; Retrieved from:
37;; http://192.220.96.201/dylan/linearization-oopsla96.html 37;; http://192.220.96.201/dylan/linearization-oopsla96.html
38 38
39;; There is funny stuff going on with typep and deftype. This
40;; is the only way I seem to be able to make this stuff load properly.
41
42;; @TODO - fix :initform to be a form, not a quoted value 39;; @TODO - fix :initform to be a form, not a quoted value
43;; @TODO - Prefix non-clos functions with `eieio-'. 40;; @TODO - Prefix non-clos functions with `eieio-'.
44 41
42;; TODO: better integrate CL's defstructs and classes. E.g. make it possible
43;; to create a new class that inherits from a struct.
44
45;;; Code: 45;;; Code:
46 46
47(defvar eieio-version "1.4" 47(defvar eieio-version "1.4"
@@ -924,7 +924,7 @@ variable PRINT-FUNCTION. Optional argument NOESCAPE is passed to
924 924
925;;; Start of automatically extracted autoloads. 925;;; Start of automatically extracted autoloads.
926 926
927;;;### (autoloads nil "eieio-custom" "eieio-custom.el" "9a908efef1720439feb6323c1dd01770") 927;;;### (autoloads nil "eieio-custom" "eieio-custom.el" "6baa78cfc590cc0422e12b7eb55abf24")
928;;; Generated autoloads from eieio-custom.el 928;;; Generated autoloads from eieio-custom.el
929 929
930(autoload 'customize-object "eieio-custom" "\ 930(autoload 'customize-object "eieio-custom" "\