diff options
| author | Eric M. Ludlam | 2010-09-19 00:23:57 -0400 |
|---|---|---|
| committer | Chong Yidong | 2010-09-19 00:23:57 -0400 |
| commit | a2930e438b2a70726e6d5b09de8b2a9658505c4e (patch) | |
| tree | f4fe13d1ea2291de213838578057e77d1e8afe11 | |
| parent | dd9af436d98d87c8c214a80e728c68cc02674ca0 (diff) | |
| download | emacs-a2930e438b2a70726e6d5b09de8b2a9658505c4e.tar.gz emacs-a2930e438b2a70726e6d5b09de8b2a9658505c4e.zip | |
Update to CEDET 1.0's version of EIEIO.
* emacs-lisp/eieio.el (eieio-specialized-key-to-generic-key): New
function.
(eieio-defmethod, eieio-generic-form, eieio-generic-call): Use it.
(eieio-default-eval-maybe): Eval val instead of unquoting only.
(class-precedence-list): If class is nil, return nil.
(eieio-generic-call): If class of first input arg is nil, don't
look up static methods, and do check for primary methods.
(initialize-instance): See if the default needs to be evaluated
during the constructor.
(eieio-perform-slot-validation-for-default): Don't do the check
for values that will eventually be evaluated.
(eieio-eval-default-p): New function.
(eieio-default-eval-maybe): Use it.
* emacs-lisp/eieio.el (eieio-defclass): Allow :c3
method-invocation-order.
(eieio-c3-candidate, eieio-c3-merge-lists): New functions.
(eieio-class-precedence-dfs): Compute class precedence list using
dfs algorithm.
(eieio-class-precedence-bfs): Compute class precedence list using
bfs algorithm.
(eieio-class-precedence-c3): compute class precedence list using
c3 algorithm.
(class-precedence-list): New function.
(eieiomt-method-list, eieiomt-sym-optimize): Use it.
(inconsistent-class-hierarchy): New error symbol.
(call-next-method): Stow the replacement argument list for future
call-next-method invocations.
| -rw-r--r-- | lisp/ChangeLog | 35 | ||||
| -rw-r--r-- | lisp/emacs-lisp/eieio.el | 299 |
2 files changed, 250 insertions, 84 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 29f7f77fc0a..647ccd42ada 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,38 @@ | |||
| 1 | 2010-09-19 Eric M. Ludlam <zappo@gnu.org> | ||
| 2 | |||
| 3 | Update to CEDET 1.0's version of EIEIO. | ||
| 4 | |||
| 5 | * emacs-lisp/eieio.el (eieio-specialized-key-to-generic-key): New | ||
| 6 | function. | ||
| 7 | (eieio-defmethod, eieio-generic-form, eieio-generic-call): Use it. | ||
| 8 | (eieio-default-eval-maybe): Eval val instead of unquoting only. | ||
| 9 | (class-precedence-list): If class is nil, return nil. | ||
| 10 | (eieio-generic-call): If class of first input arg is nil, don't | ||
| 11 | look up static methods, and do check for primary methods. | ||
| 12 | (initialize-instance): See if the default needs to be evaluated | ||
| 13 | during the constructor. | ||
| 14 | (eieio-perform-slot-validation-for-default): Don't do the check | ||
| 15 | for values that will eventually be evaluated. | ||
| 16 | (eieio-eval-default-p): New function. | ||
| 17 | (eieio-default-eval-maybe): Use it. | ||
| 18 | |||
| 19 | 2010-07-03 Jan Moringen <jan.moringen@uni-bielefeld.de> | ||
| 20 | |||
| 21 | * emacs-lisp/eieio.el (eieio-defclass): Allow :c3 | ||
| 22 | method-invocation-order. | ||
| 23 | (eieio-c3-candidate, eieio-c3-merge-lists): New functions. | ||
| 24 | (eieio-class-precedence-dfs): Compute class precedence list using | ||
| 25 | dfs algorithm. | ||
| 26 | (eieio-class-precedence-bfs): Compute class precedence list using | ||
| 27 | bfs algorithm. | ||
| 28 | (eieio-class-precedence-c3): compute class precedence list using | ||
| 29 | c3 algorithm. | ||
| 30 | (class-precedence-list): New function. | ||
| 31 | (eieiomt-method-list, eieiomt-sym-optimize): Use it. | ||
| 32 | (inconsistent-class-hierarchy): New error symbol. | ||
| 33 | (call-next-method): Stow the replacement argument list for future | ||
| 34 | call-next-method invocations. | ||
| 35 | |||
| 1 | 2010-09-15 Glenn Morris <rgm@gnu.org> | 36 | 2010-09-15 Glenn Morris <rgm@gnu.org> |
| 2 | 37 | ||
| 3 | * calendar/appt.el (appt-check): If not displaying the diary, | 38 | * calendar/appt.el (appt-check): If not displaying the diary, |
diff --git a/lisp/emacs-lisp/eieio.el b/lisp/emacs-lisp/eieio.el index f5e684e1323..97022f0acbe 100644 --- a/lisp/emacs-lisp/eieio.el +++ b/lisp/emacs-lisp/eieio.el | |||
| @@ -5,7 +5,7 @@ | |||
| 5 | ;; 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. | 5 | ;; 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. |
| 6 | 6 | ||
| 7 | ;; Author: Eric M. Ludlam <zappo@gnu.org> | 7 | ;; Author: Eric M. Ludlam <zappo@gnu.org> |
| 8 | ;; Version: 0.2 | 8 | ;; Version: 1.3 |
| 9 | ;; Keywords: OO, lisp | 9 | ;; Keywords: OO, lisp |
| 10 | 10 | ||
| 11 | ;; This file is part of GNU Emacs. | 11 | ;; This file is part of GNU Emacs. |
| @@ -31,6 +31,11 @@ | |||
| 31 | ;; Emacs running environment. | 31 | ;; Emacs running environment. |
| 32 | ;; | 32 | ;; |
| 33 | ;; See eieio.texi for complete documentation on using this package. | 33 | ;; See eieio.texi for complete documentation on using this package. |
| 34 | ;; | ||
| 35 | ;; Note: the implementation of the c3 algorithm is based on: | ||
| 36 | ;; Kim Barrett et al.: A Monotonic Superclass Linearization for Dylan | ||
| 37 | ;; Retrieved from: | ||
| 38 | ;; http://192.220.96.201/dylan/linearization-oopsla96.html | ||
| 34 | 39 | ||
| 35 | ;; There is funny stuff going on with typep and deftype. This | 40 | ;; There is funny stuff going on with typep and deftype. This |
| 36 | ;; is the only way I seem to be able to make this stuff load properly. | 41 | ;; is the only way I seem to be able to make this stuff load properly. |
| @@ -44,7 +49,7 @@ | |||
| 44 | (require 'cl) | 49 | (require 'cl) |
| 45 | (require 'eieio-comp)) | 50 | (require 'eieio-comp)) |
| 46 | 51 | ||
| 47 | (defvar eieio-version "1.2" | 52 | (defvar eieio-version "1.3" |
| 48 | "Current version of EIEIO.") | 53 | "Current version of EIEIO.") |
| 49 | 54 | ||
| 50 | (defun eieio-version () | 55 | (defun eieio-version () |
| @@ -79,7 +84,7 @@ | |||
| 79 | "*This hook is executed, then cleared each time `defclass' is called.") | 84 | "*This hook is executed, then cleared each time `defclass' is called.") |
| 80 | 85 | ||
| 81 | (defvar eieio-error-unsupported-class-tags nil | 86 | (defvar eieio-error-unsupported-class-tags nil |
| 82 | "*Non-nil to throw an error if an encountered tag us unsupported. | 87 | "Non-nil to throw an error if an encountered tag is unsupported. |
| 83 | This may prevent classes from CLOS applications from being used with EIEIO | 88 | This may prevent classes from CLOS applications from being used with EIEIO |
| 84 | since EIEIO does not support all CLOS tags.") | 89 | since EIEIO does not support all CLOS tags.") |
| 85 | 90 | ||
| @@ -170,6 +175,13 @@ Stored outright without modifications or stripping.") | |||
| 170 | (defconst method-generic-after 6 "Index into generic :after tag on a method.") | 175 | (defconst method-generic-after 6 "Index into generic :after tag on a method.") |
| 171 | (defconst method-num-slots 7 "Number of indexes into a method's vector.") | 176 | (defconst method-num-slots 7 "Number of indexes into a method's vector.") |
| 172 | 177 | ||
| 178 | (defsubst eieio-specialized-key-to-generic-key (key) | ||
| 179 | "Convert a specialized KEY into a generic method key." | ||
| 180 | (cond ((eq key method-static) 0) ;; don't convert | ||
| 181 | ((< key method-num-lists) (+ key 3)) ;; The conversion | ||
| 182 | (t key) ;; already generic.. maybe. | ||
| 183 | )) | ||
| 184 | |||
| 173 | ;; How to specialty compile stuff. | 185 | ;; How to specialty compile stuff. |
| 174 | (autoload 'byte-compile-file-form-defmethod "eieio-comp" | 186 | (autoload 'byte-compile-file-form-defmethod "eieio-comp" |
| 175 | "This function is used to byte compile methods in a nice way.") | 187 | "This function is used to byte compile methods in a nice way.") |
| @@ -243,8 +255,7 @@ Methods with only primary implementations are executed in an optimized way." | |||
| 243 | )) | 255 | )) |
| 244 | 256 | ||
| 245 | (defmacro class-option-assoc (list option) | 257 | (defmacro class-option-assoc (list option) |
| 246 | "Return from LIST the found OPTION. | 258 | "Return from LIST the found OPTION, or nil if it doesn't exist." |
| 247 | Return nil if it doesn't exist." | ||
| 248 | `(car-safe (cdr (memq ,option ,list)))) | 259 | `(car-safe (cdr (memq ,option ,list)))) |
| 249 | 260 | ||
| 250 | (defmacro class-option (class option) | 261 | (defmacro class-option (class option) |
| @@ -518,7 +529,7 @@ See `defclass' for more information." | |||
| 518 | 529 | ||
| 519 | ;; Make sure the method invocation order is a valid value. | 530 | ;; Make sure the method invocation order is a valid value. |
| 520 | (let ((io (class-option-assoc options :method-invocation-order))) | 531 | (let ((io (class-option-assoc options :method-invocation-order))) |
| 521 | (when (and io (not (member io '(:depth-first :breadth-first)))) | 532 | (when (and io (not (member io '(:depth-first :breadth-first :c3)))) |
| 522 | (error "Method invocation order %s is not allowed" io) | 533 | (error "Method invocation order %s is not allowed" io) |
| 523 | )) | 534 | )) |
| 524 | 535 | ||
| @@ -800,11 +811,11 @@ See `defclass' for more information." | |||
| 800 | (defun eieio-perform-slot-validation-for-default (slot spec value skipnil) | 811 | (defun eieio-perform-slot-validation-for-default (slot spec value skipnil) |
| 801 | "For SLOT, signal if SPEC does not match VALUE. | 812 | "For SLOT, signal if SPEC does not match VALUE. |
| 802 | If SKIPNIL is non-nil, then if VALUE is nil return t instead." | 813 | If SKIPNIL is non-nil, then if VALUE is nil return t instead." |
| 803 | (let ((val (eieio-default-eval-maybe value))) | 814 | (if (and (not (eieio-eval-default-p value)) |
| 804 | (if (and (not eieio-skip-typecheck) | 815 | (not eieio-skip-typecheck) |
| 805 | (not (and skipnil (null val))) | 816 | (not (and skipnil (null value))) |
| 806 | (not (eieio-perform-slot-validation spec val))) | 817 | (not (eieio-perform-slot-validation spec value))) |
| 807 | (signal 'invalid-slot-type (list slot spec val))))) | 818 | (signal 'invalid-slot-type (list slot spec value)))) |
| 808 | 819 | ||
| 809 | (defun eieio-add-new-slot (newc a d doc type cust label custg print prot init alloc | 820 | (defun eieio-add-new-slot (newc a d doc type cust label custg print prot init alloc |
| 810 | &optional defaultoverride skipnil) | 821 | &optional defaultoverride skipnil) |
| @@ -1340,7 +1351,7 @@ Summary: | |||
| 1340 | (if (= key -1) | 1351 | (if (= key -1) |
| 1341 | (signal 'wrong-type-argument (list :static 'non-class-arg))) | 1352 | (signal 'wrong-type-argument (list :static 'non-class-arg))) |
| 1342 | ;; generics are higher | 1353 | ;; generics are higher |
| 1343 | (setq key (+ key 3))) | 1354 | (setq key (eieio-specialized-key-to-generic-key key))) |
| 1344 | ;; Put this lambda into the symbol so we can find it | 1355 | ;; Put this lambda into the symbol so we can find it |
| 1345 | (if (byte-code-function-p (car-safe body)) | 1356 | (if (byte-code-function-p (car-safe body)) |
| 1346 | (eieiomt-add method (car-safe body) key argclass) | 1357 | (eieiomt-add method (car-safe body) key argclass) |
| @@ -1516,13 +1527,21 @@ Fills in OBJ's SLOT with its default value." | |||
| 1516 | (eieio-default-eval-maybe val)) | 1527 | (eieio-default-eval-maybe val)) |
| 1517 | obj cl 'oref-default)))) | 1528 | obj cl 'oref-default)))) |
| 1518 | 1529 | ||
| 1530 | (defsubst eieio-eval-default-p (val) | ||
| 1531 | "Whether the default value VAL should be evaluated for use." | ||
| 1532 | (and (consp val) (symbolp (car val)) (fboundp (car val)))) | ||
| 1533 | |||
| 1519 | (defun eieio-default-eval-maybe (val) | 1534 | (defun eieio-default-eval-maybe (val) |
| 1520 | "Check VAL, and return what `oref-default' would provide." | 1535 | "Check VAL, and return what `oref-default' would provide." |
| 1521 | ;; check for quoted things, and unquote them | 1536 | (cond |
| 1522 | (if (and (listp val) (eq (car val) 'quote)) | 1537 | ;; Is it a function call? If so, evaluate it. |
| 1523 | (car (cdr val)) | 1538 | ((eieio-eval-default-p val) |
| 1524 | ;; return it verbatim | 1539 | (eval val)) |
| 1525 | val)) | 1540 | ;;;; check for quoted things, and unquote them |
| 1541 | ;;((and (consp val) (eq (car val) 'quote)) | ||
| 1542 | ;; (car (cdr val))) | ||
| 1543 | ;; return it verbatim | ||
| 1544 | (t val))) | ||
| 1526 | 1545 | ||
| 1527 | ;;; Object Set macros | 1546 | ;;; Object Set macros |
| 1528 | ;; | 1547 | ;; |
| @@ -1678,6 +1697,116 @@ The CLOS function `class-direct-subclasses' is aliased to this function." | |||
| 1678 | (if (not (class-p class)) (signal 'wrong-type-argument (list 'class-p class))) | 1697 | (if (not (class-p class)) (signal 'wrong-type-argument (list 'class-p class))) |
| 1679 | (class-children-fast class)) | 1698 | (class-children-fast class)) |
| 1680 | 1699 | ||
| 1700 | (defun eieio-c3-candidate (class remaining-inputs) | ||
| 1701 | "Returns CLASS if it can go in the result now, otherwise nil" | ||
| 1702 | ;; Ensure CLASS is not in any position but the first in any of the | ||
| 1703 | ;; element lists of REMAINING-INPUTS. | ||
| 1704 | (and (not (let ((found nil)) | ||
| 1705 | (while (and remaining-inputs (not found)) | ||
| 1706 | (setq found (member class (cdr (car remaining-inputs))) | ||
| 1707 | remaining-inputs (cdr remaining-inputs))) | ||
| 1708 | found)) | ||
| 1709 | class)) | ||
| 1710 | |||
| 1711 | (defun eieio-c3-merge-lists (reversed-partial-result remaining-inputs) | ||
| 1712 | "Merge REVERSED-PARTIAL-RESULT REMAINING-INPUTS in a consistent order, if possible. | ||
| 1713 | If a consistent order does not exist, signal an error." | ||
| 1714 | (if (let ((tail remaining-inputs) | ||
| 1715 | (found nil)) | ||
| 1716 | (while (and tail (not found)) | ||
| 1717 | (setq found (car tail) tail (cdr tail))) | ||
| 1718 | (not found)) | ||
| 1719 | ;; If all remaining inputs are empty lists, we are done. | ||
| 1720 | (nreverse reversed-partial-result) | ||
| 1721 | ;; Otherwise, we try to find the next element of the result. This | ||
| 1722 | ;; is achieved by considering the first element of each | ||
| 1723 | ;; (non-empty) input list and accepting a candidate if it is | ||
| 1724 | ;; consistent with the rests of the input lists. | ||
| 1725 | (let* ((found nil) | ||
| 1726 | (tail remaining-inputs) | ||
| 1727 | (next (progn | ||
| 1728 | (while (and tail (not found)) | ||
| 1729 | (setq found (and (car tail) | ||
| 1730 | (eieio-c3-candidate (caar tail) | ||
| 1731 | remaining-inputs)) | ||
| 1732 | tail (cdr tail))) | ||
| 1733 | found))) | ||
| 1734 | (if next | ||
| 1735 | ;; The graph is consistent so far, add NEXT to result and | ||
| 1736 | ;; merge input lists, dropping NEXT from their heads where | ||
| 1737 | ;; applicable. | ||
| 1738 | (eieio-c3-merge-lists | ||
| 1739 | (cons next reversed-partial-result) | ||
| 1740 | (mapcar (lambda (l) (if (eq (first l) next) (rest l) l)) | ||
| 1741 | remaining-inputs)) | ||
| 1742 | ;; The graph is inconsistent, give up | ||
| 1743 | (signal 'inconsistent-class-hierarchy (list remaining-inputs)))))) | ||
| 1744 | |||
| 1745 | (defun eieio-class-precedence-dfs (class) | ||
| 1746 | "Return all parents of CLASS in depth-first order." | ||
| 1747 | (let* ((parents (class-parents-fast class)) | ||
| 1748 | (classes (copy-sequence | ||
| 1749 | (apply #'append | ||
| 1750 | (list class) | ||
| 1751 | (or | ||
| 1752 | (mapcar | ||
| 1753 | (lambda (parent) | ||
| 1754 | (cons parent | ||
| 1755 | (eieio-class-precedence-dfs parent))) | ||
| 1756 | parents) | ||
| 1757 | '((eieio-default-superclass)))))) | ||
| 1758 | (tail classes)) | ||
| 1759 | ;; Remove duplicates. | ||
| 1760 | (while tail | ||
| 1761 | (setcdr tail (delq (car tail) (cdr tail))) | ||
| 1762 | (setq tail (cdr tail))) | ||
| 1763 | classes)) | ||
| 1764 | |||
| 1765 | (defun eieio-class-precedence-bfs (class) | ||
| 1766 | "Return all parents of CLASS in breadth-first order." | ||
| 1767 | (let ((result) | ||
| 1768 | (queue (or (class-parents-fast class) | ||
| 1769 | '(eieio-default-superclass)))) | ||
| 1770 | (while queue | ||
| 1771 | (let ((head (pop queue))) | ||
| 1772 | (unless (member head result) | ||
| 1773 | (push head result) | ||
| 1774 | (unless (eq head 'eieio-default-superclass) | ||
| 1775 | (setq queue (append queue (or (class-parents-fast head) | ||
| 1776 | '(eieio-default-superclass)))))))) | ||
| 1777 | (cons class (nreverse result))) | ||
| 1778 | ) | ||
| 1779 | |||
| 1780 | (defun eieio-class-precedence-c3 (class) | ||
| 1781 | "Return all parents of CLASS in c3 order." | ||
| 1782 | (let ((parents (class-parents-fast class))) | ||
| 1783 | (eieio-c3-merge-lists | ||
| 1784 | (list class) | ||
| 1785 | (append | ||
| 1786 | (or | ||
| 1787 | (mapcar | ||
| 1788 | (lambda (x) | ||
| 1789 | (eieio-class-precedence-c3 x)) | ||
| 1790 | parents) | ||
| 1791 | '((eieio-default-superclass))) | ||
| 1792 | (list parents)))) | ||
| 1793 | ) | ||
| 1794 | |||
| 1795 | (defun class-precedence-list (class) | ||
| 1796 | "Return (transitively closed) list of parents of CLASS. | ||
| 1797 | The order, in which the parents are returned depends on the | ||
| 1798 | method invocation orders of the involved classes." | ||
| 1799 | (if (or (null class) (eq class 'eieio-default-superclass)) | ||
| 1800 | nil | ||
| 1801 | (case (class-method-invocation-order class) | ||
| 1802 | (:depth-first | ||
| 1803 | (eieio-class-precedence-dfs class)) | ||
| 1804 | (:breadth-first | ||
| 1805 | (eieio-class-precedence-bfs class)) | ||
| 1806 | (:c3 | ||
| 1807 | (eieio-class-precedence-c3 class)))) | ||
| 1808 | ) | ||
| 1809 | |||
| 1681 | ;; Official CLOS functions. | 1810 | ;; Official CLOS functions. |
| 1682 | (defalias 'class-direct-superclasses 'class-parents) | 1811 | (defalias 'class-direct-superclasses 'class-parents) |
| 1683 | (defalias 'class-direct-subclasses 'class-children) | 1812 | (defalias 'class-direct-subclasses 'class-children) |
| @@ -1715,7 +1844,8 @@ The CLOS function `class-direct-subclasses' is aliased to this function." | |||
| 1715 | p (cdr p))) | 1844 | p (cdr p))) |
| 1716 | (if child t))) | 1845 | (if child t))) |
| 1717 | 1846 | ||
| 1718 | (defun object-slots (obj) "Return list of slots available in OBJ." | 1847 | (defun object-slots (obj) |
| 1848 | "Return list of slots available in OBJ." | ||
| 1719 | (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj))) | 1849 | (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj))) |
| 1720 | (aref (class-v (object-class-fast obj)) class-public-a)) | 1850 | (aref (class-v (object-class-fast obj)) class-public-a)) |
| 1721 | 1851 | ||
| @@ -2009,14 +2139,26 @@ This should only be called from a generic function." | |||
| 2009 | keys (append (make-list (length tlambdas) method-before) keys)) | 2139 | keys (append (make-list (length tlambdas) method-before) keys)) |
| 2010 | ) | 2140 | ) |
| 2011 | 2141 | ||
| 2012 | ;; If there were no methods found, then there could be :static methods. | 2142 | (if mclass |
| 2013 | (when (not lambdas) | 2143 | ;; For the case of a class, |
| 2144 | ;; if there were no methods found, then there could be :static methods. | ||
| 2145 | (when (not lambdas) | ||
| 2146 | (setq tlambdas | ||
| 2147 | (eieio-generic-form method method-static mclass)) | ||
| 2148 | (setq lambdas (cons tlambdas lambdas) | ||
| 2149 | keys (cons method-static keys) | ||
| 2150 | primarymethodlist ;; Re-use even with bad name here | ||
| 2151 | (eieiomt-method-list method method-static mclass))) | ||
| 2152 | ;; For the case of no class (ie - mclass == nil) then there may | ||
| 2153 | ;; be a primary method. | ||
| 2014 | (setq tlambdas | 2154 | (setq tlambdas |
| 2015 | (eieio-generic-form method method-static mclass)) | 2155 | (eieio-generic-form method method-primary nil)) |
| 2016 | (setq lambdas (cons tlambdas lambdas) | 2156 | (when tlambdas |
| 2017 | keys (cons method-static keys) | 2157 | (setq lambdas (cons tlambdas lambdas) |
| 2018 | primarymethodlist ;; Re-use even with bad name here | 2158 | keys (cons method-primary keys) |
| 2019 | (eieiomt-method-list method method-static mclass))) | 2159 | primarymethodlist |
| 2160 | (eieiomt-method-list method method-primary nil))) | ||
| 2161 | ) | ||
| 2020 | 2162 | ||
| 2021 | (run-hook-with-args 'eieio-pre-method-execution-hooks | 2163 | (run-hook-with-args 'eieio-pre-method-execution-hooks |
| 2022 | primarymethodlist) | 2164 | primarymethodlist) |
| @@ -2143,37 +2285,23 @@ CLASS is the starting class to search from in the method tree. | |||
| 2143 | If CLASS is nil, then an empty list of methods should be returned." | 2285 | If CLASS is nil, then an empty list of methods should be returned." |
| 2144 | ;; Note: eieiomt - the MT means MethodTree. See more comments below | 2286 | ;; Note: eieiomt - the MT means MethodTree. See more comments below |
| 2145 | ;; for the rest of the eieiomt methods. | 2287 | ;; for the rest of the eieiomt methods. |
| 2146 | (let ((lambdas nil) | 2288 | |
| 2147 | (mclass (list class))) | 2289 | ;; Collect lambda expressions stored for the class and its parent |
| 2148 | (while mclass | 2290 | ;; classes. |
| 2149 | ;; Note: a nil can show up in the class list once we start | 2291 | (let (lambdas) |
| 2150 | ;; searching through the method tree. | 2292 | (dolist (ancestor (class-precedence-list class)) |
| 2151 | (when (car mclass) | 2293 | ;; Lookup the form to use for the PRIMARY object for the next level |
| 2152 | ;; lookup the form to use for the PRIMARY object for the next level | 2294 | (let ((tmpl (eieio-generic-form method key ancestor))) |
| 2153 | (let ((tmpl (eieio-generic-form method key (car mclass)))) | 2295 | (when (and tmpl |
| 2154 | (when (or (not lambdas) | 2296 | (or (not lambdas) |
| 2155 | ;; This prevents duplicates coming out of the | 2297 | ;; This prevents duplicates coming out of the |
| 2156 | ;; class method optimizer. Perhaps we should | 2298 | ;; class method optimizer. Perhaps we should |
| 2157 | ;; just not optimize before/afters? | 2299 | ;; just not optimize before/afters? |
| 2158 | (not (eq (car tmpl) (car (car lambdas))))) | 2300 | (not (member tmpl lambdas)))) |
| 2159 | (setq lambdas (cons tmpl lambdas)) | 2301 | (push tmpl lambdas)))) |
| 2160 | (if (null (car lambdas)) | 2302 | |
| 2161 | (setq lambdas (cdr lambdas)))))) | 2303 | ;; Return collected lambda. For :after methods, return in current |
| 2162 | ;; Add new classes to mclass. Since our input might not be a class | 2304 | ;; order (most general class last); Otherwise, reverse order. |
| 2163 | ;; protect against that. | ||
| 2164 | (if (car mclass) | ||
| 2165 | ;; If there is a class, append any methods it may provide | ||
| 2166 | ;; to the remainder of the class list. | ||
| 2167 | (let ((io (class-method-invocation-order (car mclass)))) | ||
| 2168 | (if (eq io :depth-first) | ||
| 2169 | ;; Depth first. | ||
| 2170 | (setq mclass (append (eieiomt-next (car mclass)) (cdr mclass))) | ||
| 2171 | ;; Breadth first. | ||
| 2172 | (setq mclass (append (cdr mclass) (eieiomt-next (car mclass))))) | ||
| 2173 | ) | ||
| 2174 | ;; Advance to next entry in mclass if it is nil. | ||
| 2175 | (setq mclass (cdr mclass))) | ||
| 2176 | ) | ||
| 2177 | (if (eq key method-after) | 2305 | (if (eq key method-after) |
| 2178 | lambdas | 2306 | lambdas |
| 2179 | (nreverse lambdas)))) | 2307 | (nreverse lambdas)))) |
| @@ -2207,6 +2335,7 @@ Use `next-method-p' to find out if there is a next method to call." | |||
| 2207 | (apply 'no-next-method (car newargs) (cdr newargs)) | 2335 | (apply 'no-next-method (car newargs) (cdr newargs)) |
| 2208 | (let* ((eieio-generic-call-next-method-list | 2336 | (let* ((eieio-generic-call-next-method-list |
| 2209 | (cdr eieio-generic-call-next-method-list)) | 2337 | (cdr eieio-generic-call-next-method-list)) |
| 2338 | (eieio-generic-call-arglst newargs) | ||
| 2210 | (scoped-class (cdr next)) | 2339 | (scoped-class (cdr next)) |
| 2211 | (fcn (car next)) | 2340 | (fcn (car next)) |
| 2212 | ) | 2341 | ) |
| @@ -2299,32 +2428,18 @@ nil for superclasses. This function performs no type checking!" | |||
| 2299 | 2428 | ||
| 2300 | (defun eieiomt-sym-optimize (s) | 2429 | (defun eieiomt-sym-optimize (s) |
| 2301 | "Find the next class above S which has a function body for the optimizer." | 2430 | "Find the next class above S which has a function body for the optimizer." |
| 2302 | ;; (message "Optimizing %S" s) | 2431 | ;; Set the value to nil in case there is no nearest cell. |
| 2303 | (let* ((es (intern-soft (symbol-name s))) ;external symbol of class | 2432 | (set s nil) |
| 2304 | (io (class-method-invocation-order es)) | 2433 | ;; Find the nearest cell that has a function body. If we find one, |
| 2305 | (ov nil) | 2434 | ;; we replace the nil from above. |
| 2306 | (cont t)) | 2435 | (let ((external-symbol (intern-soft (symbol-name s)))) |
| 2307 | ;; This converts ES from a single symbol to a list of parent classes. | 2436 | (catch 'done |
| 2308 | (setq es (eieiomt-next es)) | 2437 | (dolist (ancestor (rest (class-precedence-list external-symbol))) |
| 2309 | ;; Loop over ES, then its children individually. | 2438 | (let ((ov (intern-soft (symbol-name ancestor) |
| 2310 | ;; We can have multiple hits only at one level of the parent tree. | 2439 | eieiomt-optimizing-obarray))) |
| 2311 | (while (and es cont) | 2440 | (when (fboundp ov) |
| 2312 | (setq ov (intern-soft (symbol-name (car es)) eieiomt-optimizing-obarray)) | 2441 | (set s ov) ;; store ov as our next symbol |
| 2313 | (if (fboundp ov) | 2442 | (throw 'done ancestor))))))) |
| 2314 | (progn | ||
| 2315 | (set s ov) ;store ov as our next symbol | ||
| 2316 | (setq cont nil)) | ||
| 2317 | (if (eq io :depth-first) | ||
| 2318 | ;; Pre-pend the subclasses of (car es) so we get | ||
| 2319 | ;; DEPTH FIRST optimization. | ||
| 2320 | (setq es (append (eieiomt-next (car es)) (cdr es))) | ||
| 2321 | ;; Else, we are breadth first. | ||
| 2322 | ;; (message "Class %s is breadth first" es) | ||
| 2323 | (setq es (append (cdr es) (eieiomt-next (car es)))) | ||
| 2324 | ))) | ||
| 2325 | ;; If there is no nearest call, then set our value to nil | ||
| 2326 | (if (not es) (set s nil)) | ||
| 2327 | )) | ||
| 2328 | 2443 | ||
| 2329 | (defun eieio-generic-form (method key class) | 2444 | (defun eieio-generic-form (method key class) |
| 2330 | "Return the lambda form belonging to METHOD using KEY based upon CLASS. | 2445 | "Return the lambda form belonging to METHOD using KEY based upon CLASS. |
| @@ -2333,7 +2448,7 @@ no form, but has a parent class, then trace to that parent class. | |||
| 2333 | The first time a form is requested from a symbol, an optimized path | 2448 | The first time a form is requested from a symbol, an optimized path |
| 2334 | is memorized for faster future use." | 2449 | is memorized for faster future use." |
| 2335 | (let ((emto (aref (get method 'eieio-method-obarray) | 2450 | (let ((emto (aref (get method 'eieio-method-obarray) |
| 2336 | (if class key (+ key 3))))) | 2451 | (if class key (eieio-specialized-key-to-generic-key key))))) |
| 2337 | (if (class-p class) | 2452 | (if (class-p class) |
| 2338 | ;; 1) find our symbol | 2453 | ;; 1) find our symbol |
| 2339 | (let ((cs (intern-soft (symbol-name class) emto))) | 2454 | (let ((cs (intern-soft (symbol-name class) emto))) |
| @@ -2366,7 +2481,7 @@ is memorized for faster future use." | |||
| 2366 | nil))) | 2481 | nil))) |
| 2367 | ;; for a generic call, what is a list, is the function body we want. | 2482 | ;; for a generic call, what is a list, is the function body we want. |
| 2368 | (let ((emtl (aref (get method 'eieio-method-tree) | 2483 | (let ((emtl (aref (get method 'eieio-method-tree) |
| 2369 | (if class key (+ key 3))))) | 2484 | (if class key (eieio-specialized-key-to-generic-key key))))) |
| 2370 | (if emtl | 2485 | (if emtl |
| 2371 | ;; The car of EMTL is supposed to be a class, which in this | 2486 | ;; The car of EMTL is supposed to be a class, which in this |
| 2372 | ;; case is nil, so skip it. | 2487 | ;; case is nil, so skip it. |
| @@ -2431,6 +2546,11 @@ This is usually a symbol that starts with `:'." | |||
| 2431 | (put 'unbound-slot 'error-conditions '(unbound-slot error nil)) | 2546 | (put 'unbound-slot 'error-conditions '(unbound-slot error nil)) |
| 2432 | (put 'unbound-slot 'error-message "Unbound slot") | 2547 | (put 'unbound-slot 'error-message "Unbound slot") |
| 2433 | 2548 | ||
| 2549 | (intern "inconsistent-class-hierarchy") | ||
| 2550 | (put 'inconsistent-class-hierarchy 'error-conditions | ||
| 2551 | '(inconsistent-class-hierarchy error nil)) | ||
| 2552 | (put 'inconsistent-class-hierarchy 'error-message "Inconsistent class hierarchy") | ||
| 2553 | |||
| 2434 | ;;; Here are some CLOS items that need the CL package | 2554 | ;;; Here are some CLOS items that need the CL package |
| 2435 | ;; | 2555 | ;; |
| 2436 | 2556 | ||
| @@ -2526,6 +2646,17 @@ dynamically set from SLOTS." | |||
| 2526 | (slot (aref scoped-class class-public-a)) | 2646 | (slot (aref scoped-class class-public-a)) |
| 2527 | (defaults (aref scoped-class class-public-d))) | 2647 | (defaults (aref scoped-class class-public-d))) |
| 2528 | (while slot | 2648 | (while slot |
| 2649 | ;; For each slot, see if we need to evaluate it. | ||
| 2650 | ;; | ||
| 2651 | ;; Paul Landes said in an email: | ||
| 2652 | ;; > CL evaluates it if it can, and otherwise, leaves it as | ||
| 2653 | ;; > the quoted thing as you already have. This is by the | ||
| 2654 | ;; > Sonya E. Keene book and other things I've look at on the | ||
| 2655 | ;; > web. | ||
| 2656 | (let ((dflt (eieio-default-eval-maybe (car defaults)))) | ||
| 2657 | (when (not (eq dflt (car defaults))) | ||
| 2658 | (eieio-oset this (car slot) dflt) )) | ||
| 2659 | ;; Next. | ||
| 2529 | (setq slot (cdr slot) | 2660 | (setq slot (cdr slot) |
| 2530 | defaults (cdr defaults)))) | 2661 | defaults (cdr defaults)))) |
| 2531 | ;; Shared initialize will parse our slots for us. | 2662 | ;; Shared initialize will parse our slots for us. |