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

Last change on this file since 4650 was 4650, checked in by piso, 19 years ago

:DEFAULT-INITARGS option.

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