diff options
Diffstat (limited to 'lisp/emacs-lisp/cl-generic.el')
| -rw-r--r-- | lisp/emacs-lisp/cl-generic.el | 71 |
1 files changed, 51 insertions, 20 deletions
diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el index c64376b940f..1a3f8e1f4d5 100644 --- a/lisp/emacs-lisp/cl-generic.el +++ b/lisp/emacs-lisp/cl-generic.el | |||
| @@ -166,6 +166,10 @@ SPECIALIZERS-FUNCTION takes as first argument a tag value TAG | |||
| 166 | (defmacro cl--generic (name) | 166 | (defmacro cl--generic (name) |
| 167 | `(get ,name 'cl--generic)) | 167 | `(get ,name 'cl--generic)) |
| 168 | 168 | ||
| 169 | (defun cl-generic-p (f) | ||
| 170 | "Return non-nil if F is a generic function." | ||
| 171 | (and (symbolp f) (cl--generic f))) | ||
| 172 | |||
| 169 | (defun cl-generic-ensure-function (name &optional noerror) | 173 | (defun cl-generic-ensure-function (name &optional noerror) |
| 170 | (let (generic | 174 | (let (generic |
| 171 | (origname name)) | 175 | (origname name)) |
| @@ -182,8 +186,7 @@ SPECIALIZERS-FUNCTION takes as first argument a tag value TAG | |||
| 182 | origname)) | 186 | origname)) |
| 183 | (if generic | 187 | (if generic |
| 184 | (cl-assert (eq name (cl--generic-name generic))) | 188 | (cl-assert (eq name (cl--generic-name generic))) |
| 185 | (setf (cl--generic name) (setq generic (cl--generic-make name))) | 189 | (setf (cl--generic name) (setq generic (cl--generic-make name)))) |
| 186 | (defalias name (cl--generic-make-function generic))) | ||
| 187 | generic)) | 190 | generic)) |
| 188 | 191 | ||
| 189 | ;;;###autoload | 192 | ;;;###autoload |
| @@ -410,7 +413,7 @@ The set of acceptable TYPEs (also called \"specializers\") is defined | |||
| 410 | \(and can be extended) by the various methods of `cl-generic-generalizers'. | 413 | \(and can be extended) by the various methods of `cl-generic-generalizers'. |
| 411 | 414 | ||
| 412 | \(fn NAME [QUALIFIER] ARGS &rest [DOCSTRING] BODY)" | 415 | \(fn NAME [QUALIFIER] ARGS &rest [DOCSTRING] BODY)" |
| 413 | (declare (doc-string 3) (indent 2) | 416 | (declare (doc-string 3) (indent defun) |
| 414 | (debug | 417 | (debug |
| 415 | (&define ; this means we are defining something | 418 | (&define ; this means we are defining something |
| 416 | [&or name ("setf" name :name setf)] | 419 | [&or name ("setf" name :name setf)] |
| @@ -501,25 +504,26 @@ The set of acceptable TYPEs (also called \"specializers\") is defined | |||
| 501 | (cons method mt) | 504 | (cons method mt) |
| 502 | ;; Keep the ordering; important for methods with :extra qualifiers. | 505 | ;; Keep the ordering; important for methods with :extra qualifiers. |
| 503 | (mapcar (lambda (x) (if (eq x (car me)) method x)) mt))) | 506 | (mapcar (lambda (x) (if (eq x (car me)) method x)) mt))) |
| 504 | (cl-pushnew `(cl-defmethod . ,(cl--generic-load-hist-format | 507 | (let ((sym (cl--generic-name generic))) ; Actual name (for aliases). |
| 505 | (cl--generic-name generic) | 508 | (unless (symbol-function sym) |
| 506 | qualifiers specializers)) | 509 | (defalias sym 'dummy)) ;Record definition into load-history. |
| 507 | current-load-list :test #'equal) | 510 | (cl-pushnew `(cl-defmethod . ,(cl--generic-load-hist-format |
| 508 | ;; FIXME: Try to avoid re-constructing a new function if the old one | 511 | (cl--generic-name generic) |
| 509 | ;; is still valid (e.g. still empty method cache)? | 512 | qualifiers specializers)) |
| 510 | (let ((gfun (cl--generic-make-function generic)) | 513 | current-load-list :test #'equal) |
| 511 | ;; Prevent `defalias' from recording this as the definition site of | 514 | ;; FIXME: Try to avoid re-constructing a new function if the old one |
| 512 | ;; the generic function. | 515 | ;; is still valid (e.g. still empty method cache)? |
| 513 | current-load-list) | 516 | (let ((gfun (cl--generic-make-function generic)) |
| 514 | ;; For aliases, cl--generic-name gives us the actual name. | 517 | ;; Prevent `defalias' from recording this as the definition site of |
| 515 | (let ((purify-flag | 518 | ;; the generic function. |
| 516 | ;; BEWARE! Don't purify this function definition, since that leads | 519 | current-load-list |
| 517 | ;; to memory corruption if the hash-tables it holds are modified | 520 | ;; BEWARE! Don't purify this function definition, since that leads |
| 518 | ;; (the GC doesn't trace those pointers). | 521 | ;; to memory corruption if the hash-tables it holds are modified |
| 519 | nil)) | 522 | ;; (the GC doesn't trace those pointers). |
| 523 | (purify-flag nil)) | ||
| 520 | ;; But do use `defalias', so that it interacts properly with nadvice, | 524 | ;; But do use `defalias', so that it interacts properly with nadvice, |
| 521 | ;; e.g. for tracing/debug-on-entry. | 525 | ;; e.g. for tracing/debug-on-entry. |
| 522 | (defalias (cl--generic-name generic) gfun))))) | 526 | (defalias sym gfun))))) |
| 523 | 527 | ||
| 524 | (defmacro cl--generic-with-memoization (place &rest code) | 528 | (defmacro cl--generic-with-memoization (place &rest code) |
| 525 | (declare (indent 1) (debug t)) | 529 | (declare (indent 1) (debug t)) |
| @@ -1023,6 +1027,20 @@ The value returned is a list of elements of the form | |||
| 1023 | (push (cl--generic-method-info method) docs)))) | 1027 | (push (cl--generic-method-info method) docs)))) |
| 1024 | docs)) | 1028 | docs)) |
| 1025 | 1029 | ||
| 1030 | (defun cl--generic-method-files (method) | ||
| 1031 | "Return a list of files where METHOD is defined by `cl-defmethod'. | ||
| 1032 | The list will have entries of the form (FILE . (METHOD ...)) | ||
| 1033 | where (METHOD ...) contains the qualifiers and specializers of | ||
| 1034 | the method and is a suitable argument for | ||
| 1035 | `find-function-search-for-symbol'. Filenames are absolute." | ||
| 1036 | (let (result) | ||
| 1037 | (pcase-dolist (`(,file . ,defs) load-history) | ||
| 1038 | (dolist (def defs) | ||
| 1039 | (when (and (eq (car-safe def) 'cl-defmethod) | ||
| 1040 | (eq (cadr def) method)) | ||
| 1041 | (push (cons file (cdr def)) result)))) | ||
| 1042 | result)) | ||
| 1043 | |||
| 1026 | ;;; Support for (head <val>) specializers. | 1044 | ;;; Support for (head <val>) specializers. |
| 1027 | 1045 | ||
| 1028 | ;; For both the `eql' and the `head' specializers, the dispatch | 1046 | ;; For both the `eql' and the `head' specializers, the dispatch |
| @@ -1210,5 +1228,18 @@ Used internally for the (major-mode MODE) context specializers." | |||
| 1210 | (progn (cl-assert (null modes)) mode) | 1228 | (progn (cl-assert (null modes)) mode) |
| 1211 | `(derived-mode ,mode . ,modes)))) | 1229 | `(derived-mode ,mode . ,modes)))) |
| 1212 | 1230 | ||
| 1231 | ;;; Support for unloading. | ||
| 1232 | |||
| 1233 | (cl-defmethod loadhist-unload-element ((x (head cl-defmethod))) | ||
| 1234 | (pcase-let* | ||
| 1235 | ((`(,name ,qualifiers . ,specializers) (cdr x)) | ||
| 1236 | (generic (cl-generic-ensure-function name 'noerror))) | ||
| 1237 | (when generic | ||
| 1238 | (let* ((mt (cl--generic-method-table generic)) | ||
| 1239 | (me (cl--generic-member-method specializers qualifiers mt))) | ||
| 1240 | (when me | ||
| 1241 | (setf (cl--generic-method-table generic) (delq (car me) mt))))))) | ||
| 1242 | |||
| 1243 | |||
| 1213 | (provide 'cl-generic) | 1244 | (provide 'cl-generic) |
| 1214 | ;;; cl-generic.el ends here | 1245 | ;;; cl-generic.el ends here |