diff options
| author | Stefan Monnier | 2015-01-26 09:04:55 -0500 |
|---|---|---|
| committer | Stefan Monnier | 2015-01-26 09:04:55 -0500 |
| commit | 4cdde9196fb4fafb00b0c51b908fd605274147bd (patch) | |
| tree | 34b825a588203225f126027cff47f95772af2a28 | |
| parent | 242354a23acf214ad06d4e3e7e5f5580c8b21d4a (diff) | |
| download | emacs-4cdde9196fb4fafb00b0c51b908fd605274147bd.tar.gz emacs-4cdde9196fb4fafb00b0c51b908fd605274147bd.zip | |
* lisp/emacs-lisp/cl-generic.el: Add a method-combination hook.
(cl-generic-method-combination-function): New var.
(cl--generic-lambda): Remove `with-cnm' arg.
(cl-defmethod): Change accordingly.
(cl-generic-define-method): Don't check qualifiers validity.
Preserve all qualifiers in `method-table'.
(cl-generic-call-method): New function.
(cl--generic-nest): Remove (morph into cl-generic-call-method).
(cl--generic-build-combined-method): Adjust to new format of method-table
and use cl-generic-method-combination-function.
(cl--generic-standard-method-combination): New function, extracted from
cl--generic-build-combined-method.
(cl--generic-cnm-sample): Adjust to new format of method-table.
* lisp/emacs-lisp/eieio-compat.el (eieio--defmethod): Use () qualifiers
instead of :primary.
* lisp/emacs-lisp/eieio-datadebug.el (eieio-debug-methodinvoke):
Remove obsolete function.
* test/automated/cl-generic-tests.el (cl-generic-test-11-next-method-p):
New test.
| -rw-r--r-- | lisp/ChangeLog | 22 | ||||
| -rw-r--r-- | lisp/emacs-lisp/cl-generic.el | 205 | ||||
| -rw-r--r-- | lisp/emacs-lisp/eieio-compat.el | 6 | ||||
| -rw-r--r-- | lisp/emacs-lisp/eieio-datadebug.el | 16 | ||||
| -rw-r--r-- | test/ChangeLog | 5 | ||||
| -rw-r--r-- | test/automated/cl-generic-tests.el | 8 |
6 files changed, 155 insertions, 107 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 8af0ec46cad..0bdf4e275fa 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,25 @@ | |||
| 1 | 2015-01-26 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | * emacs-lisp/cl-generic.el: Add a method-combination hook. | ||
| 4 | (cl-generic-method-combination-function): New var. | ||
| 5 | (cl--generic-lambda): Remove `with-cnm' arg. | ||
| 6 | (cl-defmethod): Change accordingly. | ||
| 7 | (cl-generic-define-method): Don't check qualifiers validity. | ||
| 8 | Preserve all qualifiers in `method-table'. | ||
| 9 | (cl-generic-call-method): New function. | ||
| 10 | (cl--generic-nest): Remove (morph into cl-generic-call-method). | ||
| 11 | (cl--generic-build-combined-method): Adjust to new format of method-table | ||
| 12 | and use cl-generic-method-combination-function. | ||
| 13 | (cl--generic-standard-method-combination): New function, extracted from | ||
| 14 | cl--generic-build-combined-method. | ||
| 15 | (cl--generic-cnm-sample): Adjust to new format of method-table. | ||
| 16 | |||
| 17 | * emacs-lisp/eieio-compat.el (eieio--defmethod): Use () qualifiers | ||
| 18 | instead of :primary. | ||
| 19 | |||
| 20 | * emacs-lisp/eieio-datadebug.el (eieio-debug-methodinvoke): | ||
| 21 | Remove obsolete function. | ||
| 22 | |||
| 1 | 2015-01-26 Lars Ingebrigtsen <larsi@gnus.org> | 23 | 2015-01-26 Lars Ingebrigtsen <larsi@gnus.org> |
| 2 | 24 | ||
| 3 | * net/shr.el (shr-make-table-1): Fix colspan typo. | 25 | * net/shr.el (shr-make-table-1): Fix colspan typo. |
diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el index 02a43514019..4245959c8a4 100644 --- a/lisp/emacs-lisp/cl-generic.el +++ b/lisp/emacs-lisp/cl-generic.el | |||
| @@ -30,7 +30,9 @@ | |||
| 30 | ;; CLOS's define-method-combination is IMO overly complicated, and it suffers | 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 | 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 | 32 | ;; that needs to be `eval'uated or compiled. IOW it requires run-time |
| 33 | ;; code generation. | 33 | ;; code generation. Given how rarely method-combinations are used, |
| 34 | ;; I just provided a cl-generic-method-combination-function, which | ||
| 35 | ;; people can use if they are really desperate for such functionality. | ||
| 34 | ;; - Method and generic function objects: CLOS defines methods as objects | 36 | ;; - Method and generic function objects: CLOS defines methods as objects |
| 35 | ;; (same for generic functions), whereas we don't offer such an abstraction. | 37 | ;; (same for generic functions), whereas we don't offer such an abstraction. |
| 36 | ;; - `no-next-method' should receive the "calling method" object, but since we | 38 | ;; - `no-next-method' should receive the "calling method" object, but since we |
| @@ -115,10 +117,10 @@ They should be sorted from most specific to least specific.") | |||
| 115 | ;; The most important dispatch is last in the list (and the least is first). | 117 | ;; The most important dispatch is last in the list (and the least is first). |
| 116 | (dispatches nil :type (list-of (cons natnum (list-of tagcode)))) | 118 | (dispatches nil :type (list-of (cons natnum (list-of tagcode)))) |
| 117 | ;; `method-table' is a list of | 119 | ;; `method-table' is a list of |
| 118 | ;; ((SPECIALIZERS . QUALIFIER) USES-CNM . FUNCTION), where | 120 | ;; ((SPECIALIZERS . QUALIFIERS) USES-CNM . FUNCTION), where |
| 119 | ;; USES-CNM is a boolean indicating if FUNCTION calls `cl-call-next-method' | 121 | ;; USES-CNM is a boolean indicating if FUNCTION calls `cl-call-next-method' |
| 120 | ;; (and hence expects an extra argument holding the next-method). | 122 | ;; (and hence expects an extra argument holding the next-method). |
| 121 | (method-table nil :type (list-of (cons (cons (list-of type) keyword) | 123 | (method-table nil :type (list-of (cons (cons (list-of type) (list-of atom)) |
| 122 | (cons boolean function))))) | 124 | (cons boolean function))))) |
| 123 | 125 | ||
| 124 | (defmacro cl--generic (name) | 126 | (defmacro cl--generic (name) |
| @@ -232,7 +234,7 @@ This macro can only be used within the lexical scope of a cl-generic method." | |||
| 232 | (and (memq sexp vars) (not (memq sexp res)) (push sexp res)) | 234 | (and (memq sexp vars) (not (memq sexp res)) (push sexp res)) |
| 233 | res)) | 235 | res)) |
| 234 | 236 | ||
| 235 | (defun cl--generic-lambda (args body with-cnm) | 237 | (defun cl--generic-lambda (args body) |
| 236 | "Make the lambda expression for a method with ARGS and BODY." | 238 | "Make the lambda expression for a method with ARGS and BODY." |
| 237 | (let ((plain-args ()) | 239 | (let ((plain-args ()) |
| 238 | (specializers nil) | 240 | (specializers nil) |
| @@ -255,36 +257,34 @@ This macro can only be used within the lexical scope of a cl-generic method." | |||
| 255 | . ,(lambda () specializers)) | 257 | . ,(lambda () specializers)) |
| 256 | macroexpand-all-environment))) | 258 | macroexpand-all-environment))) |
| 257 | (require 'cl-lib) ;Needed to expand `cl-flet' and `cl-function'. | 259 | (require 'cl-lib) ;Needed to expand `cl-flet' and `cl-function'. |
| 258 | (if (not with-cnm) | 260 | ;; First macroexpand away the cl-function stuff (e.g. &key and |
| 259 | (cons nil (macroexpand-all fun macroenv)) | 261 | ;; destructuring args, `declare' and whatnot). |
| 260 | ;; First macroexpand away the cl-function stuff (e.g. &key and | 262 | (pcase (macroexpand fun macroenv) |
| 261 | ;; destructuring args, `declare' and whatnot). | 263 | (`#'(lambda ,args . ,body) |
| 262 | (pcase (macroexpand fun macroenv) | 264 | (let* ((doc-string (and doc-string (stringp (car body)) (cdr body) |
| 263 | (`#'(lambda ,args . ,body) | 265 | (pop body))) |
| 264 | (let* ((doc-string (and doc-string (stringp (car body)) (cdr body) | 266 | (cnm (make-symbol "cl--cnm")) |
| 265 | (pop body))) | 267 | (nmp (make-symbol "cl--nmp")) |
| 266 | (cnm (make-symbol "cl--cnm")) | 268 | (nbody (macroexpand-all |
| 267 | (nmp (make-symbol "cl--nmp")) | 269 | `(cl-flet ((cl-call-next-method ,cnm) |
| 268 | (nbody (macroexpand-all | 270 | (cl-next-method-p ,nmp)) |
| 269 | `(cl-flet ((cl-call-next-method ,cnm) | 271 | ,@body) |
| 270 | (cl-next-method-p ,nmp)) | 272 | macroenv)) |
| 271 | ,@body) | 273 | ;; FIXME: Rather than `grep' after the fact, the |
| 272 | macroenv)) | 274 | ;; macroexpansion should directly set some flag when cnm |
| 273 | ;; FIXME: Rather than `grep' after the fact, the | 275 | ;; is used. |
| 274 | ;; macroexpansion should directly set some flag when cnm | 276 | ;; FIXME: Also, optimize the case where call-next-method is |
| 275 | ;; is used. | 277 | ;; only called with explicit arguments. |
| 276 | ;; FIXME: Also, optimize the case where call-next-method is | 278 | (uses-cnm (cl--generic-fgrep (list cnm nmp) nbody))) |
| 277 | ;; only called with explicit arguments. | 279 | (cons (not (not uses-cnm)) |
| 278 | (uses-cnm (cl--generic-fgrep (list cnm nmp) nbody))) | 280 | `#'(lambda (,@(if uses-cnm (list cnm)) ,@args) |
| 279 | (cons (not (not uses-cnm)) | 281 | ,@(if doc-string (list doc-string)) |
| 280 | `#'(lambda (,@(if uses-cnm (list cnm)) ,@args) | 282 | ,(if (not (memq nmp uses-cnm)) |
| 281 | ,@(if doc-string (list doc-string)) | 283 | nbody |
| 282 | ,(if (not (memq nmp uses-cnm)) | 284 | `(let ((,nmp (lambda () |
| 283 | nbody | 285 | (cl--generic-isnot-nnm-p ,cnm)))) |
| 284 | `(let ((,nmp (lambda () | 286 | ,nbody)))))) |
| 285 | (cl--generic-isnot-nnm-p ,cnm)))) | 287 | (f (error "Unexpected macroexpansion result: %S" f))))))) |
| 286 | ,nbody)))))) | ||
| 287 | (f (error "Unexpected macroexpansion result: %S" f)))))))) | ||
| 288 | 288 | ||
| 289 | 289 | ||
| 290 | ;;;###autoload | 290 | ;;;###autoload |
| @@ -324,8 +324,7 @@ which case this method will be invoked when the argument is `eql' to VAL. | |||
| 324 | (while (not (listp args)) | 324 | (while (not (listp args)) |
| 325 | (push args qualifiers) | 325 | (push args qualifiers) |
| 326 | (setq args (pop body))) | 326 | (setq args (pop body))) |
| 327 | (pcase-let* ((with-cnm (not (memq (car qualifiers) '(:before :after)))) | 327 | (pcase-let* ((`(,uses-cnm . ,fun) (cl--generic-lambda args body))) |
| 328 | (`(,uses-cnm . ,fun) (cl--generic-lambda args body with-cnm))) | ||
| 329 | `(progn | 328 | `(progn |
| 330 | ,(when setfizer | 329 | ,(when setfizer |
| 331 | (setq name (car setfizer)) | 330 | (setq name (car setfizer)) |
| @@ -347,15 +346,11 @@ which case this method will be invoked when the argument is `eql' to VAL. | |||
| 347 | 346 | ||
| 348 | ;;;###autoload | 347 | ;;;###autoload |
| 349 | (defun cl-generic-define-method (name qualifiers args uses-cnm function) | 348 | (defun cl-generic-define-method (name qualifiers args uses-cnm function) |
| 350 | (when (> (length qualifiers) 1) | ||
| 351 | (error "We only support a single qualifier per method: %S" qualifiers)) | ||
| 352 | (unless (memq (car qualifiers) '(nil :primary :around :after :before)) | ||
| 353 | (error "Unsupported qualifier in: %S" qualifiers)) | ||
| 354 | (let* ((generic (cl-generic-ensure-function name)) | 349 | (let* ((generic (cl-generic-ensure-function name)) |
| 355 | (mandatory (cl--generic-mandatory-args args)) | 350 | (mandatory (cl--generic-mandatory-args args)) |
| 356 | (specializers | 351 | (specializers |
| 357 | (mapcar (lambda (arg) (if (consp arg) (cadr arg) t)) mandatory)) | 352 | (mapcar (lambda (arg) (if (consp arg) (cadr arg) t)) mandatory)) |
| 358 | (key (cons specializers (or (car qualifiers) ':primary))) | 353 | (key (cons specializers qualifiers)) |
| 359 | (mt (cl--generic-method-table generic)) | 354 | (mt (cl--generic-method-table generic)) |
| 360 | (me (assoc key mt)) | 355 | (me (assoc key mt)) |
| 361 | (dispatches (cl--generic-dispatches generic)) | 356 | (dispatches (cl--generic-dispatches generic)) |
| @@ -438,22 +433,19 @@ which case this method will be invoked when the argument is `eql' to VAL. | |||
| 438 | (cdr dispatch) (car dispatch)))) | 433 | (cdr dispatch) (car dispatch)))) |
| 439 | (funcall dispatcher generic dispatches))))) | 434 | (funcall dispatcher generic dispatches))))) |
| 440 | 435 | ||
| 441 | (defun cl--generic-nest (fun methods) | 436 | (defvar cl-generic-method-combination-function |
| 442 | (pcase-dolist (`(,uses-cnm . ,method) methods) | 437 | #'cl--generic-standard-method-combination |
| 443 | (setq fun | 438 | "Function to build the effective method. |
| 444 | (if (not uses-cnm) method | 439 | Called with 2 arguments: NAME and METHOD-ALIST. |
| 445 | (let ((next fun)) | 440 | It should return an effective method, i.e. a function that expects the same |
| 446 | (lambda (&rest args) | 441 | arguments as the methods, and calls those methods in some appropriate order. |
| 447 | (apply method | 442 | NAME is the name (a symbol) of the corresponding generic function. |
| 448 | ;; FIXME: This sucks: passing just `next' would | 443 | METHOD-ALIST is a list of elements (QUALIFIERS . METHODS) where |
| 449 | ;; be a lot more efficient than the lambda+apply | 444 | QUALIFIERS is a list of qualifiers, and METHODS is a list of the selected |
| 450 | ;; quasi-η, but we need this to implement the | 445 | methods for that qualifier list. |
| 451 | ;; "if call-next-method is called with no | 446 | The METHODS lists are sorted from most generic first to most specific last. |
| 452 | ;; arguments, then use the previous arguments". | 447 | The function can use `cl-generic-call-method' to create functions that call those |
| 453 | (lambda (&rest cnm-args) | 448 | methods.") |
| 454 | (apply next (or cnm-args args))) | ||
| 455 | args)))))) | ||
| 456 | fun) | ||
| 457 | 449 | ||
| 458 | (defvar cl--generic-combined-method-memoization | 450 | (defvar cl--generic-combined-method-memoization |
| 459 | (make-hash-table :test #'equal :weakness 'value) | 451 | (make-hash-table :test #'equal :weakness 'value) |
| @@ -462,6 +454,22 @@ This is particularly useful when many different tags select the same set | |||
| 462 | of methods, since this table then allows us to share a single combined-method | 454 | of methods, since this table then allows us to share a single combined-method |
| 463 | for all those different tags in the method-cache.") | 455 | for all those different tags in the method-cache.") |
| 464 | 456 | ||
| 457 | (defun cl--generic-build-combined-method (generic-name methods) | ||
| 458 | (cl--generic-with-memoization | ||
| 459 | (gethash (cons generic-name methods) | ||
| 460 | cl--generic-combined-method-memoization) | ||
| 461 | (let ((mets-by-qual ())) | ||
| 462 | (dolist (qm methods) | ||
| 463 | (let* ((qualifiers (cdar qm)) | ||
| 464 | (x (assoc qualifiers mets-by-qual))) | ||
| 465 | ;; FIXME: sadly, alist-get only uses `assq' and we need `assoc'. | ||
| 466 | ;;(push (cdr qm) (alist-get qualifiers mets-by-qual))) | ||
| 467 | (if x | ||
| 468 | (push (cdr qm) (cdr x)) | ||
| 469 | (push (list qualifiers (cdr qm)) mets-by-qual)))) | ||
| 470 | (funcall cl-generic-method-combination-function | ||
| 471 | generic-name mets-by-qual)))) | ||
| 472 | |||
| 465 | (defun cl--generic-no-next-method-function (generic) | 473 | (defun cl--generic-no-next-method-function (generic) |
| 466 | (lambda (&rest args) | 474 | (lambda (&rest args) |
| 467 | ;; FIXME: CLOS passes as second arg the "calling method". | 475 | ;; FIXME: CLOS passes as second arg the "calling method". |
| @@ -474,42 +482,61 @@ for all those different tags in the method-cache.") | |||
| 474 | ;; it anyway. So we pass nil for now. | 482 | ;; it anyway. So we pass nil for now. |
| 475 | (apply #'cl-no-next-method generic nil args))) | 483 | (apply #'cl-no-next-method generic nil args))) |
| 476 | 484 | ||
| 477 | (defun cl--generic-build-combined-method (generic-name methods) | 485 | (defun cl-generic-call-method (generic-name method &optional fun) |
| 478 | (let ((mets-by-qual ())) | 486 | "Return a function that calls METHOD. |
| 479 | (dolist (qm methods) | 487 | FUN is the function that should be called when METHOD calls |
| 480 | (push (cdr qm) (alist-get (cdar qm) mets-by-qual))) | 488 | `call-next-method'." |
| 481 | (cl--generic-with-memoization | 489 | (pcase method |
| 482 | (gethash (cons generic-name mets-by-qual) | 490 | (`(nil . ,method) method) |
| 483 | cl--generic-combined-method-memoization) | 491 | (`(,_uses-cnm . ,method) |
| 484 | (cond | 492 | (let ((next (or fun (cl--generic-no-next-method-function generic-name)))) |
| 485 | ((null mets-by-qual) | 493 | (lambda (&rest args) |
| 486 | (lambda (&rest args) | 494 | (apply method |
| 487 | (apply #'cl-no-applicable-method generic-name args))) | 495 | ;; FIXME: This sucks: passing just `next' would |
| 488 | ((null (alist-get :primary mets-by-qual)) | 496 | ;; be a lot more efficient than the lambda+apply |
| 489 | (lambda (&rest args) | 497 | ;; quasi-η, but we need this to implement the |
| 490 | (apply #'cl-no-primary-method generic-name args))) | 498 | ;; "if call-next-method is called with no |
| 491 | (t | 499 | ;; arguments, then use the previous arguments". |
| 492 | (let* ((fun (cl--generic-no-next-method-function generic-name)) | 500 | (lambda (&rest cnm-args) |
| 493 | ;; We use `cdr' to drop the `uses-cnm' annotations. | 501 | (apply next (or cnm-args args))) |
| 494 | (before | 502 | args)))))) |
| 495 | (mapcar #'cdr (reverse (alist-get :before mets-by-qual)))) | 503 | |
| 496 | (after (mapcar #'cdr (alist-get :after mets-by-qual)))) | 504 | (defun cl--generic-standard-method-combination (generic-name mets-by-qual) |
| 497 | (setq fun (cl--generic-nest fun (alist-get :primary mets-by-qual))) | 505 | (dolist (x mets-by-qual) |
| 498 | (when (or after before) | 506 | (unless (member (car x) '(() (:after) (:before) (:around))) |
| 499 | (let ((next fun)) | 507 | (error "Unsupported qualifiers in function %S: %S" generic-name (car x)))) |
| 500 | (setq fun (lambda (&rest args) | 508 | (cond |
| 501 | (dolist (bf before) | 509 | ((null mets-by-qual) |
| 502 | (apply bf args)) | 510 | (lambda (&rest args) |
| 503 | (prog1 | 511 | (apply #'cl-no-applicable-method generic-name args))) |
| 504 | (apply next args) | 512 | ((null (alist-get nil mets-by-qual)) |
| 505 | (dolist (af after) | 513 | (lambda (&rest args) |
| 506 | (apply af args))))))) | 514 | (apply #'cl-no-primary-method generic-name args))) |
| 507 | (cl--generic-nest fun (alist-get :around mets-by-qual)))))))) | 515 | (t |
| 516 | (let* ((fun nil) | ||
| 517 | (ab-call (lambda (m) (cl-generic-call-method generic-name m))) | ||
| 518 | (before | ||
| 519 | (mapcar ab-call (reverse (cdr (assoc '(:before) mets-by-qual))))) | ||
| 520 | (after (mapcar ab-call (cdr (assoc '(:after) mets-by-qual))))) | ||
| 521 | (dolist (method (cdr (assoc nil mets-by-qual))) | ||
| 522 | (setq fun (cl-generic-call-method generic-name method fun))) | ||
| 523 | (when (or after before) | ||
| 524 | (let ((next fun)) | ||
| 525 | (setq fun (lambda (&rest args) | ||
| 526 | (dolist (bf before) | ||
| 527 | (apply bf args)) | ||
| 528 | (prog1 | ||
| 529 | (apply next args) | ||
| 530 | (dolist (af after) | ||
| 531 | (apply af args))))))) | ||
| 532 | (dolist (method (cdr (assoc '(:around) mets-by-qual))) | ||
| 533 | (setq fun (cl-generic-call-method generic-name method fun))) | ||
| 534 | fun)))) | ||
| 508 | 535 | ||
| 509 | (defconst cl--generic-nnm-sample (cl--generic-no-next-method-function 'dummy)) | 536 | (defconst cl--generic-nnm-sample (cl--generic-no-next-method-function 'dummy)) |
| 510 | (defconst cl--generic-cnm-sample | 537 | (defconst cl--generic-cnm-sample |
| 511 | (funcall (cl--generic-build-combined-method | 538 | (funcall (cl--generic-build-combined-method |
| 512 | nil `(((specializer . :primary) t . ,#'identity))))) | 539 | nil `(((specializer . nil) t . ,#'identity))))) |
| 513 | 540 | ||
| 514 | (defun cl--generic-isnot-nnm-p (cnm) | 541 | (defun cl--generic-isnot-nnm-p (cnm) |
| 515 | "Return non-nil if CNM is the function that calls `cl-no-next-method'." | 542 | "Return non-nil if CNM is the function that calls `cl-no-next-method'." |
diff --git a/lisp/emacs-lisp/eieio-compat.el b/lisp/emacs-lisp/eieio-compat.el index c2dabf7f446..30bb5cee994 100644 --- a/lisp/emacs-lisp/eieio-compat.el +++ b/lisp/emacs-lisp/eieio-compat.el | |||
| @@ -181,7 +181,8 @@ Summary: | |||
| 181 | (lambda (generic arg &rest args) (apply code arg generic args))) | 181 | (lambda (generic arg &rest args) (apply code arg generic args))) |
| 182 | (_ code)))) | 182 | (_ code)))) |
| 183 | (cl-generic-define-method | 183 | (cl-generic-define-method |
| 184 | method (if kind (list kind)) specializers uses-cnm | 184 | method (unless (memq kind '(nil :primary)) (list kind)) |
| 185 | specializers uses-cnm | ||
| 185 | (if uses-cnm | 186 | (if uses-cnm |
| 186 | (let* ((docstring (documentation code 'raw)) | 187 | (let* ((docstring (documentation code 'raw)) |
| 187 | (args (help-function-arglist code 'preserve-names)) | 188 | (args (help-function-arglist code 'preserve-names)) |
| @@ -201,10 +202,11 @@ Summary: | |||
| 201 | ;; applicable but only of the before/after kind. So if we add a :before | 202 | ;; applicable but only of the before/after kind. So if we add a :before |
| 202 | ;; or :after, make sure there's a matching dummy primary. | 203 | ;; or :after, make sure there's a matching dummy primary. |
| 203 | (when (and (memq kind '(:before :after)) | 204 | (when (and (memq kind '(:before :after)) |
| 205 | ;; FIXME: Use `cl-find-method'? | ||
| 204 | (not (assoc (cons (mapcar (lambda (arg) | 206 | (not (assoc (cons (mapcar (lambda (arg) |
| 205 | (if (consp arg) (nth 1 arg) t)) | 207 | (if (consp arg) (nth 1 arg) t)) |
| 206 | specializers) | 208 | specializers) |
| 207 | :primary) | 209 | nil) |
| 208 | (cl--generic-method-table (cl--generic method))))) | 210 | (cl--generic-method-table (cl--generic method))))) |
| 209 | (cl-generic-define-method method () specializers t | 211 | (cl-generic-define-method method () specializers t |
| 210 | (lambda (cnm &rest args) | 212 | (lambda (cnm &rest args) |
diff --git a/lisp/emacs-lisp/eieio-datadebug.el b/lisp/emacs-lisp/eieio-datadebug.el index 6534bd0fecf..119f7cce038 100644 --- a/lisp/emacs-lisp/eieio-datadebug.el +++ b/lisp/emacs-lisp/eieio-datadebug.el | |||
| @@ -129,22 +129,6 @@ PREBUTTONTEXT is some text between PREFIX and the object button." | |||
| 129 | (data-debug-new-buffer (format "*%s DDEBUG*" (eieio-object-name obj))) | 129 | (data-debug-new-buffer (format "*%s DDEBUG*" (eieio-object-name obj))) |
| 130 | (data-debug-insert-object-slots obj "]")) | 130 | (data-debug-insert-object-slots obj "]")) |
| 131 | 131 | ||
| 132 | ;;; DEBUG FUNCTIONS | ||
| 133 | ;; | ||
| 134 | (defun eieio-debug-methodinvoke (method class) | ||
| 135 | "Show the method invocation order for METHOD with CLASS object." | ||
| 136 | (interactive "aMethod: \nXClass Expression: ") | ||
| 137 | (let* ((eieio-pre-method-execution-functions | ||
| 138 | (lambda (l) (throw 'moose l) )) | ||
| 139 | (data | ||
| 140 | (catch 'moose (eieio--generic-call | ||
| 141 | method (list class)))) | ||
| 142 | (_buf (data-debug-new-buffer "*Method Invocation*")) | ||
| 143 | (data2 (mapcar (lambda (sym) | ||
| 144 | (symbol-function (car sym))) | ||
| 145 | data))) | ||
| 146 | (data-debug-insert-thing data2 ">" ""))) | ||
| 147 | |||
| 148 | (provide 'eieio-datadebug) | 132 | (provide 'eieio-datadebug) |
| 149 | 133 | ||
| 150 | ;;; eieio-datadebug.el ends here | 134 | ;;; eieio-datadebug.el ends here |
diff --git a/test/ChangeLog b/test/ChangeLog index d8cd36790f2..9a31da45416 100644 --- a/test/ChangeLog +++ b/test/ChangeLog | |||
| @@ -1,3 +1,8 @@ | |||
| 1 | 2015-01-26 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | * automated/cl-generic-tests.el (cl-generic-test-11-next-method-p): | ||
| 4 | New test. | ||
| 5 | |||
| 1 | 2015-01-25 Paul Eggert <eggert@cs.ucla.edu> | 6 | 2015-01-25 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 7 | ||
| 3 | * indent/shell.sh (bar): Use '[ $# -eq 0 ]', not '[ $# == 0 ]'. | 8 | * indent/shell.sh (bar): Use '[ $# -eq 0 ]', not '[ $# == 0 ]'. |
diff --git a/test/automated/cl-generic-tests.el b/test/automated/cl-generic-tests.el index bc9a1ece423..5b3a9fdc2a1 100644 --- a/test/automated/cl-generic-tests.el +++ b/test/automated/cl-generic-tests.el | |||
| @@ -171,5 +171,13 @@ | |||
| 171 | (should (equal (cl--generic-1 'a 'b) '(a b))) | 171 | (should (equal (cl--generic-1 'a 'b) '(a b))) |
| 172 | (should (equal (cl--generic-1 1 2) '("integer" 2 1)))) | 172 | (should (equal (cl--generic-1 1 2) '("integer" 2 1)))) |
| 173 | 173 | ||
| 174 | (ert-deftest cl-generic-test-11-next-method-p () | ||
| 175 | (cl-defgeneric cl--generic-1 (x y)) | ||
| 176 | (cl-defmethod cl--generic-1 ((x t) y) | ||
| 177 | (list x y (cl-next-method-p))) | ||
| 178 | (cl-defmethod cl--generic-1 ((_x (eql 4)) _y) | ||
| 179 | (cl-list* "quatre" (cl-next-method-p) (cl-call-next-method))) | ||
| 180 | (should (equal (cl--generic-1 4 5) '("quatre" t 4 5 nil)))) | ||
| 181 | |||
| 174 | (provide 'cl-generic-tests) | 182 | (provide 'cl-generic-tests) |
| 175 | ;;; cl-generic-tests.el ends here | 183 | ;;; cl-generic-tests.el ends here |