aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2016-07-12 12:04:01 -0400
committerStefan Monnier2016-07-12 12:04:01 -0400
commit3698c4e475fb59730626af5d001599785ef5ef9e (patch)
treeb1df3f083764e634912c28598f1da14e7ccb7eec
parent5155144bd4cece3bab200a0eb613ffcdef523202 (diff)
downloademacs-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.el60
-rw-r--r--lisp/emacs-lisp/eieio-core.el3
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
372The absence of QUALIFIER means this is a \"primary\" method. 392The absence of QUALIFIER means this is a \"primary\" method.
393The set of acceptable qualifiers and their meaning is defined
394\(and can be extended) by the methods of `cl-generic-combine-methods'.
373 395
374TYPE can be one of the basic types (see the full list and their 396ARGS can also include so-called context specializers, introduced by
375hierarchy in `cl--generic-typeof-types'), CL struct type, or an 397`&context' (which should appear right after the mandatory arguments,
376EIEIO class. 398before any &optional or &rest). They have the form (EXPR TYPE) where
399EXPR is an Elisp expression whose value should match TYPE for the
400method to be applicable.
377 401
378Other than that, TYPE can also be of the form `(eql VAL)' in 402The set of acceptable TYPEs (also called \"specializers\") is defined
379which case this method will be invoked when the argument is `eql' 403\(and can be extended) by the various methods of `cl-generic-generalizers'.
380to VAL, or `(head VAL)', in which case the argument is required
381to 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.
1022These 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.
1043These 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.
1143See 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.
1182Used 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.
1098These 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)