source: branches/0.20.x/abcl/src/org/armedbear/lisp/clos.lisp

Last change on this file was 12665, checked in by ehuelsmann, 15 years ago

Apply the speed improvement used for dispatching everywhere: all
standard classes get a constant (not a variable) assigned, because
that gets evaluated only at class-loading time, variables and
dynamic lookups get evaluated *every* time.

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