source: trunk/j/src/org/armedbear/lisp/clos.lisp @ 5856

Last change on this file since 5856 was 5856, checked in by piso, 17 years ago

DEFMETHOD: environment support.

File size: 73.5 KB
Line 
1;;; clos.lisp
2;;;
3;;; Copyright (C) 2003-2004 Peter Graves
4;;; $Id: clos.lisp,v 1.86 2004-02-16 19:14:00 piso Exp $
5;;;
6;;; This program is free software; you can redistribute it and/or
7;;; modify it under the terms of the GNU General Public License
8;;; as published by the Free Software Foundation; either version 2
9;;; of the License, or (at your option) any later version.
10;;;
11;;; This program is distributed in the hope that it will be useful,
12;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14;;; GNU General Public License for more details.
15;;;
16;;; You should have received a copy of the GNU General Public License
17;;; along with this program; if not, write to the Free Software
18;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19
20;;; Adapted from Closette.
21
22;;; Closette Version 1.0 (February 10, 1991)
23;;;
24;;; Copyright (c) 1990, 1991 Xerox Corporation.
25;;; All rights reserved.
26;;;
27;;; Use and copying of this software and preparation of derivative works
28;;; based upon this software are permitted.  Any distribution of this
29;;; software or derivative works must comply with all applicable United
30;;; States export control laws.
31;;;
32;;; This software is made available AS IS, and Xerox Corporation makes no
33;;; warranty about the software, its performance or its conformity to any
34;;; specification.
35;;;
36;;; Closette is an implementation of a subset of CLOS with a metaobject
37;;; protocol as described in "The Art of The Metaobject Protocol",
38;;; MIT Press, 1991.
39
40(in-package "SYSTEM")
41
42(defmacro push-on-end (value location)
43  `(setf ,location (nconc ,location (list ,value))))
44
45;;; (SETF GETF*) is like (SETF GETF) except that it always changes the list,
46;;; which must be non-nil.
47
48(defun (setf getf*) (new-value plist key)
49  (block body
50    (do ((x plist (cddr x)))
51        ((null x))
52      (when (eq (car x) key)
53        (setf (car (cdr x)) new-value)
54        (return-from body new-value)))
55    (push-on-end key plist)
56    (push-on-end new-value plist)
57    new-value))
58
59(defun mapappend (fun &rest args)
60  (if (some #'null args)
61      ()
62      (append (apply fun (mapcar #'car args))
63              (apply #'mapappend fun (mapcar #'cdr args)))))
64
65(defun mapplist (fun x)
66  (if (null x)
67      ()
68      (cons (funcall fun (car x) (cadr x))
69            (mapplist fun (cddr x)))))
70
71(defsetf class-layout %set-class-layout)
72(defsetf class-direct-superclasses %set-class-direct-superclasses)
73(defsetf class-direct-subclasses %set-class-direct-subclasses)
74(defsetf class-direct-methods %set-class-direct-methods)
75(defsetf class-direct-slots %set-class-direct-slots)
76(defsetf class-slots %set-class-slots)
77(defsetf class-direct-default-initargs %set-class-direct-default-initargs)
78(defsetf class-default-initargs %set-class-default-initargs)
79(defsetf class-precedence-list %set-class-precedence-list)
80(defsetf std-instance-layout %set-std-instance-layout)
81(defsetf std-instance-slots %set-std-instance-slots)
82(defsetf instance-ref %set-instance-ref)
83
84(defun (setf find-class) (new-value symbol &optional errorp environment)
85  (%set-find-class symbol new-value))
86
87(defun canonicalize-direct-slots (direct-slots)
88  `(list ,@(mapcar #'canonicalize-direct-slot direct-slots)))
89
90(defun canonicalize-direct-slot (spec)
91  (if (symbolp spec)
92      `(list :name ',spec)
93      (let ((name (car spec))
94            (initfunction nil)
95            (initform nil)
96            (initargs ())
97            (type nil)
98            (allocation nil)
99            (documentation nil)
100            (readers ())
101            (writers ())
102            (other-options ()))
103        (do ((olist (cdr spec) (cddr olist)))
104            ((null olist))
105          (case (car olist)
106            (:initform
107             (when initform
108               (error 'program-error
109                      "duplicate slot option :INITFORM for slot named ~S"
110                      name))
111             (setq initfunction
112                   `(function (lambda () ,(cadr olist))))
113             (setq initform `',(cadr olist)))
114            (:initarg
115             (push-on-end (cadr olist) initargs))
116            (:allocation
117             (when allocation
118               (error 'program-error
119                      "duplicate slot option :ALLOCATION for slot named ~S"
120                      name))
121             (setf allocation (cadr olist))
122             (push-on-end (car olist) other-options)
123             (push-on-end (cadr olist) other-options))
124            (:type
125             (when type
126               (error 'program-error
127                      "duplicate slot option :TYPE for slot named ~S"
128                      name))
129             (setf type (cadr olist))) ;; FIXME type is ignored
130            (:documentation
131             (when documentation
132               (error 'program-error
133                      "duplicate slot option :DOCUMENTATION for slot named ~S"
134                      name))
135             (setf documentation (cadr olist))) ;; FIXME documentation is ignored
136            (:reader
137             (push-on-end (cadr olist) readers))
138            (:writer
139             (push-on-end (cadr olist) writers))
140            (:accessor
141             (push-on-end (cadr olist) readers)
142             (push-on-end `(setf ,(cadr olist)) writers))
143            (t
144             (error 'program-error
145                    "invalid initialization argument ~S for slot named ~S"
146                    (car olist) name))))
147        `(list
148          :name ',name
149          ,@(when initfunction
150              `(:initform ,initform
151                          :initfunction ,initfunction))
152          ,@(when initargs `(:initargs ',initargs))
153          ,@(when readers `(:readers ',readers))
154          ,@(when writers `(:writers ',writers))
155          ,@other-options))))
156
157(defun canonicalize-direct-superclasses (direct-superclasses)
158  `(list ,@(mapcar #'canonicalize-direct-superclass direct-superclasses)))
159
160(defun canonicalize-direct-superclass (class-name)
161  `(find-class ',class-name))
162
163(defun canonicalize-defclass-options (options)
164  (mapappend #'canonicalize-defclass-option options))
165
166(defun canonicalize-defclass-option (option)
167  (case (car option)
168    (:metaclass
169     (list ':metaclass
170           `(find-class ',(cadr option))))
171    (:default-initargs
172     (list
173      ':direct-default-initargs
174      `(list ,@(mapappend
175                #'(lambda (x) x)
176                (mapplist
177                 #'(lambda (key value)
178                    `(',key ,(make-initfunction value)))
179                 (cdr option))))))
180    ((:documentation :report)
181     (list (car option) `',(cadr option)))
182    (t
183     (error 'program-error
184            :format-control "invalid DEFCLASS option ~S"
185            :format-arguments (list (car option))))))
186
187(defun make-initfunction (initform)
188  `(function (lambda () ,initform)))
189
190(defconstant +slot-unbound+ (make-symbol "SLOT-UNBOUND"))
191
192;;; Slot definition metaobjects
193
194(defstruct slot-definition
195  name
196  initfunction
197  initform
198  initargs
199  readers
200  writers
201  allocation
202  allocation-class
203  (location nil))
204
205(defun make-direct-slot-definition (class &rest properties
206                                          &key name
207                                          (initargs ())
208                                          (initform nil)
209                                          (initfunction nil)
210                                          (readers ())
211                                          (writers ())
212                                          (allocation :instance)
213                                          &allow-other-keys)
214  (let ((slot (make-slot-definition)))
215    (setf (slot-definition-name slot) name)
216    (setf (slot-definition-initargs slot) initargs)
217    (setf (slot-definition-initform slot) initform)
218    (setf (slot-definition-initfunction slot) initfunction)
219    (setf (slot-definition-readers slot) readers)
220    (setf (slot-definition-writers slot) writers)
221    (setf (slot-definition-allocation slot) allocation)
222    (setf (slot-definition-allocation-class slot) class)
223    slot))
224
225(defun make-effective-slot-definition (&rest properties
226                                             &key name
227                                             (initargs ())
228                                             (initform nil)
229                                             (initfunction nil)
230                                             (allocation :instance)
231                                             (allocation-class nil)
232                                             &allow-other-keys)
233  (let ((slot (make-slot-definition)))
234    (setf (slot-definition-name slot) name)
235    (setf (slot-definition-initargs slot) initargs)
236    (setf (slot-definition-initform slot) initform)
237    (setf (slot-definition-initfunction slot) initfunction)
238    (setf (slot-definition-allocation slot) allocation)
239    (setf (slot-definition-allocation-class slot) allocation-class)
240    slot))
241
242;;; finalize-inheritance
243
244(defun std-finalize-inheritance (class)
245  (setf (class-precedence-list class)
246        (funcall (if (eq (class-of class) the-class-standard-class)
247                     #'std-compute-class-precedence-list
248                     #'compute-class-precedence-list)
249                 class))
250  (setf (class-slots class)
251        (funcall (if (eq (class-of class) the-class-standard-class)
252                     #'std-compute-slots
253                     #'compute-slots)
254                 class))
255  (let ((length 0)
256        (instance-slots ()))
257    (dolist (slot (class-slots class))
258      (case (slot-definition-allocation slot)
259        (:instance
260         (setf (slot-definition-location slot) length)
261         (incf length)
262         (push (slot-definition-name slot) instance-slots))
263        (:class
264         (unless (slot-definition-location slot)
265           (let ((allocation-class (slot-definition-allocation-class slot)))
266             (setf (slot-definition-location slot)
267                   (if (eq class allocation-class)
268                       (cons (slot-definition-name slot) +slot-unbound+)
269                       (slot-location allocation-class (slot-definition-name slot)))))))))
270    (setf (class-layout class)
271          (make-layout class length (nreverse instance-slots))))
272  (setf (class-default-initargs class)
273        (compute-class-default-initargs class)))
274
275(defun compute-class-default-initargs (class)
276  (mapappend #'class-direct-default-initargs
277             (class-precedence-list class)))
278
279;;; Class precedence lists
280
281(defun std-compute-class-precedence-list (class)
282  (let ((classes-to-order (collect-superclasses* class)))
283    (topological-sort classes-to-order
284                      (remove-duplicates
285                       (mapappend #'local-precedence-ordering
286                                  classes-to-order))
287                      #'std-tie-breaker-rule)))
288
289;;; topological-sort implements the standard algorithm for topologically
290;;; sorting an arbitrary set of elements while honoring the precedence
291;;; constraints given by a set of (X,Y) pairs that indicate that element
292;;; X must precede element Y.  The tie-breaker procedure is called when it
293;;; is necessary to choose from multiple minimal elements; both a list of
294;;; candidates and the ordering so far are provided as arguments.
295
296(defun topological-sort (elements constraints tie-breaker)
297  (let ((remaining-constraints constraints)
298        (remaining-elements elements)
299        (result ()))
300    (loop
301      (let ((minimal-elements
302             (remove-if
303              #'(lambda (class)
304                 (member class remaining-constraints
305                         :key #'cadr))
306              remaining-elements)))
307        (when (null minimal-elements)
308          (if (null remaining-elements)
309              (return-from topological-sort result)
310              (error "Inconsistent precedence graph.")))
311        (let ((choice (if (null (cdr minimal-elements))
312                          (car minimal-elements)
313                          (funcall tie-breaker
314                                   minimal-elements
315                                   result))))
316          (setq result (append result (list choice)))
317          (setq remaining-elements
318                (remove choice remaining-elements))
319          (setq remaining-constraints
320                (remove choice
321                        remaining-constraints
322                        :test #'member)))))))
323
324;;; In the event of a tie while topologically sorting class precedence lists,
325;;; the CLOS Specification says to "select the one that has a direct subclass
326;;; rightmost in the class precedence list computed so far."  The same result
327;;; is obtained by inspecting the partially constructed class precedence list
328;;; from right to left, looking for the first minimal element to show up among
329;;; the direct superclasses of the class precedence list constituent.
330;;; (There's a lemma that shows that this rule yields a unique result.)
331
332(defun std-tie-breaker-rule (minimal-elements cpl-so-far)
333  (dolist (cpl-constituent (reverse cpl-so-far))
334    (let* ((supers (class-direct-superclasses cpl-constituent))
335           (common (intersection minimal-elements supers)))
336      (when (not (null common))
337        (return-from std-tie-breaker-rule (car common))))))
338
339;;; This version of collect-superclasses* isn't bothered by cycles in the class
340;;; hierarchy, which sometimes happen by accident.
341
342(defun collect-superclasses* (class)
343  (labels ((all-superclasses-loop (seen superclasses)
344                                  (let ((to-be-processed
345                                         (set-difference superclasses seen)))
346                                    (if (null to-be-processed)
347                                        superclasses
348                                        (let ((class-to-process
349                                               (car to-be-processed)))
350                                          (all-superclasses-loop
351                                           (cons class-to-process seen)
352                                           (union (class-direct-superclasses
353                                                   class-to-process)
354                                                  superclasses)))))))
355          (all-superclasses-loop () (list class))))
356
357;;; The local precedence ordering of a class C with direct superclasses C_1,
358;;; C_2, ..., C_n is the set ((C C_1) (C_1 C_2) ...(C_n-1 C_n)).
359
360(defun local-precedence-ordering (class)
361  (mapcar #'list
362          (cons class
363                (butlast (class-direct-superclasses class)))
364          (class-direct-superclasses class)))
365
366;;; Slot inheritance
367
368(defun std-compute-slots (class)
369  (let* ((all-slots (mapappend #'class-direct-slots
370                               (class-precedence-list class)))
371         (all-names (remove-duplicates
372                     (mapcar #'slot-definition-name all-slots))))
373    (mapcar #'(lambda (name)
374               (funcall
375                (if (eq (class-of class) the-class-standard-class)
376                    #'std-compute-effective-slot-definition
377                    #'compute-effective-slot-definition)
378                class
379                (remove name all-slots
380                        :key #'slot-definition-name
381                        :test-not #'eq)))
382            all-names)))
383
384(defun std-compute-effective-slot-definition (class direct-slots)
385  (declare (ignore class))
386  (let ((initer (find-if-not #'null direct-slots
387                             :key #'slot-definition-initfunction)))
388    (make-effective-slot-definition
389     :name (slot-definition-name (car direct-slots))
390     :initform (if initer
391                   (slot-definition-initform initer)
392                   nil)
393     :initfunction (if initer
394                       (slot-definition-initfunction initer)
395                       nil)
396     :initargs (remove-duplicates
397                (mapappend #'slot-definition-initargs
398                           direct-slots))
399     :allocation (slot-definition-allocation (car direct-slots))
400     :allocation-class (slot-definition-allocation-class (car direct-slots)))))
401
402;;; Standard instance slot access
403
404;;; N.B. The location of the effective-slots slots in the class metaobject for
405;;; standard-class must be determined without making any further slot
406;;; references.
407
408(defvar the-slots-of-standard-class) ;standard-class's class-slots
409(defvar the-class-standard-class (find-class 'standard-class))
410
411(defun find-slot-definition (class slot-name)
412  (dolist (slot (class-slots class) nil)
413    (when (eq slot-name (slot-definition-name slot))
414      (return slot))))
415
416(defun slot-location (class slot-name)
417  (let ((slot (find-slot-definition class slot-name)))
418    (if slot
419        (slot-definition-location slot)
420        nil)))
421
422(defun instance-slot-location (instance slot-name)
423  (let* ((layout (std-instance-layout instance))
424         (location (and layout (instance-slot-index layout slot-name))))
425    (if location
426        location
427        (slot-location (class-of instance) slot-name))))
428
429(defun std-slot-value (instance slot-name)
430  (let* ((location (instance-slot-location instance slot-name))
431         (value (cond ((fixnump location)
432                       (instance-ref instance location))
433                      ((consp location)
434                       (cdr location))
435                      (t
436                       (slot-missing (class-of instance) instance slot-name 'slot-value)))))
437    (if (eq +slot-unbound+ value)
438        (slot-unbound (class-of instance) instance slot-name)
439        value)))
440
441(defun slot-value (object slot-name)
442  (if (eq (class-of (class-of object)) the-class-standard-class)
443      (std-slot-value object slot-name)
444      (slot-value-using-class (class-of object) object slot-name)))
445
446(defun %set-std-slot-value (instance slot-name new-value)
447  (let ((location (instance-slot-location instance slot-name)))
448    (cond ((fixnump location)
449           (setf (instance-ref instance location) new-value))
450          ((consp location)
451           (setf (cdr location) new-value))
452          (t
453           (slot-missing (class-of instance) instance slot-name 'setf new-value))))
454  new-value)
455
456(defsetf std-slot-value %set-std-slot-value)
457
458(defun (setf slot-value) (new-value object slot-name)
459  (if (eq (class-of (class-of object)) the-class-standard-class)
460      (setf (std-slot-value object slot-name) new-value)
461      (setf-slot-value-using-class
462       new-value (class-of object) object slot-name)))
463
464(defun std-slot-boundp (instance slot-name)
465  (let ((location (instance-slot-location instance slot-name)))
466    (cond ((fixnump location)
467           (neq +slot-unbound+ (instance-ref instance location)))
468          ((consp location)
469           (neq +slot-unbound+ (cdr location)))
470          (t
471           (not (null (slot-missing (class-of instance) instance slot-name 'slot-boundp)))))))
472
473(defun slot-boundp (object slot-name)
474  (if (eq (class-of (class-of object)) the-class-standard-class)
475      (std-slot-boundp object slot-name)
476      (slot-boundp-using-class (class-of object) object slot-name)))
477
478(defun std-slot-makunbound (instance slot-name)
479  (let ((location (instance-slot-location instance slot-name)))
480    (cond ((fixnump location)
481           (setf (instance-ref instance location) +slot-unbound+))
482          ((consp location)
483           (setf (cdr location) +slot-unbound+))
484          (t
485           (slot-missing (class-of instance) instance slot-name 'slot-makunbound))))
486  instance)
487
488(defun slot-makunbound (object slot-name)
489  (if (eq (class-of (class-of object)) the-class-standard-class)
490      (std-slot-makunbound object slot-name)
491      (slot-makunbound-using-class (class-of object) object slot-name)))
492
493(defun std-slot-exists-p (instance slot-name)
494  (not (null (find slot-name (class-slots (class-of instance))
495                   :key #'slot-definition-name))))
496
497(defun slot-exists-p (object slot-name)
498  (if (eq (class-of (class-of object)) the-class-standard-class)
499      (std-slot-exists-p object slot-name)
500      (slot-exists-p-using-class (class-of object) object slot-name)))
501
502(defun instance-slot-p (slot)
503  (eq (slot-definition-allocation slot) :instance))
504
505(defun std-allocate-instance (class)
506  (let* ((layout (class-layout class))
507         (length (and layout (layout-length layout))))
508    (unless layout
509      (format t "no layout for class ~S~%" class)
510      (backtrace))
511    (unless length
512      (format t "no layout length for class ~S~%" class)
513      (setf length (count-if #'instance-slot-p (class-slots class))))
514    (allocate-std-instance class
515                           (allocate-slot-storage length +slot-unbound+))))
516
517(defun make-instance-standard-class (metaclass
518                                     &key name direct-superclasses direct-slots
519                                     direct-default-initargs
520                                     documentation
521                                     &allow-other-keys)
522  (declare (ignore metaclass))
523  (let ((class (std-allocate-instance (find-class 'standard-class))))
524    (%set-class-name class name)
525    (setf (class-direct-subclasses class) ())
526    (setf (class-direct-methods class) ())
527    (%set-class-documentation class documentation)
528    (std-after-initialization-for-classes class
529                                          :direct-superclasses direct-superclasses
530                                          :direct-slots direct-slots
531                                          :direct-default-initargs direct-default-initargs)
532    class))
533
534(defun std-after-initialization-for-classes (class
535                                             &key direct-superclasses direct-slots
536                                             direct-default-initargs
537                                             &allow-other-keys)
538  (let ((supers (or direct-superclasses
539                    (list (find-class 'standard-object)))))
540    (setf (class-direct-superclasses class) supers)
541    (dolist (superclass supers)
542      (push class (class-direct-subclasses superclass))))
543  (let ((slots (mapcar #'(lambda (slot-properties)
544                          (apply #'make-direct-slot-definition class slot-properties))
545                       direct-slots)))
546    (setf (class-direct-slots class) slots)
547    (dolist (direct-slot slots)
548      (dolist (reader (slot-definition-readers direct-slot))
549        (add-reader-method
550         class reader (slot-definition-name direct-slot)))
551      (dolist (writer (slot-definition-writers direct-slot))
552        (add-writer-method
553         class writer (slot-definition-name direct-slot)))))
554  (setf (class-direct-default-initargs class) direct-default-initargs)
555  (funcall (if (eq (class-of class) (find-class 'standard-class))
556               #'std-finalize-inheritance
557               #'finalize-inheritance)
558           class)
559  (values))
560
561(defun canonical-slot-name (canonical-slot)
562  (getf canonical-slot :name))
563
564(defun ensure-class (name &rest all-keys &allow-other-keys)
565  ;; Check for duplicate slots.
566  (let ((slots (getf all-keys :direct-slots)))
567    (dolist (s1 slots)
568      (let ((name1 (canonical-slot-name s1)))
569        (dolist (s2 (cdr (memq s1 slots)))
570    (when (eq name1 (canonical-slot-name s2))
571            (error 'program-error "duplicate slot ~S" name1))))))
572  ;; Check for duplicate argument names in :DEFAULT-INITARGS.
573  (let ((names ()))
574    (do* ((initargs (getf all-keys :direct-default-initargs) (cddr initargs))
575          (name (car initargs) (car initargs)))
576         ((null initargs))
577      (push name names))
578    (do* ((names names (cdr names))
579          (name (car names) (car names)))
580         ((null names))
581      (when (memq name (cdr names))
582        (error 'program-error
583               :format-control "Duplicate initialization argument name ~S in :DEFAULT-INITARGS."
584               :format-arguments (list name)))))
585  (let ((class (find-class name nil)))
586    (unless class
587      (setf class (apply #'make-instance-standard-class (find-class 'standard-class)
588                         :name name all-keys))
589      (%set-find-class name class))
590    class))
591
592(defmacro defclass (&whole form name direct-superclasses direct-slots &rest options)
593  (unless (>= (length form) 3)
594    (error 'program-error "Wrong number of arguments for DEFCLASS."))
595  `(ensure-class ',name
596                 :direct-superclasses
597                 ,(canonicalize-direct-superclasses direct-superclasses)
598                 :direct-slots
599                 ,(canonicalize-direct-slots direct-slots)
600                 ,@(canonicalize-defclass-options options)))
601
602(defstruct method-combination
603  name
604  operator
605  identity-with-one-argument
606  documentation)
607
608(defmacro define-method-combination (&whole form &rest args)
609  (declare (ignore args))
610  (if (and (cddr form)
611           (listp (caddr form)))
612      (expand-long-defcombin form)
613      (expand-short-defcombin form)))
614
615(defun expand-short-defcombin (whole)
616  (let* ((name (cadr whole))
617   (documentation
618          (getf (cddr whole) :documentation ""))
619   (identity-with-one-arg
620          (getf (cddr whole) :identity-with-one-argument nil))
621   (operator
622          (getf (cddr whole) :operator name)))
623    `(progn
624       (setf (get ',name 'method-combination-object)
625             (make-method-combination :name ',name
626                                      :operator ',operator
627                                      :identity-with-one-argument ',identity-with-one-arg
628                                      :documentation ',documentation))
629       ',name)))
630
631(defun expand-long-defcombin (whole)
632  (error "The long form of DEFINE-METHOD-COMBINATION is not yet supported."))
633
634(define-method-combination +      :identity-with-one-argument t)
635(define-method-combination and    :identity-with-one-argument t)
636(define-method-combination append :identity-with-one-argument nil)
637(define-method-combination list   :identity-with-one-argument nil)
638(define-method-combination max    :identity-with-one-argument t)
639(define-method-combination min    :identity-with-one-argument t)
640(define-method-combination nconc  :identity-with-one-argument t)
641(define-method-combination or     :identity-with-one-argument t)
642(define-method-combination progn  :identity-with-one-argument t)
643
644(defstruct eql-specializer
645  object)
646
647(defparameter *eql-specializer-table* (make-hash-table :test 'eql))
648
649(defun intern-eql-specializer (object)
650  (or (gethash object *eql-specializer-table*)
651      (setf (gethash object *eql-specializer-table*)
652      (make-eql-specializer :object object))))
653
654(defclass standard-generic-function (generic-function)
655  ((name :initarg :name)      ; :accessor generic-function-name
656   (lambda-list               ; :accessor generic-function-lambda-list
657    :initarg :lambda-list)
658   (documentation
659    :initarg :documentation)  ; :accessor generic-function-documentation
660   (methods :initform ())     ; :accessor generic-function-methods
661   (method-class              ; :accessor generic-function-method-class
662    :initarg :method-class)
663   ;; The method-combination slot contains either the name of the method
664   ;; combination type or a list whose car is the name of the method
665   ;; combination type and whose cdr is a list of options.
666   (method-combination
667    :initarg :method-combination)
668   (argument-precedence-order
669    :initarg :argument-precedence-order)
670   (classes-to-emf-table      ; :accessor classes-to-emf-table
671    :initform (make-hash-table :test #'equal))
672   (required-args :initform ())))
673
674(defvar the-class-standard-gf (find-class 'standard-generic-function))
675
676(defvar *sgf-required-args-index*
677  (slot-location the-class-standard-gf 'required-args))
678
679(defvar *sgf-classes-to-emf-table-index*
680  (slot-location the-class-standard-gf 'classes-to-emf-table))
681
682(defun generic-function-name (gf)
683  (slot-value gf 'name))
684(defun (setf generic-function-name) (new-value gf)
685  (setf (slot-value gf 'name) new-value))
686
687(defun generic-function-lambda-list (gf)
688  (slot-value gf 'lambda-list))
689(defun (setf generic-function-lambda-list) (new-value gf)
690  (setf (slot-value gf 'lambda-list) new-value))
691
692(defun generic-function-documentation (gf)
693  (slot-value gf 'documentation))
694(defun (setf generic-function-documentation) (new-value gf)
695  (setf (slot-value gf 'documentation) new-value))
696
697(defun generic-function-methods (gf)
698  (slot-value gf 'methods))
699(defun (setf generic-function-methods) (new-value gf)
700  (setf (slot-value gf 'methods) new-value))
701
702(defsetf generic-function-discriminating-function
703  %set-generic-function-discriminating-function)
704
705(defun generic-function-method-class (gf)
706  (slot-value gf 'method-class))
707(defun (setf generic-function-method-class) (new-value gf)
708  (setf (slot-value gf 'method-class) new-value))
709
710(defun generic-function-method-combination (gf)
711  (slot-value gf 'method-combination))
712(defun (setf generic-function-method-combination) (new-value gf)
713  (setf (slot-value gf 'method-combination) new-value))
714
715(defun generic-function-argument-precedence-order (gf)
716  (slot-value gf 'argument-precedence-order))
717(defun (setf generic-function-argument-precedence-order) (new-value gf)
718  (setf (slot-value gf 'argument-precedence-order) new-value))
719
720;;; Internal accessor for effective method function table
721
722(defun classes-to-emf-table (gf)
723  (instance-ref gf *sgf-classes-to-emf-table-index*))
724
725(defun (setf classes-to-emf-table) (new-value gf)
726  (setf (slot-value gf 'classes-to-emf-table) new-value))
727
728;;; Method metaobjects and standard-method
729
730(defclass standard-method (method)
731  ((lambda-list :initarg :lambda-list)     ; :accessor method-lambda-list
732   (qualifiers :initarg :qualifiers)       ; :accessor method-qualifiers
733   (specializers :initarg :specializers)   ; :accessor method-specializers
734   (declarations :initarg :declarations)   ; :accessir method-declarations
735   (body :initarg :body)                   ; :accessor method-body
736   (environment :initarg :environment)     ; :accessor method-environment
737   (generic-function :initform nil)        ; :accessor method-generic-function
738   (function)                              ; :accessor method-function
739   (documentation)))                       ; :accessor method-documentation
740
741(defvar the-class-standard-method (find-class 'standard-method))
742
743(defvar *sm-function-index*
744  (slot-location the-class-standard-method 'function))
745
746(defun method-lambda-list (method) (slot-value method 'lambda-list))
747(defun (setf method-lambda-list) (new-value method)
748  (setf (slot-value method 'lambda-list) new-value))
749
750(defun method-qualifiers (method) (slot-value method 'qualifiers))
751(defun (setf method-qualifiers) (new-value method)
752  (setf (slot-value method 'qualifiers) new-value))
753
754(defun method-specializers (method) (slot-value method 'specializers))
755(defun (setf method-specializers) (new-value method)
756  (setf (slot-value method 'specializers) new-value))
757
758(defun method-declarations (method) (slot-value method 'declarations))
759(defun (setf method-declarations) (new-value method)
760  (setf (slot-value method 'declarations) new-value))
761
762(defun method-body (method) (slot-value method 'body))
763(defun (setf method-body) (new-value method)
764  (setf (slot-value method 'body) new-value))
765
766(defun method-environment (method) (slot-value method 'environment))
767(defun (setf method-environment) (new-value method)
768  (setf (slot-value method 'environment) new-value))
769
770(defun method-generic-function (method)
771  (slot-value method 'generic-function))
772(defun (setf method-generic-function) (new-value method)
773  (setf (slot-value method 'generic-function) new-value))
774
775(defun method-function (method)
776  (instance-ref method *sm-function-index*))
777
778(defun (setf method-function) (new-value method)
779  (setf (slot-value method 'function) new-value))
780
781(defun method-documentation (method)
782  (slot-value method 'documentation))
783
784(defun (setf method-documentation) (new-value method)
785  (setf (slot-value method 'documentation) new-value))
786
787;;; defgeneric
788
789(defmacro defgeneric (function-name lambda-list
790                                    &rest options-and-method-descriptions)
791  (let ((options ())
792        (methods ())
793        (documentation nil))
794    (dolist (item options-and-method-descriptions)
795      (case (car item)
796        (declare) ; FIXME
797        (:documentation
798         (when documentation
799           (error 'program-error
800                  :format-control "Documentation option was specified twice for generic function ~S."
801                  :format-arguments (list function-name)))
802         (setf documentation t)
803         (push item options))
804        (:method
805         (push `(defmethod ,function-name ,@(cdr item)) methods))
806        (t
807         (push item options))))
808    (setf options (nreverse options)
809          methods (nreverse methods))
810    `(prog1
811       (ensure-generic-function
812        ',function-name
813        :lambda-list ',lambda-list
814        ,@(canonicalize-defgeneric-options options))
815       ,@methods)))
816
817(defun canonicalize-defgeneric-options (options)
818  (mapappend #'canonicalize-defgeneric-option options))
819
820(defun canonicalize-defgeneric-option (option)
821  (case (car option)
822    (:generic-function-class
823     (list :generic-function-class `(find-class ',(cadr option))))
824    (:method-class
825     (list :method-class `(find-class ',(cadr option))))
826    (:method-combination
827     (list :method-combination `',(cdr option)))
828    (:argument-precedence-order
829     (list :argument-precedence-order `',(cdr option)))
830    (t
831     (list `',(car option) `',(cadr option)))))
832
833;; From OpenMCL.
834(defun canonicalize-argument-precedence-order (apo req)
835  (cond ((equal apo req) nil)
836        ((not (eql (length apo) (length req)))
837         (error 'program-error
838                :format-control "Specified argument precedence order ~S does not match lambda list."
839                :format-arguments (list apo)))
840        (t (let ((res nil))
841             (dolist (arg apo (nreverse res))
842               (let ((index (position arg req)))
843                 (if (or (null index) (memq index res))
844                     (error 'program-error
845                            :format-control "Specified argument precedence order ~S does not match lambda list."
846                            :format-arguments (list apo)))
847                 (push index res)))))))
848
849(defparameter generic-function-table (make-hash-table :test #'equal))
850
851;; FIXME Do we still need this?
852(defun find-generic-function (symbol &optional (errorp t))
853  (let ((gf (gethash symbol generic-function-table nil)))
854    (if (and (null gf) errorp)
855        (error "no generic function named ~S" symbol)
856        gf)))
857
858(defun (setf find-generic-function) (new-value symbol)
859  (setf (gethash symbol generic-function-table) new-value))
860
861(defun lambda-lists-congruent-p (lambda-list1 lambda-list2)
862  (let* ((plist1 (analyze-lambda-list lambda-list1))
863         (args1 (getf plist1 :required-args))
864         (plist2 (analyze-lambda-list lambda-list2))
865         (args2 (getf plist2 :required-args)))
866    (= (length args1) (length args2))))
867
868(defun ensure-generic-function (function-name
869                                &rest all-keys
870                                &key
871                                lambda-list
872                                (generic-function-class the-class-standard-gf)
873                                (method-class the-class-standard-method)
874                                (method-combination 'standard)
875                                documentation
876                                &allow-other-keys)
877  (when (autoloadp function-name)
878    (resolve function-name))
879  (let ((gf (find-generic-function function-name nil)))
880    (if gf
881        (progn
882          (unless (or (null (generic-function-methods gf))
883                      (lambda-lists-congruent-p lambda-list (generic-function-lambda-list gf)))
884            (error 'simple-error
885                   :format-control "The lambda list ~S is incompatible with the existing methods of ~S."
886                   :format-arguments (list lambda-list gf)))
887          (setf (generic-function-lambda-list gf) lambda-list)
888          (setf (generic-function-documentation gf) documentation)
889          gf)
890        (progn
891          (when (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-class-standard-gf)
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          (setf (find-generic-function function-name) gf)
904          gf))))
905
906(defun finalize-generic-function (gf)
907  (setf (generic-function-discriminating-function gf)
908        (funcall (if (eq (class-of gf) the-class-standard-gf)
909                     #'std-compute-discriminating-function
910                     #'compute-discriminating-function)
911                 gf))
912  (setf (fdefinition (generic-function-name gf)) gf)
913  (clrhash (classes-to-emf-table gf))
914  (values))
915
916(defun gf-required-args (gf)
917  (instance-ref gf *sgf-required-args-index*))
918
919(defun make-instance-standard-generic-function (generic-function-class
920                                                &key name lambda-list
921                                                method-class
922                                                method-combination
923                                                argument-precedence-order
924                                                documentation)
925  (declare (ignore generic-function-class))
926  (let ((gf (std-allocate-instance the-class-standard-gf)))
927    (setf (generic-function-name gf) name)
928    (setf (generic-function-lambda-list gf) lambda-list)
929    (setf (generic-function-methods gf) ())
930    (setf (generic-function-method-class gf) method-class)
931    (setf (generic-function-method-combination gf) method-combination)
932    (setf (generic-function-documentation gf) documentation)
933    (setf (classes-to-emf-table gf) (make-hash-table :test #'equal))
934    (let* ((plist (analyze-lambda-list (generic-function-lambda-list gf)))
935           (required-args (getf plist ':required-args)))
936      (setf (slot-value gf 'required-args) required-args)
937      (setf (slot-value gf 'argument-precedence-order)
938            (if argument-precedence-order
939                (canonicalize-argument-precedence-order argument-precedence-order
940                                                        required-args)
941                nil)))
942    (finalize-generic-function gf)
943    gf))
944
945(defun top-level-environment ()
946  nil)
947
948(defun compile-in-lexical-environment (env lambda-expr)
949  (make-closure lambda-expr env))
950
951(defmacro defmethod (&rest args &environment environment)
952  (multiple-value-bind
953    (function-name qualifiers lambda-list specializers documentation declarations body)
954    (parse-defmethod args)
955    `(progn
956       (unless (find-generic-function ',function-name nil)
957         (ensure-generic-function
958          ',function-name
959          :lambda-list ',lambda-list))
960       (ensure-method (find-generic-function ',function-name)
961                      :lambda-list ',lambda-list
962                      :qualifiers ',qualifiers
963                      :specializers ',specializers
964                      :documentation ,documentation
965                      :declarations ',declarations
966                      :body ',body
967                      :environment ,environment))))
968
969(defun canonicalize-specializers (specializers)
970  (mapcar #'canonicalize-specializer specializers))
971
972(defun canonicalize-specializer (specializer)
973  (cond ((classp specializer)
974         specializer)
975        ((eql-specializer-p specializer)
976         specializer)
977        ((symbolp specializer)
978         (find-class specializer))
979        ((and (consp specializer)
980              (eq (car specializer) 'eql))
981         (let ((object (cadr specializer)))
982           (when (and (consp object)
983                      (eq (car object) 'quote))
984             (setf object (cadr object)))
985           (intern-eql-specializer object)))
986        (t
987         (error "Unknown specializer: ~S~%." specializer))))
988
989(defun parse-defmethod (args)
990  (let ((function-name (car args))
991        (qualifiers ())
992        (specialized-lambda-list ())
993        (specializers ())
994        (body ())
995        (parse-state :qualifiers))
996    (dolist (arg (cdr args))
997      (ecase parse-state
998        (:qualifiers
999         (if (and (atom arg) (not (null arg)))
1000             (push-on-end arg qualifiers)
1001             (progn (setf specialized-lambda-list arg)
1002               (setf parse-state :body))))
1003        (:body (push-on-end arg body))))
1004    (setf specializers
1005          (canonicalize-specializers (extract-specializers specialized-lambda-list)))
1006    (multiple-value-bind (real-body declarations documentation)
1007      (parse-body body)
1008        (values function-name
1009                qualifiers
1010                (extract-lambda-list specialized-lambda-list)
1011                specializers
1012                documentation
1013                declarations
1014                (list* 'block
1015                         (if (consp function-name)
1016                             (cadr function-name)
1017                             function-name)
1018                         real-body)))))
1019
1020(defun required-portion (gf args)
1021  (let ((number-required (length (gf-required-args gf))))
1022    (when (< (length args) number-required)
1023      (error 'program-error
1024             :format-control "Not enough arguments for generic function ~S."
1025             :format-arguments (list gf)))
1026    (subseq args 0 number-required)))
1027
1028(defun extract-lambda-list (specialized-lambda-list)
1029  (let* ((plist (analyze-lambda-list specialized-lambda-list))
1030         (requireds (getf plist :required-names))
1031         (rv (getf plist :rest-var))
1032         (ks (getf plist :key-args))
1033         (keysp (getf plist :keysp))
1034         (aok (getf plist :allow-other-keys))
1035         (opts (getf plist :optional-args))
1036         (auxs (getf plist :auxiliary-args)))
1037    `(,@requireds
1038      ,@(if rv `(&rest ,rv) ())
1039      ,@(if (or ks keysp aok) `(&key ,@ks) ())
1040      ,@(if aok '(&allow-other-keys) ())
1041      ,@(if opts `(&optional ,@opts) ())
1042      ,@(if auxs `(&aux ,@auxs) ()))))
1043
1044(defun extract-specializers (specialized-lambda-list)
1045  (let ((plist (analyze-lambda-list specialized-lambda-list)))
1046    (getf plist ':specializers)))
1047
1048(defun analyze-lambda-list (lambda-list)
1049  (labels ((make-keyword (symbol)
1050                         (intern (symbol-name symbol)
1051                                 (find-package 'keyword)))
1052           (get-keyword-from-arg (arg)
1053                                 (if (listp arg)
1054                                     (if (listp (car arg))
1055                                         (caar arg)
1056                                         (make-keyword (car arg)))
1057                                     (make-keyword arg))))
1058          (let ((keys ())           ; Just the keywords
1059                (key-args ())       ; Keywords argument specs
1060                (keysp nil)         ;
1061                (required-names ()) ; Just the variable names
1062                (required-args ())  ; Variable names & specializers
1063                (specializers ())   ; Just the specializers
1064                (rest-var nil)
1065                (optionals ())
1066                (auxs ())
1067                (allow-other-keys nil)
1068                (state :parsing-required))
1069            (dolist (arg lambda-list)
1070              (if (member arg lambda-list-keywords)
1071                  (ecase arg
1072                    (&optional
1073                     (setq state :parsing-optional))
1074                    (&rest
1075                     (setq state :parsing-rest))
1076                    (&key
1077                     (setq keysp t)
1078                     (setq state :parsing-key))
1079                    (&allow-other-keys
1080                     (setq allow-other-keys 't))
1081                    (&aux
1082                     (setq state :parsing-aux)))
1083                  (case state
1084                    (:parsing-required
1085                     (push-on-end arg required-args)
1086                     (if (listp arg)
1087                         (progn (push-on-end (car arg) required-names)
1088                           (push-on-end (cadr arg) specializers))
1089                         (progn (push-on-end arg required-names)
1090                           (push-on-end 't specializers))))
1091                    (:parsing-optional (push-on-end arg optionals))
1092                    (:parsing-rest (setq rest-var arg))
1093                    (:parsing-key
1094                     (push-on-end (get-keyword-from-arg arg) keys)
1095                     (push-on-end arg key-args))
1096                    (:parsing-aux (push-on-end arg auxs)))))
1097            (list  :required-names required-names
1098                   :required-args required-args
1099                   :specializers specializers
1100                   :rest-var rest-var
1101                   :keywords keys
1102                   :key-args key-args
1103                   :keysp keysp
1104                   :auxiliary-args auxs
1105                   :optional-args optionals
1106                   :allow-other-keys allow-other-keys))))
1107
1108#+nil
1109(defun check-method-arg-info (gf arg-info method)
1110  (multiple-value-bind (nreq nopt keysp restp allow-other-keys-p keywords)
1111    (analyze-lambda-list (if (consp method)
1112                             (early-method-lambda-list method)
1113                             (method-lambda-list method)))
1114    (flet ((lose (string &rest args)
1115                 (error 'simple-program-error
1116                        :format-control "~@<attempt to add the method~2I~_~S~I~_~
1117                        to the generic function~2I~_~S;~I~_~
1118                        but ~?~:>"
1119                        :format-arguments (list method gf string args)))
1120     (comparison-description (x y)
1121                                   (if (> x y) "more" "fewer")))
1122      (let ((gf-nreq (arg-info-number-required arg-info))
1123      (gf-nopt (arg-info-number-optional arg-info))
1124      (gf-key/rest-p (arg-info-key/rest-p arg-info))
1125      (gf-keywords (arg-info-keys arg-info)))
1126  (unless (= nreq gf-nreq)
1127    (lose
1128     "the method has ~A required arguments than the generic function."
1129     (comparison-description nreq gf-nreq)))
1130  (unless (= nopt gf-nopt)
1131    (lose
1132     "the method has ~A optional arguments than the generic function."
1133     (comparison-description nopt gf-nopt)))
1134  (unless (eq (or keysp restp) gf-key/rest-p)
1135    (lose
1136     "the method and generic function differ in whether they accept~_~
1137      &REST or &KEY arguments."))
1138  (when (consp gf-keywords)
1139    (unless (or (and restp (not keysp))
1140          allow-other-keys-p
1141          (every (lambda (k) (memq k keywords)) gf-keywords))
1142      (lose "the method does not accept each of the &KEY arguments~2I~_~
1143            ~S."
1144      gf-keywords)))))))
1145
1146(defun check-method-lambda-list (method-lambda-list gf-lambda-list)
1147  (let* ((gf-restp (not (null (memq '&rest gf-lambda-list))))
1148         (gf-plist (analyze-lambda-list gf-lambda-list))
1149         (gf-keysp (getf gf-plist :keysp))
1150         (gf-keywords (getf gf-plist :keywords))
1151         (method-plist (analyze-lambda-list method-lambda-list))
1152         (method-restp (not (null (memq '&rest method-lambda-list))))
1153         (method-keysp (getf method-plist :keysp))
1154         (method-keywords (getf method-plist :keywords))
1155         (method-allow-other-keys-p (getf method-plist :allow-other-keys)))
1156    (unless (= (length (getf gf-plist :required-args))
1157               (length (getf method-plist :required-args)))
1158      (error "The method has the wrong number of required arguments for the generic function."))
1159    (unless (= (length (getf gf-plist :optional-args))
1160               (length (getf method-plist :optional-args)))
1161      (error "The method has the wrong number of optional arguments for the generic function."))
1162    (unless (eq (or gf-restp gf-keysp) (or method-restp method-keysp))
1163      (error "The method and the generic function differ in whether they accept &REST or &KEY arguments."))
1164    (when (consp gf-keywords)
1165      (unless (or (and method-restp (not method-keysp))
1166                  method-allow-other-keys-p
1167                  (every (lambda (k) (memq k method-keywords)) gf-keywords))
1168        (error "The method does not accept all of the keyword arguments defined for the generic function.")))))
1169
1170(defun ensure-method (gf &rest all-keys)
1171  (let ((method-lambda-list (getf all-keys :lambda-list))
1172        (gf-lambda-list (generic-function-lambda-list gf)))
1173    (check-method-lambda-list method-lambda-list gf-lambda-list))
1174  (let ((method
1175         (apply
1176          (if (eq (generic-function-method-class gf) the-class-standard-method)
1177              #'make-instance-standard-method
1178              #'make-instance)
1179          (generic-function-method-class gf)
1180          all-keys)))
1181    (%add-method gf method)
1182    method))
1183
1184(defun make-instance-standard-method (method-class
1185                                      &key
1186                                      lambda-list qualifiers specializers
1187                                      documentation declarations body
1188                                      environment)
1189  (declare (ignore method-class))
1190  (let ((method (std-allocate-instance the-class-standard-method)))
1191    (setf (method-lambda-list method) lambda-list)
1192    (setf (method-qualifiers method) qualifiers)
1193    (setf (method-specializers method) specializers)
1194    (setf (method-documentation method) documentation)
1195    (setf (method-declarations method) declarations)
1196    (setf (method-body method) (precompile-form body nil))
1197    (setf (method-environment method) environment)
1198    (setf (method-generic-function method) nil)
1199    (setf (method-function method) (std-compute-method-function method))
1200    method))
1201
1202(defun add-method (gf method)
1203  (let ((method-lambda-list (method-lambda-list method))
1204        (gf-lambda-list (generic-function-lambda-list gf)))
1205    (check-method-lambda-list method-lambda-list gf-lambda-list))
1206  (%add-method gf method))
1207
1208(defun %add-method (gf method)
1209  (when (method-generic-function method)
1210    (error 'simple-error
1211           :format-control "ADD-METHOD: ~S is a method of ~S."
1212           :format-arguments (list method (method-generic-function method))))
1213  ;; Remove existing method with same qualifiers and specializers (if any).
1214  (let ((old-method (find-method gf (method-qualifiers method)
1215                                 (method-specializers method) nil)))
1216    (when old-method
1217      (remove-method gf old-method)))
1218  (setf (method-generic-function method) gf)
1219  (push method (generic-function-methods gf))
1220  (dolist (specializer (method-specializers method))
1221    (when (typep specializer 'class) ;; FIXME What about EQL specializer objects?
1222      (pushnew method (class-direct-methods specializer))))
1223  (finalize-generic-function gf)
1224  gf)
1225
1226(defun remove-method (gf method)
1227  (setf (generic-function-methods gf)
1228        (remove method (generic-function-methods gf)))
1229  (setf (method-generic-function method) nil)
1230  (dolist (specializer (method-specializers method))
1231    (when (typep specializer 'class) ;; FIXME What about EQL specializer objects?
1232      (setf (class-direct-methods specializer)
1233            (remove method (class-direct-methods specializer)))))
1234  (finalize-generic-function gf)
1235  gf)
1236
1237(defun find-method (gf qualifiers specializers &optional (errorp t))
1238  (let* ((canonical-specializers (canonicalize-specializers specializers))
1239         (method
1240          (find-if #'(lambda (method)
1241                      (and (equal qualifiers
1242                                  (method-qualifiers method))
1243                           (equal canonical-specializers
1244                                  (method-specializers method))))
1245                   (generic-function-methods gf))))
1246    (if (and (null method) errorp)
1247        (error "No such method for ~S." (generic-function-name gf))
1248        method)))
1249
1250;;; Reader and writer methods
1251
1252(defun add-reader-method (class fn-name slot-name)
1253  (ensure-method
1254   (ensure-generic-function fn-name :lambda-list '(object))
1255   :lambda-list '(object)
1256   :qualifiers ()
1257   :specializers (list class)
1258   :body `(slot-value object ',slot-name)
1259   :environment (top-level-environment))
1260  (values))
1261
1262(defun add-writer-method (class fn-name slot-name)
1263  (ensure-method
1264   (ensure-generic-function
1265    fn-name :lambda-list '(new-value object))
1266   :lambda-list '(new-value object)
1267   :qualifiers ()
1268   :specializers (list (find-class 't) class)
1269   :body `(setf (slot-value object ',slot-name)
1270                new-value)
1271   :environment (top-level-environment))
1272  (values))
1273
1274(defun subclassp (c1 c2)
1275  (not (null (find c2 (class-precedence-list c1)))))
1276
1277(defun methods-contain-eql-specializer-p (methods)
1278  (dolist (method methods nil)
1279    (when (dolist (spec (method-specializers method) nil)
1280            (when (eql-specializer-p spec) (return t)))
1281      (return t))))
1282
1283(defun std-compute-discriminating-function (gf)
1284  (if (methods-contain-eql-specializer-p (generic-function-methods gf))
1285      #'(lambda (&rest args)
1286         (slow-method-lookup gf args nil))
1287      #'(lambda (&rest args)
1288         (let* ((classes (mapcar #'class-of
1289                                 (required-portion gf args)))
1290                (emfun (gethash classes (classes-to-emf-table gf) nil)))
1291           (if emfun
1292               (funcall emfun args)
1293               (slow-method-lookup gf args classes))))))
1294
1295(defun method-applicable-p (method args)
1296  (do* ((specializers (method-specializers method) (cdr specializers))
1297        (args args (cdr args)))
1298       ((null specializers) t)
1299    (let ((specializer (car specializers)))
1300      (if (typep specializer 'eql-specializer)
1301          (unless (eql (car args) (eql-specializer-object specializer))
1302            (return nil))
1303          (unless (subclassp (class-of (car args)) specializer)
1304            (return nil))))))
1305
1306(defun %compute-applicable-methods (gf args)
1307  (let ((required-classes (mapcar #'class-of (required-portion gf args)))
1308        (methods ()))
1309    (dolist (method (generic-function-methods gf))
1310      (when (method-applicable-p method args)
1311        (push method methods)))
1312    (sort methods
1313          (if (eq (class-of gf) the-class-standard-gf)
1314              #'(lambda (m1 m2)
1315                 (std-method-more-specific-p m1 m2 required-classes
1316                                             (generic-function-argument-precedence-order gf)))
1317              #'(lambda (m1 m2)
1318                 (method-more-specific-p gf m1 m2 required-classes))))))
1319
1320(defun slow-method-lookup (gf args classes)
1321  (let ((applicable-methods (%compute-applicable-methods gf args)))
1322    (if applicable-methods
1323        (let ((emfun (funcall (if (eq (class-of gf) the-class-standard-gf)
1324                                  #'std-compute-effective-method-function
1325                                  #'compute-effective-method-function)
1326                              gf applicable-methods)))
1327          (when classes
1328            (setf (gethash classes (classes-to-emf-table gf)) emfun))
1329          (funcall emfun args))
1330        (error "No applicable methods for generic function ~A with arguments ~S of classes ~S."
1331               (generic-function-name gf) args classes))))
1332
1333(defun sub-specializer-p (c1 c2 c-arg)
1334  (find c2 (cdr (memq c1 (class-precedence-list c-arg)))))
1335
1336(defun std-method-more-specific-p (method1 method2 required-classes argument-precedence-order)
1337  (if argument-precedence-order
1338      (let ((specializers-1 (method-specializers method1))
1339            (specializers-2 (method-specializers method2)))
1340        (dolist (index argument-precedence-order)
1341          (let ((spec1 (nth index specializers-1))
1342                (spec2 (nth index specializers-2)))
1343            (unless (eq spec1 spec2)
1344              (cond ((eql-specializer-p spec1)
1345                     (return t))
1346                    ((eql-specializer-p spec2)
1347                     (return nil))
1348                    (t
1349                     (return (sub-specializer-p spec1 spec2
1350                                                (nth index required-classes)))))))))
1351      (do ((specializers-1 (method-specializers method1) (cdr specializers-1))
1352           (specializers-2 (method-specializers method2) (cdr specializers-2))
1353           (classes required-classes (cdr classes)))
1354          ((null specializers-1) nil)
1355        (let ((spec1 (car specializers-1))
1356              (spec2 (car specializers-2)))
1357          (unless (eq spec1 spec2)
1358            (cond ((eql-specializer-p spec1)
1359                   (return t))
1360                  ((eql-specializer-p spec2)
1361                   (return nil))
1362                  (t
1363                   (return (sub-specializer-p spec1 spec2 (car classes))))))))))
1364
1365(defun primary-method-p (method)
1366  (null (intersection '(:before :after :around) (method-qualifiers method))))
1367
1368(defun before-method-p (method)
1369  (equal '(:before) (method-qualifiers method)))
1370
1371(defun after-method-p (method)
1372  (equal '(:after) (method-qualifiers method)))
1373
1374(defun around-method-p (method)
1375  (equal '(:around) (method-qualifiers method)))
1376
1377(defun std-compute-effective-method-function (gf methods)
1378  (let* ((mc (generic-function-method-combination gf))
1379         (mc-name (if (atom mc) mc (car mc)))
1380         (options (if (atom mc) () (cdr mc)))
1381         (order (car options))
1382         (primaries ())
1383         (arounds ())
1384         around)
1385    (dolist (m methods)
1386      (let ((qualifiers (method-qualifiers m)))
1387        (cond ((null qualifiers)
1388               (if (eq mc-name 'standard)
1389                   (push m primaries)
1390                   (error "Method combination type mismatch.")))
1391              ((cdr qualifiers)
1392               (error "Invalid method qualifiers."))
1393              ((eq (car qualifiers) :around)
1394               (push m arounds))
1395              ((eq (car qualifiers) mc-name)
1396               (push m primaries))
1397              ((memq (car qualifiers) '(:before :after)))
1398              (t
1399               (error "Invalid method qualifiers.")))))
1400    (unless (eq order :most-specific-last)
1401      (setf primaries (nreverse primaries)))
1402    (setf arounds (nreverse arounds))
1403    (setf around (car arounds))
1404    (when (null primaries)
1405      (error "No primary methods for the generic function ~S." gf))
1406    (cond (around
1407           (let ((next-emfun
1408                  (funcall
1409                   (if (eq (class-of gf) the-class-standard-gf)
1410                       #'std-compute-effective-method-function
1411                       #'compute-effective-method-function)
1412                   gf (remove around methods))))
1413             #'(lambda (args)
1414                (funcall (method-function around) args next-emfun))))
1415          ((eq mc-name 'standard)
1416           (let ((next-emfun (compute-primary-emfun (cdr primaries)))
1417                 (befores (remove-if-not #'before-method-p methods))
1418                 (reverse-afters
1419                  (reverse (remove-if-not #'after-method-p methods))))
1420             #'(lambda (args)
1421                (dolist (before befores)
1422                  (funcall (method-function before) args nil))
1423                (multiple-value-prog1
1424                 (funcall (method-function (car primaries)) args next-emfun)
1425                 (dolist (after reverse-afters)
1426                   (funcall (method-function after) args nil))))))
1427          (t
1428           (let ((mc-obj (get mc-name 'method-combination-object)))
1429             (unless mc-obj
1430               (error "Unsupported method combination type ~A." mc-name))
1431             (let* ((operator (method-combination-operator mc-obj))
1432                    (ioa (method-combination-identity-with-one-argument mc-obj))
1433                    (form
1434                     (if (and (null (cdr primaries))
1435                              (not (null ioa)))
1436                         `(lambda (args)
1437                            (funcall ,(method-function (car primaries)) args nil))
1438                         `(lambda (args)
1439                            (,operator ,@(mapcar
1440                                          (lambda (primary)
1441                                            `(funcall ,(method-function primary) args nil))
1442                                          primaries))))))
1443               (coerce-to-function form)))))))
1444
1445;;; compute an effective method function from a list of primary methods:
1446
1447(defun compute-primary-emfun (methods)
1448  (if (null methods)
1449      nil
1450      (let ((next-emfun (compute-primary-emfun (cdr methods))))
1451        #'(lambda (args)
1452           (funcall (method-function (car methods)) args next-emfun)))))
1453
1454(defvar *call-next-method-p*)
1455(defvar *next-method-p-p*)
1456
1457(defun walk-form (form)
1458  (cond ((atom form)
1459         (cond ((eq form 'call-next-method)
1460                (setf *call-next-method-p* t))
1461               ((eq form 'next-method-p)
1462                (setf *next-method-p-p* t))))
1463        (t
1464         (walk-form (car form))
1465         (walk-form (cdr form)))))
1466
1467(defun std-compute-method-function (method)
1468  (let ((body (method-body method))
1469        (declarations (method-declarations method))
1470        (lambda-list (method-lambda-list method))
1471        (*call-next-method-p* nil)
1472        (*next-method-p-p* nil))
1473    (walk-form body)
1474    (setf lambda-list (kludge-arglist lambda-list))
1475    (compile-in-lexical-environment
1476     (method-environment method)
1477     (if (or *call-next-method-p* *next-method-p-p*)
1478         `(lambda (args next-emfun)
1479            (flet ((call-next-method (&rest cnm-args)
1480                                     (if (null next-emfun)
1481                                         (error "No next method for generic function ~S."
1482                                                (method-generic-function ',method))
1483                                         (funcall next-emfun (or cnm-args args))))
1484                   (next-method-p ()
1485                                  (not (null next-emfun))))
1486              (apply #'(lambda ,lambda-list ,@declarations ,body) args)))
1487         `(lambda (args next-emfun)
1488            (apply #'(lambda ,lambda-list ,@declarations ,body) args))))))
1489
1490;;; N.B. The function kludge-arglist is used to pave over the differences
1491;;; between argument keyword compatibility for regular functions versus
1492;;; generic functions.
1493
1494;; FIXME
1495;; From CLHS section 7.6.5:
1496;; "When a generic function or any of its methods mentions &key in a lambda
1497;; list, the specific set of keyword arguments accepted by the generic function
1498;; varies according to the applicable methods. The set of keyword arguments
1499;; accepted by the generic function for a particular call is the union of the
1500;; keyword arguments accepted by all applicable methods and the keyword
1501;; arguments mentioned after &key in the generic function definition, if any."
1502
1503(defun kludge-arglist (lambda-list)
1504  (if (and (member '&key lambda-list)
1505           (not (member '&allow-other-keys lambda-list)))
1506      (append lambda-list '(&allow-other-keys))
1507      (if (and (not (member '&rest lambda-list))
1508               (not (member '&key lambda-list)))
1509          (append lambda-list '(&key &allow-other-keys))
1510          lambda-list)))
1511
1512(fmakunbound 'class-name)
1513
1514(defgeneric class-name (class))
1515
1516(defmethod class-name ((class class))
1517  (%class-name class))
1518
1519(defgeneric (setf class-name) (new-value class))
1520
1521(defmethod (setf class-name) (new-value (class class))
1522  (%set-class-name class new-value))
1523
1524(fmakunbound 'documentation)
1525
1526(defgeneric documentation (x doc-type))
1527
1528(defgeneric (setf documentation) (new-value x doc-type))
1529
1530(defmethod documentation ((x symbol) doc-type)
1531  (case doc-type
1532    (FUNCTION
1533     (get x '%function-documentation))
1534    (VARIABLE
1535     (get x '%variable-documentation))
1536    (STRUCTURE
1537     (get x '%structure-documentation))))
1538
1539(defmethod (setf documentation) (new-value (x symbol) doc-type)
1540  (case doc-type
1541    (FUNCTION
1542     (setf (get x '%function-documentation) docstring))
1543    (VARIABLE
1544     (setf (get x '%variable-documentation) docstring))
1545    (STRUCTURE
1546     (setf (get x '%structure-documentation) docstring))))
1547
1548(defmethod documentation ((x standard-class) (doc-type (eql 't)))
1549  (class-documentation x))
1550
1551(defmethod documentation ((x standard-class) (doc-type (eql 'type)))
1552  (class-documentation x))
1553
1554(defmethod (setf documentation) (new-value (x standard-class) (doc-type (eql 't)))
1555  (%set-class-documentation x new-value))
1556
1557(defmethod (setf documentation) (new-value (x standard-class) (doc-type (eql 'type)))
1558  (%set-class-documentation x new-value))
1559
1560(defmethod documentation ((x standard-generic-function) (doc-type (eql 't)))
1561  (generic-function-documentation x))
1562
1563(defmethod (setf documentation) (new-value (x standard-generic-function) (doc-type (eql 't)))
1564  (setf (generic-function-documentation x) new-value))
1565
1566(defmethod documentation ((x standard-generic-function) (doc-type (eql 'function)))
1567  (generic-function-documentation x))
1568
1569(defmethod (setf documentation) (new-value (x standard-generic-function) (doc-type (eql 'function)))
1570  (setf (generic-function-documentation x) new-value))
1571
1572(defmethod documentation ((x standard-method) (doc-type (eql 't)))
1573  (method-documentation x))
1574
1575(defmethod (setf documentation) (new-value (x standard-method) (doc-type (eql 't)))
1576  (setf (method-documentation x) new-value))
1577
1578;; FIXME
1579(defmethod documentation ((x package) (doc-type (eql 't)))
1580  nil)
1581
1582;; FIXME
1583(defmethod (setf documentation) (new-value (x package) (doc-type (eql 't)))
1584  new-value)
1585
1586;;; Slot access
1587
1588(defun setf-slot-value-using-class (new-value class instance slot-name)
1589  (setf (std-slot-value instance slot-name) new-value))
1590
1591(defgeneric slot-value-using-class (class instance slot-name))
1592
1593(defmethod slot-value-using-class ((class standard-class) instance slot-name)
1594  (std-slot-value instance slot-name))
1595
1596(defgeneric (setf slot-value-using-class) (new-value class instance slot-name))
1597(defmethod (setf slot-value-using-class)
1598  (new-value (class standard-class) instance slot-name)
1599  (setf (std-slot-value instance slot-name) new-value))
1600
1601(defgeneric slot-exists-p-using-class (class instance slot-name))
1602
1603(defmethod slot-exists-p-using-class (class instance slot-name)
1604  nil)
1605
1606(defmethod slot-exists-p-using-class ((class standard-class) instance slot-name)
1607  (std-slot-exists-p instance slot-name))
1608
1609(defmethod slot-exists-p-using-class ((class structure-class) instance slot-name)
1610  (dolist (dsd (class-slots class))
1611    (when (eq (dsd-name dsd) slot-name)
1612      (return-from slot-exists-p-using-class t)))
1613  nil)
1614
1615(defgeneric slot-boundp-using-class (class instance slot-name))
1616(defmethod slot-boundp-using-class
1617  ((class standard-class) instance slot-name)
1618  (std-slot-boundp instance slot-name))
1619
1620(defgeneric slot-makunbound-using-class (class instance slot-name))
1621(defmethod slot-makunbound-using-class
1622  ((class standard-class) instance slot-name)
1623  (std-slot-makunbound instance slot-name))
1624
1625(defgeneric slot-missing (class instance slot-name operation &optional new-value))
1626
1627(defmethod slot-missing ((class t) instance slot-name operation &optional new-value)
1628  (error "The slot ~S is missing from the class ~S." slot-name class))
1629
1630(defgeneric slot-unbound (class instance slot-name))
1631
1632(defmethod slot-unbound ((class t) instance slot-name)
1633  (error 'unbound-slot :instance instance :name slot-name))
1634
1635;;; Instance creation and initialization
1636
1637(defgeneric allocate-instance (class &rest initargs &key &allow-other-keys))
1638
1639(defmethod allocate-instance ((class standard-class) &rest initargs)
1640  (std-allocate-instance class))
1641
1642(defmethod allocate-instance ((class structure-class) &rest initargs)
1643  (%make-structure (%class-name class)
1644                   (make-list (length (class-slots class))
1645                              :initial-element +slot-unbound+)))
1646
1647(defgeneric make-instance (class &key))
1648
1649(defmethod make-instance ((class standard-class) &rest initargs)
1650  (when (oddp (length initargs))
1651    (error 'program-error
1652           :format-control "Odd number of keyword arguments."))
1653  (let ((class-default-initargs (class-default-initargs class)))
1654    (when class-default-initargs
1655      (let ((default-initargs ()))
1656        (do* ((list class-default-initargs (cddr list))
1657              (key (car list) (car list))
1658              (fn (cadr list) (cadr list)))
1659             ((null list))
1660          (when (eq (getf initargs key 'not-found) 'not-found)
1661            (setf default-initargs (append default-initargs (list key (funcall fn))))))
1662        (setf initargs (append initargs default-initargs)))))
1663  (let ((instance (std-allocate-instance class)))
1664    (apply #'initialize-instance instance initargs)
1665    instance))
1666
1667(defmethod make-instance ((class symbol) &rest initargs)
1668  (apply #'make-instance (find-class class) initargs))
1669
1670(defgeneric initialize-instance (instance &key))
1671
1672(defmethod initialize-instance ((instance standard-object) &rest initargs)
1673  (apply #'shared-initialize instance t initargs))
1674
1675(defgeneric reinitialize-instance (instance &key))
1676
1677(defmethod reinitialize-instance
1678  ((instance standard-object) &rest initargs)
1679  (apply #'shared-initialize instance () initargs))
1680
1681(defun std-shared-initialize (instance slot-names all-keys)
1682  (dolist (slot (class-slots (class-of instance)))
1683    (let ((slot-name (slot-definition-name slot)))
1684      (multiple-value-bind (init-key init-value foundp)
1685        (get-properties all-keys (slot-definition-initargs slot))
1686        (if foundp
1687            (setf (std-slot-value instance slot-name) init-value)
1688            (when (and (not (std-slot-boundp instance slot-name))
1689                       (slot-definition-initfunction slot)
1690                       (or (eq slot-names t)
1691                           (member slot-name slot-names)))
1692              (setf (std-slot-value instance slot-name)
1693                    (funcall (slot-definition-initfunction slot))))))))
1694  instance)
1695
1696(defgeneric shared-initialize (instance slot-names &key))
1697
1698(defmethod shared-initialize ((instance standard-object)
1699                              slot-names &rest all-keys)
1700  (std-shared-initialize instance slot-names all-keys))
1701
1702;;; change-class
1703
1704(defgeneric change-class (instance new-class &key))
1705
1706(defmethod change-class ((old-instance standard-object) (new-class standard-class)
1707                         &rest initargs)
1708  (let ((new-instance (allocate-instance new-class)))
1709    (dolist (slot-name (mapcar #'slot-definition-name
1710                               (class-slots new-class)))
1711      (when (and (slot-exists-p old-instance slot-name)
1712                 (slot-boundp old-instance slot-name))
1713        (setf (slot-value new-instance slot-name)
1714              (slot-value old-instance slot-name))))
1715    (rotatef (std-instance-slots new-instance)
1716             (std-instance-slots old-instance))
1717    (rotatef (std-instance-layout new-instance)
1718             (std-instance-layout old-instance))
1719    (apply #'update-instance-for-different-class
1720           new-instance old-instance initargs)
1721    old-instance))
1722
1723(defmethod change-class ((instance standard-object) (new-class symbol) &rest initargs)
1724  (apply #'change-class instance (find-class new-class) initargs))
1725
1726(defgeneric update-instance-for-different-class (old new &key))
1727
1728(defmethod update-instance-for-different-class
1729  ((old standard-object) (new standard-object) &rest initargs)
1730  (let ((added-slots
1731         (remove-if #'(lambda (slot-name)
1732                       (slot-exists-p old slot-name))
1733                    (mapcar #'slot-definition-name
1734                            (class-slots (class-of new))))))
1735    (apply #'shared-initialize new added-slots initargs)))
1736
1737;;;  Methods having to do with class metaobjects.
1738
1739(defmethod initialize-instance :after ((class standard-class) &rest args)
1740  (apply #'std-after-initialization-for-classes class args))
1741
1742;;; Finalize inheritance
1743
1744(defgeneric finalize-inheritance (class))
1745
1746(defmethod finalize-inheritance ((class standard-class))
1747  (std-finalize-inheritance class))
1748
1749;;; Class precedence lists
1750
1751(defgeneric compute-class-precedence-list (class))
1752(defmethod compute-class-precedence-list ((class standard-class))
1753  (std-compute-class-precedence-list class))
1754
1755;;; Slot inheritance
1756
1757(defgeneric compute-slots (class))
1758(defmethod compute-slots ((class standard-class))
1759  (std-compute-slots class))
1760
1761(defgeneric compute-effective-slot-definition (class direct-slots))
1762(defmethod compute-effective-slot-definition
1763  ((class standard-class) direct-slots)
1764  (std-compute-effective-slot-definition class direct-slots))
1765
1766;;; Methods having to do with generic function metaobjects.
1767
1768(defmethod initialize-instance :after ((gf standard-generic-function) &key)
1769  (finalize-generic-function gf))
1770
1771;;; Methods having to do with generic function invocation.
1772
1773(defgeneric compute-discriminating-function (gf))
1774(defmethod compute-discriminating-function ((gf standard-generic-function))
1775  (std-compute-discriminating-function gf))
1776
1777(defgeneric method-more-specific-p (gf method1 method2 required-classes))
1778
1779(defmethod method-more-specific-p ((gf standard-generic-function)
1780                                   method1 method2 required-classes)
1781  (std-method-more-specific-p method1 method2 required-classes
1782                              (generic-function-argument-precedence-order gf)))
1783
1784(defgeneric compute-effective-method-function (gf methods))
1785(defmethod compute-effective-method-function ((gf standard-generic-function) methods)
1786  (std-compute-effective-method-function gf methods))
1787
1788(defgeneric compute-applicable-methods (gf args))
1789(defmethod compute-applicable-methods ((gf standard-generic-function) args)
1790  (%compute-applicable-methods gf args))
1791
1792;;; Conditions.
1793
1794(defmacro define-condition (name (&rest parent-types) (&rest slot-specs)
1795         &body options)
1796  (let ((parent-types (or parent-types '(condition)))
1797        (report nil))
1798    (dolist (option options)
1799      (when (eq (car option) :report)
1800        (let ((arg (cadr option)))
1801          (setf report
1802                (if (stringp arg)
1803                    `#'(lambda (condition stream)
1804                        (declare (ignore condition))
1805                        (write-string ,arg stream))
1806                    `#'(lambda (condition stream)
1807                        (funcall #',arg condition stream)))))))
1808    `(progn
1809       (defclass ,name ,parent-types ,slot-specs ,@options)
1810       (defmethod print-object ((condition ,name) stream)
1811         (if *print-escape*
1812             (call-next-method)
1813             (funcall ,report condition stream)))
1814       ',name)))
1815
1816(defun make-condition (type &rest initargs)
1817  (or (%make-condition type initargs)
1818      (apply #'make-instance (find-class type) initargs)))
1819
1820(defgeneric make-load-form (object &optional environment))
1821
1822(defmethod make-load-form ((object t) &optional environment)
1823  (error 'simple-error
1824         :format-control "No applicable method for MAKE-LOAD-FORM."))
1825
1826(defmethod make-load-form ((class class) &optional environment)
1827  (let ((name (class-name class)))
1828    (unless (and name (eq (find-class name nil) class))
1829      (error 'simple-type-error
1830             :format-control "Can't use anonymous or undefined class as a constant: ~S."
1831             :format-arguments (list class)))
1832    `(find-class ',name)))
1833
1834(provide 'clos)
Note: See TracBrowser for help on using the repository browser.