diff options
| author | Stefan Monnier | 2016-07-12 12:04:01 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2016-07-12 12:04:01 -0400 |
| commit | 3698c4e475fb59730626af5d001599785ef5ef9e (patch) | |
| tree | b1df3f083764e634912c28598f1da14e7ccb7eec | |
| parent | 5155144bd4cece3bab200a0eb613ffcdef523202 (diff) | |
| download | emacs-3698c4e475fb59730626af5d001599785ef5ef9e.tar.gz emacs-3698c4e475fb59730626af5d001599785ef5ef9e.zip | |
* cl-generic.el (cl-defmethod): Make docstring dynamic
* lisp/emacs-lisp/cl-generic.el (cl-defmethod): Make docstring dynamic.
(cl--generic-make-defmethod-docstring): New function for that.
(cl-defmethod, cl-generic-generalizers): Tweak docstrings accordingly.
(cl-generic-define-method, cl--generic-describe): Change `load-history'
format of cl-defmethods, so as not to confused methods with equal
specializers but different qualifiers.
* lisp/emacs-lisp/eieio-core.el (cl-generic-generalizers): Provide docstrings.
| -rw-r--r-- | lisp/emacs-lisp/cl-generic.el | 60 | ||||
| -rw-r--r-- | lisp/emacs-lisp/eieio-core.el | 3 |
2 files changed, 47 insertions, 16 deletions
diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el index 0144daf3793..b7c8395f715 100644 --- a/lisp/emacs-lisp/cl-generic.el +++ b/lisp/emacs-lisp/cl-generic.el | |||
| @@ -353,6 +353,26 @@ the specializer used will be the one returned by BODY." | |||
| 353 | ,nbody)))))) | 353 | ,nbody)))))) |
| 354 | (f (error "Unexpected macroexpansion result: %S" f)))))) | 354 | (f (error "Unexpected macroexpansion result: %S" f)))))) |
| 355 | 355 | ||
| 356 | (put 'cl-defmethod 'function-documentation | ||
| 357 | '(cl--generic-make-defmethod-docstring)) | ||
| 358 | |||
| 359 | (defun cl--generic-make-defmethod-docstring () | ||
| 360 | ;; FIXME: Copy&paste from pcase--make-docstring. | ||
| 361 | (let* ((main (documentation (symbol-function 'cl-defmethod) 'raw)) | ||
| 362 | (ud (help-split-fundoc main 'cl-defmethod))) | ||
| 363 | ;; So that eg emacs -Q -l cl-lib --eval "(documentation 'pcase)" works, | ||
| 364 | ;; where cl-lib is anything using pcase-defmacro. | ||
| 365 | (require 'help-fns) | ||
| 366 | (with-temp-buffer | ||
| 367 | (insert (or (cdr ud) main)) | ||
| 368 | (insert "\n\n\tCurrently supported forms for TYPE:\n\n") | ||
| 369 | (dolist (method (reverse (cl--generic-method-table | ||
| 370 | (cl--generic 'cl-generic-generalizers)))) | ||
| 371 | (let* ((info (cl--generic-method-info method))) | ||
| 372 | (when (nth 2 info) | ||
| 373 | (insert (nth 2 info) "\n\n")))) | ||
| 374 | (let ((combined-doc (buffer-string))) | ||
| 375 | (if ud (help-add-fundoc-usage combined-doc (car ud)) combined-doc))))) | ||
| 356 | 376 | ||
| 357 | ;;;###autoload | 377 | ;;;###autoload |
| 358 | (defmacro cl-defmethod (name args &rest body) | 378 | (defmacro cl-defmethod (name args &rest body) |
| @@ -370,15 +390,17 @@ modifies how the method is combined with other methods, including: | |||
| 370 | :after - Method will be called after the primary | 390 | :after - Method will be called after the primary |
| 371 | :around - Method will be called around everything else | 391 | :around - Method will be called around everything else |
| 372 | The absence of QUALIFIER means this is a \"primary\" method. | 392 | The absence of QUALIFIER means this is a \"primary\" method. |
| 393 | The set of acceptable qualifiers and their meaning is defined | ||
| 394 | \(and can be extended) by the methods of `cl-generic-combine-methods'. | ||
| 373 | 395 | ||
| 374 | TYPE can be one of the basic types (see the full list and their | 396 | ARGS can also include so-called context specializers, introduced by |
| 375 | hierarchy in `cl--generic-typeof-types'), CL struct type, or an | 397 | `&context' (which should appear right after the mandatory arguments, |
| 376 | EIEIO class. | 398 | before any &optional or &rest). They have the form (EXPR TYPE) where |
| 399 | EXPR is an Elisp expression whose value should match TYPE for the | ||
| 400 | method to be applicable. | ||
| 377 | 401 | ||
| 378 | Other than that, TYPE can also be of the form `(eql VAL)' in | 402 | The set of acceptable TYPEs (also called \"specializers\") is defined |
| 379 | which case this method will be invoked when the argument is `eql' | 403 | \(and can be extended) by the various methods of `cl-generic-generalizers'. |
| 380 | to VAL, or `(head VAL)', in which case the argument is required | ||
| 381 | to be a cons with VAL as its head. | ||
| 382 | 404 | ||
| 383 | \(fn NAME [QUALIFIER] ARGS &rest [DOCSTRING] BODY)" | 405 | \(fn NAME [QUALIFIER] ARGS &rest [DOCSTRING] BODY)" |
| 384 | (declare (doc-string 3) (indent 2) | 406 | (declare (doc-string 3) (indent 2) |
| @@ -464,7 +486,8 @@ to be a cons with VAL as its head. | |||
| 464 | (cons method mt) | 486 | (cons method mt) |
| 465 | ;; Keep the ordering; important for methods with :extra qualifiers. | 487 | ;; Keep the ordering; important for methods with :extra qualifiers. |
| 466 | (mapcar (lambda (x) (if (eq x (car me)) method x)) mt))) | 488 | (mapcar (lambda (x) (if (eq x (car me)) method x)) mt))) |
| 467 | (cl-pushnew `(cl-defmethod . (,(cl--generic-name generic) . ,specializers)) | 489 | (cl-pushnew `(cl-defmethod . (,(cl--generic-name generic) |
| 490 | ,qualifiers . ,specializers)) | ||
| 468 | current-load-list :test #'equal) | 491 | current-load-list :test #'equal) |
| 469 | ;; FIXME: Try to avoid re-constructing a new function if the old one | 492 | ;; FIXME: Try to avoid re-constructing a new function if the old one |
| 470 | ;; is still valid (e.g. still empty method cache)? | 493 | ;; is still valid (e.g. still empty method cache)? |
| @@ -737,7 +760,7 @@ methods.") | |||
| 737 | (fset 'cl-generic-combine-methods #'cl--generic-standard-method-combination)) | 760 | (fset 'cl-generic-combine-methods #'cl--generic-standard-method-combination)) |
| 738 | 761 | ||
| 739 | (cl-defmethod cl-generic-generalizers (specializer) | 762 | (cl-defmethod cl-generic-generalizers (specializer) |
| 740 | "Support for the catch-all t specializer." | 763 | "Support for the catch-all t specializer which always matches." |
| 741 | (if (eq specializer t) (list cl--generic-t-generalizer) | 764 | (if (eq specializer t) (list cl--generic-t-generalizer) |
| 742 | (error "Unknown specializer %S" specializer))) | 765 | (error "Unknown specializer %S" specializer))) |
| 743 | 766 | ||
| @@ -909,8 +932,9 @@ MET-NAME is a cons (SYMBOL . SPECIALIZERS)." | |||
| 909 | (let* ((info (cl--generic-method-info method))) | 932 | (let* ((info (cl--generic-method-info method))) |
| 910 | ;; FIXME: Add hyperlinks for the types as well. | 933 | ;; FIXME: Add hyperlinks for the types as well. |
| 911 | (insert (format "%s%S" (nth 0 info) (nth 1 info))) | 934 | (insert (format "%s%S" (nth 0 info) (nth 1 info))) |
| 912 | (let* ((met-name (cons function | 935 | (let* ((met-name `(,function |
| 913 | (cl--generic-method-specializers method))) | 936 | ,(cl--generic-method-qualifiers method) |
| 937 | . ,(cl--generic-method-specializers method))) | ||
| 914 | (file (find-lisp-object-file-name met-name 'cl-defmethod))) | 938 | (file (find-lisp-object-file-name met-name 'cl-defmethod))) |
| 915 | (when file | 939 | (when file |
| 916 | (insert (substitute-command-keys " in `")) | 940 | (insert (substitute-command-keys " in `")) |
| @@ -994,7 +1018,8 @@ The value returned is a list of elements of the form | |||
| 994 | (lambda (tag &rest _) (if (eq (car-safe tag) 'head) (list tag)))) | 1018 | (lambda (tag &rest _) (if (eq (car-safe tag) 'head) (list tag)))) |
| 995 | 1019 | ||
| 996 | (cl-defmethod cl-generic-generalizers :extra "head" (specializer) | 1020 | (cl-defmethod cl-generic-generalizers :extra "head" (specializer) |
| 997 | "Support for the `(head VAL)' specializers." | 1021 | "Support for (head VAL) specializers. |
| 1022 | These match if the argument is a cons cell whose car is `eql' to VAL." | ||
| 998 | ;; We have to implement `head' here using the :extra qualifier, | 1023 | ;; We have to implement `head' here using the :extra qualifier, |
| 999 | ;; since we can't use the `head' specializer to implement itself. | 1024 | ;; since we can't use the `head' specializer to implement itself. |
| 1000 | (if (not (eq (car-safe specializer) 'head)) | 1025 | (if (not (eq (car-safe specializer) 'head)) |
| @@ -1014,7 +1039,8 @@ The value returned is a list of elements of the form | |||
| 1014 | (lambda (tag &rest _) (if (eq (car-safe tag) 'eql) (list tag)))) | 1039 | (lambda (tag &rest _) (if (eq (car-safe tag) 'eql) (list tag)))) |
| 1015 | 1040 | ||
| 1016 | (cl-defmethod cl-generic-generalizers ((specializer (head eql))) | 1041 | (cl-defmethod cl-generic-generalizers ((specializer (head eql))) |
| 1017 | "Support for the `(eql VAL)' specializers." | 1042 | "Support for (eql VAL) specializers. |
| 1043 | These match if the argument is `eql' to VAL." | ||
| 1018 | (puthash (cadr specializer) specializer cl--generic-eql-used) | 1044 | (puthash (cadr specializer) specializer cl--generic-eql-used) |
| 1019 | (list cl--generic-eql-generalizer)) | 1045 | (list cl--generic-eql-generalizer)) |
| 1020 | 1046 | ||
| @@ -1069,7 +1095,7 @@ The value returned is a list of elements of the form | |||
| 1069 | #'cl--generic-struct-specializers) | 1095 | #'cl--generic-struct-specializers) |
| 1070 | 1096 | ||
| 1071 | (cl-defmethod cl-generic-generalizers :extra "cl-struct" (type) | 1097 | (cl-defmethod cl-generic-generalizers :extra "cl-struct" (type) |
| 1072 | "Support for dispatch on cl-struct types." | 1098 | "Support for dispatch on types defined by `cl-defstruct'." |
| 1073 | (or | 1099 | (or |
| 1074 | (when (symbolp type) | 1100 | (when (symbolp type) |
| 1075 | ;; Use the "cl--struct-class*" (inlinable) functions/macros rather than | 1101 | ;; Use the "cl--struct-class*" (inlinable) functions/macros rather than |
| @@ -1113,7 +1139,8 @@ The value returned is a list of elements of the form | |||
| 1113 | (and (symbolp tag) (assq tag cl--generic-typeof-types)))) | 1139 | (and (symbolp tag) (assq tag cl--generic-typeof-types)))) |
| 1114 | 1140 | ||
| 1115 | (cl-defmethod cl-generic-generalizers :extra "typeof" (type) | 1141 | (cl-defmethod cl-generic-generalizers :extra "typeof" (type) |
| 1116 | "Support for dispatch on builtin types." | 1142 | "Support for dispatch on builtin types. |
| 1143 | See the full list and their hierarchy in `cl--generic-typeof-types'." | ||
| 1117 | ;; FIXME: Add support for other types accepted by `cl-typep' such | 1144 | ;; FIXME: Add support for other types accepted by `cl-typep' such |
| 1118 | ;; as `character', `atom', `face', `function', ... | 1145 | ;; as `character', `atom', `face', `function', ... |
| 1119 | (or | 1146 | (or |
| @@ -1151,7 +1178,8 @@ The value returned is a list of elements of the form | |||
| 1151 | #'cl--generic-derived-specializers) | 1178 | #'cl--generic-derived-specializers) |
| 1152 | 1179 | ||
| 1153 | (cl-defmethod cl-generic-generalizers ((_specializer (head derived-mode))) | 1180 | (cl-defmethod cl-generic-generalizers ((_specializer (head derived-mode))) |
| 1154 | "Support for the `(derived-mode MODE)' specializers." | 1181 | "Support for (derived-mode MODE) specializers. |
| 1182 | Used internally for the (major-mode MODE) context specializers." | ||
| 1155 | (list cl--generic-derived-generalizer)) | 1183 | (list cl--generic-derived-generalizer)) |
| 1156 | 1184 | ||
| 1157 | (cl-generic-define-context-rewriter major-mode (mode &rest modes) | 1185 | (cl-generic-define-context-rewriter major-mode (mode &rest modes) |
diff --git a/lisp/emacs-lisp/eieio-core.el b/lisp/emacs-lisp/eieio-core.el index fd8ae2abecb..0567c87dd39 100644 --- a/lisp/emacs-lisp/eieio-core.el +++ b/lisp/emacs-lisp/eieio-core.el | |||
| @@ -1065,6 +1065,7 @@ method invocation orders of the involved classes." | |||
| 1065 | (eieio--class-precedence-list (symbol-value tag)))))) | 1065 | (eieio--class-precedence-list (symbol-value tag)))))) |
| 1066 | 1066 | ||
| 1067 | (cl-defmethod cl-generic-generalizers :extra "class" (specializer) | 1067 | (cl-defmethod cl-generic-generalizers :extra "class" (specializer) |
| 1068 | "Support for dispatch on types defined by EIEIO's `defclass'." | ||
| 1068 | ;; CLHS says: | 1069 | ;; CLHS says: |
| 1069 | ;; A class must be defined before it can be used as a parameter | 1070 | ;; A class must be defined before it can be used as a parameter |
| 1070 | ;; specializer in a defmethod form. | 1071 | ;; specializer in a defmethod form. |
| @@ -1093,6 +1094,8 @@ method invocation orders of the involved classes." | |||
| 1093 | #'eieio--generic-subclass-specializers) | 1094 | #'eieio--generic-subclass-specializers) |
| 1094 | 1095 | ||
| 1095 | (cl-defmethod cl-generic-generalizers ((_specializer (head subclass))) | 1096 | (cl-defmethod cl-generic-generalizers ((_specializer (head subclass))) |
| 1097 | "Support for (subclass CLASS) specializers. | ||
| 1098 | These match if the argument is the name of a subclass of CLASS." | ||
| 1096 | (list eieio--generic-subclass-generalizer)) | 1099 | (list eieio--generic-subclass-generalizer)) |
| 1097 | 1100 | ||
| 1098 | (provide 'eieio-core) | 1101 | (provide 'eieio-core) |