diff options
| author | Stefan Monnier | 2015-05-12 00:10:38 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2015-05-12 00:10:38 -0400 |
| commit | d1b74200dad00cea845037064dc8b5d50db35dd2 (patch) | |
| tree | 51102ad11a51f14177fa58dc601a536cac40d0ca | |
| parent | f0352ebdf088bea19b44ddb31e94888bc2345a24 (diff) | |
| download | emacs-d1b74200dad00cea845037064dc8b5d50db35dd2.tar.gz emacs-d1b74200dad00cea845037064dc8b5d50db35dd2.zip | |
* lisp/emacs-lisp/cl-generic.el: Add dispatch on &context arguments
(cl--generic-mandatory-args): Remove.
(cl--generic-split-args): New function.
(cl-generic-define, cl--generic-lambda): Use it.
(cl-generic-define-method): Use it as well, and add support for
context args.
(cl--generic-get-dispatcher): Handle &context dispatch.
(cl--generic-cache-miss): `dispatch-arg' can now be a context expression.
(cl--generic-dispatchers): Pre-fill.
* test/automated/cl-generic-tests.el (sm-generic-test-12-context): New test.
| -rw-r--r-- | lisp/emacs-lisp/cl-generic.el | 244 | ||||
| -rw-r--r-- | test/automated/cl-generic-tests.el | 10 |
2 files changed, 140 insertions, 114 deletions
diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el index fb11a3e25a1..f6595d3035b 100644 --- a/lisp/emacs-lisp/cl-generic.el +++ b/lisp/emacs-lisp/cl-generic.el | |||
| @@ -54,6 +54,15 @@ | |||
| 54 | ;; - The standard method combination supports ":extra STRING" qualifiers | 54 | ;; - The standard method combination supports ":extra STRING" qualifiers |
| 55 | ;; which simply allows adding more methods for the same | 55 | ;; which simply allows adding more methods for the same |
| 56 | ;; specializers&qualifiers. | 56 | ;; specializers&qualifiers. |
| 57 | ;; - Methods can dispatch on the context. For that, a method needs to specify | ||
| 58 | ;; context arguments, introduced by `&context' (which need to come right | ||
| 59 | ;; after the mandatory arguments and before anything like | ||
| 60 | ;; &optional/&rest/&key). Each context argument is given as (EXP SPECIALIZER) | ||
| 61 | ;; which means that EXP is taken as an expression which computes some context | ||
| 62 | ;; and this value is then used to dispatch. | ||
| 63 | ;; E.g. (foo &context (major-mode (eql c-mode))) is an arglist specifying | ||
| 64 | ;; that this method will only be applicable when `major-mode' has value | ||
| 65 | ;; `c-mode'. | ||
| 57 | 66 | ||
| 58 | ;; Efficiency considerations: overall, I've made an effort to make this fairly | 67 | ;; Efficiency considerations: overall, I've made an effort to make this fairly |
| 59 | ;; efficient for the expected case (e.g. no constant redefinition of methods). | 68 | ;; efficient for the expected case (e.g. no constant redefinition of methods). |
| @@ -222,17 +231,12 @@ BODY, if present, is used as the body of a default method. | |||
| 222 | ,@(mapcar (lambda (method) `(cl-defmethod ,name ,@method)) | 231 | ,@(mapcar (lambda (method) `(cl-defmethod ,name ,@method)) |
| 223 | (nreverse methods))))) | 232 | (nreverse methods))))) |
| 224 | 233 | ||
| 225 | (defun cl--generic-mandatory-args (args) | ||
| 226 | (let ((res ())) | ||
| 227 | (while (not (memq (car args) '(nil &rest &optional &key))) | ||
| 228 | (push (pop args) res)) | ||
| 229 | (nreverse res))) | ||
| 230 | |||
| 231 | ;;;###autoload | 234 | ;;;###autoload |
| 232 | (defun cl-generic-define (name args options) | 235 | (defun cl-generic-define (name args options) |
| 233 | (let ((generic (cl-generic-ensure-function name)) | 236 | (pcase-let* ((generic (cl-generic-ensure-function name)) |
| 234 | (mandatory (cl--generic-mandatory-args args)) | 237 | (`(,spec-args . ,_) (cl--generic-split-args args)) |
| 235 | (apo (assq :argument-precedence-order options))) | 238 | (mandatory (mapcar #'car spec-args)) |
| 239 | (apo (assq :argument-precedence-order options))) | ||
| 236 | (setf (cl--generic-dispatches generic) nil) | 240 | (setf (cl--generic-dispatches generic) nil) |
| 237 | (when apo | 241 | (when apo |
| 238 | (dolist (arg (cdr apo)) | 242 | (dolist (arg (cdr apo)) |
| @@ -259,52 +263,70 @@ This macro can only be used within the lexical scope of a cl-generic method." | |||
| 259 | (and (memq sexp vars) (not (memq sexp res)) (push sexp res)) | 263 | (and (memq sexp vars) (not (memq sexp res)) (push sexp res)) |
| 260 | res)) | 264 | res)) |
| 261 | 265 | ||
| 262 | (defun cl--generic-lambda (args body) | 266 | (defun cl--generic-split-args (args) |
| 263 | "Make the lambda expression for a method with ARGS and BODY." | 267 | "Return (SPEC-ARGS . PLAIN-ARGS)." |
| 264 | (let ((plain-args ()) | 268 | (let ((plain-args ()) |
| 265 | (specializers nil) | 269 | (specializers nil) |
| 266 | (mandatory t)) | 270 | (mandatory t)) |
| 267 | (dolist (arg args) | 271 | (dolist (arg args) |
| 268 | (push (pcase arg | 272 | (push (pcase arg |
| 269 | ((or '&optional '&rest '&key) (setq mandatory nil) arg) | 273 | ((or '&optional '&rest '&key) (setq mandatory nil) arg) |
| 270 | ((and `(,name . ,type) (guard mandatory)) | 274 | ('&context |
| 275 | (unless mandatory | ||
| 276 | (error "&context not immediately after mandatory args")) | ||
| 277 | (setq mandatory 'context) nil) | ||
| 278 | ((let 'nil mandatory) arg) | ||
| 279 | ((let 'context mandatory) | ||
| 280 | (unless (consp arg) | ||
| 281 | (error "Invalid &context arg: %S" arg)) | ||
| 282 | (push `((&context . ,(car arg)) . ,(cadr arg)) specializers) | ||
| 283 | nil) | ||
| 284 | (`(,name . ,type) | ||
| 271 | (push (cons name (car type)) specializers) | 285 | (push (cons name (car type)) specializers) |
| 272 | name) | 286 | name) |
| 273 | (_ arg)) | 287 | (_ |
| 288 | (push (cons arg t) specializers) | ||
| 289 | arg)) | ||
| 274 | plain-args)) | 290 | plain-args)) |
| 275 | (setq plain-args (nreverse plain-args)) | 291 | (cons (nreverse specializers) |
| 276 | (let ((fun `(cl-function (lambda ,plain-args ,@body))) | 292 | (nreverse (delq nil plain-args))))) |
| 277 | (macroenv (cons `(cl-generic-current-method-specializers | 293 | |
| 278 | . ,(lambda () specializers)) | 294 | (defun cl--generic-lambda (args body) |
| 279 | macroexpand-all-environment))) | 295 | "Make the lambda expression for a method with ARGS and BODY." |
| 280 | (require 'cl-lib) ;Needed to expand `cl-flet' and `cl-function'. | 296 | (pcase-let* ((`(,spec-args . ,plain-args) |
| 281 | ;; First macroexpand away the cl-function stuff (e.g. &key and | 297 | (cl--generic-split-args args)) |
| 282 | ;; destructuring args, `declare' and whatnot). | 298 | (fun `(cl-function (lambda ,plain-args ,@body))) |
| 283 | (pcase (macroexpand fun macroenv) | 299 | (macroenv (cons `(cl-generic-current-method-specializers |
| 284 | (`#'(lambda ,args . ,body) | 300 | . ,(lambda () spec-args)) |
| 285 | (let* ((parsed-body (macroexp-parse-body body)) | 301 | macroexpand-all-environment))) |
| 286 | (cnm (make-symbol "cl--cnm")) | 302 | (require 'cl-lib) ;Needed to expand `cl-flet' and `cl-function'. |
| 287 | (nmp (make-symbol "cl--nmp")) | 303 | ;; First macroexpand away the cl-function stuff (e.g. &key and |
| 288 | (nbody (macroexpand-all | 304 | ;; destructuring args, `declare' and whatnot). |
| 289 | `(cl-flet ((cl-call-next-method ,cnm) | 305 | (pcase (macroexpand fun macroenv) |
| 290 | (cl-next-method-p ,nmp)) | 306 | (`#'(lambda ,args . ,body) |
| 291 | ,@(cdr parsed-body)) | 307 | (let* ((parsed-body (macroexp-parse-body body)) |
| 292 | macroenv)) | 308 | (cnm (make-symbol "cl--cnm")) |
| 293 | ;; FIXME: Rather than `grep' after the fact, the | 309 | (nmp (make-symbol "cl--nmp")) |
| 294 | ;; macroexpansion should directly set some flag when cnm | 310 | (nbody (macroexpand-all |
| 295 | ;; is used. | 311 | `(cl-flet ((cl-call-next-method ,cnm) |
| 296 | ;; FIXME: Also, optimize the case where call-next-method is | 312 | (cl-next-method-p ,nmp)) |
| 297 | ;; only called with explicit arguments. | 313 | ,@(cdr parsed-body)) |
| 298 | (uses-cnm (cl--generic-fgrep (list cnm nmp) nbody))) | 314 | macroenv)) |
| 299 | (cons (not (not uses-cnm)) | 315 | ;; FIXME: Rather than `grep' after the fact, the |
| 300 | `#'(lambda (,@(if uses-cnm (list cnm)) ,@args) | 316 | ;; macroexpansion should directly set some flag when cnm |
| 301 | ,@(car parsed-body) | 317 | ;; is used. |
| 302 | ,(if (not (memq nmp uses-cnm)) | 318 | ;; FIXME: Also, optimize the case where call-next-method is |
| 303 | nbody | 319 | ;; only called with explicit arguments. |
| 304 | `(let ((,nmp (lambda () | 320 | (uses-cnm (cl--generic-fgrep (list cnm nmp) nbody))) |
| 305 | (cl--generic-isnot-nnm-p ,cnm)))) | 321 | (cons (not (not uses-cnm)) |
| 306 | ,nbody)))))) | 322 | `#'(lambda (,@(if uses-cnm (list cnm)) ,@args) |
| 307 | (f (error "Unexpected macroexpansion result: %S" f))))))) | 323 | ,@(car parsed-body) |
| 324 | ,(if (not (memq nmp uses-cnm)) | ||
| 325 | nbody | ||
| 326 | `(let ((,nmp (lambda () | ||
| 327 | (cl--generic-isnot-nnm-p ,cnm)))) | ||
| 328 | ,nbody)))))) | ||
| 329 | (f (error "Unexpected macroexpansion result: %S" f)))))) | ||
| 308 | 330 | ||
| 309 | 331 | ||
| 310 | ;;;###autoload | 332 | ;;;###autoload |
| @@ -375,21 +397,26 @@ which case this method will be invoked when the argument is `eql' to VAL. | |||
| 375 | 397 | ||
| 376 | ;;;###autoload | 398 | ;;;###autoload |
| 377 | (defun cl-generic-define-method (name qualifiers args uses-cnm function) | 399 | (defun cl-generic-define-method (name qualifiers args uses-cnm function) |
| 378 | (let* ((generic (cl-generic-ensure-function name)) | 400 | (pcase-let* |
| 379 | (mandatory (cl--generic-mandatory-args args)) | 401 | ((generic (cl-generic-ensure-function name)) |
| 380 | (specializers | 402 | (`(,spec-args . ,_) (cl--generic-split-args args)) |
| 381 | (mapcar (lambda (arg) (if (consp arg) (cadr arg) t)) mandatory)) | 403 | (specializers (mapcar (lambda (spec-arg) |
| 382 | (method (cl--generic-make-method | 404 | (if (eq '&context (car-safe (car spec-arg))) |
| 383 | specializers qualifiers uses-cnm function)) | 405 | spec-arg (cdr spec-arg))) |
| 384 | (mt (cl--generic-method-table generic)) | 406 | spec-args)) |
| 385 | (me (cl--generic-member-method specializers qualifiers mt)) | 407 | (method (cl--generic-make-method |
| 386 | (dispatches (cl--generic-dispatches generic)) | 408 | specializers qualifiers uses-cnm function)) |
| 387 | (i 0)) | 409 | (mt (cl--generic-method-table generic)) |
| 388 | (dolist (specializer specializers) | 410 | (me (cl--generic-member-method specializers qualifiers mt)) |
| 389 | (let* ((generalizers (cl-generic-generalizers specializer)) | 411 | (dispatches (cl--generic-dispatches generic)) |
| 390 | (x (assq i dispatches))) | 412 | (i 0)) |
| 413 | (dolist (spec-arg spec-args) | ||
| 414 | (let* ((key (if (eq '&context (car-safe (car spec-arg))) | ||
| 415 | (car spec-arg) i)) | ||
| 416 | (generalizers (cl-generic-generalizers (cdr spec-arg))) | ||
| 417 | (x (assoc key dispatches))) | ||
| 391 | (unless x | 418 | (unless x |
| 392 | (setq x (cons i (cl-generic-generalizers t))) | 419 | (setq x (cons key (cl-generic-generalizers t))) |
| 393 | (setf (cl--generic-dispatches generic) | 420 | (setf (cl--generic-dispatches generic) |
| 394 | (setq dispatches (cons x dispatches)))) | 421 | (setq dispatches (cons x dispatches)))) |
| 395 | (dolist (generalizer generalizers) | 422 | (dolist (generalizer generalizers) |
| @@ -427,6 +454,7 @@ which case this method will be invoked when the argument is `eql' to VAL. | |||
| 427 | (defun cl--generic-get-dispatcher (dispatch) | 454 | (defun cl--generic-get-dispatcher (dispatch) |
| 428 | (cl--generic-with-memoization | 455 | (cl--generic-with-memoization |
| 429 | (gethash dispatch cl--generic-dispatchers) | 456 | (gethash dispatch cl--generic-dispatchers) |
| 457 | ;; (message "cl--generic-get-dispatcher (%S)" dispatch) | ||
| 430 | (let* ((dispatch-arg (car dispatch)) | 458 | (let* ((dispatch-arg (car dispatch)) |
| 431 | (generalizers (cdr dispatch)) | 459 | (generalizers (cdr dispatch)) |
| 432 | (lexical-binding t) | 460 | (lexical-binding t) |
| @@ -437,13 +465,14 @@ which case this method will be invoked when the argument is `eql' to VAL. | |||
| 437 | 'arg)) | 465 | 'arg)) |
| 438 | generalizers)) | 466 | generalizers)) |
| 439 | (typescodes | 467 | (typescodes |
| 440 | (mapcar (lambda (generalizer) | 468 | (mapcar |
| 441 | `(funcall ',(cl--generic-generalizer-specializers-function | 469 | (lambda (generalizer) |
| 442 | generalizer) | 470 | `(funcall ',(cl--generic-generalizer-specializers-function |
| 443 | ,(funcall (cl--generic-generalizer-tagcode-function | 471 | generalizer) |
| 444 | generalizer) | 472 | ,(funcall (cl--generic-generalizer-tagcode-function |
| 445 | 'arg))) | 473 | generalizer) |
| 446 | generalizers)) | 474 | 'arg))) |
| 475 | generalizers)) | ||
| 447 | (tag-exp | 476 | (tag-exp |
| 448 | ;; Minor optimization: since this tag-exp is | 477 | ;; Minor optimization: since this tag-exp is |
| 449 | ;; only used to lookup the method-cache, it | 478 | ;; only used to lookup the method-cache, it |
| @@ -452,23 +481,30 @@ which case this method will be invoked when the argument is `eql' to VAL. | |||
| 452 | `(or ,@(if (macroexp-const-p (car (last tagcodes))) | 481 | `(or ,@(if (macroexp-const-p (car (last tagcodes))) |
| 453 | (butlast tagcodes) | 482 | (butlast tagcodes) |
| 454 | tagcodes))) | 483 | tagcodes))) |
| 455 | (extraargs ())) | 484 | (fixedargs '(arg)) |
| 456 | (dotimes (_ dispatch-arg) | 485 | (dispatch-idx dispatch-arg) |
| 457 | (push (make-symbol "arg") extraargs)) | 486 | (bindings nil)) |
| 487 | (when (eq '&context (car-safe dispatch-arg)) | ||
| 488 | (setq bindings `((arg ,(cdr dispatch-arg)))) | ||
| 489 | (setq fixedargs nil) | ||
| 490 | (setq dispatch-idx 0)) | ||
| 491 | (dotimes (i dispatch-idx) | ||
| 492 | (push (make-symbol (format "arg%d" (- dispatch-idx i 1))) fixedargs)) | ||
| 458 | ;; FIXME: For generic functions with a single method (or with 2 methods, | 493 | ;; FIXME: For generic functions with a single method (or with 2 methods, |
| 459 | ;; one of which always matches), using a tagcode + hash-table is | 494 | ;; one of which always matches), using a tagcode + hash-table is |
| 460 | ;; overkill: better just use a `cl-typep' test. | 495 | ;; overkill: better just use a `cl-typep' test. |
| 461 | (byte-compile | 496 | (byte-compile |
| 462 | `(lambda (generic dispatches-left methods) | 497 | `(lambda (generic dispatches-left methods) |
| 463 | (let ((method-cache (make-hash-table :test #'eql))) | 498 | (let ((method-cache (make-hash-table :test #'eql))) |
| 464 | (lambda (,@extraargs arg &rest args) | 499 | (lambda (,@fixedargs &rest args) |
| 465 | (apply (cl--generic-with-memoization | 500 | (let ,bindings |
| 466 | (gethash ,tag-exp method-cache) | 501 | (apply (cl--generic-with-memoization |
| 467 | (cl--generic-cache-miss | 502 | (gethash ,tag-exp method-cache) |
| 468 | generic ',dispatch-arg dispatches-left methods | 503 | (cl--generic-cache-miss |
| 469 | ,(if (cdr typescodes) | 504 | generic ',dispatch-arg dispatches-left methods |
| 470 | `(append ,@typescodes) (car typescodes)))) | 505 | ,(if (cdr typescodes) |
| 471 | ,@extraargs arg args)))))))) | 506 | `(append ,@typescodes) (car typescodes)))) |
| 507 | ,@fixedargs args))))))))) | ||
| 472 | 508 | ||
| 473 | (defun cl--generic-make-function (generic) | 509 | (defun cl--generic-make-function (generic) |
| 474 | (cl--generic-make-next-function generic | 510 | (cl--generic-make-next-function generic |
| @@ -593,8 +629,11 @@ FUN is the function that should be called when METHOD calls | |||
| 593 | dispatch-arg dispatches-left methods-left types) | 629 | dispatch-arg dispatches-left methods-left types) |
| 594 | (let ((methods '())) | 630 | (let ((methods '())) |
| 595 | (dolist (method methods-left) | 631 | (dolist (method methods-left) |
| 596 | (let* ((specializer (or (nth dispatch-arg | 632 | (let* ((specializer (or (if (integerp dispatch-arg) |
| 597 | (cl--generic-method-specializers method)) | 633 | (nth dispatch-arg |
| 634 | (cl--generic-method-specializers method)) | ||
| 635 | (cdr (assoc dispatch-arg | ||
| 636 | (cl--generic-method-specializers method)))) | ||
| 598 | t)) | 637 | t)) |
| 599 | (m (member specializer types))) | 638 | (m (member specializer types))) |
| 600 | (when m | 639 | (when m |
| @@ -830,6 +869,17 @@ Can only be used from within the lexical body of a primary or around method." | |||
| 830 | 80 (lambda (name) `(gethash (car-safe ,name) cl--generic-head-used)) | 869 | 80 (lambda (name) `(gethash (car-safe ,name) cl--generic-head-used)) |
| 831 | (lambda (tag) (if (eq (car-safe tag) 'head) (list tag))))) | 870 | (lambda (tag) (if (eq (car-safe tag) 'head) (list tag))))) |
| 832 | 871 | ||
| 872 | ;; Pre-fill the cl--generic-dispatchers table. | ||
| 873 | ;; We have two copies of `(0 ...)' but we can't share them via `let' because | ||
| 874 | ;; they're not used at the same time (one is compile-time, one is run-time). | ||
| 875 | (puthash `(0 ,cl--generic-head-generalizer ,cl--generic-t-generalizer) | ||
| 876 | (eval-when-compile | ||
| 877 | (unless (fboundp 'cl--generic-get-dispatcher) | ||
| 878 | (require 'cl-generic)) | ||
| 879 | (cl--generic-get-dispatcher | ||
| 880 | `(0 ,cl--generic-head-generalizer ,cl--generic-t-generalizer))) | ||
| 881 | cl--generic-dispatchers) | ||
| 882 | |||
| 833 | (cl-defmethod cl-generic-generalizers :extra "head" (specializer) | 883 | (cl-defmethod cl-generic-generalizers :extra "head" (specializer) |
| 834 | "Support for the `(head VAL)' specializers." | 884 | "Support for the `(head VAL)' specializers." |
| 835 | ;; We have to implement `head' here using the :extra qualifier, | 885 | ;; We have to implement `head' here using the :extra qualifier, |
| @@ -948,40 +998,6 @@ Can only be used from within the lexical body of a primary or around method." | |||
| 948 | (list cl--generic-typeof-generalizer))) | 998 | (list cl--generic-typeof-generalizer))) |
| 949 | (cl-call-next-method))) | 999 | (cl-call-next-method))) |
| 950 | 1000 | ||
| 951 | ;;; Just for kicks: dispatch on major-mode | ||
| 952 | ;; | ||
| 953 | ;; Here's how you'd use it: | ||
| 954 | ;; (cl-defmethod foo ((x (major-mode text-mode)) y z) ...) | ||
| 955 | ;; And then | ||
| 956 | ;; (foo 'major-mode toto titi) | ||
| 957 | ;; | ||
| 958 | ;; FIXME: Better would be to do that via dispatch on an "implicit argument". | ||
| 959 | ;; E.g. (cl-defmethod foo (y z &context (major-mode text-mode)) ...) | ||
| 960 | |||
| 961 | ;; (defvar cl--generic-major-modes (make-hash-table :test #'eq)) | ||
| 962 | ;; | ||
| 963 | ;; (add-function :before-until cl-generic-generalizer-function | ||
| 964 | ;; #'cl--generic-major-mode-tagcode) | ||
| 965 | ;; (defun cl--generic-major-mode-tagcode (type name) | ||
| 966 | ;; (if (eq 'major-mode (car-safe type)) | ||
| 967 | ;; `(50 . (if (eq ,name 'major-mode) | ||
| 968 | ;; (cl--generic-with-memoization | ||
| 969 | ;; (gethash major-mode cl--generic-major-modes) | ||
| 970 | ;; `(cl--generic-major-mode . ,major-mode)))))) | ||
| 971 | ;; | ||
| 972 | ;; (add-function :before-until cl-generic-tag-types-function | ||
| 973 | ;; #'cl--generic-major-mode-types) | ||
| 974 | ;; (defun cl--generic-major-mode-types (tag) | ||
| 975 | ;; (when (eq (car-safe tag) 'cl--generic-major-mode) | ||
| 976 | ;; (if (eq tag 'fundamental-mode) '(fundamental-mode t) | ||
| 977 | ;; (let ((types `((major-mode ,(cdr tag))))) | ||
| 978 | ;; (while (get (car types) 'derived-mode-parent) | ||
| 979 | ;; (push (list 'major-mode (get (car types) 'derived-mode-parent)) | ||
| 980 | ;; types)) | ||
| 981 | ;; (unless (eq 'fundamental-mode (car types)) | ||
| 982 | ;; (push '(major-mode fundamental-mode) types)) | ||
| 983 | ;; (nreverse types))))) | ||
| 984 | |||
| 985 | ;; Local variables: | 1001 | ;; Local variables: |
| 986 | ;; generated-autoload-file: "cl-loaddefs.el" | 1002 | ;; generated-autoload-file: "cl-loaddefs.el" |
| 987 | ;; End: | 1003 | ;; End: |
diff --git a/test/automated/cl-generic-tests.el b/test/automated/cl-generic-tests.el index 5194802fa00..a6035d1cba2 100644 --- a/test/automated/cl-generic-tests.el +++ b/test/automated/cl-generic-tests.el | |||
| @@ -179,5 +179,15 @@ | |||
| 179 | (cl-list* "quatre" (cl-next-method-p) (cl-call-next-method))) | 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)))) | 180 | (should (equal (cl--generic-1 4 5) '("quatre" t 4 5 nil)))) |
| 181 | 181 | ||
| 182 | (ert-deftest sm-generic-test-12-context () | ||
| 183 | (cl-defgeneric cl--generic-1 ()) | ||
| 184 | (cl-defmethod cl--generic-1 (&context (overwrite-mode (eql t))) 'is-t) | ||
| 185 | (cl-defmethod cl--generic-1 (&context (overwrite-mode (eql nil))) 'is-nil) | ||
| 186 | (cl-defmethod cl--generic-1 () 'other) | ||
| 187 | (should (equal (list (let ((overwrite-mode t)) (cl--generic-1)) | ||
| 188 | (let ((overwrite-mode nil)) (cl--generic-1)) | ||
| 189 | (let ((overwrite-mode 1)) (cl--generic-1))) | ||
| 190 | '(is-t is-nil other)))) | ||
| 191 | |||
| 182 | (provide 'cl-generic-tests) | 192 | (provide 'cl-generic-tests) |
| 183 | ;;; cl-generic-tests.el ends here | 193 | ;;; cl-generic-tests.el ends here |