diff options
| author | Stefan Monnier | 2015-01-25 11:09:53 -0500 |
|---|---|---|
| committer | Stefan Monnier | 2015-01-25 11:09:53 -0500 |
| commit | c4e54f962714056df6c57c21f694544f237d5f4c (patch) | |
| tree | 99cbfcaf89b39352c871fc09a6fb0a6650aebe4e | |
| parent | f67446455fc0ec59f5c25c90a8783e571b60dc8f (diff) | |
| download | emacs-c4e54f962714056df6c57c21f694544f237d5f4c.tar.gz emacs-c4e54f962714056df6c57c21f694544f237d5f4c.zip | |
* lisp/emacs-lisp/cl-generic.el: Fix next-method-p test
Fixes: debbugs:19672
* lisp/emacs-lisp/cl-generic.el (cl--generic-no-next-method-function): New.
(cl--generic-build-combined-method, cl--generic-nnm-sample): Use it.
(cl--generic-typeof-types): Add support for `sequence'.
(cl-defmethod): Add non-keywords in the qualifiers.
| -rw-r--r-- | lisp/ChangeLog | 8 | ||||
| -rw-r--r-- | lisp/emacs-lisp/cl-generic.el | 56 |
2 files changed, 42 insertions, 22 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index d42670f743b..70293af2725 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,11 @@ | |||
| 1 | 2015-01-25 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | * emacs-lisp/cl-generic.el (cl--generic-no-next-method-function): New fun. | ||
| 4 | (cl--generic-build-combined-method, cl--generic-nnm-sample): Use it | ||
| 5 | (bug#19672). | ||
| 6 | (cl--generic-typeof-types): Add support for `sequence'. | ||
| 7 | (cl-defmethod): Add non-keywords in the qualifiers. | ||
| 8 | |||
| 1 | 2015-01-25 Dmitry Gutov <dgutov@yandex.ru> | 9 | 2015-01-25 Dmitry Gutov <dgutov@yandex.ru> |
| 2 | 10 | ||
| 3 | * emacs-lisp/find-func.el (find-function-regexp): Don't match | 11 | * emacs-lisp/find-func.el (find-function-regexp): Don't match |
diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el index 095f1e5d582..02a43514019 100644 --- a/lisp/emacs-lisp/cl-generic.el +++ b/lisp/emacs-lisp/cl-generic.el | |||
| @@ -27,6 +27,10 @@ | |||
| 27 | 27 | ||
| 28 | ;; Missing elements: | 28 | ;; Missing elements: |
| 29 | ;; - We don't support make-method, call-method, define-method-combination. | 29 | ;; - We don't support make-method, call-method, define-method-combination. |
| 30 | ;; CLOS's define-method-combination is IMO overly complicated, and it suffers | ||
| 31 | ;; from a significant problem: the method-combination code returns a sexp | ||
| 32 | ;; that needs to be `eval'uated or compiled. IOW it requires run-time | ||
| 33 | ;; code generation. | ||
| 30 | ;; - Method and generic function objects: CLOS defines methods as objects | 34 | ;; - Method and generic function objects: CLOS defines methods as objects |
| 31 | ;; (same for generic functions), whereas we don't offer such an abstraction. | 35 | ;; (same for generic functions), whereas we don't offer such an abstraction. |
| 32 | ;; - `no-next-method' should receive the "calling method" object, but since we | 36 | ;; - `no-next-method' should receive the "calling method" object, but since we |
| @@ -66,6 +70,10 @@ | |||
| 66 | ;; often suboptimal since after one dispatch, the remaining dispatches can | 70 | ;; often suboptimal since after one dispatch, the remaining dispatches can |
| 67 | ;; usually be simplified, or even completely skipped. | 71 | ;; usually be simplified, or even completely skipped. |
| 68 | 72 | ||
| 73 | ;; TODO/FIXME: | ||
| 74 | ;; - WIBNI we could use something like | ||
| 75 | ;; (add-function :before (cl-method-function (cl-find-method ...)) ...) | ||
| 76 | |||
| 69 | (eval-when-compile (require 'cl-lib)) | 77 | (eval-when-compile (require 'cl-lib)) |
| 70 | (eval-when-compile (require 'pcase)) | 78 | (eval-when-compile (require 'pcase)) |
| 71 | 79 | ||
| @@ -313,7 +321,7 @@ which case this method will be invoked when the argument is `eql' to VAL. | |||
| 313 | (setfizer (if (eq 'setf (car-safe name)) | 321 | (setfizer (if (eq 'setf (car-safe name)) |
| 314 | ;; Call it before we call cl--generic-lambda. | 322 | ;; Call it before we call cl--generic-lambda. |
| 315 | (cl--generic-setf-rewrite (cadr name))))) | 323 | (cl--generic-setf-rewrite (cadr name))))) |
| 316 | (while (keywordp args) | 324 | (while (not (listp args)) |
| 317 | (push args qualifiers) | 325 | (push args qualifiers) |
| 318 | (setq args (pop body))) | 326 | (setq args (pop body))) |
| 319 | (pcase-let* ((with-cnm (not (memq (car qualifiers) '(:before :after)))) | 327 | (pcase-let* ((with-cnm (not (memq (car qualifiers) '(:before :after)))) |
| @@ -454,6 +462,18 @@ This is particularly useful when many different tags select the same set | |||
| 454 | of methods, since this table then allows us to share a single combined-method | 462 | of methods, since this table then allows us to share a single combined-method |
| 455 | for all those different tags in the method-cache.") | 463 | for all those different tags in the method-cache.") |
| 456 | 464 | ||
| 465 | (defun cl--generic-no-next-method-function (generic) | ||
| 466 | (lambda (&rest args) | ||
| 467 | ;; FIXME: CLOS passes as second arg the "calling method". | ||
| 468 | ;; We don't currently have "method objects" like CLOS | ||
| 469 | ;; does so we can't really do it the CLOS way. | ||
| 470 | ;; The closest would be to pass the lambda corresponding | ||
| 471 | ;; to the method, or maybe the ((SPECIALIZERS | ||
| 472 | ;; . QUALIFIER) USE-CNM . FUNCTION) entry from the method | ||
| 473 | ;; table, but the caller wouldn't be able to do much with | ||
| 474 | ;; it anyway. So we pass nil for now. | ||
| 475 | (apply #'cl-no-next-method generic nil args))) | ||
| 476 | |||
| 457 | (defun cl--generic-build-combined-method (generic-name methods) | 477 | (defun cl--generic-build-combined-method (generic-name methods) |
| 458 | (let ((mets-by-qual ())) | 478 | (let ((mets-by-qual ())) |
| 459 | (dolist (qm methods) | 479 | (dolist (qm methods) |
| @@ -469,16 +489,7 @@ for all those different tags in the method-cache.") | |||
| 469 | (lambda (&rest args) | 489 | (lambda (&rest args) |
| 470 | (apply #'cl-no-primary-method generic-name args))) | 490 | (apply #'cl-no-primary-method generic-name args))) |
| 471 | (t | 491 | (t |
| 472 | (let* ((fun (lambda (&rest args) | 492 | (let* ((fun (cl--generic-no-next-method-function generic-name)) |
| 473 | ;; FIXME: CLOS passes as second arg the "calling method". | ||
| 474 | ;; We don't currently have "method objects" like CLOS | ||
| 475 | ;; does so we can't really do it the CLOS way. | ||
| 476 | ;; The closest would be to pass the lambda corresponding | ||
| 477 | ;; to the method, or maybe the ((SPECIALIZERS | ||
| 478 | ;; . QUALIFIER) USE-CNM . FUNCTION) entry from the method | ||
| 479 | ;; table, but the caller wouldn't be able to do much with | ||
| 480 | ;; it anyway. So we pass nil for now. | ||
| 481 | (apply #'cl-no-next-method generic-name nil args))) | ||
| 482 | ;; We use `cdr' to drop the `uses-cnm' annotations. | 493 | ;; We use `cdr' to drop the `uses-cnm' annotations. |
| 483 | (before | 494 | (before |
| 484 | (mapcar #'cdr (reverse (alist-get :before mets-by-qual)))) | 495 | (mapcar #'cdr (reverse (alist-get :before mets-by-qual)))) |
| @@ -495,8 +506,7 @@ for all those different tags in the method-cache.") | |||
| 495 | (apply af args))))))) | 506 | (apply af args))))))) |
| 496 | (cl--generic-nest fun (alist-get :around mets-by-qual)))))))) | 507 | (cl--generic-nest fun (alist-get :around mets-by-qual)))))))) |
| 497 | 508 | ||
| 498 | (defconst cl--generic-nnm-sample | 509 | (defconst cl--generic-nnm-sample (cl--generic-no-next-method-function 'dummy)) |
| 499 | (cl--generic-build-combined-method nil '(((specializer . :qualifier))))) | ||
| 500 | (defconst cl--generic-cnm-sample | 510 | (defconst cl--generic-cnm-sample |
| 501 | (funcall (cl--generic-build-combined-method | 511 | (funcall (cl--generic-build-combined-method |
| 502 | nil `(((specializer . :primary) t . ,#'identity))))) | 512 | nil `(((specializer . :primary) t . ,#'identity))))) |
| @@ -690,22 +700,24 @@ Can only be used from within the lexical body of a primary or around method." | |||
| 690 | (push 'cl-struct types) ;The "parent type" of all cl-structs. | 700 | (push 'cl-struct types) ;The "parent type" of all cl-structs. |
| 691 | (nreverse types)))) | 701 | (nreverse types)))) |
| 692 | 702 | ||
| 693 | ;;; Dispatch on "old-style types". | 703 | ;;; Dispatch on "system types". |
| 694 | 704 | ||
| 695 | (defconst cl--generic-typeof-types | 705 | (defconst cl--generic-typeof-types |
| 696 | ;; Hand made from the source code of `type-of'. | 706 | ;; Hand made from the source code of `type-of'. |
| 697 | '((integer number) (symbol) (string array) (cons list) | 707 | '((integer number) (symbol) (string array sequence) (cons list sequence) |
| 698 | ;; Markers aren't `numberp', yet they are accepted wherever integers are | 708 | ;; Markers aren't `numberp', yet they are accepted wherever integers are |
| 699 | ;; accepted, pretty much. | 709 | ;; accepted, pretty much. |
| 700 | (marker) (overlay) (float number) (window-configuration) | 710 | (marker) (overlay) (float number) (window-configuration) |
| 701 | (process) (window) (subr) (compiled-function) (buffer) (char-table array) | 711 | (process) (window) (subr) (compiled-function) (buffer) |
| 702 | (bool-vector array) | 712 | (char-table array sequence) |
| 713 | (bool-vector array sequence) | ||
| 703 | (frame) (hash-table) (font-spec) (font-entity) (font-object) | 714 | (frame) (hash-table) (font-spec) (font-entity) (font-object) |
| 704 | (vector array) | 715 | (vector array sequence) |
| 705 | ;; Plus, hand made: | 716 | ;; Plus, hand made: |
| 706 | (null list symbol) | 717 | (null symbol list sequence) |
| 707 | (list) | 718 | (list sequence) |
| 708 | (array) | 719 | (array sequence) |
| 720 | (sequence) | ||
| 709 | (number))) | 721 | (number))) |
| 710 | 722 | ||
| 711 | (add-function :before-until cl-generic-tagcode-function | 723 | (add-function :before-until cl-generic-tagcode-function |
| @@ -715,7 +727,7 @@ Can only be used from within the lexical body of a primary or around method." | |||
| 715 | ;; as `character', `atom', `face', `function', ... | 727 | ;; as `character', `atom', `face', `function', ... |
| 716 | (and (assq type cl--generic-typeof-types) | 728 | (and (assq type cl--generic-typeof-types) |
| 717 | (progn | 729 | (progn |
| 718 | (if (memq type '(vector array)) | 730 | (if (memq type '(vector array sequence)) |
| 719 | (message "`%S' also matches CL structs and EIEIO classes" type)) | 731 | (message "`%S' also matches CL structs and EIEIO classes" type)) |
| 720 | ;; FIXME: We could also change `type-of' to return `null' for nil. | 732 | ;; FIXME: We could also change `type-of' to return `null' for nil. |
| 721 | `(10 . (if ,name (type-of ,name) 'null))))) | 733 | `(10 . (if ,name (type-of ,name) 'null))))) |