home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / language / examples / closette.lsp < prev    next >
Lisp/Scheme  |  1993-10-23  |  66KB  |  1,741 lines

  1. ;;;-*-Mode:LISP; Package: (CLOSETTE :USE LISP); Base:10; Syntax:Common-lisp -*-
  2. ;;;
  3. ;;; Closette Version 1.0 (February 10, 1991)
  4. ;;;
  5. ;;; Copyright (c) 1990, 1991 Xerox Corporation.
  6. ;;; All rights reserved.
  7. ;;;
  8. ;;; Use and copying of this software and preparation of derivative works
  9. ;;; based upon this software are permitted.  Any distribution of this
  10. ;;; software or derivative works must comply with all applicable United
  11. ;;; States export control laws.
  12. ;;;
  13. ;;; This software is made available AS IS, and Xerox Corporation makes no
  14. ;;; warranty about the software, its performance or its conformity to any
  15. ;;; specification.
  16. ;;;
  17. ;;;
  18. ;;; Closette is an implementation of a subset of CLOS with a metaobject
  19. ;;; protocol as described in "The Art of The Metaobject Protocol",
  20. ;;; MIT Press, 1991.
  21. ;;;
  22. ;;; This program is available by anonymous FTP, from the /pcl/mop
  23. ;;; directory on arisia.xerox.com.
  24.  
  25. ;;; This is the file closette.lisp
  26.  
  27. (in-package 'closette :use '(lisp))
  28.  
  29. ;;; When running in a Common Lisp that doesn't yet support function names like
  30. ;;; (setf foo), you should first load the file newcl.lisp.  This next little
  31. ;;; bit imports stuff from there as needed.
  32.  
  33. #-Genera
  34. (import '(newcl:print-unreadable-object))
  35.  
  36. #-Genera
  37. (shadowing-import '(newcl:defun newcl:fboundp newcl:fmakunbound
  38.                     newcl:fdefinition))
  39.  
  40. #-Genera
  41. (export '(newcl:defun newcl:fboundp newcl:fmakunbound newcl:fdefinition))
  42.  
  43. #+Genera
  44. (shadowing-import '(future-common-lisp:setf
  45.                     future-common-lisp:fboundp
  46.                     future-common-lisp:fmakunbound
  47.                     future-common-lisp:fdefinition
  48.                     future-common-lisp:print-unreadable-object))
  49.  
  50. #+Genera
  51. (export '(future-common-lisp:setf
  52.           future-common-lisp:fboundp
  53.           future-common-lisp:fmakunbound
  54.           future-common-lisp:fdefinition
  55.           future-common-lisp:print-unreadable-object))
  56.  
  57.  
  58. (defvar exports
  59.         '(defclass defgeneric defmethod
  60.           find-class class-of
  61.           call-next-method next-method-p
  62.           slot-value slot-boundp slot-exists-p slot-makunbound
  63.           make-instance change-class
  64.           initialize-instance reinitialize-instance shared-initialize
  65.           update-instance-for-different-class
  66.           print-object
  67.  
  68.           standard-object
  69.           standard-class standard-generic-function standard-method
  70.           class-name
  71.  
  72.           class-direct-superclasses class-direct-slots
  73.           class-precedence-list class-slots class-direct-subclasses
  74.           class-direct-methods
  75.           generic-function-name generic-function-lambda-list
  76.           generic-function-methods generic-function-discriminating-function
  77.           generic-function-method-class
  78.           method-lambda-list method-qualifiers method-specializers method-body
  79.           method-environment method-generic-function method-function
  80.           slot-definition-name slot-definition-initfunction
  81.           slot-definition-initform slot-definition-initargs
  82.           slot-definition-readers slot-definition-writers
  83.           slot-definition-allocation
  84.           ;;
  85.           ;; Class-related metaobject protocol
  86.           ;;
  87.           compute-class-precedence-list compute-slots
  88.           compute-effective-slot-definition
  89.           finalize-inheritance allocate-instance
  90.           slot-value-using-class slot-boundp-using-class
  91.           slot-exists-p-using-class slot-makunbound-using-class
  92.           ;;
  93.           ;; Generic function related metaobject protocol
  94.           ;;
  95.           compute-discriminating-function
  96.           compute-applicable-methods-using-classes method-more-specific-p
  97.           compute-effective-method-function compute-method-function
  98.           apply-methods apply-method
  99.           find-generic-function  ; Necessary artifact of this implementation
  100.           ))
  101.  
  102.  
  103. (export exports)
  104.  
  105. ;;;
  106. ;;; Utilities
  107. ;;;
  108.  
  109. ;;; push-on-end is like push except it uses the other end:
  110.  
  111. (eval-when (compile load eval)
  112.  
  113. (defmacro push-on-end (item place &environment env)
  114.   (let ((itemvar (gensym)))
  115.     (multiple-value-bind (SM1 SM2 SM3 SM4 SM5) (get-setf-method place env)
  116.       (do* ((SM1r SM1 (cdr SM1r))
  117.             (SM2r SM2 (cdr SM2r))
  118.             (bindlist `((,itemvar ,item)) ))
  119.            ((null SM1r)
  120.             (push `(,(first SM3) (NCONC ,SM5 (LIST ,itemvar))) bindlist)
  121.             `(LET* ,(nreverse bindlist)
  122.                ,SM4
  123.            ) )
  124.         (push `(,(first SM1r) ,(first SM2r)) bindlist)
  125. ) ) ) )
  126.  
  127. )
  128.  
  129. ;;; (setf getf*) is like (setf getf) except that it always changes the list,
  130. ;;;              which must be non-nil.
  131.  
  132. (defun (setf getf*) (new-value plist key)
  133.   (block body
  134.     (do ((x plist (cddr x)))
  135.         ((null x))
  136.       (when (eq (car x) key)
  137.         (setf (car (cdr x)) new-value)
  138.         (return-from body new-value)))
  139.     (push-on-end key plist)
  140.     (push-on-end new-value plist)
  141.     new-value))
  142.  
  143. ;;; mapappend is like mapcar except that the results are appended together:
  144.  
  145. (eval-when (compile load eval)
  146.  
  147. #-CLISP
  148. (defun mapappend (fun &rest args)
  149.   (if (some #'null args)
  150.       ()
  151.       (append (apply fun (mapcar #'car args))
  152.               (apply #'mapappend fun (mapcar #'cdr args)))))
  153. #+CLISP
  154. (defmacro mapappend (fun &rest args)
  155.   `(mapcap ,fun ,@args)
  156. )
  157.  
  158. )
  159.  
  160. ;;; mapplist is mapcar for property lists:
  161.  
  162. (defun mapplist (fun x)
  163.   (if (null x)
  164.       ()
  165.       (cons (funcall fun (first x) (second x))
  166.             (mapplist fun (cddr x)))))
  167.  
  168. ;;;
  169. ;;; Standard instances
  170. ;;;
  171.  
  172. ;;; This implementation uses structures for instances, because they're the only
  173. ;;; kind of Lisp object that can be easily made to print whatever way we want.
  174.  
  175. (defstruct (std-instance (:constructor allocate-std-instance (class slots))
  176.                          (:predicate std-instance-p)
  177.                          (:print-function print-std-instance))
  178.   class
  179.   slots)
  180.  
  181. (defun print-std-instance (instance stream depth)
  182.   (declare (ignore depth))
  183.   (print-object instance stream))
  184.  
  185. ;;; Standard instance allocation
  186.  
  187. (defparameter secret-unbound-value (list "slot unbound"))
  188.  
  189. (defun instance-slot-p (slot)
  190.   (eq (slot-definition-allocation slot) ':instance))
  191.  
  192. (defun std-allocate-instance (class)
  193.   (allocate-std-instance
  194.     class
  195.     (allocate-slot-storage (count-if #'instance-slot-p (class-slots class))
  196.                            secret-unbound-value)))
  197.  
  198. ;;; Simple vectors are used for slot storage.
  199.  
  200. (defun allocate-slot-storage (size initial-value)
  201.   (make-array size :initial-element initial-value))
  202.  
  203. ;;; Standard instance slot access
  204.  
  205. ;;; N.B. The location of the effective-slots slots in the class metaobject for
  206. ;;; standard-class must be determined without making any further slot
  207. ;;; references.
  208.  
  209. (defvar the-slots-of-standard-class) ; standard-class's class-slots
  210. (defvar the-class-standard-class)    ; standard-class's class metaobject
  211.  
  212. (defun slot-location (class slot-name)
  213.   (if (and (eq slot-name 'effective-slots)
  214.            (eq class the-class-standard-class))
  215.       (position 'effective-slots the-slots-of-standard-class
  216.                :key #'slot-definition-name)
  217.       (let ((slot (find slot-name
  218.                         (class-slots class)
  219.                         :key #'slot-definition-name)))
  220.         (if (null slot)
  221.             (error "The slot ~S is missing from the class ~S."
  222.                    slot-name class)
  223.             (let ((pos (position slot
  224.                                  (remove-if-not #'instance-slot-p
  225.                                                 (class-slots class)))))
  226.                (if (null pos)
  227.                    (error "The slot ~S is not an instance~@
  228.                            slot in the class ~S."
  229.                           slot-name class)
  230.                    pos))))))
  231.  
  232. (defun slot-contents (slots location)
  233.   (svref slots location))
  234.  
  235. (defun (setf slot-contents) (new-value slots location)
  236.   (setf (svref slots location) new-value))
  237.  
  238. (defun std-slot-value (instance slot-name)
  239.   (let* ((location (slot-location (class-of instance) slot-name))
  240.          (slots (std-instance-slots instance))
  241.          (val (slot-contents slots location)))
  242.     (if (eq secret-unbound-value val)
  243.         (error "The slot ~S is unbound in the object ~S."
  244.                slot-name instance)
  245.         val)))
  246. (defun slot-value (object slot-name)
  247.   (if (eq (class-of (class-of object)) the-class-standard-class)
  248.       (std-slot-value object slot-name)
  249.       (slot-value-using-class (class-of object) object slot-name)))
  250.  
  251. (defun (setf std-slot-value) (new-value instance slot-name)
  252.   (let ((location (slot-location (class-of instance) slot-name))
  253.         (slots (std-instance-slots instance)))
  254.     (setf (slot-contents slots location) new-value)))
  255. (defun (setf slot-value) (new-value object slot-name)
  256.   (if (eq (class-of (class-of object)) the-class-standard-class)
  257.       (setf (std-slot-value object slot-name) new-value)
  258.       (setf-slot-value-using-class
  259.         new-value (class-of object) object slot-name)))
  260.  
  261. (defun std-slot-boundp (instance slot-name)
  262.   (let ((location (slot-location (class-of instance) slot-name))
  263.         (slots (std-instance-slots instance)))
  264.     (not (eq secret-unbound-value (slot-contents slots location)))))
  265. (defun slot-boundp (object slot-name)
  266.   (if (eq (class-of (class-of object)) the-class-standard-class)
  267.       (std-slot-boundp object slot-name)
  268.       (slot-boundp-using-class (class-of object) object slot-name)))
  269.  
  270. (defun std-slot-makunbound (instance slot-name)
  271.   (let ((location (slot-location (class-of instance) slot-name))
  272.         (slots (std-instance-slots instance)))
  273.     (setf (slot-contents slots location) secret-unbound-value))
  274.   instance)
  275. (defun slot-makunbound (object slot-name)
  276.   (if (eq (class-of (class-of object)) the-class-standard-class)
  277.       (std-slot-makunbound object slot-name)
  278.       (slot-makunbound-using-class (class-of object) object slot-name)))
  279.  
  280. (defun std-slot-exists-p (instance slot-name)
  281.   (not (null (find slot-name (class-slots (class-of instance))
  282.                    :key #'slot-definition-name))))
  283. (defun slot-exists-p (object slot-name)
  284.   (if (eq (class-of (class-of object)) the-class-standard-class)
  285.       (std-slot-exists-p object slot-name)
  286.       (slot-exists-p-using-class (class-of object) object slot-name)))
  287.  
  288. ;;; class-of
  289.  
  290. (defun class-of (x)
  291.   (if (std-instance-p x)
  292.       (std-instance-class x)
  293.       (built-in-class-of x)))
  294.  
  295. ;;; N.B. This version of built-in-class-of is straightforward but very slow.
  296.  
  297. (defun built-in-class-of (x)
  298.   (typecase x
  299.     (null                                          (find-class 'null))
  300.     ((and symbol (not null))                       (find-class 'symbol))
  301.     ((complex *)                                   (find-class 'complex))
  302.     ((integer * *)                                 (find-class 'integer))
  303.     ((float * *)                                   (find-class 'float))
  304.     (cons                                          (find-class 'cons))
  305.     (character                                     (find-class 'character))
  306.     (hash-table                                    (find-class 'hash-table))
  307.     (package                                       (find-class 'package))
  308.     (pathname                                      (find-class 'pathname))
  309.     (readtable                                     (find-class 'readtable))
  310.     (stream                                        (find-class 'stream))
  311.     ((and number (not (or integer complex float))) (find-class 'number))
  312.     ((string *)                                    (find-class 'string))
  313.     ((bit-vector *)                                (find-class 'bit-vector))
  314.     ((and (vector * *) (not (or string vector)))   (find-class 'vector))
  315.     ((and (array * *) (not vector))                (find-class 'array))
  316.     ((and sequence (not (or vector list)))         (find-class 'sequence))
  317.     (function                                      (find-class 'function))
  318.     (t                                             (find-class 't))))
  319.  
  320. ;;; subclassp and sub-specializer-p
  321.  
  322. (defun subclassp (c1 c2)
  323.   (not (null (find c2 (class-precedence-list c1)))))
  324.  
  325. (defun sub-specializer-p (c1 c2 c-arg)
  326.   (let ((cpl (class-precedence-list c-arg)))
  327.     (not (null (find c2 (cdr (member c1 cpl)))))))
  328.  
  329. ;;;
  330. ;;; Class metaobjects and standard-class
  331. ;;;
  332.  
  333. (defparameter the-defclass-standard-class  ;standard-class's defclass form
  334.  '(defclass standard-class ()
  335.       ((name :initarg :name)              ; :accessor class-name
  336.        (direct-superclasses               ; :accessor class-direct-superclasses
  337.         :initarg :direct-superclasses)
  338.        (direct-slots)                     ; :accessor class-direct-slots
  339.        (class-precedence-list)            ; :accessor class-precedence-list
  340.        (effective-slots)                  ; :accessor class-slots
  341.        (direct-subclasses :initform ())   ; :accessor class-direct-subclasses
  342.        (direct-methods :initform ()))))   ; :accessor class-direct-methods
  343.  
  344. ;;; Defining the metaobject slot accessor function as regular functions
  345. ;;; greatly simplifies the implementation without removing functionality.
  346.  
  347. (defun class-name (class) (std-slot-value class 'name))
  348. (defun (setf class-name) (new-value class)
  349.   (setf (slot-value class 'name) new-value))
  350.  
  351. (defun class-direct-superclasses (class)
  352.   (slot-value class 'direct-superclasses))
  353. (defun (setf class-direct-superclasses) (new-value class)
  354.   (setf (slot-value class 'direct-superclasses) new-value))
  355.  
  356. (defun class-direct-slots (class)
  357.   (slot-value class 'direct-slots))
  358. (defun (setf class-direct-slots) (new-value class)
  359.   (setf (slot-value class 'direct-slots) new-value))
  360.  
  361. (defun class-precedence-list (class)
  362.   (slot-value class 'class-precedence-list))
  363. (defun (setf class-precedence-list) (new-value class)
  364.   (setf (slot-value class 'class-precedence-list) new-value))
  365.  
  366. (defun class-slots (class)
  367.   (slot-value class 'effective-slots))
  368. (defun (setf class-slots) (new-value class)
  369.   (setf (slot-value class 'effective-slots) new-value))
  370.  
  371. (defun class-direct-subclasses (class)
  372.   (slot-value class 'direct-subclasses))
  373. (defun (setf class-direct-subclasses) (new-value class)
  374.   (setf (slot-value class 'direct-subclasses) new-value))
  375.  
  376. (defun class-direct-methods (class)
  377.   (slot-value class 'direct-methods))
  378. (defun (setf class-direct-methods) (new-value class)
  379.   (setf (slot-value class 'direct-methods) new-value))
  380.  
  381. ;;; defclass
  382.  
  383. (eval-when (compile load eval)
  384.  
  385. (defmacro defclass (name direct-superclasses direct-slots
  386.                     &rest options)
  387.   `(ensure-class ',name
  388.      :direct-superclasses
  389.        ,(canonicalize-direct-superclasses direct-superclasses)
  390.      :direct-slots
  391.        ,(canonicalize-direct-slots direct-slots)
  392.      ,@(canonicalize-defclass-options options)))
  393.  
  394. (defun canonicalize-direct-slots (direct-slots)
  395.    `(list ,@(mapcar #'canonicalize-direct-slot direct-slots)))
  396.  
  397. (defun canonicalize-direct-slot (spec)
  398.   (if (symbolp spec)
  399.       `(list :name ',spec)
  400.       (let ((name (car spec))
  401.             (initfunction nil)
  402.             (initform nil)
  403.             (initargs ())
  404.             (readers ())
  405.             (writers ())
  406.             (other-options ()))
  407.         (do ((olist (cdr spec) (cddr olist)))
  408.             ((null olist))
  409.           (case (car olist)
  410.             (:initform
  411.              (setq initfunction
  412.                    `(function (lambda () ,(cadr olist))))
  413.              (setq initform `',(cadr olist)))
  414.             (:initarg
  415.              (push-on-end (cadr olist) initargs))
  416.             (:reader
  417.              (push-on-end (cadr olist) readers))
  418.             (:writer
  419.              (push-on-end (cadr olist) writers))
  420.             (:accessor
  421.              (push-on-end (cadr olist) readers)
  422.              (push-on-end `(setf ,(cadr olist)) writers))
  423.             (otherwise
  424.              (push-on-end `',(car olist) other-options)
  425.              (push-on-end `',(cadr olist) other-options))))
  426.         `(list
  427.            :name ',name
  428.            ,@(when initfunction
  429.                `(:initform ,initform
  430.                  :initfunction ,initfunction))
  431.            ,@(when initargs `(:initargs ',initargs))
  432.            ,@(when readers `(:readers ',readers))
  433.            ,@(when writers `(:writers ',writers))
  434.            ,@other-options))))
  435.  
  436. (defun canonicalize-direct-superclasses (direct-superclasses)
  437.   `(list ,@(mapcar #'canonicalize-direct-superclass direct-superclasses)))
  438.  
  439. (defun canonicalize-direct-superclass (class-name)
  440.   `(find-class ',class-name))
  441.  
  442. (defun canonicalize-defclass-options (options)
  443.   (mapappend #'canonicalize-defclass-option options))
  444.  
  445. (defun canonicalize-defclass-option (option)
  446.   (case (car option)
  447.     (:metaclass
  448.       (list ':metaclass
  449.        `(find-class ',(cadr option))))
  450.     (:default-initargs
  451.       (list
  452.        ':direct-default-initargs
  453.        `(list ,@(mapappend
  454.                   #'(lambda (x) x)
  455.                   (mapplist
  456.                     #'(lambda (key value)
  457.                         `(',key ,value))
  458.                     (cdr option))))))
  459.     (t (list `',(car option) `',(cadr option)))))
  460.  
  461. )
  462.  
  463. ;;; find-class
  464.  
  465. (let ((class-table (make-hash-table :test #'eq)))
  466.  
  467.   (defun find-class (symbol &optional (errorp t))
  468.     (let ((class (gethash symbol class-table nil)))
  469.       (if (and (null class) errorp)
  470.           (error "No class named ~S." symbol)
  471.           class)))
  472.  
  473.   (defun (setf find-class) (new-value symbol)
  474.     (setf (gethash symbol class-table) new-value))
  475.  
  476.   (defun forget-all-classes ()
  477.     (clrhash class-table)
  478.     (values))
  479.  ) ;end let class-table
  480.  
  481. ;;; Ensure class
  482.  
  483. (defun ensure-class (name &rest all-keys
  484.                           &key (metaclass the-class-standard-class)
  485.                           &allow-other-keys)
  486.   (if (find-class name nil)
  487.       (error "Can't redefine the class named ~S." name)
  488.       (let ((class (apply (if (eq metaclass the-class-standard-class)
  489.                               #'make-instance-standard-class
  490.                               #'make-instance)
  491.                           metaclass :name name all-keys)))
  492.         (setf (find-class name) class)
  493.         class)))
  494.  
  495. ;;; make-instance-standard-class creates and initializes an instance of
  496. ;;; standard-class without falling into method lookup.  However, it cannot be
  497. ;;; called until standard-class itself exists.
  498.  
  499. (defun make-instance-standard-class
  500.        (metaclass &key name direct-superclasses direct-slots
  501.                   &allow-other-keys)
  502.   (declare (ignore metaclass))
  503.   (let ((class (std-allocate-instance the-class-standard-class)))
  504.     (setf (class-name class) name)
  505.     (setf (class-direct-subclasses class) ())
  506.     (setf (class-direct-methods class) ())
  507.     (std-after-initialization-for-classes class
  508.        :direct-slots direct-slots
  509.        :direct-superclasses direct-superclasses)
  510.     class))
  511.  
  512. (defun std-after-initialization-for-classes
  513.        (class &key direct-superclasses direct-slots &allow-other-keys)
  514.   (let ((supers
  515.           (or direct-superclasses
  516.               (list (find-class 'standard-object)))))
  517.     (setf (class-direct-superclasses class) supers)
  518.     (dolist (superclass supers)
  519.       (push class (class-direct-subclasses superclass))))
  520.   (let ((slots
  521.           (mapcar #'(lambda (slot-properties)
  522.                       (apply #'make-direct-slot-definition
  523.                              slot-properties))
  524.                     direct-slots)))
  525.     (setf (class-direct-slots class) slots)
  526.     (dolist (direct-slot slots)
  527.       (dolist (reader (slot-definition-readers direct-slot))
  528.         (add-reader-method
  529.           class reader (slot-definition-name direct-slot)))
  530.       (dolist (writer (slot-definition-writers direct-slot))
  531.         (add-writer-method
  532.           class writer (slot-definition-name direct-slot)))))
  533.   (funcall (if (eq (class-of class) the-class-standard-class)
  534.               #'std-finalize-inheritance
  535.               #'finalize-inheritance)
  536.            class)
  537.   (values))
  538.  
  539. ;;; Slot definition metaobjects
  540.  
  541. ;;; N.B. Quietly retain all unknown slot options (rather than signaling an
  542. ;;; error), so that it's easy to add new ones.
  543.  
  544. (defun make-direct-slot-definition
  545.        (&rest properties
  546.         &key name (initargs ()) (initform nil) (initfunction nil)
  547.              (readers ()) (writers ()) (allocation :instance)
  548.         &allow-other-keys)
  549.   (let ((slot (copy-list properties))) ; Don't want to side effect &rest list
  550.     (setf (getf* slot ':name) name)
  551.     (setf (getf* slot ':initargs) initargs)
  552.     (setf (getf* slot ':initform) initform)
  553.     (setf (getf* slot ':initfunction) initfunction)
  554.     (setf (getf* slot ':readers) readers)
  555.     (setf (getf* slot ':writers) writers)
  556.     (setf (getf* slot ':allocation) allocation)
  557.     slot))
  558.  
  559. (defun make-effective-slot-definition
  560.        (&rest properties
  561.         &key name (initargs ()) (initform nil) (initfunction nil)
  562.              (allocation :instance)
  563.         &allow-other-keys)
  564.   (let ((slot (copy-list properties)))  ; Don't want to side effect &rest list
  565.     (setf (getf* slot ':name) name)
  566.     (setf (getf* slot ':initargs) initargs)
  567.     (setf (getf* slot ':initform) initform)
  568.     (setf (getf* slot ':initfunction) initfunction)
  569.     (setf (getf* slot ':allocation) allocation)
  570.     slot))
  571.  
  572. (defun slot-definition-name (slot)
  573.   (getf slot ':name))
  574. (defun (setf slot-definition-name) (new-value slot)
  575.   (setf (getf* slot ':name) new-value))
  576.  
  577. (defun slot-definition-initfunction (slot)
  578.   (getf slot ':initfunction))
  579. (defun (setf slot-definition-initfunction) (new-value slot)
  580.   (setf (getf* slot ':initfunction) new-value))
  581.  
  582. (defun slot-definition-initform (slot)
  583.   (getf slot ':initform))
  584. (defun (setf slot-definition-initform) (new-value slot)
  585.   (setf (getf* slot ':initform) new-value))
  586.  
  587. (defun slot-definition-initargs (slot)
  588.   (getf slot ':initargs))
  589. (defun (setf slot-definition-initargs) (new-value slot)
  590.   (setf (getf* slot ':initargs) new-value))
  591.  
  592. (defun slot-definition-readers (slot)
  593.   (getf slot ':readers))
  594. (defun (setf slot-definition-readers) (new-value slot)
  595.   (setf (getf* slot ':readers) new-value))
  596.  
  597. (defun slot-definition-writers (slot)
  598.   (getf slot ':writers))
  599. (defun (setf slot-definition-writers) (new-value slot)
  600.   (setf (getf* slot ':writers) new-value))
  601.  
  602. (defun slot-definition-allocation (slot)
  603.   (getf slot ':allocation))
  604. (defun (setf slot-definition-allocation) (new-value slot)
  605.   (setf (getf* slot ':allocation) new-value))
  606.  
  607. ;;; finalize-inheritance
  608.  
  609. (defun std-finalize-inheritance (class)
  610.   (setf (class-precedence-list class)
  611.         (funcall (if (eq (class-of class) the-class-standard-class)
  612.                      #'std-compute-class-precedence-list
  613.                      #'compute-class-precedence-list)
  614.                  class))
  615.   (setf (class-slots class)
  616.         (funcall (if (eq (class-of class) the-class-standard-class)
  617.                      #'std-compute-slots
  618.                      #'compute-slots)
  619.                  class))
  620.   (values))
  621.  
  622. ;;; Class precedence lists
  623.  
  624. (defun std-compute-class-precedence-list (class)
  625.   (let ((classes-to-order (collect-superclasses* class)))
  626.     (topological-sort classes-to-order
  627.                       (remove-duplicates
  628.                         (mapappend #'local-precedence-ordering
  629.                                    classes-to-order))
  630.                       #'std-tie-breaker-rule)))
  631.  
  632. ;;; topological-sort implements the standard algorithm for topologically
  633. ;;; sorting an arbitrary set of elements while honoring the precedence
  634. ;;; constraints given by a set of (X,Y) pairs that indicate that element
  635. ;;; X must precede element Y.  The tie-breaker procedure is called when it
  636. ;;; is necessary to choose from multiple minimal elements; both a list of
  637. ;;; candidates and the ordering so far are provided as arguments.
  638.  
  639. (defun topological-sort (elements constraints tie-breaker)
  640.   (let ((remaining-constraints constraints)
  641.         (remaining-elements elements)
  642.         (result ()))
  643.     (loop
  644.      (let ((minimal-elements
  645.             (remove-if
  646.              #'(lambda (class)
  647.                  (member class remaining-constraints
  648.                          :key #'cadr))
  649.              remaining-elements)))
  650.        (when (null minimal-elements)
  651.              (if (null remaining-elements)
  652.                  (return-from topological-sort result)
  653.                (error "Inconsistent precedence graph.")))
  654.        (let ((choice (if (null (cdr minimal-elements))
  655.                          (car minimal-elements)
  656.                        (funcall tie-breaker
  657.                                 minimal-elements
  658.                                 result))))
  659.          (setq result (append result (list choice)))
  660.          (setq remaining-elements
  661.                (remove choice remaining-elements))
  662.          (setq remaining-constraints
  663.                (remove choice
  664.                        remaining-constraints
  665.                        :test #'member)))))))
  666.  
  667. ;;; In the event of a tie while topologically sorting class precedence lists,
  668. ;;; the CLOS Specification says to "select the one that has a direct subclass
  669. ;;; rightmost in the class precedence list computed so far."  The same result
  670. ;;; is obtained by inspecting the partially constructed class precedence list
  671. ;;; from right to left, looking for the first minimal element to show up among
  672. ;;; the direct superclasses of the class precedence list constituent.
  673. ;;; (There's a lemma that shows that this rule yields a unique result.)
  674.  
  675. (defun std-tie-breaker-rule (minimal-elements cpl-so-far)
  676.   (dolist (cpl-constituent (reverse cpl-so-far))
  677.     (let* ((supers (class-direct-superclasses cpl-constituent))
  678.            (common (intersection minimal-elements supers)))
  679.       (when (not (null common))
  680.         (return-from std-tie-breaker-rule (car common))))))
  681.  
  682. ;;; This version of collect-superclasses* isn't bothered by cycles in the class
  683. ;;; hierarchy, which sometimes happen by accident.
  684.  
  685. (defun collect-superclasses* (class)
  686.   (labels ((all-superclasses-loop (seen superclasses)
  687.               (let ((to-be-processed
  688.                        (set-difference superclasses seen)))
  689.                 (if (null to-be-processed)
  690.                     superclasses
  691.                     (let ((class-to-process
  692.                              (car to-be-processed)))
  693.                       (all-superclasses-loop
  694.                         (cons class-to-process seen)
  695.                         (union (class-direct-superclasses
  696.                                  class-to-process)
  697.                                superclasses)))))))
  698.     (all-superclasses-loop () (list class))))
  699.  
  700. ;;; The local precedence ordering of a class C with direct superclasses C_1,
  701. ;;; C_2, ..., C_n is the set ((C C_1) (C_1 C_2) ...(C_n-1 C_n)).
  702.  
  703. (defun local-precedence-ordering (class)
  704.   (mapcar #'list
  705.           (cons class
  706.                 (butlast (class-direct-superclasses class)))
  707.           (class-direct-superclasses class)))
  708.  
  709. ;;; Slot inheritance
  710.  
  711. (defun std-compute-slots (class)
  712.   (let* ((all-slots (mapappend #'class-direct-slots
  713.                                (class-precedence-list class)))
  714.          (all-names (remove-duplicates
  715.                       (mapcar #'slot-definition-name all-slots))))
  716.     (mapcar #'(lambda (name)
  717.                 (funcall
  718.                   (if (eq (class-of class) the-class-standard-class)
  719.                       #'std-compute-effective-slot-definition
  720.                       #'compute-effective-slot-definition)
  721.                   class
  722.                   (remove name all-slots
  723.                           :key #'slot-definition-name
  724.                           :test-not #'eq)))
  725.             all-names)))
  726.  
  727. (defun std-compute-effective-slot-definition (class direct-slots)
  728.   (declare (ignore class))
  729.   (let ((initer (find-if-not #'null direct-slots
  730.                              :key #'slot-definition-initfunction)))
  731.     (make-effective-slot-definition
  732.       :name (slot-definition-name (car direct-slots))
  733.       :initform (if initer
  734.                     (slot-definition-initform initer)
  735.                     nil)
  736.       :initfunction (if initer
  737.                         (slot-definition-initfunction initer)
  738.                         nil)
  739.       :initargs (remove-duplicates
  740.                   (mapappend #'slot-definition-initargs
  741.                              direct-slots))
  742.       :allocation (slot-definition-allocation (car direct-slots)))))
  743.  
  744. ;;;
  745. ;;; Generic function metaobjects and standard-generic-function
  746. ;;;
  747.  
  748. (defparameter the-defclass-standard-generic-function
  749.  '(defclass standard-generic-function ()
  750.       ((name :initarg :name)      ; :accessor generic-function-name
  751.        (lambda-list               ; :accessor generic-function-lambda-list
  752.           :initarg :lambda-list)
  753.        (methods :initform ())     ; :accessor generic-function-methods
  754.        (method-class              ; :accessor generic-function-method-class
  755.           :initarg :method-class)
  756.        (discriminating-function)  ; :accessor generic-function-
  757.                                   ;    -discriminating-function
  758.        (classes-to-emf-table      ; :accessor classes-to-emf-table
  759.           :initform (make-hash-table :test #'equal)))))
  760.  
  761. (defvar the-class-standard-gf) ;standard-generic-function's class metaobject
  762.  
  763. (defun generic-function-name (gf)
  764.   (slot-value gf 'name))
  765. (defun (setf generic-function-name) (new-value gf)
  766.   (setf (slot-value gf 'name) new-value))
  767.  
  768. (defun generic-function-lambda-list (gf)
  769.   (slot-value gf 'lambda-list))
  770. (defun (setf generic-function-lambda-list) (new-value gf)
  771.   (setf (slot-value gf 'lambda-list) new-value))
  772.  
  773. (defun generic-function-methods (gf)
  774.   (slot-value gf 'methods))
  775. (defun (setf generic-function-methods) (new-value gf)
  776.   (setf (slot-value gf 'methods) new-value))
  777.  
  778. (defun generic-function-discriminating-function (gf)
  779.   (slot-value gf 'discriminating-function))
  780. (defun (setf generic-function-discriminating-function) (new-value gf)
  781.   (setf (slot-value gf 'discriminating-function) new-value))
  782.  
  783. (defun generic-function-method-class (gf)
  784.   (slot-value gf 'method-class))
  785. (defun (setf generic-function-method-class) (new-value gf)
  786.   (setf (slot-value gf 'method-class) new-value))
  787.  
  788. ;;; Internal accessor for effective method function table
  789.  
  790. (defun classes-to-emf-table (gf)
  791.   (slot-value gf 'classes-to-emf-table))
  792. (defun (setf classes-to-emf-table) (new-value gf)
  793.   (setf (slot-value gf 'classes-to-emf-table) new-value))
  794.  
  795. ;;;
  796. ;;; Method metaobjects and standard-method
  797. ;;;
  798.  
  799. (defparameter the-defclass-standard-method
  800.  '(defclass standard-method ()
  801.    ((lambda-list :initarg :lambda-list)     ; :accessor method-lambda-list
  802.     (qualifiers :initarg :qualifiers)       ; :accessor method-qualifiers
  803.     (specializers :initarg :specializers)   ; :accessor method-specializers
  804.     (body :initarg :body)                   ; :accessor method-body
  805.     (environment :initarg :environment)     ; :accessor method-environment
  806.     (generic-function :initform nil)        ; :accessor method-generic-function
  807.     (function))))                           ; :accessor method-function
  808.  
  809. (defvar the-class-standard-method)    ;standard-method's class metaobject
  810.  
  811. (defun method-lambda-list (method) (slot-value method 'lambda-list))
  812. (defun (setf method-lambda-list) (new-value method)
  813.   (setf (slot-value method 'lambda-list) new-value))
  814.  
  815. (defun method-qualifiers (method) (slot-value method 'qualifiers))
  816. (defun (setf method-qualifiers) (new-value method)
  817.   (setf (slot-value method 'qualifiers) new-value))
  818.  
  819. (defun method-specializers (method) (slot-value method 'specializers))
  820. (defun (setf method-specializers) (new-value method)
  821.   (setf (slot-value method 'specializers) new-value))
  822.  
  823. (defun method-body (method) (slot-value method 'body))
  824. (defun (setf method-body) (new-value method)
  825.   (setf (slot-value method 'body) new-value))
  826.  
  827. (defun method-environment (method) (slot-value method 'environment))
  828. (defun (setf method-environment) (new-value method)
  829.   (setf (slot-value method 'environment) new-value))
  830.  
  831. (defun method-generic-function (method)
  832.   (slot-value method 'generic-function))
  833. (defun (setf method-generic-function) (new-value method)
  834.   (setf (slot-value method 'generic-function) new-value))
  835.  
  836. (defun method-function (method) (slot-value method 'function))
  837. (defun (setf method-function) (new-value method)
  838.   (setf (slot-value method 'function) new-value))
  839.  
  840. ;;; defgeneric
  841.  
  842. (eval-when (compile load eval)
  843.  
  844. (defmacro defgeneric (function-name lambda-list &rest options)
  845.   `(progn
  846.      ,@(when (and (consp function-name) (eq (first function-name) 'setf))
  847.          ; ensure setf expander also during compilation
  848.          `((defsetf ,(second function-name) (&rest all-args) (new-value)
  849.              (list* ',(newcl::setf-function-symbol function-name) new-value all-args)
  850.           ))
  851.        )
  852.      (ensure-generic-function
  853.        ',function-name
  854.        :lambda-list ',lambda-list
  855.        ,@(canonicalize-defgeneric-options options)
  856.    ) )
  857. )
  858.  
  859. (defun canonicalize-defgeneric-options (options)
  860.   (mapappend #'canonicalize-defgeneric-option options))
  861.  
  862. (defun canonicalize-defgeneric-option (option)
  863.   (case (car option)
  864.     (:generic-function-class
  865.       (list ':generic-function-class
  866.             `(find-class ',(cadr option))))
  867.     (:method-class
  868.       (list ':method-class
  869.             `(find-class ',(cadr option))))
  870.     (t (list `',(car option) `',(cadr option)))))
  871.  
  872. )
  873.  
  874. ;;; find-generic-function looks up a generic function by name.  It's an
  875. ;;; artifact of the fact that our generic function metaobjects can't legally
  876. ;;; be stored a symbol's function value.
  877.  
  878. (let ((generic-function-table (make-hash-table :test #'equal)))
  879.  
  880.   (defun find-generic-function (symbol &optional (errorp t))
  881.     (let ((gf (gethash symbol generic-function-table nil)))
  882.        (if (and (null gf) errorp)
  883.            (error "No generic function named ~S." symbol)
  884.            gf)))
  885.  
  886.   (defun (setf find-generic-function) (new-value symbol)
  887.     (setf (gethash symbol generic-function-table) new-value))
  888.  
  889.   (defun forget-all-generic-functions ()
  890.     (clrhash generic-function-table)
  891.     (values))
  892.  ) ;end let generic-function-table
  893.  
  894. ;;; ensure-generic-function
  895.  
  896. (defun ensure-generic-function
  897.        (function-name
  898.         &rest all-keys
  899.         &key (generic-function-class the-class-standard-gf)
  900.              (method-class the-class-standard-method)
  901.         &allow-other-keys)
  902.   (if (find-generic-function function-name nil)
  903.       (find-generic-function function-name)
  904.       (let ((gf (apply (if (eq generic-function-class the-class-standard-gf)
  905.                            #'make-instance-standard-generic-function
  906.                            #'make-instance)
  907.                        generic-function-class
  908.                        :name function-name
  909.                        :method-class method-class
  910.                        all-keys)))
  911.          (setf (find-generic-function function-name) gf)
  912.          gf)))
  913.  
  914. ;;; finalize-generic-function
  915.  
  916. ;;; N.B. Same basic idea as finalize-inheritance.  Takes care of recomputing
  917. ;;; and storing the discriminating function, and clearing the effective method
  918. ;;; function table.
  919.  
  920. (defun finalize-generic-function (gf)
  921.   (setf (generic-function-discriminating-function gf)
  922.         (funcall (if (eq (class-of gf) the-class-standard-gf)
  923.                      #'std-compute-discriminating-function
  924.                      #'compute-discriminating-function)
  925.                  gf))
  926.   (setf (fdefinition (generic-function-name gf))
  927.         (generic-function-discriminating-function gf))
  928.   (clrhash (classes-to-emf-table gf))
  929.   (values))
  930.  
  931. ;;; make-instance-standard-generic-function creates and initializes an
  932. ;;; instance of standard-generic-function without falling into method lookup.
  933. ;;; However, it cannot be called until standard-generic-function exists.
  934.  
  935. (defun make-instance-standard-generic-function
  936.        (generic-function-class &key name lambda-list method-class)
  937.   (declare (ignore generic-function-class))
  938.   (let ((gf (std-allocate-instance the-class-standard-gf)))
  939.     (setf (generic-function-name gf) name)
  940.     (setf (generic-function-lambda-list gf) lambda-list)
  941.     (setf (generic-function-methods gf) ())
  942.     (setf (generic-function-method-class gf) method-class)
  943.     (setf (classes-to-emf-table gf) (make-hash-table :test #'equal))
  944.     (finalize-generic-function gf)
  945.     gf))
  946.  
  947. ;;; defmethod
  948.  
  949. (eval-when (compile load eval)
  950.  
  951. (defmacro defmethod (&rest args)
  952.   (multiple-value-bind (function-name qualifiers
  953.                         lambda-list specializers body)
  954.         (parse-defmethod args)
  955.     `(ensure-method (find-generic-function ',function-name)
  956.        :lambda-list ',lambda-list
  957.        :qualifiers ',qualifiers
  958.        :specializers ,(canonicalize-specializers specializers)
  959.        :body ',body
  960.        :environment (top-level-environment))))
  961.  
  962. (defun canonicalize-specializers (specializers)
  963.   `(list ,@(mapcar #'canonicalize-specializer specializers)))
  964.  
  965. (defun canonicalize-specializer (specializer)
  966.   `(find-class ',specializer))
  967.  
  968. (defun parse-defmethod (args)
  969.   (let ((fn-spec (car args))
  970.         (qualifiers ())
  971.         (specialized-lambda-list nil)
  972.         (body ())
  973.         (parse-state :qualifiers))
  974.     (dolist (arg (cdr args))
  975.        (ecase parse-state
  976.          (:qualifiers
  977.            (if (and (atom arg) (not (null arg)))
  978.                (push-on-end arg qualifiers)
  979.                (progn (setq specialized-lambda-list arg)
  980.                       (setq parse-state :body))))
  981.          (:body (push-on-end arg body))))
  982.     (values fn-spec
  983.             qualifiers
  984.             (extract-lambda-list specialized-lambda-list)
  985.             (extract-specializers specialized-lambda-list)
  986.             (list* 'block
  987.                    (if (consp fn-spec)
  988.                        (cadr fn-spec)
  989.                        fn-spec)
  990.                    body))))
  991.  
  992. )
  993.  
  994. ;;; Several tedious functions for analyzing lambda lists
  995.  
  996. (defun required-portion (gf args)
  997.   (let ((number-required (length (gf-required-arglist gf))))
  998.     (when (< (length args) number-required)
  999.       (error "Too few arguments to generic function ~S." gf))
  1000.     (subseq args 0 number-required)))
  1001.  
  1002. (defun gf-required-arglist (gf)
  1003.   (let ((plist
  1004.           (analyze-lambda-list
  1005.             (generic-function-lambda-list gf))))
  1006.     (getf plist ':required-args)))
  1007.  
  1008. (eval-when (compile load eval)
  1009.  
  1010. (defun extract-lambda-list (specialized-lambda-list)
  1011.   (let* ((plist (analyze-lambda-list specialized-lambda-list))
  1012.          (requireds (getf plist ':required-names))
  1013.          (rv (getf plist ':rest-var))
  1014.          (ks (getf plist ':key-args))
  1015.          (aok (getf plist ':allow-other-keys))
  1016.          (opts (getf plist ':optional-args))
  1017.          (auxs (getf plist ':auxiliary-args)))
  1018.     `(,@requireds
  1019.       ,@(if rv `(&rest ,rv) ())
  1020.       ,@(if (or ks aok) `(&key ,@ks) ())
  1021.       ,@(if aok '(&allow-other-keys) ())
  1022.       ,@(if opts `(&optional ,@opts) ())
  1023.       ,@(if auxs `(&aux ,@auxs) ()))))
  1024.  
  1025. (defun extract-specializers (specialized-lambda-list)
  1026.   (let ((plist (analyze-lambda-list specialized-lambda-list)))
  1027.     (getf plist ':specializers)))
  1028.  
  1029. (defun analyze-lambda-list (lambda-list)
  1030.   (labels ((make-keyword (symbol)
  1031.               (intern (symbol-name symbol)
  1032.                       (find-package 'keyword)))
  1033.            (get-keyword-from-arg (arg)
  1034.               (if (listp arg)
  1035.                   (if (listp (car arg))
  1036.                       (caar arg)
  1037.                       (make-keyword (car arg)))
  1038.                   (make-keyword arg))))
  1039.     (let ((keys ())           ; Just the keywords
  1040.           (key-args ())       ; Keywords argument specs
  1041.           (required-names ()) ; Just the variable names
  1042.           (required-args ())  ; Variable names & specializers
  1043.           (specializers ())   ; Just the specializers
  1044.           (rest-var nil)
  1045.           (optionals ())
  1046.           (auxs ())
  1047.           (allow-other-keys nil)
  1048.           (state :parsing-required))
  1049.       (dolist (arg lambda-list)
  1050.         (if (member arg lambda-list-keywords)
  1051.           (ecase arg
  1052.             (&optional
  1053.               (setq state :parsing-optional))
  1054.             (&rest
  1055.               (setq state :parsing-rest))
  1056.             (&key
  1057.               (setq state :parsing-key))
  1058.             (&allow-other-keys
  1059.               (setq allow-other-keys 't))
  1060.             (&aux
  1061.               (setq state :parsing-aux)))
  1062.           (case state
  1063.             (:parsing-required
  1064.              (push-on-end arg required-args)
  1065.              (if (listp arg)
  1066.                  (progn (push-on-end (car arg) required-names)
  1067.                         (push-on-end (cadr arg) specializers))
  1068.                  (progn (push-on-end arg required-names)
  1069.                         (push-on-end 't specializers))))
  1070.             (:parsing-optional (push-on-end arg optionals))
  1071.             (:parsing-rest (setq rest-var arg))
  1072.             (:parsing-key
  1073.              (push-on-end (get-keyword-from-arg arg) keys)
  1074.              (push-on-end arg key-args))
  1075.             (:parsing-aux (push-on-end arg auxs)))))
  1076.       (list  :required-names required-names
  1077.              :required-args required-args
  1078.              :specializers specializers
  1079.              :rest-var rest-var
  1080.              :keywords keys
  1081.              :key-args key-args
  1082.              :auxiliary-args auxs
  1083.              :optional-args optionals
  1084.              :allow-other-keys allow-other-keys))))
  1085.  
  1086. )
  1087.  
  1088. ;;; ensure method
  1089.  
  1090. (defun ensure-method (gf &rest all-keys)
  1091.   (let ((new-method
  1092.            (apply
  1093.               (if (eq (generic-function-method-class gf)
  1094.                       the-class-standard-method)
  1095.                   #'make-instance-standard-method
  1096.                   #'make-instance)
  1097.               (generic-function-method-class gf)
  1098.               all-keys)))
  1099.     (add-method gf new-method)
  1100.     new-method))
  1101.  
  1102. ;;; make-instance-standard-method creates and initializes an instance of
  1103. ;;; standard-method without falling into method lookup.  However, it cannot
  1104. ;;; be called until standard-method exists.
  1105.  
  1106. (defun make-instance-standard-method (method-class
  1107.                                       &key lambda-list qualifiers
  1108.                                            specializers body environment)
  1109.   (declare (ignore method-class))
  1110.   (let ((method (std-allocate-instance the-class-standard-method)))
  1111.     (setf (method-lambda-list method) lambda-list)
  1112.     (setf (method-qualifiers method) qualifiers)
  1113.     (setf (method-specializers method) specializers)
  1114.     (setf (method-body method) body)
  1115.     (setf (method-environment method) environment)
  1116.     (setf (method-generic-function method) nil)
  1117.     (setf (method-function method)
  1118.           (std-compute-method-function method))
  1119.     method))
  1120.  
  1121. ;;; add-method
  1122.  
  1123. ;;; N.B. This version first removes any existing method on the generic function
  1124. ;;; with the same qualifiers and specializers.  It's a pain to develop
  1125. ;;; programs without this feature of full CLOS.
  1126.  
  1127. (defun add-method (gf method)
  1128.   (let ((old-method
  1129.            (find-method gf (method-qualifiers method)
  1130.                            (method-specializers method) nil)))
  1131.     (when old-method (remove-method gf old-method)))
  1132.   (setf (method-generic-function method) gf)
  1133.   (push method (generic-function-methods gf))
  1134.   (dolist (specializer (method-specializers method))
  1135.     (pushnew method (class-direct-methods specializer)))
  1136.   (finalize-generic-function gf)
  1137.   method)
  1138.  
  1139. (defun remove-method (gf method)
  1140.   (setf (generic-function-methods gf)
  1141.         (remove method (generic-function-methods gf)))
  1142.   (setf (method-generic-function method) nil)
  1143.   (dolist (class (method-specializers method))
  1144.     (setf (class-direct-methods class)
  1145.           (remove method (class-direct-methods class))))
  1146.   (finalize-generic-function gf)
  1147.   method)
  1148.  
  1149. (defun find-method (gf qualifiers specializers
  1150.                     &optional (errorp t))
  1151.   (let ((method
  1152.           (find-if #'(lambda (method)
  1153.                        (and (equal qualifiers
  1154.                                    (method-qualifiers method))
  1155.                             (equal specializers
  1156.                                    (method-specializers method))))
  1157.                    (generic-function-methods gf))))
  1158.       (if (and (null method) errorp)
  1159.           (error "No such method for ~S." (generic-function-name gf))
  1160.           method)))
  1161.  
  1162. ;;; Reader and write methods
  1163.  
  1164. (defun add-reader-method (class fn-name slot-name)
  1165.   (ensure-method
  1166.     (ensure-generic-function fn-name :lambda-list '(object))
  1167.     :lambda-list '(object)
  1168.     :qualifiers ()
  1169.     :specializers (list class)
  1170.     :body `(slot-value object ',slot-name)
  1171.     :environment (top-level-environment))
  1172.   (values))
  1173.  
  1174. (defun add-writer-method (class fn-name slot-name)
  1175.   (ensure-method
  1176.     (ensure-generic-function
  1177.       fn-name :lambda-list '(new-value object))
  1178.     :lambda-list '(new-value object)
  1179.     :qualifiers ()
  1180.     :specializers (list (find-class 't) class)
  1181.     :body `(setf (slot-value object ',slot-name)
  1182.                  new-value)
  1183.     :environment (top-level-environment))
  1184.   (values))
  1185.  
  1186. ;;;
  1187. ;;; Generic function invocation
  1188. ;;;
  1189.  
  1190. ;;; apply-generic-function
  1191.  
  1192. (defun apply-generic-function (gf args)
  1193.   (apply (generic-function-discriminating-function gf) args))
  1194.  
  1195. ;;; compute-discriminating-function
  1196.  
  1197. (defun std-compute-discriminating-function (gf)
  1198.   #'(lambda (&rest args)
  1199.       (let* ((classes (mapcar #'class-of
  1200.                               (required-portion gf args)))
  1201.              (emfun (gethash classes (classes-to-emf-table gf) nil)))
  1202.         (if emfun
  1203.             (funcall emfun args)
  1204.             (slow-method-lookup gf args classes)))))
  1205.  
  1206. (defun slow-method-lookup (gf args classes)
  1207.   (let* ((applicable-methods
  1208.            (compute-applicable-methods-using-classes gf classes))
  1209.          (emfun
  1210.            (funcall
  1211.              (if (eq (class-of gf) the-class-standard-gf)
  1212.                  #'std-compute-effective-method-function
  1213.                  #'compute-effective-method-function)
  1214.              gf applicable-methods)))
  1215.     (setf (gethash classes (classes-to-emf-table gf)) emfun)
  1216.     (funcall emfun args)))
  1217.  
  1218. ;;; compute-applicable-methods-using-classes
  1219.  
  1220. (defun compute-applicable-methods-using-classes
  1221.        (gf required-classes)
  1222.   (sort
  1223.     (copy-list
  1224.       (remove-if-not #'(lambda (method)
  1225.                          (every #'subclassp
  1226.                                 required-classes
  1227.                                 (method-specializers method)))
  1228.                      (generic-function-methods gf)))
  1229.     #'(lambda (m1 m2)
  1230.         (funcall
  1231.           (if (eq (class-of gf) the-class-standard-gf)
  1232.               #'std-method-more-specific-p
  1233.               #'method-more-specific-p)
  1234.           gf m1 m2 required-classes))))
  1235.  
  1236. ;;; method-more-specific-p
  1237.  
  1238. (defun std-method-more-specific-p (gf method1 method2 required-classes)
  1239.   (declare (ignore gf))
  1240.   (mapc #'(lambda (spec1 spec2 arg-class)
  1241.             (unless (eq spec1 spec2)
  1242.               (return-from std-method-more-specific-p
  1243.                  (sub-specializer-p spec1 spec2 arg-class))))
  1244.         (method-specializers method1)
  1245.         (method-specializers method2)
  1246.         required-classes)
  1247.   nil)
  1248.  
  1249. ;;; apply-methods and compute-effective-method-function
  1250.  
  1251. (defun apply-methods (gf args methods)
  1252.   (funcall (compute-effective-method-function gf methods)
  1253.            args))
  1254.  
  1255. (defun primary-method-p (method)
  1256.   (null (method-qualifiers method)))
  1257. (defun before-method-p (method)
  1258.   (equal '(:before) (method-qualifiers method)))
  1259. (defun after-method-p (method)
  1260.   (equal '(:after) (method-qualifiers method)))
  1261. (defun around-method-p (method)
  1262.   (equal '(:around) (method-qualifiers method)))
  1263.  
  1264. (defun std-compute-effective-method-function (gf methods)
  1265.   (let ((primaries (remove-if-not #'primary-method-p methods))
  1266.         (around (find-if #'around-method-p methods)))
  1267.     (when (null primaries)
  1268.       (error "No primary methods for the~@
  1269.              generic function ~S." gf))
  1270.     (if around
  1271.         (let ((next-emfun
  1272.                 (funcall
  1273.                    (if (eq (class-of gf) the-class-standard-gf)
  1274.                        #'std-compute-effective-method-function
  1275.                        #'compute-effective-method-function)
  1276.                    gf (remove around methods))))
  1277.           #'(lambda (args)
  1278.               (funcall (method-function around) args next-emfun)))
  1279.         (let ((next-emfun (compute-primary-emfun (cdr primaries)))
  1280.               (befores (remove-if-not #'before-method-p methods))
  1281.               (reverse-afters
  1282.                 (reverse (remove-if-not #'after-method-p methods))))
  1283.           #'(lambda (args)
  1284.               (dolist (before befores)
  1285.                 (funcall (method-function before) args nil))
  1286.               (multiple-value-prog1
  1287.                 (funcall (method-function (car primaries)) args next-emfun)
  1288.                 (dolist (after reverse-afters)
  1289.                   (funcall (method-function after) args nil))))))))
  1290.  
  1291. ;;; compute an effective method function from a list of primary methods:
  1292.  
  1293. (defun compute-primary-emfun (methods)
  1294.   (if (null methods)
  1295.       nil
  1296.       (let ((next-emfun (compute-primary-emfun (cdr methods))))
  1297.         #'(lambda (args)
  1298.             (funcall (method-function (car methods)) args next-emfun)))))
  1299.  
  1300. ;;; apply-method and compute-method-function
  1301.  
  1302. (defun apply-method (method args next-methods)
  1303.   (funcall (method-function method)
  1304.            args
  1305.            (if (null next-methods)
  1306.                nil
  1307.                (compute-effective-method-function
  1308.                  (method-generic-function method) next-methods))))
  1309.  
  1310. (defun std-compute-method-function (method)
  1311.   (let ((form (method-body method))
  1312.         (lambda-list (method-lambda-list method)))
  1313.     (compile-in-lexical-environment (method-environment method)
  1314.       `(lambda (args next-emfun)
  1315.          (flet ((call-next-method (&rest cnm-args)
  1316.                   (if (null next-emfun)
  1317.                       (error "No next method for the~@
  1318.                               generic function ~S."
  1319.                              (method-generic-function ',method))
  1320.                       (funcall next-emfun (or cnm-args args))))
  1321.                 (next-method-p ()
  1322.                   (not (null next-emfun))))
  1323.             (apply #'(lambda ,(kludge-arglist lambda-list)
  1324.                        ,form)
  1325.                    args))))))
  1326.  
  1327. ;;; N.B. The function kludge-arglist is used to pave over the differences
  1328. ;;; between argument keyword compatibility for regular functions versus
  1329. ;;; generic functions.
  1330.  
  1331. (defun kludge-arglist (lambda-list)
  1332.   (if (and (member '&key lambda-list)
  1333.            (not (member '&allow-other-keys lambda-list)))
  1334.       (append lambda-list '(&allow-other-keys))
  1335.       (if (and (not (member '&rest lambda-list))
  1336.                (not (member '&key lambda-list)))
  1337.           (append lambda-list '(&key &allow-other-keys))
  1338.           lambda-list)))
  1339.  
  1340. ;;; Run-time environment hacking (Common Lisp ain't got 'em).
  1341.  
  1342. #-CLISP
  1343. (defun top-level-environment ()
  1344.   nil) ; Bogus top level lexical environment
  1345. #+CLISP
  1346. (defun top-level-environment ()
  1347.   (eval `(the-environment))
  1348. )
  1349.  
  1350. #-CLISP
  1351. (defun compile-in-lexical-environment (env lambda-expr)
  1352.   (declare (ignore env))
  1353.   (compile nil lambda-expr))
  1354. #+CLISP
  1355. (defun compile-in-lexical-environment (env lambda-expr)
  1356.   (eval-env `(locally (declare (compile)) (function ,lambda-expr)) env)
  1357. )
  1358.  
  1359.  
  1360. ;;;
  1361. ;;; Bootstrap
  1362. ;;;
  1363.  
  1364. (progn  ; Extends to end-of-file (to avoid printing intermediate results).
  1365. (format t "~&Beginning to bootstrap Closette...")
  1366. (forget-all-classes)
  1367. (forget-all-generic-functions)
  1368. ;; How to create the class hierarchy in 10 easy steps:
  1369. ;; 1. Figure out standard-class's slots.
  1370. (setq the-slots-of-standard-class
  1371.       (mapcar #'(lambda (slotd)
  1372.                   (make-effective-slot-definition
  1373.                     :name (car slotd)
  1374.                     :initargs
  1375.                       (let ((a (getf (cdr slotd) ':initarg)))
  1376.                         (if a (list a) ()))
  1377.                     :initform (getf (cdr slotd) ':initform)
  1378.                     :initfunction
  1379.                       (let ((a (getf (cdr slotd) ':initform)))
  1380.                         (if a #'(lambda () (eval a)) nil))
  1381.                     :allocation ':instance))
  1382.               (nth 3 the-defclass-standard-class)))
  1383. ;; 2. Create the standard-class metaobject by hand.
  1384. (setq the-class-standard-class
  1385.       (allocate-std-instance
  1386.          'tba
  1387.          (make-array (length the-slots-of-standard-class)
  1388.                      :initial-element secret-unbound-value)))
  1389. ;; 3. Install standard-class's (circular) class-of link.
  1390. (setf (std-instance-class the-class-standard-class)
  1391.       the-class-standard-class)
  1392. ;; (It's now okay to use class-... accessor).
  1393. ;; 4. Fill in standard-class's class-slots.
  1394. (setf (class-slots the-class-standard-class) the-slots-of-standard-class)
  1395. ;; (Skeleton built; it's now okay to call make-instance-standard-class.)
  1396. ;; 5. Hand build the class t so that it has no direct superclasses.
  1397. (setf (find-class 't)
  1398.   (let ((class (std-allocate-instance the-class-standard-class)))
  1399.     (setf (class-name class) 't)
  1400.     (setf (class-direct-subclasses class) ())
  1401.     (setf (class-direct-superclasses class) ())
  1402.     (setf (class-direct-methods class) ())
  1403.     (setf (class-direct-slots class) ())
  1404.     (setf (class-precedence-list class) (list class))
  1405.     (setf (class-slots class) ())
  1406.     class))
  1407. ;; (It's now okay to define subclasses of t.)
  1408. ;; 6. Create the other superclass of standard-class (i.e., standard-object).
  1409. (defclass standard-object (t) ())
  1410. ;; 7. Define the full-blown version of standard-class.
  1411. (setq the-class-standard-class (eval the-defclass-standard-class))
  1412. ;; 8. Replace all (3) existing pointers to the skeleton with real one.
  1413. (setf (std-instance-class (find-class 't))
  1414.       the-class-standard-class)
  1415. (setf (std-instance-class (find-class 'standard-object))
  1416.       the-class-standard-class)
  1417. (setf (std-instance-class the-class-standard-class)
  1418.       the-class-standard-class)
  1419. ;; (Clear sailing from here on in).
  1420. ;; 9. Define the other built-in classes.
  1421. (defclass symbol (t) ())
  1422. (defclass sequence (t) ())
  1423. (defclass array (t) ())
  1424. (defclass number (t) ())
  1425. (defclass character (t) ())
  1426. (defclass function (t) ())
  1427. (defclass hash-table (t) ())
  1428. (defclass package (t) ())
  1429. (defclass pathname (t) ())
  1430. (defclass readtable (t) ())
  1431. (defclass stream (t) ())
  1432. (defclass list (sequence) ())
  1433. (defclass null (symbol list) ())
  1434. (defclass cons (list) ())
  1435. (defclass vector (array sequence) ())
  1436. (defclass bit-vector (vector) ())
  1437. (defclass string (vector) ())
  1438. (defclass complex (number) ())
  1439. (defclass integer (number) ())
  1440. (defclass float (number) ())
  1441. ;; 10. Define the other standard metaobject classes.
  1442. (setq the-class-standard-gf (eval the-defclass-standard-generic-function))
  1443. (setq the-class-standard-method (eval the-defclass-standard-method))
  1444. ;; Voila! The class hierarchy is in place.
  1445. (format t "Class hierarchy created.")
  1446. ;; (It's now okay to define generic functions and methods.)
  1447.  
  1448. (defgeneric print-object (instance stream))
  1449. (defmethod print-object ((instance standard-object) stream)
  1450.   (print-unreadable-object (instance stream :identity t)
  1451.     #-CLISP
  1452.     (format stream "~:(~S~)" (class-name (class-of instance)))
  1453.     #+CLISP
  1454.     (write-string
  1455.       (string-capitalize
  1456.         (write-to-string (class-name (class-of instance)) :escape t)
  1457.       )
  1458.       stream
  1459.     )
  1460.   )
  1461.   instance
  1462. )
  1463.  
  1464. ;;; Slot access
  1465.  
  1466. (defgeneric slot-value-using-class (class instance slot-name))
  1467. (defmethod slot-value-using-class
  1468.            ((class standard-class) instance slot-name)
  1469.   (std-slot-value instance slot-name))
  1470.  
  1471. (defgeneric (setf slot-value-using-class) (new-value class instance slot-name))
  1472. (defmethod (setf slot-value-using-class)
  1473.            (new-value (class standard-class) instance slot-name)
  1474.   (setf (std-slot-value instance slot-name) new-value))
  1475. ;;; N.B. To avoid making a forward reference to a (setf xxx) generic function:
  1476. (defun setf-slot-value-using-class (new-value class object slot-name)
  1477.   (setf (slot-value-using-class class object slot-name) new-value))
  1478.  
  1479. (defgeneric slot-exists-p-using-class (class instance slot-name))
  1480. (defmethod slot-exists-p-using-class
  1481.            ((class standard-class) instance slot-name)
  1482.   (std-slot-exists-p instance slot-name))
  1483.  
  1484. (defgeneric slot-boundp-using-class (class instance slot-name))
  1485. (defmethod slot-boundp-using-class
  1486.            ((class standard-class) instance slot-name)
  1487.   (std-slot-boundp instance slot-name))
  1488.  
  1489. (defgeneric slot-makunbound-using-class (class instance slot-name))
  1490. (defmethod slot-makunbound-using-class
  1491.            ((class standard-class) instance slot-name)
  1492.   (std-slot-makunbound instance slot-name))
  1493.  
  1494. ;;; Instance creation and initialization
  1495.  
  1496. (defgeneric allocate-instance (class))
  1497. (defmethod allocate-instance ((class standard-class))
  1498.   (std-allocate-instance class))
  1499.  
  1500. (defgeneric make-instance (class &key))
  1501. (defmethod make-instance ((class standard-class) &rest initargs)
  1502.   (let ((instance (allocate-instance class)))
  1503.     (apply #'initialize-instance instance initargs)
  1504.     instance))
  1505. (defmethod make-instance ((class symbol) &rest initargs)
  1506.   (apply #'make-instance (find-class class) initargs))
  1507.  
  1508. (defgeneric initialize-instance (instance &key))
  1509. (defmethod initialize-instance ((instance standard-object) &rest initargs)
  1510.   (apply #'shared-initialize instance t initargs))
  1511.  
  1512. (defgeneric reinitialize-instance (instance &key))
  1513. (defmethod reinitialize-instance
  1514.            ((instance standard-object) &rest initargs)
  1515.   (apply #'shared-initialize instance () initargs))
  1516.  
  1517. (defgeneric shared-initialize (instance slot-names &key))
  1518. (defmethod shared-initialize ((instance standard-object)
  1519.                               slot-names &rest all-keys)
  1520.   (dolist (slot (class-slots (class-of instance)))
  1521.     (let ((slot-name (slot-definition-name slot)))
  1522.       (multiple-value-bind (init-key init-value foundp)
  1523.             (get-properties
  1524.               all-keys (slot-definition-initargs slot))
  1525.          (declare (ignore init-key))
  1526.          (if foundp
  1527.              (setf (slot-value instance slot-name) init-value)
  1528.              (when (and (not (slot-boundp instance slot-name))
  1529.                         (not (null (slot-definition-initfunction slot)))
  1530.                         (or (eq slot-names t)
  1531.                             (member slot-name slot-names)))
  1532.                (setf (slot-value instance slot-name)
  1533.                      (funcall (slot-definition-initfunction slot))))))))
  1534.   instance)
  1535.  
  1536. ;;; change-class
  1537.  
  1538. (defgeneric change-class (instance new-class &key))
  1539. (defmethod change-class
  1540.            ((old-instance standard-object)
  1541.             (new-class standard-class)
  1542.             &rest initargs)
  1543.   (let ((new-instance (allocate-instance new-class)))
  1544.     (dolist (slot-name (mapcar #'slot-definition-name
  1545.                                (class-slots new-class)))
  1546.       (when (and (slot-exists-p old-instance slot-name)
  1547.                  (slot-boundp old-instance slot-name))
  1548.         (setf (slot-value new-instance slot-name)
  1549.               (slot-value old-instance slot-name))))
  1550.     (rotatef (std-instance-slots new-instance)
  1551.              (std-instance-slots old-instance))
  1552.     (rotatef (std-instance-class new-instance)
  1553.              (std-instance-class old-instance))
  1554.     (apply #'update-instance-for-different-class
  1555.            new-instance old-instance initargs)
  1556.     old-instance))
  1557.  
  1558. (defmethod change-class
  1559.            ((instance standard-object) (new-class symbol) &rest initargs)
  1560.   (apply #'change-class instance (find-class new-class) initargs))
  1561.  
  1562. (defgeneric update-instance-for-different-class (old new &key))
  1563. (defmethod update-instance-for-different-class
  1564.            ((old standard-object) (new standard-object) &rest initargs)
  1565.   (let ((added-slots
  1566.           (remove-if #'(lambda (slot-name)
  1567.                          (slot-exists-p old slot-name))
  1568.                      (mapcar #'slot-definition-name
  1569.                              (class-slots (class-of new))))))
  1570.     (apply #'shared-initialize new added-slots initargs)))
  1571.  
  1572. ;;;
  1573. ;;;  Methods having to do with class metaobjects.
  1574. ;;;
  1575.  
  1576. (defmethod print-object ((class standard-class) stream)
  1577.   (print-unreadable-object (class stream :identity t)
  1578.     #-CLISP
  1579.     (format stream "~:(~S~) ~S"
  1580.             (class-name (class-of class))
  1581.             (class-name class)
  1582.     )
  1583.     #+CLISP
  1584.     (progn
  1585.       (write-string
  1586.         (string-capitalize
  1587.           (write-to-string (class-name (class-of class)) :escape t)
  1588.         )
  1589.         stream
  1590.       )
  1591.       (write-char #\Space stream)
  1592.       (write (class-name class) :escape t :stream stream)
  1593.     )
  1594.   )
  1595.   class
  1596. )
  1597.  
  1598. (defmethod initialize-instance :after ((class standard-class) &key &rest args)
  1599.   (apply #'std-after-initialization-for-classes class args))
  1600.  
  1601. ;;; Finalize inheritance
  1602.  
  1603. (defgeneric finalize-inheritance (class))
  1604. (defmethod finalize-inheritance ((class standard-class))
  1605.   (std-finalize-inheritance class)
  1606.   (values))
  1607.  
  1608. ;;; Class precedence lists
  1609.  
  1610. (defgeneric compute-class-precedence-list (class))
  1611. (defmethod compute-class-precedence-list ((class standard-class))
  1612.   (std-compute-class-precedence-list class))
  1613.  
  1614. ;;; Slot inheritance
  1615.  
  1616. (defgeneric compute-slots (class))
  1617. (defmethod compute-slots ((class standard-class))
  1618.   (std-compute-slots class))
  1619.  
  1620. (defgeneric compute-effective-slot-definition (class direct-slots))
  1621. (defmethod compute-effective-slot-definition
  1622.            ((class standard-class) direct-slots)
  1623.   (std-compute-effective-slot-definition class direct-slots))
  1624.  
  1625. ;;;
  1626. ;;; Methods having to do with generic function metaobjects.
  1627. ;;;
  1628.  
  1629. (defmethod print-object ((gf standard-generic-function) stream)
  1630.   (print-unreadable-object (gf stream :identity t)
  1631.     #-CLISP
  1632.     (format stream "~:(~S~) ~S"
  1633.             (class-name (class-of gf))
  1634.             (generic-function-name gf)
  1635.     )
  1636.     #+CLISP
  1637.     (progn
  1638.       (write-string
  1639.         (string-capitalize
  1640.           (write-to-string (class-name (class-of gf)) :escape t)
  1641.         )
  1642.         stream
  1643.       )
  1644.       (write-char #\Space stream)
  1645.       (write (generic-function-name gf) :escape t :stream stream)
  1646.     )
  1647.   )
  1648.   gf
  1649. )
  1650.  
  1651. (defmethod initialize-instance :after ((gf standard-generic-function) &key)
  1652.   (finalize-generic-function gf))
  1653.  
  1654. ;;;
  1655. ;;; Methods having to do with method metaobjects.
  1656. ;;;
  1657.  
  1658. (defmethod print-object ((method standard-method) stream)
  1659.   (print-unreadable-object (method stream :identity t)
  1660.     #-CLISP
  1661.     (format stream "~:(~S~) ~S~{ ~S~} ~S"
  1662.                    (class-name (class-of method))
  1663.                    (generic-function-name (method-generic-function method))
  1664.                    (method-qualifiers method)
  1665.                    (mapcar #'class-name (method-specializers method))
  1666.     )
  1667.     #+CLISP
  1668.     (progn
  1669.       (write-string
  1670.         (string-capitalize
  1671.           (write-to-string (class-name (class-of method)) :escape t)
  1672.         )
  1673.         stream
  1674.       )
  1675.       (write-char #\Space stream)
  1676.       (write (generic-function-name (method-generic-function method))
  1677.              :escape t :stream stream
  1678.       )
  1679.       (dolist (qual (method-qualifiers method))
  1680.         (write-char #\Space stream) (write qual :escape t :stream stream)
  1681.       )
  1682.       (write-char #\Space stream)
  1683.       (write (mapcar #'class-name (method-specializers method))
  1684.              :escape t :stream stream
  1685.     ) )
  1686.   )
  1687.   method
  1688. )
  1689.  
  1690. (defmethod initialize-instance :after ((method standard-method) &key)
  1691.   (setf (method-function method) (compute-method-function method)))
  1692.  
  1693. ;;;
  1694. ;;; Methods having to do with generic function invocation.
  1695. ;;;
  1696.  
  1697. (defgeneric compute-discriminating-function (gf))
  1698. (defmethod compute-discriminating-function ((gf standard-generic-function))
  1699.   (std-compute-discriminating-function gf))
  1700.  
  1701. (defgeneric method-more-specific-p (gf method1 method2 required-classes))
  1702. (defmethod method-more-specific-p
  1703.            ((gf standard-generic-function) method1 method2 required-classes)
  1704.   (std-method-more-specific-p gf method1 method2 required-classes))
  1705.  
  1706. (defgeneric compute-effective-method-function (gf methods))
  1707. (defmethod compute-effective-method-function
  1708.            ((gf standard-generic-function) methods)
  1709.   (std-compute-effective-method-function gf methods))
  1710.  
  1711. (defgeneric compute-method-function (method))
  1712. (defmethod compute-method-function ((method standard-method))
  1713.   (std-compute-method-function method))
  1714.  
  1715. ;;; describe-object is a handy tool for enquiring minds:
  1716.  
  1717. (defgeneric describe-object (object stream))
  1718. (defmethod describe-object ((object standard-object) stream)
  1719.   (format t "A Closette object~
  1720.              ~%Printed representation: ~S~
  1721.              ~%Class: ~S~
  1722.              ~%Structure "
  1723.           object
  1724.           (class-of object))
  1725.   (dolist (sn (mapcar #'slot-definition-name
  1726.                       (class-slots (class-of object))))
  1727.     (format t "~%    ~S <- ~:[not bound~;~S~]"
  1728.             sn
  1729.             (slot-boundp object sn)
  1730.             (and (slot-boundp object sn)
  1731.                  (slot-value object sn))))
  1732.   (values))
  1733. (defmethod describe-object ((object t) stream)
  1734.   (lisp:describe object)
  1735.   (values))
  1736.  
  1737. (format t "~%Closette is a Knights of the Lambda Calculus production.")
  1738.  
  1739. (values)) ;end progn
  1740.  
  1741.