0.pre7.95:
[sbcl.git] / src / pcl / defclass.lisp
index bcfb77b..845edaf 100644 (file)
 ;;; After the metabraid has been setup, and the protocol for defining
 ;;; classes has been defined, the real definition of LOAD-DEFCLASS is
 ;;; installed by the file std-class.lisp
-(defmacro defclass (name direct-superclasses direct-slots &rest options)
-  (expand-defclass name direct-superclasses direct-slots options))
-
-(defun expand-defclass (name supers slots options)
-  (setq supers  (copy-tree supers)
-       slots   (copy-tree slots)
-       options (copy-tree options))
-  (let ((metaclass 'standard-class))
-    (dolist (option options)
-      (if (not (listp option))
+(defmacro defclass (name %direct-superclasses %direct-slots &rest %options)
+  (let ((supers  (copy-tree %direct-superclasses))
+       (slots   (copy-tree %direct-slots))
+       (options (copy-tree %options)))
+    (let ((metaclass 'standard-class))
+      (dolist (option options)
+        (if (not (listp option))
          (error "~S is not a legal defclass option." option)
          (when (eq (car option) ':metaclass)
            (unless (legal-class-name-p (cadr option))
                      legal class name."
                     (cadr option)))
            (setq metaclass
-                 (case (cadr option)
-                   (cl:standard-class 'standard-class)
-                   (cl:structure-class 'structure-class)
-                   (t (cadr option))))
+                    (case (cadr option)
+                      (cl:standard-class 'standard-class)
+                      (cl:structure-class 'structure-class)
+                      (t (cadr option))))
            (setf options (remove option options))
            (return t))))
 
-    (let ((*initfunctions* ())
-         (*readers* ())                ;Truly a crock, but we got
-         (*writers* ()))               ;to have it to live nicely.
-      (declare (special *initfunctions* *readers* *writers*))
-      (let ((canonical-slots
-             (mapcar #'(lambda (spec)
-                         (canonicalize-slot-specification name spec))
-                     slots))
-           (other-initargs
-             (mapcar #'(lambda (option)
-                         (canonicalize-defclass-option name option))
-                     options))
-           (defstruct-p (and (eq *boot-state* 'complete)
-                             (let ((mclass (find-class metaclass nil)))
-                               (and mclass
-                                    (*subtypep
-                                     mclass
-                                     *the-class-structure-class*))))))
-       (let ((defclass-form
-               `(progn
-                  ,@(mapcar (lambda (x)
-                              `(declaim (ftype (function (t) t) ,x)))
-                            *readers*)
-                  ,@(mapcar (lambda (x)
-                              `(declaim (ftype (function (t t) t) ,x)))
-                            *writers*)
-                  (let ,(mapcar #'cdr *initfunctions*)
-                    (load-defclass ',name
-                                   ',metaclass
-                                   ',supers
-                                   (list ,@canonical-slots)
-                                   (list ,@(apply #'append
-                                                  (when defstruct-p
-                                                    '(:from-defclass-p t))
-                                                  other-initargs)))))))
-         ;; FIXME: The way that we do things like (EVAL DEFCLASS-FORM)
-         ;; here is un-ANSI-Common-Lisp-y and leads to problems
-         ;; (like DEFUN for the type predicate being called more than
-         ;; once when we do DEFCLASS at the interpreter prompt),
-         ;; causing bogus style warnings. It would be better to
-         ;; rewrite this so that the macroexpansion looks like e.g.
-         ;; (PROGN
-         ;;   (EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
-         ;;     (FROB1 ..))
-         ;;   (EVAL-WHEN (:LOAD-TOPLEVEL :EXECUTE)
-         ;;     (FROB2 ..)))
-         (if defstruct-p
-             (progn
-               (eval defclass-form) ; Define the class now, so that..
-               `(progn       ; ..the defstruct can be compiled.
-                  ,(class-defstruct-form (find-class name))
-                  ,defclass-form))
-             (progn
-               (when (eq *boot-state* 'complete)
-                 ;; FIXME: MNA (on sbcl-devel 2001-05-30) reported
-                 ;; (if I understand correctly -- WHN) that this call
-                 ;; is directly responsible for defining
-                 ;; class-predicates which always return
-                 ;; CONSTANTLY-NIL in the compile-time environment,
-                 ;; and is indirectly responsible for bogus warnings
-                 ;; about redefinitions when making definitions in
-                 ;; the interpreter. I didn't like his fix (deleting
-                 ;; the call) since I think the type system *should*
-                 ;; be informed about class definitions here. And I'm
-                 ;; not eager to look too deeply into this sort of
-                 ;; done-too-many-times-in-the-interpreter problem
-                 ;; right now, since it should be easier to make a
-                 ;; clean fix when EVAL-WHEN is made more ANSI (as
-                 ;; per the IR1 section in the BUGS file). But
-                 ;; at some point this should be cleaned up.
-                 (inform-type-system-about-std-class name))
-               defclass-form)))))))
+      (let ((*initfunctions* ())
+            (*readers* ())             ;Truly a crock, but we got
+            (*writers* ()))             ;to have it to live nicely.
+        (declare (special *initfunctions* *readers* *writers*))
+        (let ((canonical-slots
+                (mapcar #'(lambda (spec)
+                            (canonicalize-slot-specification name spec))
+                        slots))
+              (other-initargs
+                (mapcar #'(lambda (option)
+                            (canonicalize-defclass-option name option))
+                        options))
+              ;; DEFSTRUCT-P should be true, if the class is defined with a
+              ;; metaclass STRUCTURE-CLASS, such that a DEFSTRUCT is compiled
+              ;; for the class.
+              (defstruct-p (and (eq *boot-state* 'complete)
+                                (let ((mclass (find-class metaclass nil)))
+                                  (and mclass
+                                       (*subtypep
+                                        mclass
+                                        *the-class-structure-class*))))))
+          (let ((defclass-form
+                    `(progn
+                      ,@(mapcar (lambda (x)
+                                  `(declaim (ftype (function (t) t) ,x)))
+                                *readers*)
+                      ,@(mapcar (lambda (x)
+                                  `(declaim (ftype (function (t t) t) ,x)))
+                                *writers*)
+                      (let ,(mapcar #'cdr *initfunctions*)
+                        (load-defclass ',name
+                                       ',metaclass
+                                       ',supers
+                                       (list ,@canonical-slots)
+                                       (list ,@(apply #'append
+                                                      (when defstruct-p
+                                                        '(:from-defclass-p t))
+                                                      other-initargs)))))))
+            (if defstruct-p
+              (let* ((include (or (and supers
+                                       (fix-super (car supers)))
+                                  (and (not (eq name 'structure-object))
+                                       *the-class-structure-object*)))
+                     (defstruct-form (make-structure-class-defstruct-form
+                                     name slots include)))
+                `(progn
+                  (eval-when (:compile-toplevel :load-toplevel :execute)
+                    ,defstruct-form) ; really compile the defstruct-form
+                  (eval-when (:compile-toplevel :load-toplevel :execute)
+                    ,defclass-form)))
+             `(progn
+                ;; By telling the type system at compile time about
+                ;; the existence of a class named NAME, we can avoid
+                ;; various bogus warnings about "type isn't defined yet".
+                ,(when (and
+                        ;; But it's not so important to get rid of
+                        ;; "not defined yet" warnings during
+                        ;; bootstrapping, and machinery like
+                        ;; INFORM-TYPE-SYSTEM-ABOUT-STD-CLASS
+                        ;; mightn't be defined yet. So punt then.
+                        (eq *boot-state* 'complete)
+                        ;; And although we know enough about
+                        ;; STANDARD-CLASS, and ANSI imposes enough
+                        ;; restrictions on the user overloading its
+                        ;; methods, that (1) we can shortcut the
+                        ;; method dispatch and do an ordinary
+                        ;; function call, and (2) be sure we're getting
+                        ;; it right even when we do it at compile
+                        ;; time; we don't in general know how to do
+                        ;; that for other classes. So punt then too.
+                        (eq metaclass 'standard-class))
+                       `(eval-when (:compile-toplevel)
+                         ;; we only need :COMPILE-TOPLEVEL here, because this
+                         ;; should happen in the compile-time environment
+                         ;; only.
+                         ;; Later, INFORM-TYPE-SYSTEM-ABOUT-STD-CLASS is
+                         ;; called by way of LOAD-DEFCLASS (calling
+                         ;; ENSURE-CLASS-USING-CLASS) to establish the 'real'
+                         ;; type predicate.                         
+                         (inform-type-system-about-std-class ',name)))
+                ,defclass-form))))))))
 
 (defun make-initfunction (initform)
   (declare (special *initfunctions*))
     (values (early-collect-slots cpl)
            cpl
            (early-collect-default-initargs cpl)
-           (gathering1 (collecting)
+           (let (collect)
              (dolist (definition *early-class-definitions*)
                (when (memq class-name (ecd-superclass-names definition))
-                 (gather1 (ecd-class-name definition))))))))
+                 (push (ecd-class-name definition) collect)))
+              (nreverse collect)))))
 
 (defun early-collect-slots (cpl)
   (let* ((definitions (mapcar #'early-class-definition cpl))