diff options
| author | Stefan Monnier | 2015-01-17 22:50:50 -0500 |
|---|---|---|
| committer | Stefan Monnier | 2015-01-17 22:50:50 -0500 |
| commit | 909126de0f6d2e53aec44c97abccee5b32b25f28 (patch) | |
| tree | 1cd37b86acf2b8b9b1476e9f7971e3644db2c74f | |
| parent | 3065125d314a4cb97aa7982e2d06f48759865af7 (diff) | |
| download | emacs-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/ChangeLog | 20 | ||||
| -rw-r--r-- | lisp/emacs-lisp/cl-generic.el | 72 | ||||
| -rw-r--r-- | lisp/emacs-lisp/eieio.el | 8 |
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 @@ | |||
| 1 | 2015-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 | |||
| 1 | 2015-01-17 Ulrich Müller <ulm@gentoo.org> | 17 | 2015-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. |
| 134 | DOC-STRING is the base documentation for this class. A generic | 133 | DOC-STRING is the base documentation for this class. A generic |
| 135 | function has no body, as its purpose is to decide which method body | 134 | function has no body, as its purpose is to decide which method body |
| 136 | is appropriate to use. Specific methods are defined with `defmethod'. | 135 | is appropriate to use. Specific methods are defined with `cl-defmethod'. |
| 137 | With this implementation the ARGS are currently ignored. | 136 | With this implementation the ARGS are currently ignored. |
| 138 | OPTIONS-AND-METHODS is currently only used to specify the docstring, | 137 | OPTIONS-AND-METHODS is currently only used to specify the docstring, |
| 139 | via (:documentation DOCSTRING)." | 138 | via (: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 | |||
| 261 | which case this method will be invoked when the argument is `eql' to VAL. | 266 | which 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.") | |||
| 465 | Can only be used from within the lexical body of a primary or around method." | 511 | Can 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. | ||
| 516 | Can 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" "\ |