1 | ;;; clos.lisp |
---|
2 | ;;; |
---|
3 | ;;; Copyright (C) 2003 Peter Graves |
---|
4 | ;;; $Id: clos.lisp,v 1.7 2003-11-05 01:48:52 piso Exp $ |
---|
5 | ;;; |
---|
6 | ;;; This program is free software; you can redistribute it and/or |
---|
7 | ;;; modify it under the terms of the GNU General Public License |
---|
8 | ;;; as published by the Free Software Foundation; either version 2 |
---|
9 | ;;; of the License, or (at your option) any later version. |
---|
10 | ;;; |
---|
11 | ;;; This program is distributed in the hope that it will be useful, |
---|
12 | ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
13 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
14 | ;;; GNU General Public License for more details. |
---|
15 | ;;; |
---|
16 | ;;; You should have received a copy of the GNU General Public License |
---|
17 | ;;; along with this program; if not, write to the Free Software |
---|
18 | ;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
---|
19 | |
---|
20 | ;;; Adapted from Closette. |
---|
21 | |
---|
22 | ;;; Closette Version 1.0 (February 10, 1991) |
---|
23 | ;;; |
---|
24 | ;;; Copyright (c) 1990, 1991 Xerox Corporation. |
---|
25 | ;;; All rights reserved. |
---|
26 | ;;; |
---|
27 | ;;; Use and copying of this software and preparation of derivative works |
---|
28 | ;;; based upon this software are permitted. Any distribution of this |
---|
29 | ;;; software or derivative works must comply with all applicable United |
---|
30 | ;;; States export control laws. |
---|
31 | ;;; |
---|
32 | ;;; This software is made available AS IS, and Xerox Corporation makes no |
---|
33 | ;;; warranty about the software, its performance or its conformity to any |
---|
34 | ;;; specification. |
---|
35 | ;;; |
---|
36 | ;;; Closette is an implementation of a subset of CLOS with a metaobject |
---|
37 | ;;; protocol as described in "The Art of The Metaobject Protocol", |
---|
38 | ;;; MIT Press, 1991. |
---|
39 | |
---|
40 | (in-package "SYSTEM") |
---|
41 | |
---|
42 | (defmacro push-on-end (value location) |
---|
43 | `(setf ,location (nconc ,location (list ,value)))) |
---|
44 | |
---|
45 | ;;; (SETF GETF*) is like (SETF GETF) except that it always changes the list, |
---|
46 | ;;; which must be non-nil. |
---|
47 | |
---|
48 | (defun (setf getf*) (new-value plist key) |
---|
49 | (block body |
---|
50 | (do ((x plist (cddr x))) |
---|
51 | ((null x)) |
---|
52 | (when (eq (car x) key) |
---|
53 | (setf (car (cdr x)) new-value) |
---|
54 | (return-from body new-value))) |
---|
55 | (push-on-end key plist) |
---|
56 | (push-on-end new-value plist) |
---|
57 | new-value)) |
---|
58 | |
---|
59 | (defun mapappend (fun &rest args) |
---|
60 | (if (some #'null args) |
---|
61 | () |
---|
62 | (append (apply fun (mapcar #'car args)) |
---|
63 | (apply #'mapappend fun (mapcar #'cdr args))))) |
---|
64 | |
---|
65 | (defun mapplist (fun x) |
---|
66 | (if (null x) |
---|
67 | () |
---|
68 | (cons (funcall fun (car x) (cadr x)) |
---|
69 | (mapplist fun (cddr x))))) |
---|
70 | |
---|
71 | (defsetf class-name %set-class-name) |
---|
72 | (defsetf class-direct-superclasses %set-class-direct-superclasses) |
---|
73 | (defsetf class-direct-subclasses %set-class-direct-subclasses) |
---|
74 | (defsetf class-direct-methods %set-class-direct-methods) |
---|
75 | (defsetf class-direct-slots %set-class-direct-slots) |
---|
76 | (defsetf class-slots %set-class-slots) |
---|
77 | (defsetf class-direct-default-initargs %set-class-direct-default-initargs) |
---|
78 | (defsetf class-default-initargs %set-class-default-initargs) |
---|
79 | (defsetf class-precedence-list %set-class-precedence-list) |
---|
80 | (defsetf std-instance-class %set-std-instance-class) |
---|
81 | (defsetf std-instance-slots %set-std-instance-slots) |
---|
82 | |
---|
83 | (defun (setf find-class) (new-value symbol &optional errorp environment) |
---|
84 | (%set-find-class symbol new-value)) |
---|
85 | |
---|
86 | (defun canonicalize-direct-slots (direct-slots) |
---|
87 | `(list ,@(mapcar #'canonicalize-direct-slot direct-slots))) |
---|
88 | |
---|
89 | (defun canonicalize-direct-slot (spec) |
---|
90 | (if (symbolp spec) |
---|
91 | `(list :name ',spec) |
---|
92 | (let ((name (car spec)) |
---|
93 | (initfunction nil) |
---|
94 | (initform nil) |
---|
95 | (initargs ()) |
---|
96 | (readers ()) |
---|
97 | (writers ()) |
---|
98 | (other-options ())) |
---|
99 | (do ((olist (cdr spec) (cddr olist))) |
---|
100 | ((null olist)) |
---|
101 | (case (car olist) |
---|
102 | (:initform |
---|
103 | (setq initfunction |
---|
104 | `(function (lambda () ,(cadr olist)))) |
---|
105 | (setq initform `',(cadr olist))) |
---|
106 | (:initarg |
---|
107 | (push-on-end (cadr olist) initargs)) |
---|
108 | (:reader |
---|
109 | (push-on-end (cadr olist) readers)) |
---|
110 | (:writer |
---|
111 | (push-on-end (cadr olist) writers)) |
---|
112 | (:accessor |
---|
113 | (push-on-end (cadr olist) readers) |
---|
114 | (push-on-end `(setf ,(cadr olist)) writers)) |
---|
115 | (otherwise |
---|
116 | (push-on-end `',(car olist) other-options) |
---|
117 | (push-on-end `',(cadr olist) other-options)))) |
---|
118 | `(list |
---|
119 | :name ',name |
---|
120 | ,@(when initfunction |
---|
121 | `(:initform ,initform |
---|
122 | :initfunction ,initfunction)) |
---|
123 | ,@(when initargs `(:initargs ',initargs)) |
---|
124 | ,@(when readers `(:readers ',readers)) |
---|
125 | ,@(when writers `(:writers ',writers)) |
---|
126 | ,@other-options)))) |
---|
127 | |
---|
128 | (defun canonicalize-direct-superclasses (direct-superclasses) |
---|
129 | `(list ,@(mapcar #'canonicalize-direct-superclass direct-superclasses))) |
---|
130 | |
---|
131 | (defun canonicalize-direct-superclass (class-name) |
---|
132 | `(find-class ',class-name)) |
---|
133 | |
---|
134 | (defun canonicalize-defclass-options (options) |
---|
135 | (mapappend #'canonicalize-defclass-option options)) |
---|
136 | |
---|
137 | (defun canonicalize-defclass-option (option) |
---|
138 | (case (car option) |
---|
139 | (:metaclass |
---|
140 | (list ':metaclass |
---|
141 | `(find-class ',(cadr option)))) |
---|
142 | (:default-initargs |
---|
143 | (list |
---|
144 | ':direct-default-initargs |
---|
145 | `(list ,@(mapappend |
---|
146 | #'(lambda (x) x) |
---|
147 | (mapplist |
---|
148 | #'(lambda (key value) |
---|
149 | `(',key ,value)) |
---|
150 | (cdr option)))))) |
---|
151 | (t (list `',(car option) `',(cadr option))))) |
---|
152 | |
---|
153 | ;;; Slot definition metaobjects |
---|
154 | |
---|
155 | (defun make-direct-slot-definition (&rest properties |
---|
156 | &key name |
---|
157 | (initargs ()) |
---|
158 | (initform nil) |
---|
159 | (initfunction nil) |
---|
160 | (readers ()) |
---|
161 | (writers ()) |
---|
162 | (allocation :instance) |
---|
163 | &allow-other-keys) |
---|
164 | (let ((slot (copy-list properties))) ; Don't want to side effect &rest list |
---|
165 | (setf (getf* slot ':name) name) |
---|
166 | (setf (getf* slot ':initargs) initargs) |
---|
167 | (setf (getf* slot ':initform) initform) |
---|
168 | (setf (getf* slot ':initfunction) initfunction) |
---|
169 | (setf (getf* slot ':readers) readers) |
---|
170 | (setf (getf* slot ':writers) writers) |
---|
171 | (setf (getf* slot ':allocation) allocation) |
---|
172 | slot)) |
---|
173 | |
---|
174 | (defun make-effective-slot-definition (&rest properties |
---|
175 | &key name |
---|
176 | (initargs ()) |
---|
177 | (initform nil) |
---|
178 | (initfunction nil) |
---|
179 | (allocation :instance) |
---|
180 | &allow-other-keys) |
---|
181 | (let ((slot (copy-list properties))) ; Don't want to side effect &rest list |
---|
182 | (setf (getf* slot ':name) name) |
---|
183 | (setf (getf* slot ':initargs) initargs) |
---|
184 | (setf (getf* slot ':initform) initform) |
---|
185 | (setf (getf* slot ':initfunction) initfunction) |
---|
186 | (setf (getf* slot ':allocation) allocation) |
---|
187 | slot)) |
---|
188 | |
---|
189 | (defun slot-definition-name (slot) |
---|
190 | (getf slot ':name)) |
---|
191 | (defun (setf slot-definition-name) (new-value slot) |
---|
192 | (setf (getf* slot ':name) new-value)) |
---|
193 | |
---|
194 | (defun slot-definition-initfunction (slot) |
---|
195 | (getf slot ':initfunction)) |
---|
196 | (defun (setf slot-definition-initfunction) (new-value slot) |
---|
197 | (setf (getf* slot ':initfunction) new-value)) |
---|
198 | |
---|
199 | (defun slot-definition-initform (slot) |
---|
200 | (getf slot ':initform)) |
---|
201 | (defun (setf slot-definition-initform) (new-value slot) |
---|
202 | (setf (getf* slot ':initform) new-value)) |
---|
203 | |
---|
204 | (defun slot-definition-initargs (slot) |
---|
205 | (getf slot ':initargs)) |
---|
206 | (defun (setf slot-definition-initargs) (new-value slot) |
---|
207 | (setf (getf* slot ':initargs) new-value)) |
---|
208 | |
---|
209 | (defun slot-definition-readers (slot) |
---|
210 | (getf slot ':readers)) |
---|
211 | (defun (setf slot-definition-readers) (new-value slot) |
---|
212 | (setf (getf* slot ':readers) new-value)) |
---|
213 | |
---|
214 | (defun slot-definition-writers (slot) |
---|
215 | (getf slot ':writers)) |
---|
216 | (defun (setf slot-definition-writers) (new-value slot) |
---|
217 | (setf (getf* slot ':writers) new-value)) |
---|
218 | |
---|
219 | (defun slot-definition-allocation (slot) |
---|
220 | (getf slot ':allocation)) |
---|
221 | (defun (setf slot-definition-allocation) (new-value slot) |
---|
222 | (setf (getf* slot ':allocation) new-value)) |
---|
223 | |
---|
224 | ;;; finalize-inheritance |
---|
225 | |
---|
226 | (defun std-finalize-inheritance (class) |
---|
227 | (setf (class-precedence-list class) |
---|
228 | (funcall (if (eq (class-of class) the-class-standard-class) |
---|
229 | #'std-compute-class-precedence-list |
---|
230 | #'compute-class-precedence-list) |
---|
231 | class)) |
---|
232 | (setf (class-slots class) |
---|
233 | (funcall (if (eq (class-of class) the-class-standard-class) |
---|
234 | #'std-compute-slots |
---|
235 | #'compute-slots) |
---|
236 | class)) |
---|
237 | (setf (class-default-initargs class) |
---|
238 | (compute-class-default-initargs class)) |
---|
239 | (values)) |
---|
240 | |
---|
241 | (defun compute-class-default-initargs (class) |
---|
242 | (mapappend #'class-direct-default-initargs |
---|
243 | (class-precedence-list class))) |
---|
244 | |
---|
245 | ;;; Class precedence lists |
---|
246 | |
---|
247 | (defun std-compute-class-precedence-list (class) |
---|
248 | (let ((classes-to-order (collect-superclasses* class))) |
---|
249 | (topological-sort classes-to-order |
---|
250 | (remove-duplicates |
---|
251 | (mapappend #'local-precedence-ordering |
---|
252 | classes-to-order)) |
---|
253 | #'std-tie-breaker-rule))) |
---|
254 | |
---|
255 | ;;; topological-sort implements the standard algorithm for topologically |
---|
256 | ;;; sorting an arbitrary set of elements while honoring the precedence |
---|
257 | ;;; constraints given by a set of (X,Y) pairs that indicate that element |
---|
258 | ;;; X must precede element Y. The tie-breaker procedure is called when it |
---|
259 | ;;; is necessary to choose from multiple minimal elements; both a list of |
---|
260 | ;;; candidates and the ordering so far are provided as arguments. |
---|
261 | |
---|
262 | (defun topological-sort (elements constraints tie-breaker) |
---|
263 | (let ((remaining-constraints constraints) |
---|
264 | (remaining-elements elements) |
---|
265 | (result ())) |
---|
266 | (loop |
---|
267 | (let ((minimal-elements |
---|
268 | (remove-if |
---|
269 | #'(lambda (class) |
---|
270 | (member class remaining-constraints |
---|
271 | :key #'cadr)) |
---|
272 | remaining-elements))) |
---|
273 | (when (null minimal-elements) |
---|
274 | (if (null remaining-elements) |
---|
275 | (return-from topological-sort result) |
---|
276 | (error "Inconsistent precedence graph."))) |
---|
277 | (let ((choice (if (null (cdr minimal-elements)) |
---|
278 | (car minimal-elements) |
---|
279 | (funcall tie-breaker |
---|
280 | minimal-elements |
---|
281 | result)))) |
---|
282 | (setq result (append result (list choice))) |
---|
283 | (setq remaining-elements |
---|
284 | (remove choice remaining-elements)) |
---|
285 | (setq remaining-constraints |
---|
286 | (remove choice |
---|
287 | remaining-constraints |
---|
288 | :test #'member))))))) |
---|
289 | |
---|
290 | ;;; In the event of a tie while topologically sorting class precedence lists, |
---|
291 | ;;; the CLOS Specification says to "select the one that has a direct subclass |
---|
292 | ;;; rightmost in the class precedence list computed so far." The same result |
---|
293 | ;;; is obtained by inspecting the partially constructed class precedence list |
---|
294 | ;;; from right to left, looking for the first minimal element to show up among |
---|
295 | ;;; the direct superclasses of the class precedence list constituent. |
---|
296 | ;;; (There's a lemma that shows that this rule yields a unique result.) |
---|
297 | |
---|
298 | (defun std-tie-breaker-rule (minimal-elements cpl-so-far) |
---|
299 | (dolist (cpl-constituent (reverse cpl-so-far)) |
---|
300 | (let* ((supers (class-direct-superclasses cpl-constituent)) |
---|
301 | (common (intersection minimal-elements supers))) |
---|
302 | (when (not (null common)) |
---|
303 | (return-from std-tie-breaker-rule (car common)))))) |
---|
304 | |
---|
305 | ;;; This version of collect-superclasses* isn't bothered by cycles in the class |
---|
306 | ;;; hierarchy, which sometimes happen by accident. |
---|
307 | |
---|
308 | (defun collect-superclasses* (class) |
---|
309 | (labels ((all-superclasses-loop (seen superclasses) |
---|
310 | (let ((to-be-processed |
---|
311 | (set-difference superclasses seen))) |
---|
312 | (if (null to-be-processed) |
---|
313 | superclasses |
---|
314 | (let ((class-to-process |
---|
315 | (car to-be-processed))) |
---|
316 | (all-superclasses-loop |
---|
317 | (cons class-to-process seen) |
---|
318 | (union (class-direct-superclasses |
---|
319 | class-to-process) |
---|
320 | superclasses))))))) |
---|
321 | (all-superclasses-loop () (list class)))) |
---|
322 | |
---|
323 | ;;; The local precedence ordering of a class C with direct superclasses C_1, |
---|
324 | ;;; C_2, ..., C_n is the set ((C C_1) (C_1 C_2) ...(C_n-1 C_n)). |
---|
325 | |
---|
326 | (defun local-precedence-ordering (class) |
---|
327 | (mapcar #'list |
---|
328 | (cons class |
---|
329 | (butlast (class-direct-superclasses class))) |
---|
330 | (class-direct-superclasses class))) |
---|
331 | |
---|
332 | ;;; Slot inheritance |
---|
333 | |
---|
334 | (defun std-compute-slots (class) |
---|
335 | (let* ((all-slots (mapappend #'class-direct-slots |
---|
336 | (class-precedence-list class))) |
---|
337 | (all-names (remove-duplicates |
---|
338 | (mapcar #'slot-definition-name all-slots)))) |
---|
339 | (mapcar #'(lambda (name) |
---|
340 | (funcall |
---|
341 | (if (eq (class-of class) the-class-standard-class) |
---|
342 | #'std-compute-effective-slot-definition |
---|
343 | #'compute-effective-slot-definition) |
---|
344 | class |
---|
345 | (remove name all-slots |
---|
346 | :key #'slot-definition-name |
---|
347 | :test-not #'eq))) |
---|
348 | all-names))) |
---|
349 | |
---|
350 | (defun std-compute-effective-slot-definition (class direct-slots) |
---|
351 | (declare (ignore class)) |
---|
352 | (let ((initer (find-if-not #'null direct-slots |
---|
353 | :key #'slot-definition-initfunction))) |
---|
354 | (make-effective-slot-definition |
---|
355 | :name (slot-definition-name (car direct-slots)) |
---|
356 | :initform (if initer |
---|
357 | (slot-definition-initform initer) |
---|
358 | nil) |
---|
359 | :initfunction (if initer |
---|
360 | (slot-definition-initfunction initer) |
---|
361 | nil) |
---|
362 | :initargs (remove-duplicates |
---|
363 | (mapappend #'slot-definition-initargs |
---|
364 | direct-slots)) |
---|
365 | :allocation (slot-definition-allocation (car direct-slots))))) |
---|
366 | |
---|
367 | ;;; Simple vectors are used for slot storage. |
---|
368 | |
---|
369 | (defun allocate-slot-storage (size initial-value) |
---|
370 | (make-array size :initial-element initial-value)) |
---|
371 | |
---|
372 | ;;; Standard instance slot access |
---|
373 | |
---|
374 | ;;; N.B. The location of the effective-slots slots in the class metaobject for |
---|
375 | ;;; standard-class must be determined without making any further slot |
---|
376 | ;;; references. |
---|
377 | |
---|
378 | (defvar the-slots-of-standard-class) ;standard-class's class-slots |
---|
379 | (defvar the-class-standard-class (find-class 'standard-class)) |
---|
380 | |
---|
381 | (defun slot-location (class slot-name) |
---|
382 | (if (and (eq slot-name 'effective-slots) |
---|
383 | (eq class the-class-standard-class)) |
---|
384 | (position 'effective-slots the-slots-of-standard-class |
---|
385 | :key #'slot-definition-name) |
---|
386 | (let ((slot (find slot-name (class-slots class) |
---|
387 | :key #'slot-definition-name))) |
---|
388 | (if slot |
---|
389 | (position slot (remove-if-not #'instance-slot-p (class-slots class))) |
---|
390 | nil)))) |
---|
391 | |
---|
392 | (defun slot-contents (slots location) |
---|
393 | (svref slots location)) |
---|
394 | |
---|
395 | (defun (setf slot-contents) (new-value slots location) |
---|
396 | (setf (svref slots location) new-value)) |
---|
397 | |
---|
398 | (defun std-slot-value (instance slot-name) |
---|
399 | (let ((location (slot-location (class-of instance) slot-name))) |
---|
400 | (if location |
---|
401 | (let* ((slots (std-instance-slots instance)) |
---|
402 | (val (slot-contents slots location))) |
---|
403 | (if (eq secret-unbound-value val) |
---|
404 | (error "the slot ~S is unbound in the object ~S" slot-name instance) |
---|
405 | val)) |
---|
406 | (slot-missing (class-of instance) instance slot-name 'slot-value)))) |
---|
407 | |
---|
408 | (defun slot-value (object slot-name) |
---|
409 | (if (eq (class-of (class-of object)) the-class-standard-class) |
---|
410 | (std-slot-value object slot-name) |
---|
411 | (slot-value-using-class (class-of object) object slot-name))) |
---|
412 | |
---|
413 | (defun (setf std-slot-value) (new-value instance slot-name) |
---|
414 | (let ((location (slot-location (class-of instance) slot-name)) |
---|
415 | (slots (std-instance-slots instance))) |
---|
416 | (if location |
---|
417 | (setf (slot-contents slots location) new-value) |
---|
418 | (progn |
---|
419 | (slot-missing (class-of instance) instance slot-name 'setf new-value) |
---|
420 | new-value)))) |
---|
421 | (defun (setf slot-value) (new-value object slot-name) |
---|
422 | (if (eq (class-of (class-of object)) the-class-standard-class) |
---|
423 | (setf (std-slot-value object slot-name) new-value) |
---|
424 | (setf-slot-value-using-class |
---|
425 | new-value (class-of object) object slot-name))) |
---|
426 | |
---|
427 | (defun std-slot-boundp (instance slot-name) |
---|
428 | (let ((location (slot-location (class-of instance) slot-name)) |
---|
429 | (slots (std-instance-slots instance))) |
---|
430 | (if location |
---|
431 | (not (eq secret-unbound-value (slot-contents slots location))) |
---|
432 | (not (null (slot-missing (class-of instance) instance slot-name 'slot-boundp)))))) |
---|
433 | (defun slot-boundp (object slot-name) |
---|
434 | (if (eq (class-of (class-of object)) the-class-standard-class) |
---|
435 | (std-slot-boundp object slot-name) |
---|
436 | (slot-boundp-using-class (class-of object) object slot-name))) |
---|
437 | |
---|
438 | (defun std-slot-makunbound (instance slot-name) |
---|
439 | (let ((location (slot-location (class-of instance) slot-name)) |
---|
440 | (slots (std-instance-slots instance))) |
---|
441 | (if location |
---|
442 | (setf (slot-contents slots location) secret-unbound-value) |
---|
443 | (slot-missing (class-of instance) instance slot-name 'slot-makunbound)) |
---|
444 | instance)) |
---|
445 | (defun slot-makunbound (object slot-name) |
---|
446 | (if (eq (class-of (class-of object)) the-class-standard-class) |
---|
447 | (std-slot-makunbound object slot-name) |
---|
448 | (slot-makunbound-using-class (class-of object) object slot-name))) |
---|
449 | |
---|
450 | (defun std-slot-exists-p (instance slot-name) |
---|
451 | (not (null (find slot-name (class-slots (class-of instance)) |
---|
452 | :key #'slot-definition-name)))) |
---|
453 | (defun slot-exists-p (object slot-name) |
---|
454 | (if (eq (class-of (class-of object)) the-class-standard-class) |
---|
455 | (std-slot-exists-p object slot-name) |
---|
456 | (slot-exists-p-using-class (class-of object) object slot-name))) |
---|
457 | |
---|
458 | ;;; Standard instance allocation |
---|
459 | |
---|
460 | (defparameter secret-unbound-value (list "slot unbound")) |
---|
461 | |
---|
462 | (defun instance-slot-p (slot) |
---|
463 | (eq (slot-definition-allocation slot) ':instance)) |
---|
464 | |
---|
465 | (defun std-allocate-instance (class) |
---|
466 | (allocate-std-instance |
---|
467 | class |
---|
468 | (allocate-slot-storage (count-if #'instance-slot-p (class-slots class)) |
---|
469 | secret-unbound-value))) |
---|
470 | |
---|
471 | (defun allocate-instance (class) |
---|
472 | (std-allocate-instance class)) |
---|
473 | |
---|
474 | (defun make-instance-standard-class (metaclass |
---|
475 | &key name direct-superclasses direct-slots |
---|
476 | direct-default-initargs |
---|
477 | &allow-other-keys) |
---|
478 | (declare (ignore metaclass)) |
---|
479 | (let ((class (std-allocate-instance (find-class 'standard-class)))) |
---|
480 | (setf (class-name class) name) |
---|
481 | (setf (class-direct-subclasses class) ()) |
---|
482 | (setf (class-direct-methods class) ()) |
---|
483 | (std-after-initialization-for-classes class |
---|
484 | :direct-superclasses direct-superclasses |
---|
485 | :direct-slots direct-slots |
---|
486 | :direct-default-initargs direct-default-initargs) |
---|
487 | class)) |
---|
488 | |
---|
489 | (defun std-after-initialization-for-classes (class |
---|
490 | &key direct-superclasses direct-slots |
---|
491 | direct-default-initargs |
---|
492 | &allow-other-keys) |
---|
493 | (let ((supers (or direct-superclasses |
---|
494 | (list (find-class 'standard-object))))) |
---|
495 | (setf (class-direct-superclasses class) supers) |
---|
496 | (dolist (superclass supers) |
---|
497 | (push class (class-direct-subclasses superclass)))) |
---|
498 | (let ((slots (mapcar #'(lambda (slot-properties) |
---|
499 | (apply #'make-direct-slot-definition slot-properties)) |
---|
500 | direct-slots))) |
---|
501 | (setf (class-direct-slots class) slots) |
---|
502 | (dolist (direct-slot slots) |
---|
503 | (dolist (reader (slot-definition-readers direct-slot)) |
---|
504 | (add-reader-method |
---|
505 | class reader (slot-definition-name direct-slot))) |
---|
506 | (dolist (writer (slot-definition-writers direct-slot)) |
---|
507 | (add-writer-method |
---|
508 | class writer (slot-definition-name direct-slot))))) |
---|
509 | (setf (class-direct-default-initargs class) direct-default-initargs) |
---|
510 | (funcall (if (eq (class-of class) (find-class 'standard-class)) |
---|
511 | #'std-finalize-inheritance |
---|
512 | #'finalize-inheritance) |
---|
513 | class) |
---|
514 | (values)) |
---|
515 | |
---|
516 | (defun canonical-slot-name (canonical-slot) |
---|
517 | (getf canonical-slot :name)) |
---|
518 | |
---|
519 | (defun ensure-class (name &rest all-keys &allow-other-keys) |
---|
520 | ;; Check for duplicate slots. |
---|
521 | (let ((slots (getf all-keys :direct-slots))) |
---|
522 | (dolist (s1 slots) |
---|
523 | (let ((name1 (canonical-slot-name s1))) |
---|
524 | (dolist (s2 (cdr (memq s1 slots))) |
---|
525 | (when (eq name1 (canonical-slot-name s2)) |
---|
526 | (error 'program-error "duplicate slot ~S" name1)))))) |
---|
527 | (let ((class (find-class name nil))) |
---|
528 | (unless class |
---|
529 | (setf class (apply #'make-instance-standard-class (find-class 'standard-class) |
---|
530 | :name name all-keys)) |
---|
531 | (%set-find-class name class)) |
---|
532 | class)) |
---|
533 | |
---|
534 | (defmacro defclass (name direct-superclasses direct-slots |
---|
535 | &rest options) |
---|
536 | `(ensure-class ',name |
---|
537 | :direct-superclasses |
---|
538 | ,(canonicalize-direct-superclasses direct-superclasses) |
---|
539 | :direct-slots |
---|
540 | ,(canonicalize-direct-slots direct-slots) |
---|
541 | ,@(canonicalize-defclass-options options))) |
---|
542 | |
---|
543 | ;;; Generic function metaobjects and standard-generic-function |
---|
544 | |
---|
545 | (defun method-combination-type (method-combination) |
---|
546 | (if (atom method-combination) |
---|
547 | method-combination |
---|
548 | (car method-combination))) |
---|
549 | |
---|
550 | (defun method-combination-options (method-combination) |
---|
551 | (if (atom method-combination) |
---|
552 | nil |
---|
553 | (cdr method-combination))) |
---|
554 | |
---|
555 | (defclass standard-generic-function (generic-function) |
---|
556 | ((name :initarg :name) ; :accessor generic-function-name |
---|
557 | (lambda-list ; :accessor generic-function-lambda-list |
---|
558 | :initarg :lambda-list) |
---|
559 | (methods :initform ()) ; :accessor generic-function-methods |
---|
560 | (method-class ; :accessor generic-function-method-class |
---|
561 | :initarg :method-class) |
---|
562 | (method-combination |
---|
563 | :initarg :method-combination) |
---|
564 | (classes-to-emf-table ; :accessor classes-to-emf-table |
---|
565 | :initform (make-hash-table :test #'equal)))) |
---|
566 | |
---|
567 | (defvar the-class-standard-gf (find-class 'standard-generic-function)) |
---|
568 | |
---|
569 | (defun generic-function-name (gf) |
---|
570 | (slot-value gf 'name)) |
---|
571 | (defun (setf generic-function-name) (new-value gf) |
---|
572 | (setf (slot-value gf 'name) new-value)) |
---|
573 | |
---|
574 | (defun generic-function-lambda-list (gf) |
---|
575 | (slot-value gf 'lambda-list)) |
---|
576 | (defun (setf generic-function-lambda-list) (new-value gf) |
---|
577 | (setf (slot-value gf 'lambda-list) new-value)) |
---|
578 | |
---|
579 | (defun generic-function-methods (gf) |
---|
580 | (slot-value gf 'methods)) |
---|
581 | (defun (setf generic-function-methods) (new-value gf) |
---|
582 | (setf (slot-value gf 'methods) new-value)) |
---|
583 | |
---|
584 | (defsetf generic-function-discriminating-function |
---|
585 | %set-generic-function-discriminating-function) |
---|
586 | |
---|
587 | (defun generic-function-method-class (gf) |
---|
588 | (slot-value gf 'method-class)) |
---|
589 | (defun (setf generic-function-method-class) (new-value gf) |
---|
590 | (setf (slot-value gf 'method-class) new-value)) |
---|
591 | |
---|
592 | (defun generic-function-method-combination (gf) |
---|
593 | (slot-value gf 'method-combination)) |
---|
594 | (defun (setf generic-function-method-combination) (new-value gf) |
---|
595 | (setf (slot-value gf 'method-combination) new-value)) |
---|
596 | |
---|
597 | ;;; Internal accessor for effective method function table |
---|
598 | |
---|
599 | (defun classes-to-emf-table (gf) |
---|
600 | (slot-value gf 'classes-to-emf-table)) |
---|
601 | (defun (setf classes-to-emf-table) (new-value gf) |
---|
602 | (setf (slot-value gf 'classes-to-emf-table) new-value)) |
---|
603 | |
---|
604 | ;;; Method metaobjects and standard-method |
---|
605 | |
---|
606 | (defclass standard-method (method) |
---|
607 | ((lambda-list :initarg :lambda-list) ; :accessor method-lambda-list |
---|
608 | (qualifiers :initarg :qualifiers) ; :accessor method-qualifiers |
---|
609 | (specializers :initarg :specializers) ; :accessor method-specializers |
---|
610 | (body :initarg :body) ; :accessor method-body |
---|
611 | (environment :initarg :environment) ; :accessor method-environment |
---|
612 | (generic-function :initform nil) ; :accessor method-generic-function |
---|
613 | (function))) ; :accessor method-function |
---|
614 | |
---|
615 | (defvar the-class-standard-method (find-class 'standard-method)) |
---|
616 | |
---|
617 | (defun method-lambda-list (method) (slot-value method 'lambda-list)) |
---|
618 | (defun (setf method-lambda-list) (new-value method) |
---|
619 | (setf (slot-value method 'lambda-list) new-value)) |
---|
620 | |
---|
621 | (defun method-qualifiers (method) (slot-value method 'qualifiers)) |
---|
622 | (defun (setf method-qualifiers) (new-value method) |
---|
623 | (setf (slot-value method 'qualifiers) new-value)) |
---|
624 | |
---|
625 | (defun method-specializers (method) (slot-value method 'specializers)) |
---|
626 | (defun (setf method-specializers) (new-value method) |
---|
627 | (setf (slot-value method 'specializers) new-value)) |
---|
628 | |
---|
629 | (defun method-body (method) (slot-value method 'body)) |
---|
630 | (defun (setf method-body) (new-value method) |
---|
631 | (setf (slot-value method 'body) new-value)) |
---|
632 | |
---|
633 | (defun method-environment (method) (slot-value method 'environment)) |
---|
634 | (defun (setf method-environment) (new-value method) |
---|
635 | (setf (slot-value method 'environment) new-value)) |
---|
636 | |
---|
637 | (defun method-generic-function (method) |
---|
638 | (slot-value method 'generic-function)) |
---|
639 | (defun (setf method-generic-function) (new-value method) |
---|
640 | (setf (slot-value method 'generic-function) new-value)) |
---|
641 | |
---|
642 | (defun method-function (method) (slot-value method 'function)) |
---|
643 | (defun (setf method-function) (new-value method) |
---|
644 | (setf (slot-value method 'function) new-value)) |
---|
645 | |
---|
646 | ;;; defgeneric |
---|
647 | |
---|
648 | (defmacro defgeneric (function-name lambda-list |
---|
649 | &rest options-and-method-descriptions) |
---|
650 | (let ((options ()) |
---|
651 | (methods ())) |
---|
652 | (dolist (item options-and-method-descriptions) |
---|
653 | (case (car item) |
---|
654 | (declare) ; FIXME |
---|
655 | (:documentation) ; FIXME |
---|
656 | (:method |
---|
657 | (push `(defmethod ,function-name ,@(cdr item)) methods)) |
---|
658 | (t |
---|
659 | (push item options)))) |
---|
660 | (setf options (nreverse options) |
---|
661 | methods (nreverse methods)) |
---|
662 | `(prog1 |
---|
663 | (ensure-generic-function |
---|
664 | ',function-name |
---|
665 | :lambda-list ',lambda-list |
---|
666 | ,@(canonicalize-defgeneric-options options)) |
---|
667 | ,@methods))) |
---|
668 | |
---|
669 | (defun canonicalize-defgeneric-options (options) |
---|
670 | (mapappend #'canonicalize-defgeneric-option options)) |
---|
671 | |
---|
672 | (defun canonicalize-defgeneric-option (option) |
---|
673 | (case (car option) |
---|
674 | (:generic-function-class |
---|
675 | (list ':generic-function-class `(find-class ',(cadr option)))) |
---|
676 | (:method-class |
---|
677 | (list ':method-class `(find-class ',(cadr option)))) |
---|
678 | (:method-combination |
---|
679 | (list `',(car option) `',(cdr option))) |
---|
680 | (t |
---|
681 | (list `',(car option) `',(cadr option))))) |
---|
682 | |
---|
683 | (defparameter generic-function-table (make-hash-table :test #'equal)) |
---|
684 | |
---|
685 | (defun find-generic-function (symbol &optional (errorp t)) |
---|
686 | (let ((gf (gethash symbol generic-function-table nil))) |
---|
687 | (if (and (null gf) errorp) |
---|
688 | (error "no generic function named ~S" symbol) |
---|
689 | gf))) |
---|
690 | |
---|
691 | (defun (setf find-generic-function) (new-value symbol) |
---|
692 | (setf (gethash symbol generic-function-table) new-value)) |
---|
693 | |
---|
694 | ;;; ensure-generic-function |
---|
695 | |
---|
696 | (defun ensure-generic-function (function-name |
---|
697 | &rest all-keys |
---|
698 | &key |
---|
699 | (generic-function-class the-class-standard-gf) |
---|
700 | (method-class the-class-standard-method) |
---|
701 | (method-combination 'standard) |
---|
702 | &allow-other-keys) |
---|
703 | (when (autoloadp function-name) |
---|
704 | (resolve function-name)) |
---|
705 | (if (find-generic-function function-name nil) |
---|
706 | (find-generic-function function-name) |
---|
707 | (progn |
---|
708 | (when (fboundp function-name) |
---|
709 | (error 'program-error |
---|
710 | "~A already names an ordinary function, macro, or special operator" |
---|
711 | function-name)) |
---|
712 | (let ((gf (apply (if (eq generic-function-class the-class-standard-gf) |
---|
713 | #'make-instance-standard-generic-function |
---|
714 | #'make-instance) |
---|
715 | generic-function-class |
---|
716 | :name function-name |
---|
717 | :method-class method-class |
---|
718 | :method-combination method-combination |
---|
719 | all-keys))) |
---|
720 | (setf (find-generic-function function-name) gf) |
---|
721 | gf)))) |
---|
722 | |
---|
723 | ;;; finalize-generic-function |
---|
724 | |
---|
725 | (defun finalize-generic-function (gf) |
---|
726 | (setf (generic-function-discriminating-function gf) |
---|
727 | (funcall (if (eq (class-of gf) the-class-standard-gf) |
---|
728 | #'std-compute-discriminating-function |
---|
729 | #'compute-discriminating-function) |
---|
730 | gf)) |
---|
731 | (setf (fdefinition (generic-function-name gf)) gf) |
---|
732 | (clrhash (classes-to-emf-table gf)) |
---|
733 | (values)) |
---|
734 | |
---|
735 | (defun make-instance-standard-generic-function (generic-function-class |
---|
736 | &key name lambda-list |
---|
737 | method-class |
---|
738 | method-combination) |
---|
739 | (declare (ignore generic-function-class)) |
---|
740 | (let ((gf (std-allocate-instance the-class-standard-gf))) |
---|
741 | (setf (generic-function-name gf) name) |
---|
742 | (setf (generic-function-lambda-list gf) lambda-list) |
---|
743 | (setf (generic-function-methods gf) ()) |
---|
744 | (setf (generic-function-method-class gf) method-class) |
---|
745 | (setf (generic-function-method-combination gf) method-combination) |
---|
746 | (setf (classes-to-emf-table gf) (make-hash-table :test #'equal)) |
---|
747 | (finalize-generic-function gf) |
---|
748 | gf)) |
---|
749 | |
---|
750 | ;;; Run-time environment hacking (Common Lisp ain't got 'em). |
---|
751 | |
---|
752 | (defun top-level-environment () |
---|
753 | nil) ; Bogus top level lexical environment |
---|
754 | |
---|
755 | (defvar compile-methods nil) ; by default, run everything interpreted |
---|
756 | |
---|
757 | (defun compile-in-lexical-environment (env lambda-expr) |
---|
758 | (declare (ignore env)) |
---|
759 | (if compile-methods |
---|
760 | (compile nil lambda-expr) |
---|
761 | (eval `(function ,lambda-expr)))) |
---|
762 | |
---|
763 | ;;; defmethod |
---|
764 | |
---|
765 | (defmacro defmethod (&rest args) |
---|
766 | (multiple-value-bind (function-name qualifiers lambda-list specializers body) |
---|
767 | (parse-defmethod args) |
---|
768 | `(progn |
---|
769 | (ensure-generic-function |
---|
770 | ',function-name |
---|
771 | :lambda-list ',lambda-list) |
---|
772 | (ensure-method (find-generic-function ',function-name) |
---|
773 | :lambda-list ',lambda-list |
---|
774 | :qualifiers ',qualifiers |
---|
775 | :specializers ,(canonicalize-specializers specializers) |
---|
776 | :body ',body |
---|
777 | :environment (top-level-environment))))) |
---|
778 | |
---|
779 | (defun canonicalize-specializers (specializers) |
---|
780 | `(list ,@(mapcar #'canonicalize-specializer specializers))) |
---|
781 | |
---|
782 | (defun canonicalize-specializer (specializer) |
---|
783 | ;; FIXME (EQL specializers) |
---|
784 | `(if (atom ',specializer) (find-class ',specializer) (find-class 't))) |
---|
785 | |
---|
786 | (defun parse-defmethod (args) |
---|
787 | (let ((fn-spec (car args)) |
---|
788 | (qualifiers ()) |
---|
789 | (specialized-lambda-list nil) |
---|
790 | (body ()) |
---|
791 | (parse-state :qualifiers)) |
---|
792 | (dolist (arg (cdr args)) |
---|
793 | (ecase parse-state |
---|
794 | (:qualifiers |
---|
795 | (if (and (atom arg) (not (null arg))) |
---|
796 | (push-on-end arg qualifiers) |
---|
797 | (progn (setq specialized-lambda-list arg) |
---|
798 | (setq parse-state :body)))) |
---|
799 | (:body (push-on-end arg body)))) |
---|
800 | (values fn-spec |
---|
801 | qualifiers |
---|
802 | (extract-lambda-list specialized-lambda-list) |
---|
803 | (extract-specializers specialized-lambda-list) |
---|
804 | (list* 'block |
---|
805 | (if (consp fn-spec) |
---|
806 | (cadr fn-spec) |
---|
807 | fn-spec) |
---|
808 | body)))) |
---|
809 | |
---|
810 | ;;; Several tedious functions for analyzing lambda lists |
---|
811 | |
---|
812 | (defun required-portion (gf args) |
---|
813 | (let ((number-required (length (gf-required-arglist gf)))) |
---|
814 | (when (< (length args) number-required) |
---|
815 | (error 'program-error "not enough arguments for generic function ~S" gf)) |
---|
816 | (subseq args 0 number-required))) |
---|
817 | |
---|
818 | (defun gf-required-arglist (gf) |
---|
819 | (let ((plist (analyze-lambda-list (generic-function-lambda-list gf)))) |
---|
820 | (getf plist ':required-args))) |
---|
821 | |
---|
822 | (defun extract-lambda-list (specialized-lambda-list) |
---|
823 | (let* ((plist (analyze-lambda-list specialized-lambda-list)) |
---|
824 | (requireds (getf plist :required-names)) |
---|
825 | (rv (getf plist :rest-var)) |
---|
826 | (ks (getf plist :key-args)) |
---|
827 | (keysp (getf plist :keysp)) |
---|
828 | (aok (getf plist :allow-other-keys)) |
---|
829 | (opts (getf plist :optional-args)) |
---|
830 | (auxs (getf plist :auxiliary-args))) |
---|
831 | `(,@requireds |
---|
832 | ,@(if rv `(&rest ,rv) ()) |
---|
833 | ,@(if (or ks keysp aok) `(&key ,@ks) ()) |
---|
834 | ,@(if aok '(&allow-other-keys) ()) |
---|
835 | ,@(if opts `(&optional ,@opts) ()) |
---|
836 | ,@(if auxs `(&aux ,@auxs) ())))) |
---|
837 | |
---|
838 | (defun extract-specializers (specialized-lambda-list) |
---|
839 | (let ((plist (analyze-lambda-list specialized-lambda-list))) |
---|
840 | (getf plist ':specializers))) |
---|
841 | |
---|
842 | (defun analyze-lambda-list (lambda-list) |
---|
843 | (labels ((make-keyword (symbol) |
---|
844 | (intern (symbol-name symbol) |
---|
845 | (find-package 'keyword))) |
---|
846 | (get-keyword-from-arg (arg) |
---|
847 | (if (listp arg) |
---|
848 | (if (listp (car arg)) |
---|
849 | (caar arg) |
---|
850 | (make-keyword (car arg))) |
---|
851 | (make-keyword arg)))) |
---|
852 | (let ((keys ()) ; Just the keywords |
---|
853 | (key-args ()) ; Keywords argument specs |
---|
854 | (keysp nil) ; |
---|
855 | (required-names ()) ; Just the variable names |
---|
856 | (required-args ()) ; Variable names & specializers |
---|
857 | (specializers ()) ; Just the specializers |
---|
858 | (rest-var nil) |
---|
859 | (optionals ()) |
---|
860 | (auxs ()) |
---|
861 | (allow-other-keys nil) |
---|
862 | (state :parsing-required)) |
---|
863 | (dolist (arg lambda-list) |
---|
864 | (if (member arg lambda-list-keywords) |
---|
865 | (ecase arg |
---|
866 | (&optional |
---|
867 | (setq state :parsing-optional)) |
---|
868 | (&rest |
---|
869 | (setq state :parsing-rest)) |
---|
870 | (&key |
---|
871 | (setq keysp t) |
---|
872 | (setq state :parsing-key)) |
---|
873 | (&allow-other-keys |
---|
874 | (setq allow-other-keys 't)) |
---|
875 | (&aux |
---|
876 | (setq state :parsing-aux))) |
---|
877 | (case state |
---|
878 | (:parsing-required |
---|
879 | (push-on-end arg required-args) |
---|
880 | (if (listp arg) |
---|
881 | (progn (push-on-end (car arg) required-names) |
---|
882 | (push-on-end (cadr arg) specializers)) |
---|
883 | (progn (push-on-end arg required-names) |
---|
884 | (push-on-end 't specializers)))) |
---|
885 | (:parsing-optional (push-on-end arg optionals)) |
---|
886 | (:parsing-rest (setq rest-var arg)) |
---|
887 | (:parsing-key |
---|
888 | (push-on-end (get-keyword-from-arg arg) keys) |
---|
889 | (push-on-end arg key-args)) |
---|
890 | (:parsing-aux (push-on-end arg auxs))))) |
---|
891 | (list :required-names required-names |
---|
892 | :required-args required-args |
---|
893 | :specializers specializers |
---|
894 | :rest-var rest-var |
---|
895 | :keywords keys |
---|
896 | :key-args key-args |
---|
897 | :keysp keysp |
---|
898 | :auxiliary-args auxs |
---|
899 | :optional-args optionals |
---|
900 | :allow-other-keys allow-other-keys)))) |
---|
901 | |
---|
902 | ;;; ensure method |
---|
903 | |
---|
904 | #+nil |
---|
905 | (defun check-method-arg-info (gf arg-info method) |
---|
906 | (multiple-value-bind (nreq nopt keysp restp allow-other-keys-p keywords) |
---|
907 | (analyze-lambda-list (if (consp method) |
---|
908 | (early-method-lambda-list method) |
---|
909 | (method-lambda-list method))) |
---|
910 | (flet ((lose (string &rest args) |
---|
911 | (error 'simple-program-error |
---|
912 | :format-control "~@<attempt to add the method~2I~_~S~I~_~ |
---|
913 | to the generic function~2I~_~S;~I~_~ |
---|
914 | but ~?~:>" |
---|
915 | :format-arguments (list method gf string args))) |
---|
916 | (comparison-description (x y) |
---|
917 | (if (> x y) "more" "fewer"))) |
---|
918 | (let ((gf-nreq (arg-info-number-required arg-info)) |
---|
919 | (gf-nopt (arg-info-number-optional arg-info)) |
---|
920 | (gf-key/rest-p (arg-info-key/rest-p arg-info)) |
---|
921 | (gf-keywords (arg-info-keys arg-info))) |
---|
922 | (unless (= nreq gf-nreq) |
---|
923 | (lose |
---|
924 | "the method has ~A required arguments than the generic function." |
---|
925 | (comparison-description nreq gf-nreq))) |
---|
926 | (unless (= nopt gf-nopt) |
---|
927 | (lose |
---|
928 | "the method has ~A optional arguments than the generic function." |
---|
929 | (comparison-description nopt gf-nopt))) |
---|
930 | (unless (eq (or keysp restp) gf-key/rest-p) |
---|
931 | (lose |
---|
932 | "the method and generic function differ in whether they accept~_~ |
---|
933 | &REST or &KEY arguments.")) |
---|
934 | (when (consp gf-keywords) |
---|
935 | (unless (or (and restp (not keysp)) |
---|
936 | allow-other-keys-p |
---|
937 | (every (lambda (k) (memq k keywords)) gf-keywords)) |
---|
938 | (lose "the method does not accept each of the &KEY arguments~2I~_~ |
---|
939 | ~S." |
---|
940 | gf-keywords))))))) |
---|
941 | |
---|
942 | (defun ensure-method (gf &rest all-keys) |
---|
943 | (let* ((gf-lambda-list (generic-function-lambda-list gf)) |
---|
944 | (gf-restp (not (null (memq '&rest gf-lambda-list)))) |
---|
945 | (gf-plist (analyze-lambda-list gf-lambda-list)) |
---|
946 | (gf-keysp (getf gf-plist :keysp)) |
---|
947 | (gf-keywords (getf gf-plist :keywords)) |
---|
948 | (method-lambda-list (getf all-keys :lambda-list)) |
---|
949 | (method-plist (analyze-lambda-list method-lambda-list)) |
---|
950 | (method-restp (not (null (memq '&rest method-lambda-list)))) |
---|
951 | (method-keysp (getf method-plist :keysp)) |
---|
952 | (method-keywords (getf method-plist :keywords)) |
---|
953 | (method-allow-other-keys-p (getf method-plist :allow-other-keys))) |
---|
954 | (unless (= (length (getf gf-plist :required-args)) |
---|
955 | (length (getf method-plist :required-args))) |
---|
956 | (error "the method has the wrong number of required arguments for the generic function")) |
---|
957 | (unless (= (length (getf gf-plist :optional-args)) |
---|
958 | (length (getf method-plist :optional-args))) |
---|
959 | (error "the method has the wrong number of optional arguments for the generic function")) |
---|
960 | (unless (eq (or gf-restp gf-keysp) (or method-restp method-keysp)) |
---|
961 | (error "the method and the generic function differ in whether they accept &REST or &KEY arguments")) |
---|
962 | (when (consp gf-keywords) |
---|
963 | (unless (or (and method-restp (not method-keysp)) |
---|
964 | method-allow-other-keys-p |
---|
965 | (every (lambda (k) (memq k method-keywords)) gf-keywords)) |
---|
966 | (error "the method does not accept all of the keyword arguments defined for the generic function")))) |
---|
967 | (let ((new-method |
---|
968 | (apply |
---|
969 | (if (eq (generic-function-method-class gf) the-class-standard-method) |
---|
970 | #'make-instance-standard-method |
---|
971 | #'make-instance) |
---|
972 | (generic-function-method-class gf) |
---|
973 | all-keys))) |
---|
974 | (add-method gf new-method) |
---|
975 | new-method)) |
---|
976 | |
---|
977 | (defun make-instance-standard-method (method-class |
---|
978 | &key lambda-list qualifiers |
---|
979 | specializers body environment) |
---|
980 | (declare (ignore method-class)) |
---|
981 | (let ((method (std-allocate-instance the-class-standard-method))) |
---|
982 | (setf (method-lambda-list method) lambda-list) |
---|
983 | (setf (method-qualifiers method) qualifiers) |
---|
984 | (setf (method-specializers method) specializers) |
---|
985 | (setf (method-body method) body) |
---|
986 | (setf (method-environment method) environment) |
---|
987 | (setf (method-generic-function method) nil) |
---|
988 | (setf (method-function method) |
---|
989 | (std-compute-method-function method)) |
---|
990 | method)) |
---|
991 | |
---|
992 | (defun check-congruent (gf method) |
---|
993 | (let* ((plist1 (analyze-lambda-list (generic-function-lambda-list gf))) |
---|
994 | (args1 (getf plist1 :required-args)) |
---|
995 | (plist2 (analyze-lambda-list (method-lambda-list method))) |
---|
996 | (args2 (getf plist2 :required-args))) |
---|
997 | (unless (= (length args1) (length args2)) |
---|
998 | (error "lambda lists are not congruent")))) |
---|
999 | |
---|
1000 | (defun add-method (gf method) |
---|
1001 | (check-congruent gf method) |
---|
1002 | ;; Remove existing method with same qualifiers and specializers (if any). |
---|
1003 | (let ((old-method (find-method gf (method-qualifiers method) |
---|
1004 | (method-specializers method) nil))) |
---|
1005 | (when old-method |
---|
1006 | (remove-method gf old-method))) |
---|
1007 | (setf (method-generic-function method) gf) |
---|
1008 | (push method (generic-function-methods gf)) |
---|
1009 | (dolist (specializer (method-specializers method)) |
---|
1010 | (pushnew method (class-direct-methods specializer))) |
---|
1011 | (finalize-generic-function gf) |
---|
1012 | gf) |
---|
1013 | |
---|
1014 | (defun remove-method (gf method) |
---|
1015 | (setf (generic-function-methods gf) |
---|
1016 | (remove method (generic-function-methods gf))) |
---|
1017 | (setf (method-generic-function method) nil) |
---|
1018 | ;; (format t "remove-method method-specializers = ~S~%" (method-specializers method)) |
---|
1019 | (dolist (class (method-specializers method)) |
---|
1020 | (setf (class-direct-methods class) |
---|
1021 | (remove method (class-direct-methods class)))) |
---|
1022 | (finalize-generic-function gf) |
---|
1023 | gf) |
---|
1024 | |
---|
1025 | (defun find-method (gf qualifiers specializers &optional (errorp t)) |
---|
1026 | (let ((method |
---|
1027 | (find-if #'(lambda (method) |
---|
1028 | (and (equal qualifiers |
---|
1029 | (method-qualifiers method)) |
---|
1030 | (equal specializers |
---|
1031 | (method-specializers method)))) |
---|
1032 | (generic-function-methods gf)))) |
---|
1033 | (if (and (null method) errorp) |
---|
1034 | (error "no such method for ~S" (generic-function-name gf)) |
---|
1035 | method))) |
---|
1036 | |
---|
1037 | ;;; Reader and writer methods |
---|
1038 | |
---|
1039 | (defun add-reader-method (class fn-name slot-name) |
---|
1040 | (ensure-method |
---|
1041 | (ensure-generic-function fn-name :lambda-list '(object)) |
---|
1042 | :lambda-list '(object) |
---|
1043 | :qualifiers () |
---|
1044 | :specializers (list class) |
---|
1045 | :body `(slot-value object ',slot-name) |
---|
1046 | :environment (top-level-environment)) |
---|
1047 | (values)) |
---|
1048 | |
---|
1049 | (defun add-writer-method (class fn-name slot-name) |
---|
1050 | (ensure-method |
---|
1051 | (ensure-generic-function |
---|
1052 | fn-name :lambda-list '(new-value object)) |
---|
1053 | :lambda-list '(new-value object) |
---|
1054 | :qualifiers () |
---|
1055 | :specializers (list (find-class 't) class) |
---|
1056 | :body `(setf (slot-value object ',slot-name) |
---|
1057 | new-value) |
---|
1058 | :environment (top-level-environment)) |
---|
1059 | (values)) |
---|
1060 | |
---|
1061 | ;;; subclassp and sub-specializer-p |
---|
1062 | |
---|
1063 | (defun subclassp (c1 c2) |
---|
1064 | (not (null (find c2 (class-precedence-list c1))))) |
---|
1065 | |
---|
1066 | (defun sub-specializer-p (c1 c2 c-arg) |
---|
1067 | (let ((cpl (class-precedence-list c-arg))) |
---|
1068 | (not (null (find c2 (cdr (member c1 cpl))))))) |
---|
1069 | |
---|
1070 | ;;; |
---|
1071 | ;;; Generic function invocation |
---|
1072 | ;;; |
---|
1073 | |
---|
1074 | ;;; apply-generic-function |
---|
1075 | |
---|
1076 | (defun apply-generic-function (gf args) |
---|
1077 | (apply (generic-function-discriminating-function gf) args)) |
---|
1078 | |
---|
1079 | ;;; compute-discriminating-function |
---|
1080 | |
---|
1081 | (defun std-compute-discriminating-function (gf) |
---|
1082 | #'(lambda (&rest args) |
---|
1083 | (let* ((classes (mapcar #'class-of |
---|
1084 | (required-portion gf args))) |
---|
1085 | (emfun (gethash classes (classes-to-emf-table gf) nil))) |
---|
1086 | (if emfun |
---|
1087 | (funcall emfun args) |
---|
1088 | (slow-method-lookup gf args classes))))) |
---|
1089 | |
---|
1090 | (defun slow-method-lookup (gf args classes) |
---|
1091 | (let* ((applicable-methods |
---|
1092 | (compute-applicable-methods-using-classes gf classes)) |
---|
1093 | (emfun |
---|
1094 | (funcall |
---|
1095 | (if (eq (class-of gf) the-class-standard-gf) |
---|
1096 | #'std-compute-effective-method-function |
---|
1097 | #'compute-effective-method-function) |
---|
1098 | gf applicable-methods))) |
---|
1099 | (setf (gethash classes (classes-to-emf-table gf)) emfun) |
---|
1100 | (funcall emfun args))) |
---|
1101 | |
---|
1102 | ;;; compute-applicable-methods-using-classes |
---|
1103 | |
---|
1104 | (defun compute-applicable-methods-using-classes (gf required-classes) |
---|
1105 | (sort |
---|
1106 | (copy-list |
---|
1107 | (remove-if-not #'(lambda (method) |
---|
1108 | (every #'subclassp |
---|
1109 | required-classes |
---|
1110 | (method-specializers method))) |
---|
1111 | (generic-function-methods gf))) |
---|
1112 | #'(lambda (m1 m2) |
---|
1113 | (funcall |
---|
1114 | (if (eq (class-of gf) the-class-standard-gf) |
---|
1115 | #'std-method-more-specific-p |
---|
1116 | #'method-more-specific-p) |
---|
1117 | gf m1 m2 required-classes)))) |
---|
1118 | |
---|
1119 | ;;; method-more-specific-p |
---|
1120 | |
---|
1121 | (defun std-method-more-specific-p (gf method1 method2 required-classes) |
---|
1122 | (declare (ignore gf)) |
---|
1123 | (mapc #'(lambda (spec1 spec2 arg-class) |
---|
1124 | (unless (eq spec1 spec2) |
---|
1125 | (return-from std-method-more-specific-p |
---|
1126 | (sub-specializer-p spec1 spec2 arg-class)))) |
---|
1127 | (method-specializers method1) |
---|
1128 | (method-specializers method2) |
---|
1129 | required-classes) |
---|
1130 | nil) |
---|
1131 | |
---|
1132 | ;;; apply-methods and compute-effective-method-function |
---|
1133 | |
---|
1134 | (defun apply-methods (gf args methods) |
---|
1135 | (funcall (compute-effective-method-function gf methods) |
---|
1136 | args)) |
---|
1137 | |
---|
1138 | (defun primary-method-p (method) |
---|
1139 | (null (intersection '(:before :after :around) (method-qualifiers method)))) |
---|
1140 | |
---|
1141 | (defun before-method-p (method) |
---|
1142 | (equal '(:before) (method-qualifiers method))) |
---|
1143 | |
---|
1144 | (defun after-method-p (method) |
---|
1145 | (equal '(:after) (method-qualifiers method))) |
---|
1146 | |
---|
1147 | (defun around-method-p (method) |
---|
1148 | (equal '(:around) (method-qualifiers method))) |
---|
1149 | |
---|
1150 | (defun std-compute-effective-method-function (gf methods) |
---|
1151 | (let* ((mc (generic-function-method-combination gf)) |
---|
1152 | (type (method-combination-type mc)) |
---|
1153 | (options (method-combination-options mc)) |
---|
1154 | (order (car options)) |
---|
1155 | (primaries ()) |
---|
1156 | (arounds ()) |
---|
1157 | around) |
---|
1158 | (dolist (m methods) |
---|
1159 | (let ((qualifiers (method-qualifiers m))) |
---|
1160 | (cond ((null qualifiers) |
---|
1161 | (if (eq type 'standard) |
---|
1162 | (push m primaries) |
---|
1163 | (error "method combination type mismatch"))) |
---|
1164 | ((cdr qualifiers) |
---|
1165 | (error "invalid method qualifiers")) |
---|
1166 | ((eq (car qualifiers) :around) |
---|
1167 | (push m arounds)) |
---|
1168 | ((eq (car qualifiers) type) |
---|
1169 | (push m primaries)) |
---|
1170 | ((memq (car qualifiers) '(:before :after))) |
---|
1171 | (t |
---|
1172 | (invalid generic-function combin m))))) |
---|
1173 | (unless (eq order :most-specific-last) |
---|
1174 | (setq primaries (nreverse primaries))) |
---|
1175 | (setq arounds (nreverse arounds)) |
---|
1176 | (setq around (car arounds)) |
---|
1177 | (when (null primaries) |
---|
1178 | (error "no primary methods for the generic function ~S" gf)) |
---|
1179 | (if around |
---|
1180 | (let ((next-emfun |
---|
1181 | (funcall |
---|
1182 | (if (eq (class-of gf) the-class-standard-gf) |
---|
1183 | #'std-compute-effective-method-function |
---|
1184 | #'compute-effective-method-function) |
---|
1185 | gf (remove around methods)))) |
---|
1186 | #'(lambda (args) |
---|
1187 | (funcall (method-function around) args next-emfun))) |
---|
1188 | (case type |
---|
1189 | (STANDARD |
---|
1190 | (let ((next-emfun (compute-primary-emfun (cdr primaries))) |
---|
1191 | (befores (remove-if-not #'before-method-p methods)) |
---|
1192 | (reverse-afters |
---|
1193 | (reverse (remove-if-not #'after-method-p methods)))) |
---|
1194 | #'(lambda (args) |
---|
1195 | (dolist (before befores) |
---|
1196 | (funcall (method-function before) args nil)) |
---|
1197 | (multiple-value-prog1 |
---|
1198 | (funcall (method-function (car primaries)) args next-emfun) |
---|
1199 | (dolist (after reverse-afters) |
---|
1200 | (funcall (method-function after) args nil)))))) |
---|
1201 | (LIST |
---|
1202 | #'(lambda (args) |
---|
1203 | (let ((result ())) |
---|
1204 | (dolist (primary primaries) |
---|
1205 | (push (funcall (method-function primary) args nil) result)) |
---|
1206 | (nreverse result)))) |
---|
1207 | (APPEND |
---|
1208 | #'(lambda (args) |
---|
1209 | (let ((result ())) |
---|
1210 | (dolist (primary primaries) |
---|
1211 | (setf result (append result (funcall (method-function primary) args nil)))) |
---|
1212 | result))) |
---|
1213 | (NCONC |
---|
1214 | #'(lambda (args) |
---|
1215 | (let ((result ())) |
---|
1216 | (dolist (primary primaries) |
---|
1217 | (setf result (nconc result (funcall (method-function primary) args nil)))) |
---|
1218 | result))) |
---|
1219 | (PROGN |
---|
1220 | #'(lambda (args) |
---|
1221 | (let ((result nil)) |
---|
1222 | (dolist (primary primaries) |
---|
1223 | (setf result (funcall (method-function primary) args nil))) |
---|
1224 | result))) |
---|
1225 | (AND |
---|
1226 | #'(lambda (args) |
---|
1227 | (let ((result t)) |
---|
1228 | (dolist (primary primaries) |
---|
1229 | (setf result |
---|
1230 | (and result |
---|
1231 | (funcall (method-function primary) args nil))) |
---|
1232 | (unless result (return))) |
---|
1233 | result))) |
---|
1234 | (OR |
---|
1235 | #'(lambda (args) |
---|
1236 | (let ((result nil)) |
---|
1237 | (dolist (primary primaries) |
---|
1238 | (setf result |
---|
1239 | (or result |
---|
1240 | (funcall (method-function primary) args nil))) |
---|
1241 | (when result (return))) |
---|
1242 | result))) |
---|
1243 | (+ |
---|
1244 | #'(lambda (args) |
---|
1245 | (let ((result 0)) |
---|
1246 | (dolist (primary primaries) |
---|
1247 | (incf result (funcall (method-function primary) args nil))) |
---|
1248 | result))) |
---|
1249 | (MAX |
---|
1250 | #'(lambda (args) |
---|
1251 | (let ((result ())) |
---|
1252 | (dolist (primary primaries) |
---|
1253 | (push (funcall (method-function primary) args nil) result)) |
---|
1254 | (apply #'max result)))) |
---|
1255 | (MIN |
---|
1256 | #'(lambda (args) |
---|
1257 | (let ((result ())) |
---|
1258 | (dolist (primary primaries) |
---|
1259 | (push (funcall (method-function primary) args nil) result)) |
---|
1260 | (apply #'min result)))) |
---|
1261 | (t |
---|
1262 | (error "unsupported method combination type ~S" type)))))) |
---|
1263 | |
---|
1264 | ;;; compute an effective method function from a list of primary methods: |
---|
1265 | |
---|
1266 | (defun compute-primary-emfun (methods) |
---|
1267 | (if (null methods) |
---|
1268 | nil |
---|
1269 | (let ((next-emfun (compute-primary-emfun (cdr methods)))) |
---|
1270 | #'(lambda (args) |
---|
1271 | (funcall (method-function (car methods)) args next-emfun))))) |
---|
1272 | |
---|
1273 | ;;; apply-method and compute-method-function |
---|
1274 | |
---|
1275 | (defun apply-method (method args next-methods) |
---|
1276 | (funcall (method-function method) |
---|
1277 | args |
---|
1278 | (if (null next-methods) |
---|
1279 | nil |
---|
1280 | (compute-effective-method-function |
---|
1281 | (method-generic-function method) next-methods)))) |
---|
1282 | |
---|
1283 | (defun std-compute-method-function (method) |
---|
1284 | (let ((form (method-body method)) |
---|
1285 | (lambda-list (method-lambda-list method))) |
---|
1286 | (compile-in-lexical-environment |
---|
1287 | (method-environment method) |
---|
1288 | `(lambda (args next-emfun) |
---|
1289 | (flet ((call-next-method (&rest cnm-args) |
---|
1290 | (if (null next-emfun) |
---|
1291 | (error "no next method for the generic function ~S" |
---|
1292 | (method-generic-function ',method)) |
---|
1293 | (funcall next-emfun (or cnm-args args)))) |
---|
1294 | (next-method-p () |
---|
1295 | (not (null next-emfun)))) |
---|
1296 | (apply #'(lambda ,(kludge-arglist lambda-list) |
---|
1297 | ,form) |
---|
1298 | args)))))) |
---|
1299 | |
---|
1300 | ;;; N.B. The function kludge-arglist is used to pave over the differences |
---|
1301 | ;;; between argument keyword compatibility for regular functions versus |
---|
1302 | ;;; generic functions. |
---|
1303 | |
---|
1304 | (defun kludge-arglist (lambda-list) |
---|
1305 | (if (and (member '&key lambda-list) |
---|
1306 | (not (member '&allow-other-keys lambda-list))) |
---|
1307 | (append lambda-list '(&allow-other-keys)) |
---|
1308 | (if (and (not (member '&rest lambda-list)) |
---|
1309 | (not (member '&key lambda-list))) |
---|
1310 | (append lambda-list '(&key &allow-other-keys)) |
---|
1311 | lambda-list))) |
---|
1312 | |
---|
1313 | ;;; Slot access |
---|
1314 | |
---|
1315 | (defun setf-slot-value-using-class (new-value class instance slot-name) |
---|
1316 | (setf (std-slot-value instance slot-name) new-value)) |
---|
1317 | |
---|
1318 | (defgeneric slot-value-using-class (class instance slot-name)) |
---|
1319 | (defmethod slot-value-using-class ((class standard-class) instance slot-name) |
---|
1320 | (std-slot-value instance slot-name)) |
---|
1321 | |
---|
1322 | (defgeneric (setf slot-value-using-class) (new-value class instance slot-name)) |
---|
1323 | (defmethod (setf slot-value-using-class) |
---|
1324 | (new-value (class standard-class) instance slot-name) |
---|
1325 | (setf (std-slot-value instance slot-name) new-value)) |
---|
1326 | |
---|
1327 | (defgeneric slot-exists-p-using-class (class instance slot-name)) |
---|
1328 | (defmethod slot-exists-p-using-class |
---|
1329 | ((class standard-class) instance slot-name) |
---|
1330 | (std-slot-exists-p instance slot-name)) |
---|
1331 | |
---|
1332 | (defgeneric slot-boundp-using-class (class instance slot-name)) |
---|
1333 | (defmethod slot-boundp-using-class |
---|
1334 | ((class standard-class) instance slot-name) |
---|
1335 | (std-slot-boundp instance slot-name)) |
---|
1336 | |
---|
1337 | (defgeneric slot-makunbound-using-class (class instance slot-name)) |
---|
1338 | (defmethod slot-makunbound-using-class |
---|
1339 | ((class standard-class) instance slot-name) |
---|
1340 | (std-slot-makunbound instance slot-name)) |
---|
1341 | |
---|
1342 | (defgeneric slot-missing (class instance slot-name operation &optional new-value)) |
---|
1343 | (defmethod slot-missing ((class t) instance slot-name operation &optional new-value) |
---|
1344 | (error "the slot ~S is missing from the class ~S" slot-name class)) |
---|
1345 | |
---|
1346 | ;;; Instance creation and initialization |
---|
1347 | |
---|
1348 | (defgeneric make-instance (class &key)) |
---|
1349 | (defmethod make-instance ((class standard-class) &rest initargs) |
---|
1350 | (let ((instance (allocate-instance class))) |
---|
1351 | (apply #'initialize-instance instance |
---|
1352 | (append initargs (class-default-initargs class))) |
---|
1353 | instance)) |
---|
1354 | (defmethod make-instance ((class symbol) &rest initargs) |
---|
1355 | (apply #'make-instance (find-class class) initargs)) |
---|
1356 | |
---|
1357 | (defgeneric initialize-instance (instance &key)) |
---|
1358 | (defmethod initialize-instance ((instance standard-object) &rest initargs) |
---|
1359 | (apply #'shared-initialize instance t initargs)) |
---|
1360 | |
---|
1361 | (defgeneric reinitialize-instance (instance &key)) |
---|
1362 | (defmethod reinitialize-instance |
---|
1363 | ((instance standard-object) &rest initargs) |
---|
1364 | (apply #'shared-initialize instance () initargs)) |
---|
1365 | |
---|
1366 | (defgeneric shared-initialize (instance slot-names &key)) |
---|
1367 | (defmethod shared-initialize ((instance standard-object) |
---|
1368 | slot-names &rest all-keys) |
---|
1369 | (dolist (slot (class-slots (class-of instance))) |
---|
1370 | (let ((slot-name (slot-definition-name slot))) |
---|
1371 | (multiple-value-bind (init-key init-value foundp) |
---|
1372 | (get-properties |
---|
1373 | all-keys (slot-definition-initargs slot)) |
---|
1374 | (declare (ignore init-key)) |
---|
1375 | (if foundp |
---|
1376 | (setf (slot-value instance slot-name) init-value) |
---|
1377 | (when (and (not (slot-boundp instance slot-name)) |
---|
1378 | (not (null (slot-definition-initfunction slot))) |
---|
1379 | (or (eq slot-names t) |
---|
1380 | (member slot-name slot-names))) |
---|
1381 | (setf (slot-value instance slot-name) |
---|
1382 | (funcall (slot-definition-initfunction slot)))))))) |
---|
1383 | instance) |
---|
1384 | |
---|
1385 | ;;; change-class |
---|
1386 | |
---|
1387 | (defgeneric change-class (instance new-class &key)) |
---|
1388 | (defmethod change-class |
---|
1389 | ((old-instance standard-object) |
---|
1390 | (new-class standard-class) |
---|
1391 | &rest initargs) |
---|
1392 | (let ((new-instance (allocate-instance new-class))) |
---|
1393 | (dolist (slot-name (mapcar #'slot-definition-name |
---|
1394 | (class-slots new-class))) |
---|
1395 | (when (and (slot-exists-p old-instance slot-name) |
---|
1396 | (slot-boundp old-instance slot-name)) |
---|
1397 | (setf (slot-value new-instance slot-name) |
---|
1398 | (slot-value old-instance slot-name)))) |
---|
1399 | (rotatef (std-instance-slots new-instance) |
---|
1400 | (std-instance-slots old-instance)) |
---|
1401 | (rotatef (std-instance-class new-instance) |
---|
1402 | (std-instance-class old-instance)) |
---|
1403 | (apply #'update-instance-for-different-class |
---|
1404 | new-instance old-instance initargs) |
---|
1405 | old-instance)) |
---|
1406 | |
---|
1407 | (defmethod change-class |
---|
1408 | ((instance standard-object) (new-class symbol) &rest initargs) |
---|
1409 | (apply #'change-class instance (find-class new-class) initargs)) |
---|
1410 | |
---|
1411 | (defgeneric update-instance-for-different-class (old new &key)) |
---|
1412 | (defmethod update-instance-for-different-class |
---|
1413 | ((old standard-object) (new standard-object) &rest initargs) |
---|
1414 | (let ((added-slots |
---|
1415 | (remove-if #'(lambda (slot-name) |
---|
1416 | (slot-exists-p old slot-name)) |
---|
1417 | (mapcar #'slot-definition-name |
---|
1418 | (class-slots (class-of new)))))) |
---|
1419 | (apply #'shared-initialize new added-slots initargs))) |
---|
1420 | |
---|
1421 | ;;; Methods having to do with class metaobjects. |
---|
1422 | |
---|
1423 | (defmethod initialize-instance :after ((class standard-class) &rest args) |
---|
1424 | (apply #'std-after-initialization-for-classes class args)) |
---|
1425 | |
---|
1426 | ;;; Finalize inheritance |
---|
1427 | |
---|
1428 | (defgeneric finalize-inheritance (class)) |
---|
1429 | (defmethod finalize-inheritance ((class standard-class)) |
---|
1430 | (std-finalize-inheritance class) |
---|
1431 | (values)) |
---|
1432 | |
---|
1433 | ;;; Class precedence lists |
---|
1434 | |
---|
1435 | (defgeneric compute-class-precedence-list (class)) |
---|
1436 | (defmethod compute-class-precedence-list ((class standard-class)) |
---|
1437 | (std-compute-class-precedence-list class)) |
---|
1438 | |
---|
1439 | ;;; Slot inheritance |
---|
1440 | |
---|
1441 | (defgeneric compute-slots (class)) |
---|
1442 | (defmethod compute-slots ((class standard-class)) |
---|
1443 | (std-compute-slots class)) |
---|
1444 | |
---|
1445 | (defgeneric compute-effective-slot-definition (class direct-slots)) |
---|
1446 | (defmethod compute-effective-slot-definition |
---|
1447 | ((class standard-class) direct-slots) |
---|
1448 | (std-compute-effective-slot-definition class direct-slots)) |
---|
1449 | |
---|
1450 | ;;; Methods having to do with generic function metaobjects. |
---|
1451 | |
---|
1452 | (defmethod initialize-instance :after ((gf standard-generic-function) &key) |
---|
1453 | (finalize-generic-function gf)) |
---|
1454 | |
---|
1455 | ;;; Methods having to do with method metaobjects. |
---|
1456 | |
---|
1457 | (defmethod initialize-instance :after ((method standard-method) &key) |
---|
1458 | (setf (method-function method) (compute-method-function method))) |
---|
1459 | |
---|
1460 | ;;; Methods having to do with generic function invocation. |
---|
1461 | |
---|
1462 | (defgeneric compute-discriminating-function (gf)) |
---|
1463 | (defmethod compute-discriminating-function ((gf standard-generic-function)) |
---|
1464 | (std-compute-discriminating-function gf)) |
---|
1465 | |
---|
1466 | (defgeneric method-more-specific-p (gf method1 method2 required-classes)) |
---|
1467 | (defmethod method-more-specific-p |
---|
1468 | ((gf standard-generic-function) method1 method2 required-classes) |
---|
1469 | (std-method-more-specific-p gf method1 method2 required-classes)) |
---|
1470 | |
---|
1471 | (defgeneric compute-effective-method-function (gf methods)) |
---|
1472 | (defmethod compute-effective-method-function |
---|
1473 | ((gf standard-generic-function) methods) |
---|
1474 | (std-compute-effective-method-function gf methods)) |
---|
1475 | |
---|
1476 | (defgeneric compute-method-function (method)) |
---|
1477 | (defmethod compute-method-function ((method standard-method)) |
---|
1478 | (std-compute-method-function method)) |
---|
1479 | |
---|
1480 | (defgeneric compute-applicable-methods (gf args)) |
---|
1481 | (defmethod compute-applicable-methods ((gf standard-generic-function) args) |
---|
1482 | (compute-applicable-methods-using-classes gf (mapcar #'class-of args))) |
---|
1483 | |
---|
1484 | (provide 'clos) |
---|