1 | ;;; clos.lisp |
---|
2 | ;;; |
---|
3 | ;;; Copyright (C) 2003-2007 Peter Graves |
---|
4 | ;;; $Id: clos.lisp 12805 2010-07-13 19:16:25Z astalla $ |
---|
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
---|
19 | ;;; |
---|
20 | ;;; As a special exception, the copyright holders of this library give you |
---|
21 | ;;; permission to link this library with independent modules to produce an |
---|
22 | ;;; executable, regardless of the license terms of these independent |
---|
23 | ;;; modules, and to copy and distribute the resulting executable under |
---|
24 | ;;; terms of your choice, provided that you also meet, for each linked |
---|
25 | ;;; independent module, the terms and conditions of the license of that |
---|
26 | ;;; module. An independent module is a module which is not derived from |
---|
27 | ;;; or based on this library. If you modify this library, you may extend |
---|
28 | ;;; this exception to your version of the library, but you are not |
---|
29 | ;;; obligated to do so. If you do not wish to do so, delete this |
---|
30 | ;;; exception statement from your version. |
---|
31 | |
---|
32 | ;;; Originally based on Closette. |
---|
33 | |
---|
34 | ;;; Closette Version 1.0 (February 10, 1991) |
---|
35 | ;;; |
---|
36 | ;;; Copyright (c) 1990, 1991 Xerox Corporation. |
---|
37 | ;;; All rights reserved. |
---|
38 | ;;; |
---|
39 | ;;; Use and copying of this software and preparation of derivative works |
---|
40 | ;;; based upon this software are permitted. Any distribution of this |
---|
41 | ;;; software or derivative works must comply with all applicable United |
---|
42 | ;;; States export control laws. |
---|
43 | ;;; |
---|
44 | ;;; This software is made available AS IS, and Xerox Corporation makes no |
---|
45 | ;;; warranty about the software, its performance or its conformity to any |
---|
46 | ;;; specification. |
---|
47 | ;;; |
---|
48 | ;;; Closette is an implementation of a subset of CLOS with a metaobject |
---|
49 | ;;; protocol as described in "The Art of The Metaobject Protocol", |
---|
50 | ;;; MIT Press, 1991. |
---|
51 | |
---|
52 | (in-package #:mop) |
---|
53 | |
---|
54 | (export '(class-precedence-list class-slots)) |
---|
55 | (defconstant +the-standard-class+ (find-class 'standard-class)) |
---|
56 | (defconstant +the-structure-class+ (find-class 'structure-class)) |
---|
57 | (defconstant +the-standard-object-class+ (find-class 'standard-object)) |
---|
58 | (defconstant +the-standard-method-class+ (find-class 'standard-method)) |
---|
59 | (defconstant +the-standard-reader-method-class+ |
---|
60 | (find-class 'standard-reader-method)) |
---|
61 | (defconstant +the-standard-generic-function-class+ |
---|
62 | (find-class 'standard-generic-function)) |
---|
63 | (defconstant +the-T-class+ (find-class 'T)) |
---|
64 | (defconstant +the-slot-definition-class+ (find-class 'slot-definition)) |
---|
65 | (defconstant +the-direct-slot-definition-class+ (find-class 'direct-slot-definition)) |
---|
66 | (defconstant +the-effective-slot-definition-class+ (find-class 'effective-slot-definition)) |
---|
67 | |
---|
68 | ;; Don't use DEFVAR, because that disallows loading clos.lisp |
---|
69 | ;; after compiling it: the binding won't get assigned to T anymore |
---|
70 | (defparameter *clos-booting* t) |
---|
71 | |
---|
72 | (defmacro define-class->%class-forwarder (name) |
---|
73 | (let* (($name (if (consp name) (cadr name) name)) |
---|
74 | (%name (intern (concatenate 'string |
---|
75 | "%" |
---|
76 | (if (consp name) |
---|
77 | (symbol-name 'set-) "") |
---|
78 | (symbol-name $name)) |
---|
79 | (symbol-package $name)))) |
---|
80 | `(progn |
---|
81 | (declaim (notinline ,name)) |
---|
82 | (defun ,name (&rest args) |
---|
83 | (apply #',%name args))))) |
---|
84 | |
---|
85 | (define-class->%class-forwarder class-name) |
---|
86 | (define-class->%class-forwarder (setf class-name)) |
---|
87 | (define-class->%class-forwarder class-slots) |
---|
88 | (define-class->%class-forwarder (setf class-slots)) |
---|
89 | (define-class->%class-forwarder class-direct-slots) |
---|
90 | (define-class->%class-forwarder (setf class-direct-slots)) |
---|
91 | (define-class->%class-forwarder class-layout) |
---|
92 | (define-class->%class-forwarder (setf class-layout)) |
---|
93 | (define-class->%class-forwarder class-direct-superclasses) |
---|
94 | (define-class->%class-forwarder (setf class-direct-superclasses)) |
---|
95 | (define-class->%class-forwarder class-direct-subclasses) |
---|
96 | (define-class->%class-forwarder (setf class-direct-subclasses)) |
---|
97 | (define-class->%class-forwarder class-direct-methods) |
---|
98 | (define-class->%class-forwarder (setf class-direct-methods)) |
---|
99 | (define-class->%class-forwarder class-precedence-list) |
---|
100 | (define-class->%class-forwarder (setf class-precedence-list)) |
---|
101 | (define-class->%class-forwarder class-finalized-p) |
---|
102 | (define-class->%class-forwarder (setf class-finalized-p)) |
---|
103 | (define-class->%class-forwarder class-default-initargs) |
---|
104 | (define-class->%class-forwarder (setf class-default-initargs)) |
---|
105 | (define-class->%class-forwarder class-direct-default-initargs) |
---|
106 | (define-class->%class-forwarder (setf class-direct-default-initargs)) |
---|
107 | |
---|
108 | (defun no-applicable-method (generic-function &rest args) |
---|
109 | (error "There is no applicable method for the generic function ~S when called with arguments ~S." |
---|
110 | generic-function |
---|
111 | args)) |
---|
112 | |
---|
113 | |
---|
114 | |
---|
115 | (defmacro push-on-end (value location) |
---|
116 | `(setf ,location (nconc ,location (list ,value)))) |
---|
117 | |
---|
118 | ;;; (SETF GETF*) is like (SETF GETF) except that it always changes the list, |
---|
119 | ;;; which must be non-nil. |
---|
120 | |
---|
121 | (defun (setf getf*) (new-value plist key) |
---|
122 | (block body |
---|
123 | (do ((x plist (cddr x))) |
---|
124 | ((null x)) |
---|
125 | (when (eq (car x) key) |
---|
126 | (setf (car (cdr x)) new-value) |
---|
127 | (return-from body new-value))) |
---|
128 | (push-on-end key plist) |
---|
129 | (push-on-end new-value plist) |
---|
130 | new-value)) |
---|
131 | |
---|
132 | (defun mapappend (fun &rest args) |
---|
133 | (if (some #'null args) |
---|
134 | () |
---|
135 | (append (apply fun (mapcar #'car args)) |
---|
136 | (apply #'mapappend fun (mapcar #'cdr args))))) |
---|
137 | |
---|
138 | (defun mapplist (fun x) |
---|
139 | (if (null x) |
---|
140 | () |
---|
141 | (cons (funcall fun (car x) (cadr x)) |
---|
142 | (mapplist fun (cddr x))))) |
---|
143 | |
---|
144 | (defsetf std-instance-layout %set-std-instance-layout) |
---|
145 | (defsetf standard-instance-access %set-standard-instance-access) |
---|
146 | |
---|
147 | (defun (setf find-class) (new-value symbol &optional errorp environment) |
---|
148 | (declare (ignore errorp environment)) |
---|
149 | (%set-find-class symbol new-value)) |
---|
150 | |
---|
151 | (defun canonicalize-direct-slots (direct-slots) |
---|
152 | `(list ,@(mapcar #'canonicalize-direct-slot direct-slots))) |
---|
153 | |
---|
154 | (defun canonicalize-direct-slot (spec) |
---|
155 | (if (symbolp spec) |
---|
156 | `(list :name ',spec) |
---|
157 | (let ((name (car spec)) |
---|
158 | (initfunction nil) |
---|
159 | (initform nil) |
---|
160 | (initargs ()) |
---|
161 | (type nil) |
---|
162 | (allocation nil) |
---|
163 | (documentation nil) |
---|
164 | (readers ()) |
---|
165 | (writers ()) |
---|
166 | (other-options ()) |
---|
167 | (non-std-options ())) |
---|
168 | (do ((olist (cdr spec) (cddr olist))) |
---|
169 | ((null olist)) |
---|
170 | (case (car olist) |
---|
171 | (:initform |
---|
172 | (when initform |
---|
173 | (error 'program-error |
---|
174 | "duplicate slot option :INITFORM for slot named ~S" |
---|
175 | name)) |
---|
176 | (setq initfunction |
---|
177 | `(function (lambda () ,(cadr olist)))) |
---|
178 | (setq initform `',(cadr olist))) |
---|
179 | (:initarg |
---|
180 | (push-on-end (cadr olist) initargs)) |
---|
181 | (:allocation |
---|
182 | (when allocation |
---|
183 | (error 'program-error |
---|
184 | "duplicate slot option :ALLOCATION for slot named ~S" |
---|
185 | name)) |
---|
186 | (setf allocation (cadr olist)) |
---|
187 | (push-on-end (car olist) other-options) |
---|
188 | (push-on-end (cadr olist) other-options)) |
---|
189 | (:type |
---|
190 | (when type |
---|
191 | (error 'program-error |
---|
192 | "duplicate slot option :TYPE for slot named ~S" |
---|
193 | name)) |
---|
194 | (setf type (cadr olist))) ;; FIXME type is ignored |
---|
195 | (:documentation |
---|
196 | (when documentation |
---|
197 | (error 'program-error |
---|
198 | "duplicate slot option :DOCUMENTATION for slot named ~S" |
---|
199 | name)) |
---|
200 | (setf documentation (cadr olist))) ;; FIXME documentation is ignored |
---|
201 | (:reader |
---|
202 | (maybe-note-name-defined (cadr olist)) |
---|
203 | (push-on-end (cadr olist) readers)) |
---|
204 | (:writer |
---|
205 | (maybe-note-name-defined (cadr olist)) |
---|
206 | (push-on-end (cadr olist) writers)) |
---|
207 | (:accessor |
---|
208 | (maybe-note-name-defined (cadr olist)) |
---|
209 | (push-on-end (cadr olist) readers) |
---|
210 | (push-on-end `(setf ,(cadr olist)) writers)) |
---|
211 | (t |
---|
212 | (push-on-end `(quote ,(car olist)) non-std-options) |
---|
213 | (push-on-end (cadr olist) non-std-options)))) |
---|
214 | `(list |
---|
215 | :name ',name |
---|
216 | ,@(when initfunction |
---|
217 | `(:initform ,initform |
---|
218 | :initfunction ,initfunction)) |
---|
219 | ,@(when initargs `(:initargs ',initargs)) |
---|
220 | ,@(when readers `(:readers ',readers)) |
---|
221 | ,@(when writers `(:writers ',writers)) |
---|
222 | ,@other-options |
---|
223 | ,@non-std-options)))) |
---|
224 | |
---|
225 | (defun maybe-note-name-defined (name) |
---|
226 | (when (fboundp 'note-name-defined) |
---|
227 | (note-name-defined name))) |
---|
228 | |
---|
229 | (defun canonicalize-direct-superclasses (direct-superclasses) |
---|
230 | (let ((classes '())) |
---|
231 | (dolist (class-specifier direct-superclasses) |
---|
232 | (if (classp class-specifier) |
---|
233 | (push class-specifier classes) |
---|
234 | (let ((class (find-class class-specifier nil))) |
---|
235 | (unless class |
---|
236 | (setf class (make-forward-referenced-class class-specifier))) |
---|
237 | (push class classes)))) |
---|
238 | (nreverse classes))) |
---|
239 | |
---|
240 | (defun canonicalize-defclass-options (options) |
---|
241 | (mapappend #'canonicalize-defclass-option options)) |
---|
242 | |
---|
243 | (defun canonicalize-defclass-option (option) |
---|
244 | (case (car option) |
---|
245 | (:metaclass |
---|
246 | (list ':metaclass |
---|
247 | `(find-class ',(cadr option)))) |
---|
248 | (:default-initargs |
---|
249 | (list |
---|
250 | ':direct-default-initargs |
---|
251 | `(list ,@(mapappend |
---|
252 | #'(lambda (x) x) |
---|
253 | (mapplist |
---|
254 | #'(lambda (key value) |
---|
255 | `(',key ,(make-initfunction value))) |
---|
256 | (cdr option)))))) |
---|
257 | ((:documentation :report) |
---|
258 | (list (car option) `',(cadr option))) |
---|
259 | (t (list `(quote ,(car option)) `(quote ,(cdr option)))))) |
---|
260 | |
---|
261 | (defun make-initfunction (initform) |
---|
262 | `(function (lambda () ,initform))) |
---|
263 | |
---|
264 | (defun slot-definition-allocation (slot-definition) |
---|
265 | (%slot-definition-allocation slot-definition)) |
---|
266 | |
---|
267 | (declaim (notinline (setf slot-definition-allocation))) |
---|
268 | (defun (setf slot-definition-allocation) (value slot-definition) |
---|
269 | (set-slot-definition-allocation slot-definition value)) |
---|
270 | |
---|
271 | (defun slot-definition-initargs (slot-definition) |
---|
272 | (%slot-definition-initargs slot-definition)) |
---|
273 | |
---|
274 | (declaim (notinline (setf slot-definition-initargs))) |
---|
275 | (defun (setf slot-definition-initargs) (value slot-definition) |
---|
276 | (set-slot-definition-initargs slot-definition value)) |
---|
277 | |
---|
278 | (defun slot-definition-initform (slot-definition) |
---|
279 | (%slot-definition-initform slot-definition)) |
---|
280 | |
---|
281 | (declaim (notinline (setf slot-definition-initform))) |
---|
282 | (defun (setf slot-definition-initform) (value slot-definition) |
---|
283 | (set-slot-definition-initform slot-definition value)) |
---|
284 | |
---|
285 | (defun slot-definition-initfunction (slot-definition) |
---|
286 | (%slot-definition-initfunction slot-definition)) |
---|
287 | |
---|
288 | (declaim (notinline (setf slot-definition-initfunction))) |
---|
289 | (defun (setf slot-definition-initfunction) (value slot-definition) |
---|
290 | (set-slot-definition-initfunction slot-definition value)) |
---|
291 | |
---|
292 | (defun slot-definition-name (slot-definition) |
---|
293 | (%slot-definition-name slot-definition)) |
---|
294 | |
---|
295 | (declaim (notinline (setf slot-definition-name))) |
---|
296 | (defun (setf slot-definition-name) (value slot-definition) |
---|
297 | (set-slot-definition-name slot-definition value)) |
---|
298 | |
---|
299 | (defun slot-definition-readers (slot-definition) |
---|
300 | (%slot-definition-readers slot-definition)) |
---|
301 | |
---|
302 | (declaim (notinline (setf slot-definition-readers))) |
---|
303 | (defun (setf slot-definition-readers) (value slot-definition) |
---|
304 | (set-slot-definition-readers slot-definition value)) |
---|
305 | |
---|
306 | (defun slot-definition-writers (slot-definition) |
---|
307 | (%slot-definition-writers slot-definition)) |
---|
308 | |
---|
309 | (declaim (notinline (setf slot-definition-writers))) |
---|
310 | (defun (setf slot-definition-writers) (value slot-definition) |
---|
311 | (set-slot-definition-writers slot-definition value)) |
---|
312 | |
---|
313 | (defun slot-definition-allocation-class (slot-definition) |
---|
314 | (%slot-definition-allocation-class slot-definition)) |
---|
315 | |
---|
316 | (declaim (notinline (setf slot-definition-allocation-class))) |
---|
317 | (defun (setf slot-definition-allocation-class) (value slot-definition) |
---|
318 | (set-slot-definition-allocation-class slot-definition value)) |
---|
319 | |
---|
320 | (defun slot-definition-location (slot-definition) |
---|
321 | (%slot-definition-location slot-definition)) |
---|
322 | |
---|
323 | (declaim (notinline (setf slot-definition-location-class))) |
---|
324 | (defun (setf slot-definition-location) (value slot-definition) |
---|
325 | (set-slot-definition-location slot-definition value)) |
---|
326 | |
---|
327 | (defun init-slot-definition (slot &key name |
---|
328 | (initargs ()) |
---|
329 | (initform nil) |
---|
330 | (initfunction nil) |
---|
331 | (readers ()) |
---|
332 | (writers ()) |
---|
333 | (allocation :instance) |
---|
334 | (allocation-class nil)) |
---|
335 | (setf (slot-definition-name slot) name) |
---|
336 | (setf (slot-definition-initargs slot) initargs) |
---|
337 | (setf (slot-definition-initform slot) initform) |
---|
338 | (setf (slot-definition-initfunction slot) initfunction) |
---|
339 | (setf (slot-definition-readers slot) readers) |
---|
340 | (setf (slot-definition-writers slot) writers) |
---|
341 | (setf (slot-definition-allocation slot) allocation) |
---|
342 | (setf (slot-definition-allocation-class slot) allocation-class) |
---|
343 | slot) |
---|
344 | |
---|
345 | (defun make-direct-slot-definition (class &rest args) |
---|
346 | (let ((slot-class (direct-slot-definition-class class))) |
---|
347 | (if (eq slot-class +the-direct-slot-definition-class+) |
---|
348 | (let ((slot (make-slot-definition +the-direct-slot-definition-class+))) |
---|
349 | (apply #'init-slot-definition slot :allocation-class class args) |
---|
350 | slot) |
---|
351 | (progn |
---|
352 | (let ((slot (apply #'make-instance slot-class :allocation-class class |
---|
353 | args))) |
---|
354 | slot))))) |
---|
355 | |
---|
356 | (defun make-effective-slot-definition (class &rest args) |
---|
357 | (let ((slot-class (effective-slot-definition-class class))) |
---|
358 | (if (eq slot-class +the-effective-slot-definition-class+) |
---|
359 | (let ((slot (make-slot-definition +the-effective-slot-definition-class+))) |
---|
360 | (apply #'init-slot-definition slot args) |
---|
361 | slot) |
---|
362 | (progn |
---|
363 | (let ((slot (apply #'make-instance slot-class args))) |
---|
364 | slot))))) |
---|
365 | |
---|
366 | ;;; finalize-inheritance |
---|
367 | |
---|
368 | (defun std-compute-class-default-initargs (class) |
---|
369 | (mapcan #'(lambda (c) |
---|
370 | (copy-list |
---|
371 | (class-direct-default-initargs c))) |
---|
372 | (class-precedence-list class))) |
---|
373 | |
---|
374 | (defun std-finalize-inheritance (class) |
---|
375 | (setf (class-precedence-list class) |
---|
376 | (funcall (if (eq (class-of class) +the-standard-class+) |
---|
377 | #'std-compute-class-precedence-list |
---|
378 | #'compute-class-precedence-list) |
---|
379 | class)) |
---|
380 | (dolist (class (class-precedence-list class)) |
---|
381 | (when (typep class 'forward-referenced-class) |
---|
382 | (return-from std-finalize-inheritance))) |
---|
383 | (setf (class-slots class) |
---|
384 | (funcall (if (eq (class-of class) +the-standard-class+) |
---|
385 | #'std-compute-slots |
---|
386 | #'compute-slots) class)) |
---|
387 | (let ((old-layout (class-layout class)) |
---|
388 | (length 0) |
---|
389 | (instance-slots '()) |
---|
390 | (shared-slots '())) |
---|
391 | (dolist (slot (class-slots class)) |
---|
392 | (case (slot-definition-allocation slot) |
---|
393 | (:instance |
---|
394 | (setf (slot-definition-location slot) length) |
---|
395 | (incf length) |
---|
396 | (push (slot-definition-name slot) instance-slots)) |
---|
397 | (:class |
---|
398 | (unless (slot-definition-location slot) |
---|
399 | (let ((allocation-class (slot-definition-allocation-class slot))) |
---|
400 | (setf (slot-definition-location slot) |
---|
401 | (if (eq allocation-class class) |
---|
402 | (cons (slot-definition-name slot) +slot-unbound+) |
---|
403 | (slot-location allocation-class (slot-definition-name slot)))))) |
---|
404 | (push (slot-definition-location slot) shared-slots)))) |
---|
405 | (when old-layout |
---|
406 | ;; Redefined class: initialize added shared slots. |
---|
407 | (dolist (location shared-slots) |
---|
408 | (let* ((slot-name (car location)) |
---|
409 | (old-location (layout-slot-location old-layout slot-name))) |
---|
410 | (unless old-location |
---|
411 | (let* ((slot-definition (find slot-name (class-slots class) :key 'slot-definition-name)) |
---|
412 | (initfunction (slot-definition-initfunction slot-definition))) |
---|
413 | (when initfunction |
---|
414 | (setf (cdr location) (funcall initfunction)))))))) |
---|
415 | (setf (class-layout class) |
---|
416 | (make-layout class (nreverse instance-slots) (nreverse shared-slots)))) |
---|
417 | (setf (class-default-initargs class) |
---|
418 | (std-compute-class-default-initargs class)) |
---|
419 | (setf (class-finalized-p class) t)) |
---|
420 | |
---|
421 | ;;; Class precedence lists |
---|
422 | |
---|
423 | (defun std-compute-class-precedence-list (class) |
---|
424 | (let ((classes-to-order (collect-superclasses* class))) |
---|
425 | (topological-sort classes-to-order |
---|
426 | (remove-duplicates |
---|
427 | (mapappend #'local-precedence-ordering |
---|
428 | classes-to-order)) |
---|
429 | #'std-tie-breaker-rule))) |
---|
430 | |
---|
431 | ;;; topological-sort implements the standard algorithm for topologically |
---|
432 | ;;; sorting an arbitrary set of elements while honoring the precedence |
---|
433 | ;;; constraints given by a set of (X,Y) pairs that indicate that element |
---|
434 | ;;; X must precede element Y. The tie-breaker procedure is called when it |
---|
435 | ;;; is necessary to choose from multiple minimal elements; both a list of |
---|
436 | ;;; candidates and the ordering so far are provided as arguments. |
---|
437 | |
---|
438 | (defun topological-sort (elements constraints tie-breaker) |
---|
439 | (let ((remaining-constraints constraints) |
---|
440 | (remaining-elements elements) |
---|
441 | (result ())) |
---|
442 | (loop |
---|
443 | (let ((minimal-elements |
---|
444 | (remove-if |
---|
445 | #'(lambda (class) |
---|
446 | (member class remaining-constraints |
---|
447 | :key #'cadr)) |
---|
448 | remaining-elements))) |
---|
449 | (when (null minimal-elements) |
---|
450 | (if (null remaining-elements) |
---|
451 | (return-from topological-sort result) |
---|
452 | (error "Inconsistent precedence graph."))) |
---|
453 | (let ((choice (if (null (cdr minimal-elements)) |
---|
454 | (car minimal-elements) |
---|
455 | (funcall tie-breaker |
---|
456 | minimal-elements |
---|
457 | result)))) |
---|
458 | (setq result (append result (list choice))) |
---|
459 | (setq remaining-elements |
---|
460 | (remove choice remaining-elements)) |
---|
461 | (setq remaining-constraints |
---|
462 | (remove choice |
---|
463 | remaining-constraints |
---|
464 | :test #'member))))))) |
---|
465 | |
---|
466 | ;;; In the event of a tie while topologically sorting class precedence lists, |
---|
467 | ;;; the CLOS Specification says to "select the one that has a direct subclass |
---|
468 | ;;; rightmost in the class precedence list computed so far." The same result |
---|
469 | ;;; is obtained by inspecting the partially constructed class precedence list |
---|
470 | ;;; from right to left, looking for the first minimal element to show up among |
---|
471 | ;;; the direct superclasses of the class precedence list constituent. |
---|
472 | ;;; (There's a lemma that shows that this rule yields a unique result.) |
---|
473 | |
---|
474 | (defun std-tie-breaker-rule (minimal-elements cpl-so-far) |
---|
475 | (dolist (cpl-constituent (reverse cpl-so-far)) |
---|
476 | (let* ((supers (class-direct-superclasses cpl-constituent)) |
---|
477 | (common (intersection minimal-elements supers))) |
---|
478 | (when (not (null common)) |
---|
479 | (return-from std-tie-breaker-rule (car common)))))) |
---|
480 | |
---|
481 | ;;; This version of collect-superclasses* isn't bothered by cycles in the class |
---|
482 | ;;; hierarchy, which sometimes happen by accident. |
---|
483 | |
---|
484 | (defun collect-superclasses* (class) |
---|
485 | (labels ((all-superclasses-loop (seen superclasses) |
---|
486 | (let ((to-be-processed |
---|
487 | (set-difference superclasses seen))) |
---|
488 | (if (null to-be-processed) |
---|
489 | superclasses |
---|
490 | (let ((class-to-process |
---|
491 | (car to-be-processed))) |
---|
492 | (all-superclasses-loop |
---|
493 | (cons class-to-process seen) |
---|
494 | (union (class-direct-superclasses |
---|
495 | class-to-process) |
---|
496 | superclasses))))))) |
---|
497 | (all-superclasses-loop () (list class)))) |
---|
498 | |
---|
499 | ;;; The local precedence ordering of a class C with direct superclasses C_1, |
---|
500 | ;;; C_2, ..., C_n is the set ((C C_1) (C_1 C_2) ...(C_n-1 C_n)). |
---|
501 | |
---|
502 | (defun local-precedence-ordering (class) |
---|
503 | (mapcar #'list |
---|
504 | (cons class |
---|
505 | (butlast (class-direct-superclasses class))) |
---|
506 | (class-direct-superclasses class))) |
---|
507 | |
---|
508 | ;;; Slot inheritance |
---|
509 | |
---|
510 | (defun std-compute-slots (class) |
---|
511 | (let* ((all-slots (mapappend #'class-direct-slots |
---|
512 | (class-precedence-list class))) |
---|
513 | (all-names (remove-duplicates |
---|
514 | (mapcar 'slot-definition-name all-slots)))) |
---|
515 | (mapcar #'(lambda (name) |
---|
516 | (funcall |
---|
517 | (if (eq (class-of class) +the-standard-class+) |
---|
518 | #'std-compute-effective-slot-definition |
---|
519 | #'compute-effective-slot-definition) |
---|
520 | class |
---|
521 | (remove name all-slots |
---|
522 | :key 'slot-definition-name |
---|
523 | :test-not #'eq))) |
---|
524 | all-names))) |
---|
525 | |
---|
526 | (defun std-compute-effective-slot-definition (class direct-slots) |
---|
527 | (let ((initer (find-if-not #'null direct-slots |
---|
528 | :key 'slot-definition-initfunction))) |
---|
529 | (make-effective-slot-definition |
---|
530 | class |
---|
531 | :name (slot-definition-name (car direct-slots)) |
---|
532 | :initform (if initer |
---|
533 | (slot-definition-initform initer) |
---|
534 | nil) |
---|
535 | :initfunction (if initer |
---|
536 | (slot-definition-initfunction initer) |
---|
537 | nil) |
---|
538 | :initargs (remove-duplicates |
---|
539 | (mapappend 'slot-definition-initargs |
---|
540 | direct-slots)) |
---|
541 | :allocation (slot-definition-allocation (car direct-slots)) |
---|
542 | :allocation-class (when (slot-boundp (car direct-slots) |
---|
543 | 'sys::allocation-class) |
---|
544 | ;;for some classes created in Java |
---|
545 | ;;(e.g. SimpleCondition) this slot is unbound |
---|
546 | (slot-definition-allocation-class (car direct-slots)))))) |
---|
547 | |
---|
548 | ;;; Standard instance slot access |
---|
549 | |
---|
550 | ;;; N.B. The location of the effective-slots slots in the class metaobject for |
---|
551 | ;;; standard-class must be determined without making any further slot |
---|
552 | ;;; references. |
---|
553 | |
---|
554 | (defun find-slot-definition (class slot-name) |
---|
555 | (dolist (slot (class-slots class) nil) |
---|
556 | (when (eq slot-name (slot-definition-name slot)) |
---|
557 | (return slot)))) |
---|
558 | |
---|
559 | (defun slot-location (class slot-name) |
---|
560 | (let ((slot (find-slot-definition class slot-name))) |
---|
561 | (if slot |
---|
562 | (slot-definition-location slot) |
---|
563 | nil))) |
---|
564 | |
---|
565 | (defun instance-slot-location (instance slot-name) |
---|
566 | (let ((layout (std-instance-layout instance))) |
---|
567 | (and layout (layout-slot-location layout slot-name)))) |
---|
568 | |
---|
569 | (defun slot-value (object slot-name) |
---|
570 | (if (or (eq (class-of (class-of object)) +the-standard-class+) |
---|
571 | (eq (class-of (class-of object)) +the-structure-class+)) |
---|
572 | (std-slot-value object slot-name) |
---|
573 | (slot-value-using-class (class-of object) object slot-name))) |
---|
574 | |
---|
575 | (defsetf std-slot-value set-std-slot-value) |
---|
576 | |
---|
577 | (defun %set-slot-value (object slot-name new-value) |
---|
578 | (if (or (eq (class-of (class-of object)) +the-standard-class+) |
---|
579 | (eq (class-of (class-of object)) +the-structure-class+)) |
---|
580 | (setf (std-slot-value object slot-name) new-value) |
---|
581 | (set-slot-value-using-class new-value (class-of object) |
---|
582 | object slot-name))) |
---|
583 | |
---|
584 | (defsetf slot-value %set-slot-value) |
---|
585 | |
---|
586 | (defun slot-boundp (object slot-name) |
---|
587 | (if (eq (class-of (class-of object)) +the-standard-class+) |
---|
588 | (std-slot-boundp object slot-name) |
---|
589 | (slot-boundp-using-class (class-of object) object slot-name))) |
---|
590 | |
---|
591 | (defun std-slot-makunbound (instance slot-name) |
---|
592 | (let ((location (instance-slot-location instance slot-name))) |
---|
593 | (cond ((fixnump location) |
---|
594 | (setf (standard-instance-access instance location) +slot-unbound+)) |
---|
595 | ((consp location) |
---|
596 | (setf (cdr location) +slot-unbound+)) |
---|
597 | (t |
---|
598 | (slot-missing (class-of instance) instance slot-name 'slot-makunbound)))) |
---|
599 | instance) |
---|
600 | |
---|
601 | (defun slot-makunbound (object slot-name) |
---|
602 | (if (eq (class-of (class-of object)) +the-standard-class+) |
---|
603 | (std-slot-makunbound object slot-name) |
---|
604 | (slot-makunbound-using-class (class-of object) object slot-name))) |
---|
605 | |
---|
606 | (defun std-slot-exists-p (instance slot-name) |
---|
607 | (not (null (find slot-name (class-slots (class-of instance)) |
---|
608 | :key 'slot-definition-name)))) |
---|
609 | |
---|
610 | (defun slot-exists-p (object slot-name) |
---|
611 | (if (eq (class-of (class-of object)) +the-standard-class+) |
---|
612 | (std-slot-exists-p object slot-name) |
---|
613 | (slot-exists-p-using-class (class-of object) object slot-name))) |
---|
614 | |
---|
615 | (defun instance-slot-p (slot) |
---|
616 | (eq (slot-definition-allocation slot) :instance)) |
---|
617 | |
---|
618 | (defun make-instance-standard-class (metaclass |
---|
619 | &rest initargs |
---|
620 | &key name direct-superclasses direct-slots |
---|
621 | direct-default-initargs |
---|
622 | documentation) |
---|
623 | (declare (ignore metaclass)) |
---|
624 | (let ((class (std-allocate-instance +the-standard-class+))) |
---|
625 | (check-initargs class t initargs) |
---|
626 | (%set-class-name name class) |
---|
627 | (%set-class-layout nil class) |
---|
628 | (%set-class-direct-subclasses () class) |
---|
629 | (%set-class-direct-methods () class) |
---|
630 | (%set-class-documentation class documentation) |
---|
631 | (std-after-initialization-for-classes class |
---|
632 | :direct-superclasses direct-superclasses |
---|
633 | :direct-slots direct-slots |
---|
634 | :direct-default-initargs direct-default-initargs) |
---|
635 | class)) |
---|
636 | |
---|
637 | ;(defun convert-to-direct-slot-definition (class canonicalized-slot) |
---|
638 | ; (apply #'make-instance |
---|
639 | ; (apply #'direct-slot-definition-class |
---|
640 | ; class canonicalized-slot) |
---|
641 | ; canonicalized-slot)) |
---|
642 | |
---|
643 | (defun std-after-initialization-for-classes (class |
---|
644 | &key direct-superclasses direct-slots |
---|
645 | direct-default-initargs |
---|
646 | &allow-other-keys) |
---|
647 | (let ((supers (or direct-superclasses |
---|
648 | (list +the-standard-object-class+)))) |
---|
649 | (setf (class-direct-superclasses class) supers) |
---|
650 | (dolist (superclass supers) |
---|
651 | (pushnew class (class-direct-subclasses superclass)))) |
---|
652 | (let ((slots (mapcar #'(lambda (slot-properties) |
---|
653 | (apply #'make-direct-slot-definition class slot-properties)) |
---|
654 | direct-slots))) |
---|
655 | (setf (class-direct-slots class) slots) |
---|
656 | (dolist (direct-slot slots) |
---|
657 | (dolist (reader (slot-definition-readers direct-slot)) |
---|
658 | (add-reader-method class reader (slot-definition-name direct-slot))) |
---|
659 | (dolist (writer (slot-definition-writers direct-slot)) |
---|
660 | (add-writer-method class writer (slot-definition-name direct-slot))))) |
---|
661 | (setf (class-direct-default-initargs class) direct-default-initargs) |
---|
662 | (funcall (if (eq (class-of class) +the-standard-class+) |
---|
663 | #'std-finalize-inheritance |
---|
664 | #'finalize-inheritance) |
---|
665 | class) |
---|
666 | (values)) |
---|
667 | |
---|
668 | (defun canonical-slot-name (canonical-slot) |
---|
669 | (getf canonical-slot :name)) |
---|
670 | |
---|
671 | (defvar *extensible-built-in-classes* |
---|
672 | (list (find-class 'sequence) |
---|
673 | (find-class 'java:java-object))) |
---|
674 | |
---|
675 | (defun ensure-class (name &rest all-keys &key metaclass &allow-other-keys) |
---|
676 | ;; Check for duplicate slots. |
---|
677 | (remf all-keys :metaclass) |
---|
678 | (let ((slots (getf all-keys :direct-slots))) |
---|
679 | (dolist (s1 slots) |
---|
680 | (let ((name1 (canonical-slot-name s1))) |
---|
681 | (dolist (s2 (cdr (memq s1 slots))) |
---|
682 | (when (eq name1 (canonical-slot-name s2)) |
---|
683 | (error 'program-error "Duplicate slot ~S" name1)))))) |
---|
684 | ;; Check for duplicate argument names in :DEFAULT-INITARGS. |
---|
685 | (let ((names ())) |
---|
686 | (do* ((initargs (getf all-keys :direct-default-initargs) (cddr initargs)) |
---|
687 | (name (car initargs) (car initargs))) |
---|
688 | ((null initargs)) |
---|
689 | (push name names)) |
---|
690 | (do* ((names names (cdr names)) |
---|
691 | (name (car names) (car names))) |
---|
692 | ((null names)) |
---|
693 | (when (memq name (cdr names)) |
---|
694 | (error 'program-error |
---|
695 | :format-control "Duplicate initialization argument name ~S in :DEFAULT-INITARGS." |
---|
696 | :format-arguments (list name))))) |
---|
697 | (let ((direct-superclasses (getf all-keys :direct-superclasses))) |
---|
698 | (dolist (class direct-superclasses) |
---|
699 | (when (and (typep class 'built-in-class) |
---|
700 | (not (member class *extensible-built-in-classes*))) |
---|
701 | (error "Attempt to define a subclass of a built-in-class: ~S" class)))) |
---|
702 | (let ((old-class (find-class name nil))) |
---|
703 | (cond ((and old-class (eq name (class-name old-class))) |
---|
704 | (cond ((typep old-class 'built-in-class) |
---|
705 | (error "The symbol ~S names a built-in class." name)) |
---|
706 | ((typep old-class 'forward-referenced-class) |
---|
707 | (let ((new-class (apply #'make-instance-standard-class |
---|
708 | +the-standard-class+ |
---|
709 | :name name all-keys))) |
---|
710 | (%set-find-class name new-class) |
---|
711 | (dolist (subclass (class-direct-subclasses old-class)) |
---|
712 | (setf (class-direct-superclasses subclass) |
---|
713 | (substitute new-class old-class |
---|
714 | (class-direct-superclasses subclass)))) |
---|
715 | new-class)) |
---|
716 | (t |
---|
717 | ;; We're redefining the class. |
---|
718 | (%make-instances-obsolete old-class) |
---|
719 | (check-initargs old-class t all-keys) |
---|
720 | (apply #'std-after-initialization-for-classes old-class all-keys) |
---|
721 | old-class))) |
---|
722 | (t |
---|
723 | (let ((class (apply (if metaclass |
---|
724 | #'make-instance |
---|
725 | #'make-instance-standard-class) |
---|
726 | (or metaclass |
---|
727 | +the-standard-class+) |
---|
728 | :name name all-keys))) |
---|
729 | (%set-find-class name class) |
---|
730 | class))))) |
---|
731 | |
---|
732 | (defmacro defclass (&whole form name direct-superclasses direct-slots &rest options) |
---|
733 | (unless (>= (length form) 3) |
---|
734 | (error 'program-error "Wrong number of arguments for DEFCLASS.")) |
---|
735 | (check-declaration-type name) |
---|
736 | `(ensure-class ',name |
---|
737 | :direct-superclasses |
---|
738 | (canonicalize-direct-superclasses ',direct-superclasses) |
---|
739 | :direct-slots |
---|
740 | ,(canonicalize-direct-slots direct-slots) |
---|
741 | ,@(canonicalize-defclass-options options))) |
---|
742 | |
---|
743 | (eval-when (:compile-toplevel :load-toplevel :execute) |
---|
744 | (defstruct method-combination |
---|
745 | name |
---|
746 | operator |
---|
747 | identity-with-one-argument |
---|
748 | documentation) |
---|
749 | |
---|
750 | (defun expand-short-defcombin (whole) |
---|
751 | (let* ((name (cadr whole)) |
---|
752 | (documentation |
---|
753 | (getf (cddr whole) :documentation "")) |
---|
754 | (identity-with-one-arg |
---|
755 | (getf (cddr whole) :identity-with-one-argument nil)) |
---|
756 | (operator |
---|
757 | (getf (cddr whole) :operator name))) |
---|
758 | `(progn |
---|
759 | (setf (get ',name 'method-combination-object) |
---|
760 | (make-method-combination :name ',name |
---|
761 | :operator ',operator |
---|
762 | :identity-with-one-argument ',identity-with-one-arg |
---|
763 | :documentation ',documentation)) |
---|
764 | ',name))) |
---|
765 | |
---|
766 | (defun expand-long-defcombin (whole) |
---|
767 | (declare (ignore whole)) |
---|
768 | (error "The long form of DEFINE-METHOD-COMBINATION is not implemented."))) |
---|
769 | |
---|
770 | (defmacro define-method-combination (&whole form &rest args) |
---|
771 | (declare (ignore args)) |
---|
772 | (if (and (cddr form) |
---|
773 | (listp (caddr form))) |
---|
774 | (expand-long-defcombin form) |
---|
775 | (expand-short-defcombin form))) |
---|
776 | |
---|
777 | (define-method-combination + :identity-with-one-argument t) |
---|
778 | (define-method-combination and :identity-with-one-argument t) |
---|
779 | (define-method-combination append :identity-with-one-argument nil) |
---|
780 | (define-method-combination list :identity-with-one-argument nil) |
---|
781 | (define-method-combination max :identity-with-one-argument t) |
---|
782 | (define-method-combination min :identity-with-one-argument t) |
---|
783 | (define-method-combination nconc :identity-with-one-argument t) |
---|
784 | (define-method-combination or :identity-with-one-argument t) |
---|
785 | (define-method-combination progn :identity-with-one-argument t) |
---|
786 | |
---|
787 | (defstruct eql-specializer |
---|
788 | object) |
---|
789 | |
---|
790 | (defparameter *eql-specializer-table* (make-hash-table :test 'eql)) |
---|
791 | |
---|
792 | (defun intern-eql-specializer (object) |
---|
793 | (or (gethash object *eql-specializer-table*) |
---|
794 | (setf (gethash object *eql-specializer-table*) |
---|
795 | (make-eql-specializer :object object)))) |
---|
796 | |
---|
797 | ;; MOP (p. 216) specifies the following reader generic functions: |
---|
798 | ;; generic-function-argument-precedence-order |
---|
799 | ;; generic-function-declarations |
---|
800 | ;; generic-function-lambda-list |
---|
801 | ;; generic-function-method-class |
---|
802 | ;; generic-function-method-combination |
---|
803 | ;; generic-function-methods |
---|
804 | ;; generic-function-name |
---|
805 | |
---|
806 | (defun generic-function-lambda-list (gf) |
---|
807 | (%generic-function-lambda-list gf)) |
---|
808 | (defsetf generic-function-lambda-list %set-generic-function-lambda-list) |
---|
809 | |
---|
810 | (defun (setf generic-function-documentation) (new-value gf) |
---|
811 | (set-generic-function-documentation gf new-value)) |
---|
812 | |
---|
813 | (defun (setf generic-function-initial-methods) (new-value gf) |
---|
814 | (set-generic-function-initial-methods gf new-value)) |
---|
815 | |
---|
816 | (defun (setf generic-function-methods) (new-value gf) |
---|
817 | (set-generic-function-methods gf new-value)) |
---|
818 | |
---|
819 | (defun (setf generic-function-method-class) (new-value gf) |
---|
820 | (set-generic-function-method-class gf new-value)) |
---|
821 | |
---|
822 | (defun (setf generic-function-method-combination) (new-value gf) |
---|
823 | (set-generic-function-method-combination gf new-value)) |
---|
824 | |
---|
825 | (defun (setf generic-function-argument-precedence-order) (new-value gf) |
---|
826 | (set-generic-function-argument-precedence-order gf new-value)) |
---|
827 | |
---|
828 | (declaim (ftype (function * t) classes-to-emf-table)) |
---|
829 | (defun classes-to-emf-table (gf) |
---|
830 | (generic-function-classes-to-emf-table gf)) |
---|
831 | |
---|
832 | (defun (setf classes-to-emf-table) (new-value gf) |
---|
833 | (set-generic-function-classes-to-emf-table gf new-value)) |
---|
834 | |
---|
835 | (defun (setf method-lambda-list) (new-value method) |
---|
836 | (set-method-lambda-list method new-value)) |
---|
837 | |
---|
838 | (defun (setf method-qualifiers) (new-value method) |
---|
839 | (set-method-qualifiers method new-value)) |
---|
840 | |
---|
841 | (defun (setf method-documentation) (new-value method) |
---|
842 | (set-method-documentation method new-value)) |
---|
843 | |
---|
844 | ;;; defgeneric |
---|
845 | |
---|
846 | (defmacro defgeneric (function-name lambda-list |
---|
847 | &rest options-and-method-descriptions) |
---|
848 | (let ((options ()) |
---|
849 | (methods ()) |
---|
850 | (documentation nil)) |
---|
851 | (dolist (item options-and-method-descriptions) |
---|
852 | (case (car item) |
---|
853 | (declare) ; FIXME |
---|
854 | (:documentation |
---|
855 | (when documentation |
---|
856 | (error 'program-error |
---|
857 | :format-control "Documentation option was specified twice for generic function ~S." |
---|
858 | :format-arguments (list function-name))) |
---|
859 | (setf documentation t) |
---|
860 | (push item options)) |
---|
861 | (:method |
---|
862 | (push |
---|
863 | `(push (defmethod ,function-name ,@(cdr item)) |
---|
864 | (generic-function-initial-methods (fdefinition ',function-name))) |
---|
865 | methods)) |
---|
866 | (t |
---|
867 | (push item options)))) |
---|
868 | (setf options (nreverse options) |
---|
869 | methods (nreverse methods)) |
---|
870 | `(prog1 |
---|
871 | (%defgeneric |
---|
872 | ',function-name |
---|
873 | :lambda-list ',lambda-list |
---|
874 | ,@(canonicalize-defgeneric-options options)) |
---|
875 | ,@methods))) |
---|
876 | |
---|
877 | (defun canonicalize-defgeneric-options (options) |
---|
878 | (mapappend #'canonicalize-defgeneric-option options)) |
---|
879 | |
---|
880 | (defun canonicalize-defgeneric-option (option) |
---|
881 | (case (car option) |
---|
882 | (:generic-function-class |
---|
883 | (list :generic-function-class `(find-class ',(cadr option)))) |
---|
884 | (:method-class |
---|
885 | (list :method-class `(find-class ',(cadr option)))) |
---|
886 | (:method-combination |
---|
887 | (list :method-combination `',(cdr option))) |
---|
888 | (:argument-precedence-order |
---|
889 | (list :argument-precedence-order `',(cdr option))) |
---|
890 | (t |
---|
891 | (list `',(car option) `',(cadr option))))) |
---|
892 | |
---|
893 | ;; From OpenMCL. |
---|
894 | (defun canonicalize-argument-precedence-order (apo req) |
---|
895 | (cond ((equal apo req) nil) |
---|
896 | ((not (eql (length apo) (length req))) |
---|
897 | (error 'program-error |
---|
898 | :format-control "Specified argument precedence order ~S does not match lambda list." |
---|
899 | :format-arguments (list apo))) |
---|
900 | (t (let ((res nil)) |
---|
901 | (dolist (arg apo (nreverse res)) |
---|
902 | (let ((index (position arg req))) |
---|
903 | (if (or (null index) (memq index res)) |
---|
904 | (error 'program-error |
---|
905 | :format-control "Specified argument precedence order ~S does not match lambda list." |
---|
906 | :format-arguments (list apo))) |
---|
907 | (push index res))))))) |
---|
908 | |
---|
909 | (defun find-generic-function (name &optional (errorp t)) |
---|
910 | (let ((function (and (fboundp name) (fdefinition name)))) |
---|
911 | (when function |
---|
912 | (when (typep function 'generic-function) |
---|
913 | (return-from find-generic-function function)) |
---|
914 | (when (and *traced-names* (find name *traced-names* :test #'equal)) |
---|
915 | (setf function (untraced-function name)) |
---|
916 | (when (typep function 'generic-function) |
---|
917 | (return-from find-generic-function function))))) |
---|
918 | (if errorp |
---|
919 | (error "There is no generic function named ~S." name) |
---|
920 | nil)) |
---|
921 | |
---|
922 | (defun lambda-lists-congruent-p (lambda-list1 lambda-list2) |
---|
923 | (let* ((plist1 (analyze-lambda-list lambda-list1)) |
---|
924 | (args1 (getf plist1 :required-args)) |
---|
925 | (plist2 (analyze-lambda-list lambda-list2)) |
---|
926 | (args2 (getf plist2 :required-args))) |
---|
927 | (= (length args1) (length args2)))) |
---|
928 | |
---|
929 | (defun %defgeneric (function-name &rest all-keys) |
---|
930 | (when (fboundp function-name) |
---|
931 | (let ((gf (fdefinition function-name))) |
---|
932 | (when (typep gf 'generic-function) |
---|
933 | ;; Remove methods defined by previous DEFGENERIC forms. |
---|
934 | (dolist (method (generic-function-initial-methods gf)) |
---|
935 | (%remove-method gf method)) |
---|
936 | (setf (generic-function-initial-methods gf) '())))) |
---|
937 | (apply 'ensure-generic-function function-name all-keys)) |
---|
938 | |
---|
939 | (defun ensure-generic-function (function-name |
---|
940 | &rest all-keys |
---|
941 | &key |
---|
942 | lambda-list |
---|
943 | (generic-function-class +the-standard-generic-function-class+) |
---|
944 | (method-class +the-standard-method-class+) |
---|
945 | (method-combination 'standard) |
---|
946 | (argument-precedence-order nil apo-p) |
---|
947 | documentation |
---|
948 | &allow-other-keys) |
---|
949 | (when (autoloadp function-name) |
---|
950 | (resolve function-name)) |
---|
951 | (let ((gf (find-generic-function function-name nil))) |
---|
952 | (if gf |
---|
953 | (progn |
---|
954 | (unless (or (null (generic-function-methods gf)) |
---|
955 | (lambda-lists-congruent-p lambda-list (generic-function-lambda-list gf))) |
---|
956 | (error 'simple-error |
---|
957 | :format-control "The lambda list ~S is incompatible with the existing methods of ~S." |
---|
958 | :format-arguments (list lambda-list gf))) |
---|
959 | (setf (generic-function-lambda-list gf) lambda-list) |
---|
960 | (setf (generic-function-documentation gf) documentation) |
---|
961 | (let* ((plist (analyze-lambda-list lambda-list)) |
---|
962 | (required-args (getf plist ':required-args))) |
---|
963 | (%set-gf-required-args gf required-args) |
---|
964 | (when apo-p |
---|
965 | (setf (generic-function-argument-precedence-order gf) |
---|
966 | (if argument-precedence-order |
---|
967 | (canonicalize-argument-precedence-order argument-precedence-order |
---|
968 | required-args) |
---|
969 | nil))) |
---|
970 | (finalize-generic-function gf)) |
---|
971 | gf) |
---|
972 | (progn |
---|
973 | (when (and (null *clos-booting*) |
---|
974 | (fboundp function-name)) |
---|
975 | (error 'program-error |
---|
976 | :format-control "~A already names an ordinary function, macro, or special operator." |
---|
977 | :format-arguments (list function-name))) |
---|
978 | (setf gf (apply (if (eq generic-function-class +the-standard-generic-function-class+) |
---|
979 | #'make-instance-standard-generic-function |
---|
980 | #'make-instance) |
---|
981 | generic-function-class |
---|
982 | :name function-name |
---|
983 | :method-class method-class |
---|
984 | :method-combination method-combination |
---|
985 | all-keys)) |
---|
986 | gf)))) |
---|
987 | |
---|
988 | (defun initial-discriminating-function (gf args) |
---|
989 | (set-funcallable-instance-function |
---|
990 | gf |
---|
991 | (funcall (if (eq (class-of gf) +the-standard-generic-function-class+) |
---|
992 | #'std-compute-discriminating-function |
---|
993 | #'compute-discriminating-function) |
---|
994 | gf)) |
---|
995 | (apply gf args)) |
---|
996 | |
---|
997 | (defun collect-eql-specializer-objects (generic-function) |
---|
998 | (let ((result nil)) |
---|
999 | (dolist (method (generic-function-methods generic-function)) |
---|
1000 | (dolist (specializer (%method-specializers method)) |
---|
1001 | (when (typep specializer 'eql-specializer) |
---|
1002 | (pushnew (eql-specializer-object specializer) |
---|
1003 | result |
---|
1004 | :test 'eql)))) |
---|
1005 | result)) |
---|
1006 | |
---|
1007 | (defun finalize-generic-function (gf) |
---|
1008 | (%finalize-generic-function gf) |
---|
1009 | (setf (classes-to-emf-table gf) (make-hash-table :test #'equal)) |
---|
1010 | (%init-eql-specializations gf (collect-eql-specializer-objects gf)) |
---|
1011 | (set-funcallable-instance-function |
---|
1012 | gf #'(lambda (&rest args) |
---|
1013 | (initial-discriminating-function gf args))) |
---|
1014 | ;; FIXME Do we need to warn on redefinition somewhere else? |
---|
1015 | (let ((*warn-on-redefinition* nil)) |
---|
1016 | (setf (fdefinition (%generic-function-name gf)) gf)) |
---|
1017 | (values)) |
---|
1018 | |
---|
1019 | (defun make-instance-standard-generic-function (generic-function-class |
---|
1020 | &key name lambda-list |
---|
1021 | method-class |
---|
1022 | method-combination |
---|
1023 | argument-precedence-order |
---|
1024 | documentation) |
---|
1025 | (declare (ignore generic-function-class)) |
---|
1026 | (let ((gf (std-allocate-instance +the-standard-generic-function-class+))) |
---|
1027 | (%set-generic-function-name gf name) |
---|
1028 | (setf (generic-function-lambda-list gf) lambda-list) |
---|
1029 | (setf (generic-function-initial-methods gf) ()) |
---|
1030 | (setf (generic-function-methods gf) ()) |
---|
1031 | (setf (generic-function-method-class gf) method-class) |
---|
1032 | (setf (generic-function-method-combination gf) method-combination) |
---|
1033 | (setf (generic-function-documentation gf) documentation) |
---|
1034 | (setf (classes-to-emf-table gf) nil) |
---|
1035 | (let* ((plist (analyze-lambda-list (generic-function-lambda-list gf))) |
---|
1036 | (required-args (getf plist ':required-args))) |
---|
1037 | (%set-gf-required-args gf required-args) |
---|
1038 | (setf (generic-function-argument-precedence-order gf) |
---|
1039 | (if argument-precedence-order |
---|
1040 | (canonicalize-argument-precedence-order argument-precedence-order |
---|
1041 | required-args) |
---|
1042 | nil))) |
---|
1043 | (finalize-generic-function gf) |
---|
1044 | gf)) |
---|
1045 | |
---|
1046 | (defun canonicalize-specializers (specializers) |
---|
1047 | (mapcar #'canonicalize-specializer specializers)) |
---|
1048 | |
---|
1049 | (defun canonicalize-specializer (specializer) |
---|
1050 | (cond ((classp specializer) |
---|
1051 | specializer) |
---|
1052 | ((eql-specializer-p specializer) |
---|
1053 | specializer) |
---|
1054 | ((symbolp specializer) |
---|
1055 | (find-class specializer)) |
---|
1056 | ((and (consp specializer) |
---|
1057 | (eq (car specializer) 'eql)) |
---|
1058 | (let ((object (cadr specializer))) |
---|
1059 | (when (and (consp object) |
---|
1060 | (eq (car object) 'quote)) |
---|
1061 | (setf object (cadr object))) |
---|
1062 | (intern-eql-specializer object))) |
---|
1063 | ((and (consp specializer) |
---|
1064 | (eq (car specializer) 'java:jclass)) |
---|
1065 | (let ((jclass (eval specializer))) |
---|
1066 | (java::ensure-java-class jclass))) |
---|
1067 | (t |
---|
1068 | (error "Unknown specializer: ~S" specializer)))) |
---|
1069 | |
---|
1070 | (defun parse-defmethod (args) |
---|
1071 | (let ((function-name (car args)) |
---|
1072 | (qualifiers ()) |
---|
1073 | (specialized-lambda-list ()) |
---|
1074 | (body ()) |
---|
1075 | (parse-state :qualifiers)) |
---|
1076 | (dolist (arg (cdr args)) |
---|
1077 | (ecase parse-state |
---|
1078 | (:qualifiers |
---|
1079 | (if (and (atom arg) (not (null arg))) |
---|
1080 | (push arg qualifiers) |
---|
1081 | (progn |
---|
1082 | (setf specialized-lambda-list arg) |
---|
1083 | (setf parse-state :body)))) |
---|
1084 | (:body (push arg body)))) |
---|
1085 | (setf qualifiers (nreverse qualifiers) |
---|
1086 | body (nreverse body)) |
---|
1087 | (multiple-value-bind (real-body declarations documentation) |
---|
1088 | (parse-body body) |
---|
1089 | (values function-name |
---|
1090 | qualifiers |
---|
1091 | (extract-lambda-list specialized-lambda-list) |
---|
1092 | (extract-specializers specialized-lambda-list) |
---|
1093 | documentation |
---|
1094 | declarations |
---|
1095 | (list* 'block |
---|
1096 | (fdefinition-block-name function-name) |
---|
1097 | real-body))))) |
---|
1098 | |
---|
1099 | (defun required-portion (gf args) |
---|
1100 | (let ((number-required (length (gf-required-args gf)))) |
---|
1101 | (when (< (length args) number-required) |
---|
1102 | (error 'program-error |
---|
1103 | :format-control "Not enough arguments for generic function ~S." |
---|
1104 | :format-arguments (list (%generic-function-name gf)))) |
---|
1105 | (subseq args 0 number-required))) |
---|
1106 | |
---|
1107 | (defun extract-lambda-list (specialized-lambda-list) |
---|
1108 | (let* ((plist (analyze-lambda-list specialized-lambda-list)) |
---|
1109 | (requireds (getf plist :required-names)) |
---|
1110 | (rv (getf plist :rest-var)) |
---|
1111 | (ks (getf plist :key-args)) |
---|
1112 | (keysp (getf plist :keysp)) |
---|
1113 | (aok (getf plist :allow-other-keys)) |
---|
1114 | (opts (getf plist :optional-args)) |
---|
1115 | (auxs (getf plist :auxiliary-args))) |
---|
1116 | `(,@requireds |
---|
1117 | ,@(if rv `(&rest ,rv) ()) |
---|
1118 | ,@(if (or ks keysp aok) `(&key ,@ks) ()) |
---|
1119 | ,@(if aok '(&allow-other-keys) ()) |
---|
1120 | ,@(if opts `(&optional ,@opts) ()) |
---|
1121 | ,@(if auxs `(&aux ,@auxs) ())))) |
---|
1122 | |
---|
1123 | (defun extract-specializers (specialized-lambda-list) |
---|
1124 | (let ((plist (analyze-lambda-list specialized-lambda-list))) |
---|
1125 | (getf plist ':specializers))) |
---|
1126 | |
---|
1127 | (defun get-keyword-from-arg (arg) |
---|
1128 | (if (listp arg) |
---|
1129 | (if (listp (car arg)) |
---|
1130 | (caar arg) |
---|
1131 | (make-keyword (car arg))) |
---|
1132 | (make-keyword arg))) |
---|
1133 | |
---|
1134 | (defun analyze-lambda-list (lambda-list) |
---|
1135 | (let ((keys ()) ; Just the keywords |
---|
1136 | (key-args ()) ; Keywords argument specs |
---|
1137 | (keysp nil) ; |
---|
1138 | (required-names ()) ; Just the variable names |
---|
1139 | (required-args ()) ; Variable names & specializers |
---|
1140 | (specializers ()) ; Just the specializers |
---|
1141 | (rest-var nil) |
---|
1142 | (optionals ()) |
---|
1143 | (auxs ()) |
---|
1144 | (allow-other-keys nil) |
---|
1145 | (state :parsing-required)) |
---|
1146 | (dolist (arg lambda-list) |
---|
1147 | (if (member arg lambda-list-keywords) |
---|
1148 | (ecase arg |
---|
1149 | (&optional |
---|
1150 | (setq state :parsing-optional)) |
---|
1151 | (&rest |
---|
1152 | (setq state :parsing-rest)) |
---|
1153 | (&key |
---|
1154 | (setq keysp t) |
---|
1155 | (setq state :parsing-key)) |
---|
1156 | (&allow-other-keys |
---|
1157 | (setq allow-other-keys 't)) |
---|
1158 | (&aux |
---|
1159 | (setq state :parsing-aux))) |
---|
1160 | (case state |
---|
1161 | (:parsing-required |
---|
1162 | (push-on-end arg required-args) |
---|
1163 | (if (listp arg) |
---|
1164 | (progn (push-on-end (car arg) required-names) |
---|
1165 | (push-on-end (cadr arg) specializers)) |
---|
1166 | (progn (push-on-end arg required-names) |
---|
1167 | (push-on-end 't specializers)))) |
---|
1168 | (:parsing-optional (push-on-end arg optionals)) |
---|
1169 | (:parsing-rest (setq rest-var arg)) |
---|
1170 | (:parsing-key |
---|
1171 | (push-on-end (get-keyword-from-arg arg) keys) |
---|
1172 | (push-on-end arg key-args)) |
---|
1173 | (:parsing-aux (push-on-end arg auxs))))) |
---|
1174 | (list :required-names required-names |
---|
1175 | :required-args required-args |
---|
1176 | :specializers specializers |
---|
1177 | :rest-var rest-var |
---|
1178 | :keywords keys |
---|
1179 | :key-args key-args |
---|
1180 | :keysp keysp |
---|
1181 | :auxiliary-args auxs |
---|
1182 | :optional-args optionals |
---|
1183 | :allow-other-keys allow-other-keys))) |
---|
1184 | |
---|
1185 | #+nil |
---|
1186 | (defun check-method-arg-info (gf arg-info method) |
---|
1187 | (multiple-value-bind (nreq nopt keysp restp allow-other-keys-p keywords) |
---|
1188 | (analyze-lambda-list (if (consp method) |
---|
1189 | (early-method-lambda-list method) |
---|
1190 | (method-lambda-list method))) |
---|
1191 | (flet ((lose (string &rest args) |
---|
1192 | (error 'simple-program-error |
---|
1193 | :format-control "~@<attempt to add the method~2I~_~S~I~_~ |
---|
1194 | to the generic function~2I~_~S;~I~_~ |
---|
1195 | but ~?~:>" |
---|
1196 | :format-arguments (list method gf string args))) |
---|
1197 | (comparison-description (x y) |
---|
1198 | (if (> x y) "more" "fewer"))) |
---|
1199 | (let ((gf-nreq (arg-info-number-required arg-info)) |
---|
1200 | (gf-nopt (arg-info-number-optional arg-info)) |
---|
1201 | (gf-key/rest-p (arg-info-key/rest-p arg-info)) |
---|
1202 | (gf-keywords (arg-info-keys arg-info))) |
---|
1203 | (unless (= nreq gf-nreq) |
---|
1204 | (lose |
---|
1205 | "the method has ~A required arguments than the generic function." |
---|
1206 | (comparison-description nreq gf-nreq))) |
---|
1207 | (unless (= nopt gf-nopt) |
---|
1208 | (lose |
---|
1209 | "the method has ~A optional arguments than the generic function." |
---|
1210 | (comparison-description nopt gf-nopt))) |
---|
1211 | (unless (eq (or keysp restp) gf-key/rest-p) |
---|
1212 | (lose |
---|
1213 | "the method and generic function differ in whether they accept~_~ |
---|
1214 | &REST or &KEY arguments.")) |
---|
1215 | (when (consp gf-keywords) |
---|
1216 | (unless (or (and restp (not keysp)) |
---|
1217 | allow-other-keys-p |
---|
1218 | (every (lambda (k) (memq k keywords)) gf-keywords)) |
---|
1219 | (lose "the method does not accept each of the &KEY arguments~2I~_~ |
---|
1220 | ~S." |
---|
1221 | gf-keywords))))))) |
---|
1222 | |
---|
1223 | (defun check-method-lambda-list (method-lambda-list gf-lambda-list) |
---|
1224 | (let* ((gf-restp (not (null (memq '&rest gf-lambda-list)))) |
---|
1225 | (gf-plist (analyze-lambda-list gf-lambda-list)) |
---|
1226 | (gf-keysp (getf gf-plist :keysp)) |
---|
1227 | (gf-keywords (getf gf-plist :keywords)) |
---|
1228 | (method-plist (analyze-lambda-list method-lambda-list)) |
---|
1229 | (method-restp (not (null (memq '&rest method-lambda-list)))) |
---|
1230 | (method-keysp (getf method-plist :keysp)) |
---|
1231 | (method-keywords (getf method-plist :keywords)) |
---|
1232 | (method-allow-other-keys-p (getf method-plist :allow-other-keys))) |
---|
1233 | (unless (= (length (getf gf-plist :required-args)) |
---|
1234 | (length (getf method-plist :required-args))) |
---|
1235 | (error "The method has the wrong number of required arguments for the generic function.")) |
---|
1236 | (unless (= (length (getf gf-plist :optional-args)) |
---|
1237 | (length (getf method-plist :optional-args))) |
---|
1238 | (error "The method has the wrong number of optional arguments for the generic function.")) |
---|
1239 | (unless (eq (or gf-restp gf-keysp) (or method-restp method-keysp)) |
---|
1240 | (error "The method and the generic function differ in whether they accept &REST or &KEY arguments.")) |
---|
1241 | (when (consp gf-keywords) |
---|
1242 | (unless (or (and method-restp (not method-keysp)) |
---|
1243 | method-allow-other-keys-p |
---|
1244 | (every (lambda (k) (memq k method-keywords)) gf-keywords)) |
---|
1245 | (error "The method does not accept all of the keyword arguments defined for the generic function."))))) |
---|
1246 | |
---|
1247 | (declaim (ftype (function * method) ensure-method)) |
---|
1248 | (defun ensure-method (name &rest all-keys) |
---|
1249 | (let ((method-lambda-list (getf all-keys :lambda-list)) |
---|
1250 | (gf (find-generic-function name nil))) |
---|
1251 | (if gf |
---|
1252 | (check-method-lambda-list method-lambda-list (generic-function-lambda-list gf)) |
---|
1253 | (setf gf (ensure-generic-function name :lambda-list method-lambda-list))) |
---|
1254 | (let ((method |
---|
1255 | (if (eq (generic-function-method-class gf) +the-standard-method-class+) |
---|
1256 | (apply #'make-instance-standard-method gf all-keys) |
---|
1257 | (apply #'make-instance (generic-function-method-class gf) all-keys)))) |
---|
1258 | (%add-method gf method) |
---|
1259 | method))) |
---|
1260 | |
---|
1261 | (defun make-instance-standard-method (gf |
---|
1262 | &key |
---|
1263 | lambda-list |
---|
1264 | qualifiers |
---|
1265 | specializers |
---|
1266 | documentation |
---|
1267 | function |
---|
1268 | fast-function) |
---|
1269 | (declare (ignore gf)) |
---|
1270 | (let ((method (std-allocate-instance +the-standard-method-class+))) |
---|
1271 | (setf (method-lambda-list method) lambda-list) |
---|
1272 | (setf (method-qualifiers method) qualifiers) |
---|
1273 | (%set-method-specializers method (canonicalize-specializers specializers)) |
---|
1274 | (setf (method-documentation method) documentation) |
---|
1275 | (%set-method-generic-function method nil) |
---|
1276 | (%set-method-function method function) |
---|
1277 | (%set-method-fast-function method fast-function) |
---|
1278 | method)) |
---|
1279 | |
---|
1280 | (defun %add-method (gf method) |
---|
1281 | (when (%method-generic-function method) |
---|
1282 | (error 'simple-error |
---|
1283 | :format-control "ADD-METHOD: ~S is a method of ~S." |
---|
1284 | :format-arguments (list method (%method-generic-function method)))) |
---|
1285 | ;; Remove existing method with same qualifiers and specializers (if any). |
---|
1286 | (let ((old-method (%find-method gf (method-qualifiers method) |
---|
1287 | (%method-specializers method) nil))) |
---|
1288 | (when old-method |
---|
1289 | (%remove-method gf old-method))) |
---|
1290 | (%set-method-generic-function method gf) |
---|
1291 | (push method (generic-function-methods gf)) |
---|
1292 | (dolist (specializer (%method-specializers method)) |
---|
1293 | (when (typep specializer 'class) ;; FIXME What about EQL specializer objects? |
---|
1294 | (pushnew method (class-direct-methods specializer)))) |
---|
1295 | (finalize-generic-function gf) |
---|
1296 | gf) |
---|
1297 | |
---|
1298 | (defun %remove-method (gf method) |
---|
1299 | (setf (generic-function-methods gf) |
---|
1300 | (remove method (generic-function-methods gf))) |
---|
1301 | (%set-method-generic-function method nil) |
---|
1302 | (dolist (specializer (%method-specializers method)) |
---|
1303 | (when (typep specializer 'class) ;; FIXME What about EQL specializer objects? |
---|
1304 | (setf (class-direct-methods specializer) |
---|
1305 | (remove method (class-direct-methods specializer))))) |
---|
1306 | (finalize-generic-function gf) |
---|
1307 | gf) |
---|
1308 | |
---|
1309 | (defun %find-method (gf qualifiers specializers &optional (errorp t)) |
---|
1310 | ;; "If the specializers argument does not correspond in length to the number |
---|
1311 | ;; of required arguments of the generic-function, an an error of type ERROR |
---|
1312 | ;; is signaled." |
---|
1313 | (unless (= (length specializers) (length (gf-required-args gf))) |
---|
1314 | (error "The specializers argument has length ~S, but ~S has ~S required parameters." |
---|
1315 | (length specializers) |
---|
1316 | gf |
---|
1317 | (length (gf-required-args gf)))) |
---|
1318 | (let* ((canonical-specializers (canonicalize-specializers specializers)) |
---|
1319 | (method |
---|
1320 | (find-if #'(lambda (method) |
---|
1321 | (and (equal qualifiers |
---|
1322 | (method-qualifiers method)) |
---|
1323 | (equal canonical-specializers |
---|
1324 | (%method-specializers method)))) |
---|
1325 | (generic-function-methods gf)))) |
---|
1326 | (if (and (null method) errorp) |
---|
1327 | (error "No such method for ~S." (%generic-function-name gf)) |
---|
1328 | method))) |
---|
1329 | |
---|
1330 | (defun fast-callable-p (gf) |
---|
1331 | (and (eq (generic-function-method-combination gf) 'standard) |
---|
1332 | (null (intersection (%generic-function-lambda-list gf) |
---|
1333 | '(&rest &optional &key &allow-other-keys &aux))))) |
---|
1334 | |
---|
1335 | (declaim (ftype (function * t) slow-method-lookup-1)) |
---|
1336 | |
---|
1337 | (declaim (ftype (function (t t t) t) slow-reader-lookup)) |
---|
1338 | (defun slow-reader-lookup (gf layout slot-name) |
---|
1339 | (let ((location (layout-slot-location layout slot-name))) |
---|
1340 | (cache-slot-location gf layout location) |
---|
1341 | location)) |
---|
1342 | |
---|
1343 | (defun std-compute-discriminating-function (gf) |
---|
1344 | (let ((code |
---|
1345 | (cond |
---|
1346 | ((and (= (length (generic-function-methods gf)) 1) |
---|
1347 | (typep (car (generic-function-methods gf)) 'standard-reader-method)) |
---|
1348 | ;; (sys::%format t "standard reader function ~S~%" (generic-function-name gf)) |
---|
1349 | |
---|
1350 | (let* ((method (%car (generic-function-methods gf))) |
---|
1351 | (class (car (%method-specializers method))) |
---|
1352 | (slot-name (reader-method-slot-name method))) |
---|
1353 | #'(lambda (arg) |
---|
1354 | (declare (optimize speed)) |
---|
1355 | (let* ((layout (std-instance-layout arg)) |
---|
1356 | (location (get-cached-slot-location gf layout))) |
---|
1357 | (unless location |
---|
1358 | (unless (simple-typep arg class) |
---|
1359 | ;; FIXME no applicable method |
---|
1360 | (error 'simple-type-error |
---|
1361 | :datum arg |
---|
1362 | :expected-type class)) |
---|
1363 | (setf location (slow-reader-lookup gf layout slot-name))) |
---|
1364 | (if (consp location) |
---|
1365 | ;; Shared slot. |
---|
1366 | (cdr location) |
---|
1367 | (standard-instance-access arg location)))))) |
---|
1368 | |
---|
1369 | (t |
---|
1370 | (let* ((emf-table (classes-to-emf-table gf)) |
---|
1371 | (number-required (length (gf-required-args gf))) |
---|
1372 | (lambda-list (%generic-function-lambda-list gf)) |
---|
1373 | (exact (null (intersection lambda-list |
---|
1374 | '(&rest &optional &key |
---|
1375 | &allow-other-keys &aux))))) |
---|
1376 | (if exact |
---|
1377 | (cond |
---|
1378 | ((= number-required 1) |
---|
1379 | (cond |
---|
1380 | ((and (eq (generic-function-method-combination gf) 'standard) |
---|
1381 | (= (length (generic-function-methods gf)) 1)) |
---|
1382 | (let* ((method (%car (generic-function-methods gf))) |
---|
1383 | (specializer (car (%method-specializers method))) |
---|
1384 | (function (or (%method-fast-function method) |
---|
1385 | (%method-function method)))) |
---|
1386 | (if (eql-specializer-p specializer) |
---|
1387 | (let ((specializer-object (eql-specializer-object specializer))) |
---|
1388 | #'(lambda (arg) |
---|
1389 | (declare (optimize speed)) |
---|
1390 | (if (eql arg specializer-object) |
---|
1391 | (funcall function arg) |
---|
1392 | (no-applicable-method gf (list arg))))) |
---|
1393 | #'(lambda (arg) |
---|
1394 | (declare (optimize speed)) |
---|
1395 | (unless (simple-typep arg specializer) |
---|
1396 | ;; FIXME no applicable method |
---|
1397 | (error 'simple-type-error |
---|
1398 | :datum arg |
---|
1399 | :expected-type specializer)) |
---|
1400 | (funcall function arg))))) |
---|
1401 | (t |
---|
1402 | #'(lambda (arg) |
---|
1403 | (declare (optimize speed)) |
---|
1404 | (let* ((specialization |
---|
1405 | (%get-arg-specialization gf arg)) |
---|
1406 | (emfun (or (gethash1 specialization |
---|
1407 | emf-table) |
---|
1408 | (slow-method-lookup-1 |
---|
1409 | gf arg specialization)))) |
---|
1410 | (if emfun |
---|
1411 | (funcall emfun (list arg)) |
---|
1412 | (apply #'no-applicable-method gf (list arg)))))))) |
---|
1413 | ((= number-required 2) |
---|
1414 | #'(lambda (arg1 arg2) |
---|
1415 | (declare (optimize speed)) |
---|
1416 | (let* ((args (list arg1 arg2)) |
---|
1417 | (emfun (get-cached-emf gf args))) |
---|
1418 | (if emfun |
---|
1419 | (funcall emfun args) |
---|
1420 | (slow-method-lookup gf args))))) |
---|
1421 | ((= number-required 3) |
---|
1422 | #'(lambda (arg1 arg2 arg3) |
---|
1423 | (declare (optimize speed)) |
---|
1424 | (let* ((args (list arg1 arg2 arg3)) |
---|
1425 | (emfun (get-cached-emf gf args))) |
---|
1426 | (if emfun |
---|
1427 | (funcall emfun args) |
---|
1428 | (slow-method-lookup gf args))))) |
---|
1429 | (t |
---|
1430 | #'(lambda (&rest args) |
---|
1431 | (declare (optimize speed)) |
---|
1432 | (let ((len (length args))) |
---|
1433 | (unless (= len number-required) |
---|
1434 | (error 'program-error |
---|
1435 | :format-control "Not enough arguments for generic function ~S." |
---|
1436 | :format-arguments (list (%generic-function-name gf))))) |
---|
1437 | (let ((emfun (get-cached-emf gf args))) |
---|
1438 | (if emfun |
---|
1439 | (funcall emfun args) |
---|
1440 | (slow-method-lookup gf args)))))) |
---|
1441 | #'(lambda (&rest args) |
---|
1442 | (declare (optimize speed)) |
---|
1443 | (let ((len (length args))) |
---|
1444 | (unless (>= len number-required) |
---|
1445 | (error 'program-error |
---|
1446 | :format-control "Not enough arguments for generic function ~S." |
---|
1447 | :format-arguments (list (%generic-function-name gf))))) |
---|
1448 | (let ((emfun (get-cached-emf gf args))) |
---|
1449 | (if emfun |
---|
1450 | (funcall emfun args) |
---|
1451 | (slow-method-lookup gf args)))))))))) |
---|
1452 | |
---|
1453 | code)) |
---|
1454 | |
---|
1455 | (defun sort-methods (methods gf required-classes) |
---|
1456 | (if (or (null methods) (null (%cdr methods))) |
---|
1457 | methods |
---|
1458 | (sort methods |
---|
1459 | (if (eq (class-of gf) +the-standard-generic-function-class+) |
---|
1460 | #'(lambda (m1 m2) |
---|
1461 | (std-method-more-specific-p m1 m2 required-classes |
---|
1462 | (generic-function-argument-precedence-order gf))) |
---|
1463 | #'(lambda (m1 m2) |
---|
1464 | (method-more-specific-p gf m1 m2 required-classes)))))) |
---|
1465 | |
---|
1466 | (defun method-applicable-p (method args) |
---|
1467 | (do* ((specializers (%method-specializers method) (cdr specializers)) |
---|
1468 | (args args (cdr args))) |
---|
1469 | ((null specializers) t) |
---|
1470 | (let ((specializer (car specializers))) |
---|
1471 | (if (typep specializer 'eql-specializer) |
---|
1472 | (unless (eql (car args) (eql-specializer-object specializer)) |
---|
1473 | (return nil)) |
---|
1474 | (unless (subclassp (class-of (car args)) specializer) |
---|
1475 | (return nil)))))) |
---|
1476 | |
---|
1477 | (defun %compute-applicable-methods (gf args) |
---|
1478 | (let ((required-classes (mapcar #'class-of (required-portion gf args))) |
---|
1479 | (methods '())) |
---|
1480 | (dolist (method (generic-function-methods gf)) |
---|
1481 | (when (method-applicable-p method args) |
---|
1482 | (push method methods))) |
---|
1483 | (sort-methods methods gf required-classes))) |
---|
1484 | |
---|
1485 | ;;; METHOD-APPLICABLE-USING-CLASSES-P |
---|
1486 | ;;; |
---|
1487 | ;;; If the first return value is T, METHOD is definitely applicable to |
---|
1488 | ;;; arguments that are instances of CLASSES. If the first value is |
---|
1489 | ;;; NIL and the second value is T, METHOD is definitely not applicable |
---|
1490 | ;;; to arguments that are instances of CLASSES; if the second value is |
---|
1491 | ;;; NIL the applicability of METHOD cannot be determined by inspecting |
---|
1492 | ;;; the classes of its arguments only. |
---|
1493 | ;;; |
---|
1494 | (defun method-applicable-using-classes-p (method classes) |
---|
1495 | (do* ((specializers (%method-specializers method) (cdr specializers)) |
---|
1496 | (classes classes (cdr classes)) |
---|
1497 | (knownp t)) |
---|
1498 | ((null specializers) |
---|
1499 | (if knownp (values t t) (values nil nil))) |
---|
1500 | (let ((specializer (car specializers))) |
---|
1501 | (if (typep specializer 'eql-specializer) |
---|
1502 | (if (eql (class-of (eql-specializer-object specializer)) |
---|
1503 | (car classes)) |
---|
1504 | (setf knownp nil) |
---|
1505 | (return (values nil t))) |
---|
1506 | (unless (subclassp (car classes) specializer) |
---|
1507 | (return (values nil t))))))) |
---|
1508 | |
---|
1509 | (defun slow-method-lookup (gf args) |
---|
1510 | (let ((applicable-methods (%compute-applicable-methods gf args))) |
---|
1511 | (if applicable-methods |
---|
1512 | (let ((emfun (funcall (if (eq (class-of gf) +the-standard-generic-function-class+) |
---|
1513 | #'std-compute-effective-method-function |
---|
1514 | #'compute-effective-method-function) |
---|
1515 | gf applicable-methods))) |
---|
1516 | (cache-emf gf args emfun) |
---|
1517 | (funcall emfun args)) |
---|
1518 | (apply #'no-applicable-method gf args)))) |
---|
1519 | |
---|
1520 | (defun slow-method-lookup-1 (gf arg arg-specialization) |
---|
1521 | (let ((applicable-methods (%compute-applicable-methods gf (list arg)))) |
---|
1522 | (if applicable-methods |
---|
1523 | (let ((emfun (funcall (if (eq (class-of gf) +the-standard-generic-function-class+) |
---|
1524 | #'std-compute-effective-method-function |
---|
1525 | #'compute-effective-method-function) |
---|
1526 | gf applicable-methods))) |
---|
1527 | (when emfun |
---|
1528 | (setf (gethash arg-specialization (classes-to-emf-table gf)) emfun)) |
---|
1529 | emfun)))) |
---|
1530 | |
---|
1531 | (defun sub-specializer-p (c1 c2 c-arg) |
---|
1532 | (find c2 (cdr (memq c1 (%class-precedence-list c-arg))))) |
---|
1533 | |
---|
1534 | (defun std-method-more-specific-p (method1 method2 required-classes argument-precedence-order) |
---|
1535 | (if argument-precedence-order |
---|
1536 | (let ((specializers-1 (%method-specializers method1)) |
---|
1537 | (specializers-2 (%method-specializers method2))) |
---|
1538 | (dolist (index argument-precedence-order) |
---|
1539 | (let ((spec1 (nth index specializers-1)) |
---|
1540 | (spec2 (nth index specializers-2))) |
---|
1541 | (unless (eq spec1 spec2) |
---|
1542 | (cond ((eql-specializer-p spec1) |
---|
1543 | (return t)) |
---|
1544 | ((eql-specializer-p spec2) |
---|
1545 | (return nil)) |
---|
1546 | (t |
---|
1547 | (return (sub-specializer-p spec1 spec2 |
---|
1548 | (nth index required-classes))))))))) |
---|
1549 | (do ((specializers-1 (%method-specializers method1) (cdr specializers-1)) |
---|
1550 | (specializers-2 (%method-specializers method2) (cdr specializers-2)) |
---|
1551 | (classes required-classes (cdr classes))) |
---|
1552 | ((null specializers-1) nil) |
---|
1553 | (let ((spec1 (car specializers-1)) |
---|
1554 | (spec2 (car specializers-2))) |
---|
1555 | (unless (eq spec1 spec2) |
---|
1556 | (cond ((eql-specializer-p spec1) |
---|
1557 | (return t)) |
---|
1558 | ((eql-specializer-p spec2) |
---|
1559 | (return nil)) |
---|
1560 | (t |
---|
1561 | (return (sub-specializer-p spec1 spec2 (car classes)))))))))) |
---|
1562 | |
---|
1563 | (defun primary-method-p (method) |
---|
1564 | (null (intersection '(:before :after :around) (method-qualifiers method)))) |
---|
1565 | |
---|
1566 | (defun before-method-p (method) |
---|
1567 | (equal '(:before) (method-qualifiers method))) |
---|
1568 | |
---|
1569 | (defun after-method-p (method) |
---|
1570 | (equal '(:after) (method-qualifiers method))) |
---|
1571 | |
---|
1572 | (defun around-method-p (method) |
---|
1573 | (equal '(:around) (method-qualifiers method))) |
---|
1574 | |
---|
1575 | (defun std-compute-effective-method-function (gf methods) |
---|
1576 | (let* ((mc (generic-function-method-combination gf)) |
---|
1577 | (mc-name (if (atom mc) mc (%car mc))) |
---|
1578 | (options (if (atom mc) '() (%cdr mc))) |
---|
1579 | (order (car options)) |
---|
1580 | (primaries '()) |
---|
1581 | (arounds '()) |
---|
1582 | around |
---|
1583 | emf-form) |
---|
1584 | (dolist (m methods) |
---|
1585 | (let ((qualifiers (method-qualifiers m))) |
---|
1586 | (cond ((null qualifiers) |
---|
1587 | (if (eq mc-name 'standard) |
---|
1588 | (push m primaries) |
---|
1589 | (error "Method combination type mismatch."))) |
---|
1590 | ((cdr qualifiers) |
---|
1591 | (error "Invalid method qualifiers.")) |
---|
1592 | ((eq (car qualifiers) :around) |
---|
1593 | (push m arounds)) |
---|
1594 | ((eq (car qualifiers) mc-name) |
---|
1595 | (push m primaries)) |
---|
1596 | ((memq (car qualifiers) '(:before :after))) |
---|
1597 | (t |
---|
1598 | (error "Invalid method qualifiers."))))) |
---|
1599 | (unless (eq order :most-specific-last) |
---|
1600 | (setf primaries (nreverse primaries))) |
---|
1601 | (setf arounds (nreverse arounds)) |
---|
1602 | (setf around (car arounds)) |
---|
1603 | (when (null primaries) |
---|
1604 | (error "No primary methods for the generic function ~S." gf)) |
---|
1605 | (cond |
---|
1606 | (around |
---|
1607 | (let ((next-emfun |
---|
1608 | (funcall |
---|
1609 | (if (eq (class-of gf) +the-standard-generic-function-class+) |
---|
1610 | #'std-compute-effective-method-function |
---|
1611 | #'compute-effective-method-function) |
---|
1612 | gf (remove around methods)))) |
---|
1613 | (setf emf-form |
---|
1614 | ;;; `(lambda (args) |
---|
1615 | ;;; (funcall ,(%method-function around) args ,next-emfun)) |
---|
1616 | (generate-emf-lambda (%method-function around) next-emfun) |
---|
1617 | ))) |
---|
1618 | ((eq mc-name 'standard) |
---|
1619 | (let* ((next-emfun (compute-primary-emfun (cdr primaries))) |
---|
1620 | (befores (remove-if-not #'before-method-p methods)) |
---|
1621 | (reverse-afters |
---|
1622 | (reverse (remove-if-not #'after-method-p methods)))) |
---|
1623 | (setf emf-form |
---|
1624 | (cond |
---|
1625 | ((and (null befores) (null reverse-afters)) |
---|
1626 | (let ((fast-function (%method-fast-function (car primaries)))) |
---|
1627 | |
---|
1628 | (if fast-function |
---|
1629 | (ecase (length (gf-required-args gf)) |
---|
1630 | (1 |
---|
1631 | #'(lambda (args) |
---|
1632 | (declare (optimize speed)) |
---|
1633 | (funcall fast-function (car args)))) |
---|
1634 | (2 |
---|
1635 | #'(lambda (args) |
---|
1636 | (declare (optimize speed)) |
---|
1637 | (funcall fast-function (car args) (cadr args))))) |
---|
1638 | ;; `(lambda (args) |
---|
1639 | ;; (declare (optimize speed)) |
---|
1640 | ;; (funcall ,(%method-function (car primaries)) args ,next-emfun)) |
---|
1641 | (generate-emf-lambda (%method-function (car primaries)) |
---|
1642 | next-emfun)))) |
---|
1643 | (t |
---|
1644 | (let ((method-function (%method-function (car primaries)))) |
---|
1645 | |
---|
1646 | #'(lambda (args) |
---|
1647 | (declare (optimize speed)) |
---|
1648 | (dolist (before befores) |
---|
1649 | (funcall (%method-function before) args nil)) |
---|
1650 | (multiple-value-prog1 |
---|
1651 | (funcall method-function args next-emfun) |
---|
1652 | (dolist (after reverse-afters) |
---|
1653 | (funcall (%method-function after) args nil)))))))))) |
---|
1654 | (t |
---|
1655 | (let ((mc-obj (get mc-name 'method-combination-object))) |
---|
1656 | (unless mc-obj |
---|
1657 | (error "Unsupported method combination type ~A." mc-name)) |
---|
1658 | (let* ((operator (method-combination-operator mc-obj)) |
---|
1659 | (ioa (method-combination-identity-with-one-argument mc-obj))) |
---|
1660 | (setf emf-form |
---|
1661 | (if (and (null (cdr primaries)) |
---|
1662 | (not (null ioa))) |
---|
1663 | ;; `(lambda (args) |
---|
1664 | ;; (funcall ,(%method-function (car primaries)) args nil)) |
---|
1665 | (generate-emf-lambda (%method-function (car primaries)) nil) |
---|
1666 | `(lambda (args) |
---|
1667 | (,operator ,@(mapcar |
---|
1668 | (lambda (primary) |
---|
1669 | `(funcall ,(%method-function primary) args nil)) |
---|
1670 | primaries))))))))) |
---|
1671 | (or (ignore-errors (autocompile emf-form)) |
---|
1672 | (coerce-to-function emf-form)))) |
---|
1673 | |
---|
1674 | (defun generate-emf-lambda (method-function next-emfun) |
---|
1675 | #'(lambda (args) |
---|
1676 | (declare (optimize speed)) |
---|
1677 | (funcall method-function args next-emfun))) |
---|
1678 | |
---|
1679 | ;;; compute an effective method function from a list of primary methods: |
---|
1680 | |
---|
1681 | (defun compute-primary-emfun (methods) |
---|
1682 | (if (null methods) |
---|
1683 | nil |
---|
1684 | (let ((next-emfun (compute-primary-emfun (cdr methods)))) |
---|
1685 | #'(lambda (args) |
---|
1686 | (funcall (%method-function (car methods)) args next-emfun))))) |
---|
1687 | |
---|
1688 | (defvar *call-next-method-p*) |
---|
1689 | (defvar *next-method-p-p*) |
---|
1690 | |
---|
1691 | (defun walk-form (form) |
---|
1692 | (cond ((atom form) |
---|
1693 | (cond ((eq form 'call-next-method) |
---|
1694 | (setf *call-next-method-p* t)) |
---|
1695 | ((eq form 'next-method-p) |
---|
1696 | (setf *next-method-p-p* t)))) |
---|
1697 | (t |
---|
1698 | (walk-form (%car form)) |
---|
1699 | (walk-form (%cdr form))))) |
---|
1700 | |
---|
1701 | (defun compute-method-function (lambda-expression) |
---|
1702 | (let ((lambda-list (allow-other-keys (cadr lambda-expression))) |
---|
1703 | (body (cddr lambda-expression)) |
---|
1704 | (*call-next-method-p* nil) |
---|
1705 | (*next-method-p-p* nil)) |
---|
1706 | (multiple-value-bind (body declarations) (parse-body body) |
---|
1707 | (let ((ignorable-vars '())) |
---|
1708 | (dolist (var lambda-list) |
---|
1709 | (if (memq var lambda-list-keywords) |
---|
1710 | (return) |
---|
1711 | (push var ignorable-vars))) |
---|
1712 | (push `(declare (ignorable ,@ignorable-vars)) declarations)) |
---|
1713 | (walk-form body) |
---|
1714 | (cond ((or *call-next-method-p* *next-method-p-p*) |
---|
1715 | `(lambda (args next-emfun) |
---|
1716 | (flet ((call-next-method (&rest cnm-args) |
---|
1717 | (if (null next-emfun) |
---|
1718 | (error "No next method for generic function.") |
---|
1719 | (funcall next-emfun (or cnm-args args)))) |
---|
1720 | (next-method-p () |
---|
1721 | (not (null next-emfun)))) |
---|
1722 | (declare (ignorable (function call-next-method) |
---|
1723 | (function next-method-p))) |
---|
1724 | (apply #'(lambda ,lambda-list ,@declarations ,@body) args)))) |
---|
1725 | ((null (intersection lambda-list '(&rest &optional &key &allow-other-keys &aux))) |
---|
1726 | ;; Required parameters only. |
---|
1727 | (case (length lambda-list) |
---|
1728 | (1 |
---|
1729 | `(lambda (args next-emfun) |
---|
1730 | (declare (ignore next-emfun)) |
---|
1731 | (let ((,(%car lambda-list) (%car args))) |
---|
1732 | (declare (ignorable ,(%car lambda-list))) |
---|
1733 | ,@declarations ,@body))) |
---|
1734 | (2 |
---|
1735 | `(lambda (args next-emfun) |
---|
1736 | (declare (ignore next-emfun)) |
---|
1737 | (let ((,(%car lambda-list) (%car args)) |
---|
1738 | (,(%cadr lambda-list) (%cadr args))) |
---|
1739 | (declare (ignorable ,(%car lambda-list) |
---|
1740 | ,(%cadr lambda-list))) |
---|
1741 | ,@declarations ,@body))) |
---|
1742 | (3 |
---|
1743 | `(lambda (args next-emfun) |
---|
1744 | (declare (ignore next-emfun)) |
---|
1745 | (let ((,(%car lambda-list) (%car args)) |
---|
1746 | (,(%cadr lambda-list) (%cadr args)) |
---|
1747 | (,(%caddr lambda-list) (%caddr args))) |
---|
1748 | (declare (ignorable ,(%car lambda-list) |
---|
1749 | ,(%cadr lambda-list) |
---|
1750 | ,(%caddr lambda-list))) |
---|
1751 | ,@declarations ,@body))) |
---|
1752 | (t |
---|
1753 | `(lambda (args next-emfun) |
---|
1754 | (declare (ignore next-emfun)) |
---|
1755 | (apply #'(lambda ,lambda-list ,@declarations ,@body) args))))) |
---|
1756 | (t |
---|
1757 | `(lambda (args next-emfun) |
---|
1758 | (declare (ignore next-emfun)) |
---|
1759 | (apply #'(lambda ,lambda-list ,@declarations ,@body) args))))))) |
---|
1760 | |
---|
1761 | (defun compute-method-fast-function (lambda-expression) |
---|
1762 | (let ((lambda-list (allow-other-keys (cadr lambda-expression)))) |
---|
1763 | (when (intersection lambda-list '(&rest &optional &key &allow-other-keys &aux)) |
---|
1764 | (return-from compute-method-fast-function nil)) |
---|
1765 | ;; Only required args. |
---|
1766 | (let ((body (cddr lambda-expression)) |
---|
1767 | (*call-next-method-p* nil) |
---|
1768 | (*next-method-p-p* nil)) |
---|
1769 | (multiple-value-bind (body declarations) (parse-body body) |
---|
1770 | (walk-form body) |
---|
1771 | (when (or *call-next-method-p* *next-method-p-p*) |
---|
1772 | (return-from compute-method-fast-function nil)) |
---|
1773 | (let ((decls `(declare (ignorable ,@lambda-list)))) |
---|
1774 | (setf lambda-expression |
---|
1775 | (list* (car lambda-expression) |
---|
1776 | (cadr lambda-expression) |
---|
1777 | decls |
---|
1778 | (cddr lambda-expression)))) |
---|
1779 | (case (length lambda-list) |
---|
1780 | (1 |
---|
1781 | ;; `(lambda (args next-emfun) |
---|
1782 | ;; (let ((,(%car lambda-list) (%car args))) |
---|
1783 | ;; (declare (ignorable ,(%car lambda-list))) |
---|
1784 | ;; ,@declarations ,@body))) |
---|
1785 | lambda-expression) |
---|
1786 | (2 |
---|
1787 | ;; `(lambda (args next-emfun) |
---|
1788 | ;; (let ((,(%car lambda-list) (%car args)) |
---|
1789 | ;; (,(%cadr lambda-list) (%cadr args))) |
---|
1790 | ;; (declare (ignorable ,(%car lambda-list) |
---|
1791 | ;; ,(%cadr lambda-list))) |
---|
1792 | ;; ,@declarations ,@body))) |
---|
1793 | lambda-expression) |
---|
1794 | ;; (3 |
---|
1795 | ;; `(lambda (args next-emfun) |
---|
1796 | ;; (let ((,(%car lambda-list) (%car args)) |
---|
1797 | ;; (,(%cadr lambda-list) (%cadr args)) |
---|
1798 | ;; (,(%caddr lambda-list) (%caddr args))) |
---|
1799 | ;; (declare (ignorable ,(%car lambda-list) |
---|
1800 | ;; ,(%cadr lambda-list) |
---|
1801 | ;; ,(%caddr lambda-list))) |
---|
1802 | ;; ,@declarations ,@body))) |
---|
1803 | (t |
---|
1804 | nil)))))) |
---|
1805 | |
---|
1806 | ;; From CLHS section 7.6.5: |
---|
1807 | ;; "When a generic function or any of its methods mentions &key in a lambda |
---|
1808 | ;; list, the specific set of keyword arguments accepted by the generic function |
---|
1809 | ;; varies according to the applicable methods. The set of keyword arguments |
---|
1810 | ;; accepted by the generic function for a particular call is the union of the |
---|
1811 | ;; keyword arguments accepted by all applicable methods and the keyword |
---|
1812 | ;; arguments mentioned after &key in the generic function definition, if any." |
---|
1813 | ;; Adapted from Sacla. |
---|
1814 | (defun allow-other-keys (lambda-list) |
---|
1815 | (if (and (member '&key lambda-list) |
---|
1816 | (not (member '&allow-other-keys lambda-list))) |
---|
1817 | (let* ((key-end (or (position '&aux lambda-list) (length lambda-list))) |
---|
1818 | (aux-part (subseq lambda-list key-end))) |
---|
1819 | `(,@(subseq lambda-list 0 key-end) &allow-other-keys ,@aux-part)) |
---|
1820 | lambda-list)) |
---|
1821 | |
---|
1822 | (defmacro defmethod (&rest args) |
---|
1823 | (multiple-value-bind |
---|
1824 | (function-name qualifiers lambda-list specializers documentation declarations body) |
---|
1825 | (parse-defmethod args) |
---|
1826 | (let* ((specializers-form '()) |
---|
1827 | (lambda-expression `(lambda ,lambda-list ,@declarations ,body)) |
---|
1828 | (method-function (compute-method-function lambda-expression)) |
---|
1829 | (fast-function (compute-method-fast-function lambda-expression)) |
---|
1830 | ) |
---|
1831 | (dolist (specializer specializers) |
---|
1832 | (cond ((and (consp specializer) (eq (car specializer) 'eql)) |
---|
1833 | (push `(list 'eql ,(cadr specializer)) specializers-form)) |
---|
1834 | (t |
---|
1835 | (push `',specializer specializers-form)))) |
---|
1836 | (setf specializers-form `(list ,@(nreverse specializers-form))) |
---|
1837 | `(progn |
---|
1838 | (ensure-method ',function-name |
---|
1839 | :lambda-list ',lambda-list |
---|
1840 | :qualifiers ',qualifiers |
---|
1841 | :specializers ,specializers-form |
---|
1842 | ,@(if documentation `(:documentation ,documentation)) |
---|
1843 | :function (function ,method-function) |
---|
1844 | ,@(if fast-function `(:fast-function (function ,fast-function))) |
---|
1845 | ))))) |
---|
1846 | |
---|
1847 | ;;; Reader and writer methods |
---|
1848 | |
---|
1849 | (defun make-instance-standard-reader-method (gf |
---|
1850 | &key |
---|
1851 | lambda-list |
---|
1852 | qualifiers |
---|
1853 | specializers |
---|
1854 | documentation |
---|
1855 | function |
---|
1856 | fast-function |
---|
1857 | slot-name) |
---|
1858 | (declare (ignore gf)) |
---|
1859 | (let ((method (std-allocate-instance +the-standard-reader-method-class+))) |
---|
1860 | (setf (method-lambda-list method) lambda-list) |
---|
1861 | (setf (method-qualifiers method) qualifiers) |
---|
1862 | (%set-method-specializers method (canonicalize-specializers specializers)) |
---|
1863 | (setf (method-documentation method) documentation) |
---|
1864 | (%set-method-generic-function method nil) |
---|
1865 | (%set-method-function method function) |
---|
1866 | (%set-method-fast-function method fast-function) |
---|
1867 | (set-reader-method-slot-name method slot-name) |
---|
1868 | method)) |
---|
1869 | |
---|
1870 | (defun add-reader-method (class function-name slot-name) |
---|
1871 | (let* ((lambda-expression |
---|
1872 | (if (eq (class-of class) +the-standard-class+) |
---|
1873 | `(lambda (object) (std-slot-value object ',slot-name)) |
---|
1874 | `(lambda (object) (slot-value object ',slot-name)))) |
---|
1875 | (method-function (compute-method-function lambda-expression)) |
---|
1876 | (fast-function (compute-method-fast-function lambda-expression))) |
---|
1877 | (let ((method-lambda-list '(object)) |
---|
1878 | (gf (find-generic-function function-name nil))) |
---|
1879 | (if gf |
---|
1880 | (check-method-lambda-list method-lambda-list (generic-function-lambda-list gf)) |
---|
1881 | (setf gf (ensure-generic-function function-name :lambda-list method-lambda-list))) |
---|
1882 | (let ((method |
---|
1883 | (make-instance-standard-reader-method gf |
---|
1884 | :lambda-list '(object) |
---|
1885 | :qualifiers () |
---|
1886 | :specializers (list class) |
---|
1887 | :function (if (autoloadp 'compile) |
---|
1888 | method-function |
---|
1889 | (autocompile method-function)) |
---|
1890 | :fast-function (if (autoloadp 'compile) |
---|
1891 | fast-function |
---|
1892 | (autocompile fast-function)) |
---|
1893 | :slot-name slot-name))) |
---|
1894 | (%add-method gf method) |
---|
1895 | method)))) |
---|
1896 | |
---|
1897 | (defun add-writer-method (class function-name slot-name) |
---|
1898 | (let* ((lambda-expression |
---|
1899 | (if (eq (class-of class) +the-standard-class+) |
---|
1900 | `(lambda (new-value object) |
---|
1901 | (setf (std-slot-value object ',slot-name) new-value)) |
---|
1902 | `(lambda (new-value object) |
---|
1903 | (setf (slot-value object ',slot-name) new-value)))) |
---|
1904 | (method-function (compute-method-function lambda-expression)) |
---|
1905 | (fast-function (compute-method-fast-function lambda-expression)) |
---|
1906 | ) |
---|
1907 | (ensure-method function-name |
---|
1908 | :lambda-list '(new-value object) |
---|
1909 | :qualifiers () |
---|
1910 | :specializers (list +the-T-class+ class) |
---|
1911 | ;; :function `(function ,method-function) |
---|
1912 | :function (if (autoloadp 'compile) |
---|
1913 | method-function |
---|
1914 | (autocompile method-function)) |
---|
1915 | :fast-function (if (autoloadp 'compile) |
---|
1916 | fast-function |
---|
1917 | (autocompile fast-function)) |
---|
1918 | ))) |
---|
1919 | |
---|
1920 | (defmacro redefine-class-forwarder (name slot &optional alternative-name) |
---|
1921 | (let* (($name (if (consp name) (cadr name) name)) |
---|
1922 | (%name (intern (concatenate 'string |
---|
1923 | "%" |
---|
1924 | (if (consp name) |
---|
1925 | (symbol-name 'set-) "") |
---|
1926 | (symbol-name $name)) |
---|
1927 | (find-package "SYS")))) |
---|
1928 | (unless alternative-name |
---|
1929 | (setf alternative-name name)) |
---|
1930 | (if (consp name) |
---|
1931 | `(progn ;; setter |
---|
1932 | (defgeneric ,alternative-name (new-value class)) |
---|
1933 | (defmethod ,alternative-name (new-value (class built-in-class)) |
---|
1934 | (,%name new-value class)) |
---|
1935 | (defmethod ,alternative-name (new-value (class forward-referenced-class)) |
---|
1936 | (,%name new-value class)) |
---|
1937 | (defmethod ,alternative-name (new-value (class structure-class)) |
---|
1938 | (,%name new-value class)) |
---|
1939 | (defmethod ,alternative-name (new-value (class standard-class)) |
---|
1940 | (setf (slot-value class ',slot) new-value)) |
---|
1941 | ,@(unless (eq name alternative-name) |
---|
1942 | `((setf (get ',$name 'SETF-FUNCTION) |
---|
1943 | (symbol-function ',alternative-name)))) |
---|
1944 | ) |
---|
1945 | `(progn ;; getter |
---|
1946 | (defgeneric ,alternative-name (class)) |
---|
1947 | (defmethod ,alternative-name ((class built-in-class)) |
---|
1948 | (,%name class)) |
---|
1949 | (defmethod ,alternative-name ((class forward-referenced-class)) |
---|
1950 | (,%name class)) |
---|
1951 | (defmethod ,alternative-name ((class structure-class)) |
---|
1952 | (,%name class)) |
---|
1953 | (defmethod ,alternative-name ((class standard-class)) |
---|
1954 | (slot-value class ',slot)) |
---|
1955 | ,@(unless (eq name alternative-name) |
---|
1956 | `((setf (symbol-function ',$name) |
---|
1957 | (symbol-function ',alternative-name)))) |
---|
1958 | ) ))) |
---|
1959 | |
---|
1960 | (redefine-class-forwarder class-name name) |
---|
1961 | (redefine-class-forwarder (setf class-name) name) |
---|
1962 | (redefine-class-forwarder class-slots slots) |
---|
1963 | (redefine-class-forwarder (setf class-slots) slots) |
---|
1964 | (redefine-class-forwarder class-direct-slots direct-slots) |
---|
1965 | (redefine-class-forwarder (setf class-direct-slots) direct-slots) |
---|
1966 | (redefine-class-forwarder class-layout layout) |
---|
1967 | (redefine-class-forwarder (setf class-layout) layout) |
---|
1968 | (redefine-class-forwarder class-direct-superclasses direct-superclasses) |
---|
1969 | (redefine-class-forwarder (setf class-direct-superclasses) direct-superclasses) |
---|
1970 | (redefine-class-forwarder class-direct-subclasses direct-subclasses) |
---|
1971 | (redefine-class-forwarder (setf class-direct-subclasses) direct-subclasses) |
---|
1972 | (redefine-class-forwarder class-direct-methods direct-methods !class-direct-methods) |
---|
1973 | (redefine-class-forwarder (setf class-direct-methods) direct-methods !!class-direct-methods) |
---|
1974 | (redefine-class-forwarder class-precedence-list precedence-list) |
---|
1975 | (redefine-class-forwarder (setf class-precedence-list) precedence-list) |
---|
1976 | (redefine-class-forwarder class-finalized-p finalized-p) |
---|
1977 | (redefine-class-forwarder (setf class-finalized-p) finalized-p) |
---|
1978 | (redefine-class-forwarder class-default-initargs default-initargs) |
---|
1979 | (redefine-class-forwarder (setf class-default-initargs) default-initargs) |
---|
1980 | (redefine-class-forwarder class-direct-default-initargs direct-default-initargs) |
---|
1981 | (redefine-class-forwarder (setf class-direct-default-initargs) direct-default-initargs) |
---|
1982 | |
---|
1983 | (defgeneric direct-slot-definition-class (class &rest initargs)) |
---|
1984 | |
---|
1985 | (defmethod direct-slot-definition-class ((class class) &rest initargs) |
---|
1986 | (declare (ignore initargs)) |
---|
1987 | +the-direct-slot-definition-class+) |
---|
1988 | |
---|
1989 | (defgeneric effective-slot-definition-class (class &rest initargs)) |
---|
1990 | |
---|
1991 | (defmethod effective-slot-definition-class ((class class) &rest initargs) |
---|
1992 | (declare (ignore initargs)) |
---|
1993 | +the-effective-slot-definition-class+) |
---|
1994 | |
---|
1995 | (fmakunbound 'documentation) |
---|
1996 | (defgeneric documentation (x doc-type)) |
---|
1997 | |
---|
1998 | (defgeneric (setf documentation) (new-value x doc-type)) |
---|
1999 | |
---|
2000 | (defmethod documentation ((x symbol) doc-type) |
---|
2001 | (%documentation x doc-type)) |
---|
2002 | |
---|
2003 | (defmethod (setf documentation) (new-value (x symbol) doc-type) |
---|
2004 | (%set-documentation x doc-type new-value)) |
---|
2005 | |
---|
2006 | (defmethod documentation ((x function) doc-type) |
---|
2007 | (%documentation x doc-type)) |
---|
2008 | |
---|
2009 | (defmethod (setf documentation) (new-value (x function) doc-type) |
---|
2010 | (%set-documentation x doc-type new-value)) |
---|
2011 | |
---|
2012 | ;; FIXME This should be a weak hashtable! |
---|
2013 | (defvar *list-documentation-hashtable* (make-hash-table :test #'equal)) |
---|
2014 | |
---|
2015 | (defmethod documentation ((x list) (doc-type (eql 'function))) |
---|
2016 | (let ((alist (gethash x *list-documentation-hashtable*))) |
---|
2017 | (and alist (cdr (assoc doc-type alist))))) |
---|
2018 | |
---|
2019 | (defmethod documentation ((x list) (doc-type (eql 'compiler-macro))) |
---|
2020 | (let ((alist (gethash x *list-documentation-hashtable*))) |
---|
2021 | (and alist (cdr (assoc doc-type alist))))) |
---|
2022 | |
---|
2023 | (defmethod (setf documentation) (new-value (x list) (doc-type (eql 'function))) |
---|
2024 | (let* ((alist (gethash x *list-documentation-hashtable*)) |
---|
2025 | (entry (and alist (assoc doc-type alist)))) |
---|
2026 | (cond (entry |
---|
2027 | (setf (cdr entry) new-value)) |
---|
2028 | (t |
---|
2029 | (setf (gethash x *list-documentation-hashtable*) |
---|
2030 | (push (cons doc-type new-value) alist))))) |
---|
2031 | new-value) |
---|
2032 | |
---|
2033 | (defmethod (setf documentation) (new-value (x list) (doc-type (eql 'compiler-macro))) |
---|
2034 | (let* ((alist (gethash x *list-documentation-hashtable*)) |
---|
2035 | (entry (and alist (assoc doc-type alist)))) |
---|
2036 | (cond (entry |
---|
2037 | (setf (cdr entry) new-value)) |
---|
2038 | (t |
---|
2039 | (setf (gethash x *list-documentation-hashtable*) |
---|
2040 | (push (cons doc-type new-value) alist))))) |
---|
2041 | new-value) |
---|
2042 | |
---|
2043 | (defmethod documentation ((x standard-class) (doc-type (eql 't))) |
---|
2044 | (class-documentation x)) |
---|
2045 | |
---|
2046 | (defmethod documentation ((x standard-class) (doc-type (eql 'type))) |
---|
2047 | (class-documentation x)) |
---|
2048 | |
---|
2049 | (defmethod (setf documentation) (new-value (x standard-class) (doc-type (eql 't))) |
---|
2050 | (%set-class-documentation x new-value)) |
---|
2051 | |
---|
2052 | (defmethod (setf documentation) (new-value (x standard-class) (doc-type (eql 'type))) |
---|
2053 | (%set-class-documentation x new-value)) |
---|
2054 | |
---|
2055 | (defmethod documentation ((x structure-class) (doc-type (eql 't))) |
---|
2056 | (%documentation x doc-type)) |
---|
2057 | |
---|
2058 | (defmethod documentation ((x structure-class) (doc-type (eql 'type))) |
---|
2059 | (%documentation x doc-type)) |
---|
2060 | |
---|
2061 | (defmethod (setf documentation) (new-value (x structure-class) (doc-type (eql 't))) |
---|
2062 | (%set-documentation x doc-type new-value)) |
---|
2063 | |
---|
2064 | (defmethod (setf documentation) (new-value (x structure-class) (doc-type (eql 'type))) |
---|
2065 | (%set-documentation x doc-type new-value)) |
---|
2066 | |
---|
2067 | (defmethod documentation ((x standard-generic-function) (doc-type (eql 't))) |
---|
2068 | (generic-function-documentation x)) |
---|
2069 | |
---|
2070 | (defmethod (setf documentation) (new-value (x standard-generic-function) (doc-type (eql 't))) |
---|
2071 | (setf (generic-function-documentation x) new-value)) |
---|
2072 | |
---|
2073 | (defmethod documentation ((x standard-generic-function) (doc-type (eql 'function))) |
---|
2074 | (generic-function-documentation x)) |
---|
2075 | |
---|
2076 | (defmethod (setf documentation) (new-value (x standard-generic-function) (doc-type (eql 'function))) |
---|
2077 | (setf (generic-function-documentation x) new-value)) |
---|
2078 | |
---|
2079 | (defmethod documentation ((x standard-method) (doc-type (eql 't))) |
---|
2080 | (method-documentation x)) |
---|
2081 | |
---|
2082 | (defmethod (setf documentation) (new-value (x standard-method) (doc-type (eql 't))) |
---|
2083 | (setf (method-documentation x) new-value)) |
---|
2084 | |
---|
2085 | (defmethod documentation ((x package) (doc-type (eql 't))) |
---|
2086 | (%documentation x doc-type)) |
---|
2087 | |
---|
2088 | (defmethod (setf documentation) (new-value (x package) (doc-type (eql 't))) |
---|
2089 | (%set-documentation x doc-type new-value)) |
---|
2090 | |
---|
2091 | ;;; Applicable methods |
---|
2092 | |
---|
2093 | (defgeneric compute-applicable-methods (gf args) |
---|
2094 | (:method ((gf standard-generic-function) args) |
---|
2095 | (%compute-applicable-methods gf args))) |
---|
2096 | |
---|
2097 | (defgeneric compute-applicable-methods-using-classes (gf classes) |
---|
2098 | (:method ((gf standard-generic-function) classes) |
---|
2099 | (let ((methods '())) |
---|
2100 | (dolist (method (generic-function-methods gf)) |
---|
2101 | (multiple-value-bind (applicable knownp) |
---|
2102 | (method-applicable-using-classes-p method classes) |
---|
2103 | (cond (applicable |
---|
2104 | (push method methods)) |
---|
2105 | ((not knownp) |
---|
2106 | (return-from compute-applicable-methods-using-classes |
---|
2107 | (values nil nil)))))) |
---|
2108 | (values (sort-methods methods gf classes) |
---|
2109 | t)))) |
---|
2110 | |
---|
2111 | (export '(compute-applicable-methods |
---|
2112 | compute-applicable-methods-using-classes)) |
---|
2113 | |
---|
2114 | |
---|
2115 | ;;; Slot access |
---|
2116 | |
---|
2117 | (defun set-slot-value-using-class (new-value class instance slot-name) |
---|
2118 | (declare (ignore class)) ; FIXME |
---|
2119 | (setf (std-slot-value instance slot-name) new-value)) |
---|
2120 | |
---|
2121 | (defgeneric slot-value-using-class (class instance slot-name)) |
---|
2122 | |
---|
2123 | (defmethod slot-value-using-class ((class standard-class) instance slot-name) |
---|
2124 | (std-slot-value instance slot-name)) |
---|
2125 | |
---|
2126 | (defmethod slot-value-using-class ((class structure-class) instance slot-name) |
---|
2127 | (std-slot-value instance slot-name)) |
---|
2128 | |
---|
2129 | (defgeneric (setf slot-value-using-class) (new-value class instance slot-name)) |
---|
2130 | |
---|
2131 | (defmethod (setf slot-value-using-class) (new-value |
---|
2132 | (class standard-class) |
---|
2133 | instance |
---|
2134 | slot-name) |
---|
2135 | (setf (std-slot-value instance slot-name) new-value)) |
---|
2136 | |
---|
2137 | (defmethod (setf slot-value-using-class) (new-value |
---|
2138 | (class structure-class) |
---|
2139 | instance |
---|
2140 | slot-name) |
---|
2141 | (setf (std-slot-value instance slot-name) new-value)) |
---|
2142 | |
---|
2143 | (defgeneric slot-exists-p-using-class (class instance slot-name)) |
---|
2144 | |
---|
2145 | (defmethod slot-exists-p-using-class (class instance slot-name) |
---|
2146 | nil) |
---|
2147 | |
---|
2148 | (defmethod slot-exists-p-using-class ((class standard-class) instance slot-name) |
---|
2149 | (std-slot-exists-p instance slot-name)) |
---|
2150 | |
---|
2151 | (defmethod slot-exists-p-using-class ((class structure-class) instance slot-name) |
---|
2152 | (dolist (dsd (class-slots class)) |
---|
2153 | (when (eq (sys::dsd-name dsd) slot-name) |
---|
2154 | (return-from slot-exists-p-using-class t))) |
---|
2155 | nil) |
---|
2156 | |
---|
2157 | (defgeneric slot-boundp-using-class (class instance slot-name)) |
---|
2158 | (defmethod slot-boundp-using-class ((class standard-class) instance slot-name) |
---|
2159 | (std-slot-boundp instance slot-name)) |
---|
2160 | (defmethod slot-boundp-using-class ((class structure-class) instance slot-name) |
---|
2161 | "Structure slots can't be unbound, so this method always returns T." |
---|
2162 | (declare (ignore class instance slot-name)) |
---|
2163 | t) |
---|
2164 | |
---|
2165 | (defgeneric slot-makunbound-using-class (class instance slot-name)) |
---|
2166 | (defmethod slot-makunbound-using-class ((class standard-class) |
---|
2167 | instance |
---|
2168 | slot-name) |
---|
2169 | (std-slot-makunbound instance slot-name)) |
---|
2170 | (defmethod slot-makunbound-using-class ((class structure-class) |
---|
2171 | instance |
---|
2172 | slot-name) |
---|
2173 | (declare (ignore class instance slot-name)) |
---|
2174 | (error "Structure slots can't be unbound")) |
---|
2175 | |
---|
2176 | (defgeneric slot-missing (class instance slot-name operation &optional new-value)) |
---|
2177 | |
---|
2178 | (defmethod slot-missing ((class t) instance slot-name operation &optional new-value) |
---|
2179 | (declare (ignore new-value)) |
---|
2180 | (error "The slot ~S is missing from the class ~S." slot-name class)) |
---|
2181 | |
---|
2182 | (defgeneric slot-unbound (class instance slot-name)) |
---|
2183 | |
---|
2184 | (defmethod slot-unbound ((class t) instance slot-name) |
---|
2185 | (error 'unbound-slot :instance instance :name slot-name)) |
---|
2186 | |
---|
2187 | ;;; Instance creation and initialization |
---|
2188 | |
---|
2189 | (defgeneric allocate-instance (class &rest initargs &key &allow-other-keys)) |
---|
2190 | |
---|
2191 | (defmethod allocate-instance ((class standard-class) &rest initargs) |
---|
2192 | (declare (ignore initargs)) |
---|
2193 | (std-allocate-instance class)) |
---|
2194 | |
---|
2195 | (defmethod allocate-instance ((class structure-class) &rest initargs) |
---|
2196 | (declare (ignore initargs)) |
---|
2197 | (%make-structure (class-name class) |
---|
2198 | (make-list (length (class-slots class)) |
---|
2199 | :initial-element +slot-unbound+))) |
---|
2200 | |
---|
2201 | ;; "The set of valid initialization arguments for a class is the set of valid |
---|
2202 | ;; initialization arguments that either fill slots or supply arguments to |
---|
2203 | ;; methods, along with the predefined initialization argument :ALLOW-OTHER-KEYS." |
---|
2204 | ;; 7.1.2 |
---|
2205 | |
---|
2206 | (defun check-initargs (instance shared-initialize-param initargs) |
---|
2207 | (when (oddp (length initargs)) |
---|
2208 | (error 'program-error |
---|
2209 | :format-control "Odd number of keyword arguments.")) |
---|
2210 | (unless (getf initargs :allow-other-keys) |
---|
2211 | (let ((methods |
---|
2212 | (nconc |
---|
2213 | (compute-applicable-methods |
---|
2214 | #'shared-initialize |
---|
2215 | (if initargs |
---|
2216 | `(,instance ,shared-initialize-param ,@initargs) |
---|
2217 | (list instance shared-initialize-param))) |
---|
2218 | (compute-applicable-methods |
---|
2219 | #'initialize-instance |
---|
2220 | (if initargs |
---|
2221 | `(,instance ,@initargs) |
---|
2222 | (list instance))))) |
---|
2223 | (slots (class-slots (class-of instance)))) |
---|
2224 | (do* ((tail initargs (cddr tail)) |
---|
2225 | (initarg (car tail) (car tail))) |
---|
2226 | ((null tail)) |
---|
2227 | (unless (or (valid-initarg-p initarg slots) |
---|
2228 | (valid-methodarg-p initarg methods) |
---|
2229 | (eq initarg :allow-other-keys)) |
---|
2230 | (error 'program-error |
---|
2231 | :format-control "Invalid initarg ~S." |
---|
2232 | :format-arguments (list initarg))))))) |
---|
2233 | |
---|
2234 | (defun valid-methodarg-p (initarg methods) |
---|
2235 | (when (symbolp initarg) |
---|
2236 | (dolist (method methods nil) |
---|
2237 | (let ((valid-initargs (method-lambda-list method))) |
---|
2238 | (when (find (symbol-value initarg) valid-initargs |
---|
2239 | :test #'(lambda (a b) |
---|
2240 | (if (listp b) |
---|
2241 | (string= a (car b)) |
---|
2242 | (or |
---|
2243 | (string= a b) |
---|
2244 | (string= b "&ALLOW-OTHER-KEYS"))))) |
---|
2245 | |
---|
2246 | (return t)))))) |
---|
2247 | |
---|
2248 | (defun valid-initarg-p (initarg slots) |
---|
2249 | (dolist (slot slots nil) |
---|
2250 | (let ((valid-initargs (slot-definition-initargs slot))) |
---|
2251 | (when (memq initarg valid-initargs) |
---|
2252 | (return t))))) |
---|
2253 | |
---|
2254 | (defgeneric make-instance (class &rest initargs &key &allow-other-keys)) |
---|
2255 | |
---|
2256 | (defmethod make-instance ((class standard-class) &rest initargs) |
---|
2257 | (when (oddp (length initargs)) |
---|
2258 | (error 'program-error :format-control "Odd number of keyword arguments.")) |
---|
2259 | (unless (class-finalized-p class) |
---|
2260 | (std-finalize-inheritance class)) |
---|
2261 | (let ((class-default-initargs (class-default-initargs class))) |
---|
2262 | (when class-default-initargs |
---|
2263 | (let ((default-initargs '())) |
---|
2264 | (do* ((list class-default-initargs (cddr list)) |
---|
2265 | (key (car list) (car list)) |
---|
2266 | (fn (cadr list) (cadr list))) |
---|
2267 | ((null list)) |
---|
2268 | (when (eq (getf initargs key 'not-found) 'not-found) |
---|
2269 | (setf default-initargs (append default-initargs (list key (funcall fn)))))) |
---|
2270 | (setf initargs (append initargs default-initargs))))) |
---|
2271 | |
---|
2272 | (let ((instance (std-allocate-instance class))) |
---|
2273 | (check-initargs instance t initargs) |
---|
2274 | (apply #'initialize-instance instance initargs) |
---|
2275 | instance)) |
---|
2276 | |
---|
2277 | (defmethod make-instance ((class symbol) &rest initargs) |
---|
2278 | (apply #'make-instance (find-class class) initargs)) |
---|
2279 | |
---|
2280 | (defgeneric initialize-instance (instance &key)) |
---|
2281 | |
---|
2282 | (defmethod initialize-instance ((instance standard-object) &rest initargs) |
---|
2283 | (apply #'shared-initialize instance t initargs)) |
---|
2284 | |
---|
2285 | (defgeneric reinitialize-instance (instance &key)) |
---|
2286 | |
---|
2287 | ;; "The system-supplied primary method for REINITIALIZE-INSTANCE checks the |
---|
2288 | ;; validity of initargs and signals an error if an initarg is supplied that is |
---|
2289 | ;; not declared as valid. The method then calls the generic function SHARED- |
---|
2290 | ;; INITIALIZE with the following arguments: the instance, nil (which means no |
---|
2291 | ;; slots should be initialized according to their initforms), and the initargs |
---|
2292 | ;; it received." |
---|
2293 | (defmethod reinitialize-instance ((instance standard-object) &rest initargs) |
---|
2294 | (apply #'shared-initialize instance () initargs)) |
---|
2295 | |
---|
2296 | (defun std-shared-initialize (instance slot-names all-keys) |
---|
2297 | (when (oddp (length all-keys)) |
---|
2298 | (error 'program-error :format-control "Odd number of keyword arguments.")) |
---|
2299 | (do* ((tail all-keys (cddr tail)) |
---|
2300 | (initarg (car tail) (car tail))) |
---|
2301 | ((null tail)) |
---|
2302 | (when (and initarg (not (symbolp initarg))) |
---|
2303 | (error 'program-error |
---|
2304 | :format-control "Invalid initarg ~S." |
---|
2305 | :format-arguments (list initarg)))) |
---|
2306 | (dolist (slot (class-slots (class-of instance))) |
---|
2307 | (let ((slot-name (slot-definition-name slot))) |
---|
2308 | (multiple-value-bind (init-key init-value foundp) |
---|
2309 | (get-properties all-keys (slot-definition-initargs slot)) |
---|
2310 | (if foundp |
---|
2311 | (setf (std-slot-value instance slot-name) init-value) |
---|
2312 | (unless (std-slot-boundp instance slot-name) |
---|
2313 | (let ((initfunction (slot-definition-initfunction slot))) |
---|
2314 | (when (and initfunction (or (eq slot-names t) |
---|
2315 | (memq slot-name slot-names))) |
---|
2316 | (setf (std-slot-value instance slot-name) |
---|
2317 | (funcall initfunction))))))))) |
---|
2318 | instance) |
---|
2319 | |
---|
2320 | (defgeneric shared-initialize (instance slot-names &key)) |
---|
2321 | |
---|
2322 | (defmethod shared-initialize ((instance standard-object) slot-names &rest initargs) |
---|
2323 | (std-shared-initialize instance slot-names initargs)) |
---|
2324 | |
---|
2325 | (defmethod shared-initialize ((slot slot-definition) slot-names |
---|
2326 | &rest args |
---|
2327 | &key name initargs initform initfunction |
---|
2328 | readers writers allocation |
---|
2329 | &allow-other-keys) |
---|
2330 | ;;Keyword args are duplicated from init-slot-definition only to have |
---|
2331 | ;;them checked. |
---|
2332 | (declare (ignore slot-names)) ;;TODO? |
---|
2333 | (declare (ignore name initargs initform initfunction readers writers allocation)) |
---|
2334 | ;;For built-in slots |
---|
2335 | (apply #'init-slot-definition slot :allow-other-keys t args) |
---|
2336 | ;;For user-defined slots |
---|
2337 | (call-next-method)) |
---|
2338 | |
---|
2339 | ;;; change-class |
---|
2340 | |
---|
2341 | (defgeneric change-class (instance new-class &key)) |
---|
2342 | |
---|
2343 | (defmethod change-class ((old-instance standard-object) (new-class standard-class) |
---|
2344 | &rest initargs) |
---|
2345 | (let ((old-slots (class-slots (class-of old-instance))) |
---|
2346 | (new-slots (class-slots new-class)) |
---|
2347 | (new-instance (allocate-instance new-class))) |
---|
2348 | ;; "The values of local slots specified by both the class CTO and the class |
---|
2349 | ;; CFROM are retained. If such a local slot was unbound, it remains |
---|
2350 | ;; unbound." |
---|
2351 | (dolist (new-slot new-slots) |
---|
2352 | (when (instance-slot-p new-slot) |
---|
2353 | (let* ((slot-name (slot-definition-name new-slot)) |
---|
2354 | (old-slot (find slot-name old-slots :key 'slot-definition-name))) |
---|
2355 | ;; "The values of slots specified as shared in the class CFROM and as |
---|
2356 | ;; local in the class CTO are retained." |
---|
2357 | (when (and old-slot (slot-boundp old-instance slot-name)) |
---|
2358 | (setf (slot-value new-instance slot-name) |
---|
2359 | (slot-value old-instance slot-name)))))) |
---|
2360 | (swap-slots old-instance new-instance) |
---|
2361 | (rotatef (std-instance-layout new-instance) |
---|
2362 | (std-instance-layout old-instance)) |
---|
2363 | (apply #'update-instance-for-different-class |
---|
2364 | new-instance old-instance initargs) |
---|
2365 | old-instance)) |
---|
2366 | |
---|
2367 | (defmethod change-class ((instance standard-object) (new-class symbol) &rest initargs) |
---|
2368 | (apply #'change-class instance (find-class new-class) initargs)) |
---|
2369 | |
---|
2370 | (defgeneric update-instance-for-different-class (old new &key)) |
---|
2371 | |
---|
2372 | (defmethod update-instance-for-different-class |
---|
2373 | ((old standard-object) (new standard-object) &rest initargs) |
---|
2374 | (let ((added-slots |
---|
2375 | (remove-if #'(lambda (slot-name) |
---|
2376 | (slot-exists-p old slot-name)) |
---|
2377 | (mapcar 'slot-definition-name |
---|
2378 | (class-slots (class-of new)))))) |
---|
2379 | (check-initargs new added-slots initargs) |
---|
2380 | (apply #'shared-initialize new added-slots initargs))) |
---|
2381 | |
---|
2382 | ;;; make-instances-obsolete |
---|
2383 | |
---|
2384 | (defgeneric make-instances-obsolete (class)) |
---|
2385 | |
---|
2386 | (defmethod make-instances-obsolete ((class standard-class)) |
---|
2387 | (%make-instances-obsolete class)) |
---|
2388 | |
---|
2389 | (defmethod make-instances-obsolete ((class symbol)) |
---|
2390 | (make-instances-obsolete (find-class class)) |
---|
2391 | class) |
---|
2392 | |
---|
2393 | ;;; update-instance-for-redefined-class |
---|
2394 | |
---|
2395 | (defgeneric update-instance-for-redefined-class (instance |
---|
2396 | added-slots |
---|
2397 | discarded-slots |
---|
2398 | property-list |
---|
2399 | &rest initargs |
---|
2400 | &key |
---|
2401 | &allow-other-keys)) |
---|
2402 | |
---|
2403 | (defmethod update-instance-for-redefined-class ((instance standard-object) |
---|
2404 | added-slots |
---|
2405 | discarded-slots |
---|
2406 | property-list |
---|
2407 | &rest initargs) |
---|
2408 | (check-initargs instance added-slots initargs) |
---|
2409 | (apply #'shared-initialize instance added-slots initargs)) |
---|
2410 | |
---|
2411 | ;;; Methods having to do with class metaobjects. |
---|
2412 | |
---|
2413 | (defmethod initialize-instance :after ((class standard-class) &rest args) |
---|
2414 | (apply #'std-after-initialization-for-classes class args)) |
---|
2415 | |
---|
2416 | ;;; Finalize inheritance |
---|
2417 | |
---|
2418 | (defgeneric finalize-inheritance (class)) |
---|
2419 | |
---|
2420 | (defmethod finalize-inheritance ((class standard-class)) |
---|
2421 | (std-finalize-inheritance class)) |
---|
2422 | |
---|
2423 | ;;; Class precedence lists |
---|
2424 | |
---|
2425 | (defgeneric compute-class-precedence-list (class)) |
---|
2426 | (defmethod compute-class-precedence-list ((class standard-class)) |
---|
2427 | (std-compute-class-precedence-list class)) |
---|
2428 | |
---|
2429 | ;;; Slot inheritance |
---|
2430 | |
---|
2431 | (defgeneric compute-slots (class)) |
---|
2432 | (defmethod compute-slots ((class standard-class)) |
---|
2433 | (std-compute-slots class)) |
---|
2434 | |
---|
2435 | (defgeneric compute-effective-slot-definition (class direct-slots)) |
---|
2436 | (defmethod compute-effective-slot-definition |
---|
2437 | ((class standard-class) direct-slots) |
---|
2438 | (std-compute-effective-slot-definition class direct-slots)) |
---|
2439 | |
---|
2440 | ;;; Methods having to do with generic function metaobjects. |
---|
2441 | |
---|
2442 | (defmethod initialize-instance :after ((gf standard-generic-function) &key) |
---|
2443 | (finalize-generic-function gf)) |
---|
2444 | |
---|
2445 | ;;; Methods having to do with generic function invocation. |
---|
2446 | |
---|
2447 | (defgeneric compute-discriminating-function (gf)) |
---|
2448 | (defmethod compute-discriminating-function ((gf standard-generic-function)) |
---|
2449 | (std-compute-discriminating-function gf)) |
---|
2450 | |
---|
2451 | (defgeneric method-more-specific-p (gf method1 method2 required-classes)) |
---|
2452 | |
---|
2453 | (defmethod method-more-specific-p ((gf standard-generic-function) |
---|
2454 | method1 method2 required-classes) |
---|
2455 | (std-method-more-specific-p method1 method2 required-classes |
---|
2456 | (generic-function-argument-precedence-order gf))) |
---|
2457 | |
---|
2458 | (defgeneric compute-effective-method-function (gf methods)) |
---|
2459 | (defmethod compute-effective-method-function ((gf standard-generic-function) methods) |
---|
2460 | (std-compute-effective-method-function gf methods)) |
---|
2461 | |
---|
2462 | (defgeneric compute-applicable-methods (gf args)) |
---|
2463 | (defmethod compute-applicable-methods ((gf standard-generic-function) args) |
---|
2464 | (%compute-applicable-methods gf args)) |
---|
2465 | |
---|
2466 | ;;; Slot definition accessors |
---|
2467 | |
---|
2468 | (map nil (lambda (sym) |
---|
2469 | (fmakunbound sym) ;;we need to redefine them as GFs |
---|
2470 | (fmakunbound `(setf ,sym)) |
---|
2471 | (export sym)) |
---|
2472 | '(slot-definition-allocation |
---|
2473 | slot-definition-initargs |
---|
2474 | slot-definition-initform |
---|
2475 | slot-definition-initfunction |
---|
2476 | slot-definition-name |
---|
2477 | slot-definition-readers |
---|
2478 | slot-definition-writers |
---|
2479 | slot-definition-allocation-class)) |
---|
2480 | |
---|
2481 | (defmacro slot-definition-dispatch (slot-definition std-form generic-form) |
---|
2482 | `(let (($cl (class-of ,slot-definition))) |
---|
2483 | (case $cl |
---|
2484 | ((+the-slot-definition-class+ |
---|
2485 | +the-direct-slot-definition-class+ |
---|
2486 | +the-effective-slot-definition-class+) |
---|
2487 | ,std-form) |
---|
2488 | (t ,generic-form)))) |
---|
2489 | |
---|
2490 | (defgeneric slot-definition-allocation (slot-definition) |
---|
2491 | (:method ((slot-definition slot-definition)) |
---|
2492 | (slot-definition-dispatch slot-definition |
---|
2493 | (%slot-definition-allocation slot-definition) |
---|
2494 | (slot-value slot-definition 'sys::allocation)))) |
---|
2495 | |
---|
2496 | (defgeneric (setf slot-definition-allocation) (value slot-definition) |
---|
2497 | (:method (value (slot-definition slot-definition)) |
---|
2498 | (slot-definition-dispatch slot-definition |
---|
2499 | (set-slot-definition-allocation slot-definition value) |
---|
2500 | (setf (slot-value slot-definition 'sys::allocation) value)))) |
---|
2501 | |
---|
2502 | (defgeneric slot-definition-initargs (slot-definition) |
---|
2503 | (:method ((slot-definition slot-definition)) |
---|
2504 | (slot-definition-dispatch slot-definition |
---|
2505 | (%slot-definition-initargs slot-definition) |
---|
2506 | (slot-value slot-definition 'sys::initargs)))) |
---|
2507 | |
---|
2508 | (defgeneric (setf slot-definition-initargs) (value slot-definition) |
---|
2509 | (:method (value (slot-definition slot-definition)) |
---|
2510 | (slot-definition-dispatch slot-definition |
---|
2511 | (set-slot-definition-initargs slot-definition value) |
---|
2512 | (setf (slot-value slot-definition 'sys::initargs) value)))) |
---|
2513 | |
---|
2514 | (defgeneric slot-definition-initform (slot-definition) |
---|
2515 | (:method ((slot-definition slot-definition)) |
---|
2516 | (slot-definition-dispatch slot-definition |
---|
2517 | (%slot-definition-initform slot-definition) |
---|
2518 | (slot-value slot-definition 'sys::initform)))) |
---|
2519 | |
---|
2520 | (defgeneric (setf slot-definition-initform) (value slot-definition) |
---|
2521 | (:method (value (slot-definition slot-definition)) |
---|
2522 | (slot-definition-dispatch slot-definition |
---|
2523 | (set-slot-definition-initform slot-definition value) |
---|
2524 | (setf (slot-value slot-definition 'sys::initform) value)))) |
---|
2525 | |
---|
2526 | (defgeneric slot-definition-initfunction (slot-definition) |
---|
2527 | (:method ((slot-definition slot-definition)) |
---|
2528 | (slot-definition-dispatch slot-definition |
---|
2529 | (%slot-definition-initfunction slot-definition) |
---|
2530 | (slot-value slot-definition 'sys::initfunction)))) |
---|
2531 | |
---|
2532 | (defgeneric (setf slot-definition-initfunction) (value slot-definition) |
---|
2533 | (:method (value (slot-definition slot-definition)) |
---|
2534 | (slot-definition-dispatch slot-definition |
---|
2535 | (set-slot-definition-initfunction slot-definition value) |
---|
2536 | (setf (slot-value slot-definition 'sys::initfunction) value)))) |
---|
2537 | |
---|
2538 | (defgeneric slot-definition-name (slot-definition) |
---|
2539 | (:method ((slot-definition slot-definition)) |
---|
2540 | (slot-definition-dispatch slot-definition |
---|
2541 | (%slot-definition-name slot-definition) |
---|
2542 | (slot-value slot-definition 'sys::name)))) |
---|
2543 | |
---|
2544 | (defgeneric (setf slot-definition-name) (value slot-definition) |
---|
2545 | (:method (value (slot-definition slot-definition)) |
---|
2546 | (slot-definition-dispatch slot-definition |
---|
2547 | (set-slot-definition-name slot-definition value) |
---|
2548 | (setf (slot-value slot-definition 'sys::name) value)))) |
---|
2549 | |
---|
2550 | (defgeneric slot-definition-readers (slot-definition) |
---|
2551 | (:method ((slot-definition slot-definition)) |
---|
2552 | (slot-definition-dispatch slot-definition |
---|
2553 | (%slot-definition-readers slot-definition) |
---|
2554 | (slot-value slot-definition 'sys::readers)))) |
---|
2555 | |
---|
2556 | (defgeneric (setf slot-definition-readers) (value slot-definition) |
---|
2557 | (:method (value (slot-definition slot-definition)) |
---|
2558 | (slot-definition-dispatch slot-definition |
---|
2559 | (set-slot-definition-readers slot-definition value) |
---|
2560 | (setf (slot-value slot-definition 'sys::readers) value)))) |
---|
2561 | |
---|
2562 | (defgeneric slot-definition-writers (slot-definition) |
---|
2563 | (:method ((slot-definition slot-definition)) |
---|
2564 | (slot-definition-dispatch slot-definition |
---|
2565 | (%slot-definition-writers slot-definition) |
---|
2566 | (slot-value slot-definition 'sys::writers)))) |
---|
2567 | |
---|
2568 | (defgeneric (setf slot-definition-writers) (value slot-definition) |
---|
2569 | (:method (value (slot-definition slot-definition)) |
---|
2570 | (slot-definition-dispatch slot-definition |
---|
2571 | (set-slot-definition-writers slot-definition value) |
---|
2572 | (setf (slot-value slot-definition 'sys::writers) value)))) |
---|
2573 | |
---|
2574 | (defgeneric slot-definition-allocation-class (slot-definition) |
---|
2575 | (:method ((slot-definition slot-definition)) |
---|
2576 | (slot-definition-dispatch slot-definition |
---|
2577 | (%slot-definition-allocation-class slot-definition) |
---|
2578 | (slot-value slot-definition 'sys::allocation-class)))) |
---|
2579 | |
---|
2580 | (defgeneric (setf slot-definition-allocation-class) (value slot-definition) |
---|
2581 | (:method (value (slot-definition slot-definition)) |
---|
2582 | (slot-definition-dispatch slot-definition |
---|
2583 | (set-slot-definition-allocation-class slot-definition value) |
---|
2584 | (setf (slot-value slot-definition 'sys::allocation-class) value)))) |
---|
2585 | |
---|
2586 | (defgeneric slot-definition-location (slot-definition) |
---|
2587 | (:method ((slot-definition slot-definition)) |
---|
2588 | (slot-definition-dispatch slot-definition |
---|
2589 | (%slot-definition-location slot-definition) |
---|
2590 | (slot-value slot-definition 'sys::location)))) |
---|
2591 | |
---|
2592 | (defgeneric (setf slot-definition-location) (value slot-definition) |
---|
2593 | (:method (value (slot-definition slot-definition)) |
---|
2594 | (slot-definition-dispatch slot-definition |
---|
2595 | (set-slot-definition-location slot-definition value) |
---|
2596 | (setf (slot-value slot-definition 'sys::location) value)))) |
---|
2597 | |
---|
2598 | ;;; No %slot-definition-type. |
---|
2599 | |
---|
2600 | |
---|
2601 | ;;; Conditions. |
---|
2602 | |
---|
2603 | (defmacro define-condition (name (&rest parent-types) (&rest slot-specs) &body options) |
---|
2604 | (let ((parent-types (or parent-types '(condition))) |
---|
2605 | (report nil)) |
---|
2606 | (dolist (option options) |
---|
2607 | (when (eq (car option) :report) |
---|
2608 | (setf report (cadr option)) |
---|
2609 | (setf options (delete option options :test #'equal)) |
---|
2610 | (return))) |
---|
2611 | (typecase report |
---|
2612 | (null |
---|
2613 | `(progn |
---|
2614 | (defclass ,name ,parent-types ,slot-specs ,@options) |
---|
2615 | ',name)) |
---|
2616 | (string |
---|
2617 | `(progn |
---|
2618 | (defclass ,name ,parent-types ,slot-specs ,@options) |
---|
2619 | (defmethod print-object ((condition ,name) stream) |
---|
2620 | (if *print-escape* |
---|
2621 | (call-next-method) |
---|
2622 | (progn (write-string ,report stream) condition))) |
---|
2623 | ',name)) |
---|
2624 | (t |
---|
2625 | `(progn |
---|
2626 | (defclass ,name ,parent-types ,slot-specs ,@options) |
---|
2627 | (defmethod print-object ((condition ,name) stream) |
---|
2628 | (if *print-escape* |
---|
2629 | (call-next-method) |
---|
2630 | (funcall #',report condition stream))) |
---|
2631 | ',name))))) |
---|
2632 | |
---|
2633 | (defun make-condition (type &rest initargs) |
---|
2634 | (or (%make-condition type initargs) |
---|
2635 | (let ((class (if (symbolp type) (find-class type) type))) |
---|
2636 | (apply #'make-instance class initargs)))) |
---|
2637 | |
---|
2638 | ;; Adapted from SBCL. |
---|
2639 | ;; Originally defined in signal.lisp. Redefined here now that we have MAKE-CONDITION. |
---|
2640 | (defun coerce-to-condition (datum arguments default-type fun-name) |
---|
2641 | (cond ((typep datum 'condition) |
---|
2642 | (when arguments |
---|
2643 | (error 'simple-type-error |
---|
2644 | :datum arguments |
---|
2645 | :expected-type 'null |
---|
2646 | :format-control "You may not supply additional arguments when giving ~S to ~S." |
---|
2647 | :format-arguments (list datum fun-name))) |
---|
2648 | datum) |
---|
2649 | ((symbolp datum) |
---|
2650 | (apply #'make-condition datum arguments)) |
---|
2651 | ((or (stringp datum) (functionp datum)) |
---|
2652 | (make-condition default-type |
---|
2653 | :format-control datum |
---|
2654 | :format-arguments arguments)) |
---|
2655 | (t |
---|
2656 | (error 'simple-type-error |
---|
2657 | :datum datum |
---|
2658 | :expected-type '(or symbol string) |
---|
2659 | :format-control "Bad argument to ~S: ~S." |
---|
2660 | :format-arguments (list fun-name datum))))) |
---|
2661 | |
---|
2662 | (defgeneric make-load-form (object &optional environment)) |
---|
2663 | |
---|
2664 | (defmethod make-load-form ((object t) &optional environment) |
---|
2665 | (declare (ignore environment)) |
---|
2666 | (apply #'no-applicable-method #'make-load-form (list object))) |
---|
2667 | |
---|
2668 | (defmethod make-load-form ((class class) &optional environment) |
---|
2669 | (declare (ignore environment)) |
---|
2670 | (let ((name (class-name class))) |
---|
2671 | (unless (and name (eq (find-class name nil) class)) |
---|
2672 | (error 'simple-type-error |
---|
2673 | :format-control "Can't use anonymous or undefined class as a constant: ~S." |
---|
2674 | :format-arguments (list class))) |
---|
2675 | `(find-class ',name))) |
---|
2676 | |
---|
2677 | (defun invalid-method-error (method format-control &rest args) |
---|
2678 | (let ((message (apply #'format nil format-control args))) |
---|
2679 | (error "Invalid method error for ~S:~% ~A" method message))) |
---|
2680 | |
---|
2681 | (defun method-combination-error (format-control &rest args) |
---|
2682 | (let ((message (apply #'format nil format-control args))) |
---|
2683 | (error "Method combination error in CLOS dispatch:~% ~A" message))) |
---|
2684 | |
---|
2685 | (fmakunbound 'no-applicable-method) |
---|
2686 | (defgeneric no-applicable-method (generic-function &rest args)) |
---|
2687 | |
---|
2688 | (defmethod no-applicable-method (generic-function &rest args) |
---|
2689 | (error "There is no applicable method for the generic function ~S when called with arguments ~S." |
---|
2690 | generic-function |
---|
2691 | args)) |
---|
2692 | |
---|
2693 | (defgeneric find-method (generic-function |
---|
2694 | qualifiers |
---|
2695 | specializers |
---|
2696 | &optional errorp)) |
---|
2697 | |
---|
2698 | (defmethod find-method ((generic-function standard-generic-function) |
---|
2699 | qualifiers specializers &optional (errorp t)) |
---|
2700 | (%find-method generic-function qualifiers specializers errorp)) |
---|
2701 | |
---|
2702 | (defgeneric add-method (generic-function method)) |
---|
2703 | |
---|
2704 | (defmethod add-method ((generic-function standard-generic-function) (method method)) |
---|
2705 | (let ((method-lambda-list (method-lambda-list method)) |
---|
2706 | (gf-lambda-list (generic-function-lambda-list generic-function))) |
---|
2707 | (check-method-lambda-list method-lambda-list gf-lambda-list)) |
---|
2708 | (%add-method generic-function method)) |
---|
2709 | |
---|
2710 | (defgeneric remove-method (generic-function method)) |
---|
2711 | |
---|
2712 | (defmethod remove-method ((generic-function standard-generic-function) method) |
---|
2713 | (%remove-method generic-function method)) |
---|
2714 | |
---|
2715 | ;; See describe.lisp. |
---|
2716 | (defgeneric describe-object (object stream)) |
---|
2717 | |
---|
2718 | ;; FIXME |
---|
2719 | (defgeneric no-next-method (generic-function method &rest args)) |
---|
2720 | |
---|
2721 | ;; FIXME |
---|
2722 | (defgeneric function-keywords (method)) |
---|
2723 | |
---|
2724 | (setf *clos-booting* nil) |
---|
2725 | |
---|
2726 | (defgeneric class-prototype (class)) |
---|
2727 | |
---|
2728 | (defmethod class-prototype :before (class) |
---|
2729 | (unless (class-finalized-p class) |
---|
2730 | (error "~@<~S is not finalized.~:@>" class))) |
---|
2731 | |
---|
2732 | (defmethod class-prototype ((class standard-class)) |
---|
2733 | (allocate-instance class)) |
---|
2734 | |
---|
2735 | (defmethod class-prototype ((class structure-class)) |
---|
2736 | (allocate-instance class)) |
---|
2737 | |
---|
2738 | (provide 'clos) |
---|