(t res))))
;;; Delay looking for compiler-layout until the constructor is being
-;;; compiled, since it doesn't exist until after the EVAL-WHEN (COMPILE)
-;;; stuff is compiled.
+;;; compiled, since it doesn't exist until after the EVAL-WHEN
+;;; (COMPILE) stuff is compiled. (Or, in the oddball case when
+;;; DEFSTRUCT is executing in a non-toplevel context, the
+;;; compiler-layout still doesn't exist at compilation time, and we
+;;; delay still further.)
(sb!xc:defmacro %delayed-get-compiler-layout (name)
- `',(compiler-layout-or-lose name))
+ (let ((layout (info :type :compiler-layout name)))
+ (cond (layout
+ ;; ordinary case: When the DEFSTRUCT is at top level,
+ ;; then EVAL-WHEN (COMPILE) stuff will have set up the
+ ;; layout for us to use.
+ (unless (typep (layout-info layout) 'defstruct-description)
+ (error "Class is not a structure class: ~S" name))
+ `,layout)
+ (t
+ ;; KLUDGE: In the case that DEFSTRUCT is not at top-level
+ ;; the layout doesn't exist at compile time. In that case
+ ;; we laboriously look it up at run time. This code will
+ ;; run on every constructor call and will likely be quite
+ ;; slow, so if anyone cares about performance of
+ ;; non-toplevel DEFSTRUCTs, it should be rewritten to be
+ ;; cleverer. -- WHN 2002-10-23
+ (sb!c::compiler-note
+ "implementation limitation: ~
+ Non-toplevel DEFSTRUCT constructors are slow.")
+ (let ((layout (gensym "LAYOUT")))
+ `(let ((,layout (info :type :compiler-layout ',name)))
+ (unless (typep (layout-info ,layout) 'defstruct-description)
+ (error "Class is not a structure class: ~S" ',name))
+ ,layout))))))
;;; Get layout right away.
(sb!xc:defmacro compile-time-find-layout (name)
(:conc-name dd-)
(:make-load-form-fun just-dump-it-normally)
#-sb-xc-host (:pure t)
- (:constructor make-defstruct-description (name)))
+ (:constructor make-defstruct-description
+ (name &aux
+ (conc-name (symbolicate name "-"))
+ (copier-name (symbolicate "COPY-" name))
+ (predicate-name (symbolicate name "-P")))))
;; name of the structure
- (name (missing-arg) :type symbol)
+ (name (missing-arg) :type symbol :read-only t)
;; documentation on the structure
(doc nil :type (or string null))
;; prefix for slot names. If NIL, none.
- (conc-name (symbolicate name "-") :type (or symbol null))
+ (conc-name nil :type (or symbol null))
;; the name of the primary standard keyword constructor, or NIL if none
(default-constructor nil :type (or symbol null))
;; all the explicit :CONSTRUCTOR specs, with name defaulted
(constructors () :type list)
;; name of copying function
- (copier-name (symbolicate "COPY-" name) :type (or symbol null))
+ (copier-name nil :type (or symbol null))
;; name of type predicate
- (predicate-name (symbolicate name "-P") :type (or symbol null))
+ (predicate-name nil :type (or symbol null))
;; the arguments to the :INCLUDE option, or NIL if no included
;; structure
(include nil :type list)
fun-name)))
(cond ((not (eql pf 0))
`((def!method print-object ((,x ,name) ,s)
- (funcall #',(farg pf) ,x ,s *current-level*))))
+ (funcall #',(farg pf)
+ ,x
+ ,s
+ *current-level-in-print*))))
((not (eql po 0))
`((def!method print-object ((,x ,name) ,s)
(funcall #',(farg po) ,x ,s))))
(if (dd-class-p dd)
(let ((inherits (inherits-for-structure dd)))
`(progn
+ ;; Note we intentionally call %DEFSTRUCT first, and
+ ;; especially before %COMPILER-DEFSTRUCT. %DEFSTRUCT
+ ;; has the tests (and resulting CERROR) for collisions
+ ;; with LAYOUTs which already exist in the runtime. If
+ ;; there are any collisions, we want the user's
+ ;; response to CERROR to control what happens.
+ ;; Especially, if the user responds to the collision
+ ;; with ABORT, we don't want %COMPILER-DEFSTRUCT to
+ ;; modify the definition of the class.
+ (%defstruct ',dd ',inherits)
(eval-when (:compile-toplevel :load-toplevel :execute)
(%compiler-defstruct ',dd ',inherits))
- (%defstruct ',dd ',inherits)
,@(unless expanding-into-code-for-xc-host-p
(append ;; FIXME: We've inherited from CMU CL nonparallel
;; code for creating copiers for typed and untyped
;; structures. This should be fixed.
- ;(copier-definition dd)
+ ;(copier-definition dd)
(constructor-definitions dd)
(class-method-definitions dd)))
',name))
(when offset (incf (dd-length dd) offset)))))
(when (dd-include dd)
- (do-dd-inclusion-stuff dd))
+ (frob-dd-inclusion-stuff dd))
dd)))
;;; RAW? is true if TYPE should be stored in a raw slot.
;;; RAW-TYPE is the raw slot type, or NIL if no raw slot.
;;; WORDS is the number of words in the raw slot, or NIL if no raw slot.
+;;;
+;;; FIXME: This should use the data in *RAW-SLOT-DATA-LIST*.
(defun structure-raw-slot-type-and-size (type)
(cond #+nil
(;; FIXME: For now we suppress raw slots, since there are various
;;; Process any included slots pretty much like they were specified.
;;; Also inherit various other attributes.
-(defun do-dd-inclusion-stuff (dd)
+(defun frob-dd-inclusion-stuff (dd)
(destructuring-bind (included-name &rest modified-slots) (dd-include dd)
(let* ((type (dd-type dd))
(included-structure
(dolist (included-slot (dd-slots included-structure))
(let* ((included-name (dsd-name included-slot))
(modified (or (find included-name modified-slots
- :key #'(lambda (x) (if (atom x) x (car x)))
+ :key (lambda (x) (if (atom x) x (car x)))
:test #'string=)
`(,included-name))))
(parse-1-dsd dd
;; Various other operations only make sense on the target SBCL.
#-sb-xc-host
- (progn
- (remhash (dd-name dd) *typecheckfuns*)
- (%target-defstruct dd layout)
- (when (dd-doc dd)
- (setf (fdocumentation (dd-name dd) 'type)
- (dd-doc dd)))))
+ (%target-defstruct dd layout))
(values))
\f
,instance-type-decl
(setf ,accessor-place-form new-value))))))
+;;; Return a LAMBDA form which can be used to set a slot.
+(defun slot-setter-lambda-form (dd dsd)
+ (funcall (nth-value 1
+ (slot-accessor-inline-expansion-designators dd dsd))))
+
;;; core compile-time setup of any class with a LAYOUT, used even by
;;; !DEFSTRUCT-WITH-ALTERNATE-METACLASS weirdosities
(defun %compiler-set-up-layout (dd
(%compiler-set-up-layout dd inherits)
- (let* ((dd-name (dd-name dd))
- (dtype (dd-declarable-type dd))
- (class (sb!xc:find-class dd-name)))
+ (let* ((dtype (dd-declarable-type dd)))
(let ((copier-name (dd-copier-name dd)))
(when copier-name
(declare (type sb!xc:class class) (type layout old-layout new-layout))
(let ((name (class-proper-name class)))
(restart-case
- (error "redefining class ~S incompatibly with the current definition"
+ (error "~@<attempt to redefine the ~S class ~S incompatibly with the current definition~:@>"
+ 'structure-object
name)
(continue ()
- :report "Invalidate current definition."
- (warn "Previously loaded ~S accessors will no longer work." name)
- (register-layout new-layout))
+ :report (lambda (s)
+ (format s
+ "~@<Use the new definition of ~S, invalidating ~
+ already-loaded code and instances.~@:>"
+ name))
+ (register-layout new-layout))
+ (recklessly-continue ()
+ :report (lambda (s)
+ (format s
+ "~@<Use the new definition of ~S as if it were ~
+ compatible, allowing old accessors to use new ~
+ instances and allowing new accessors to use old ~
+ instances.~@:>"
+ name))
+ ;; classic CMU CL warning: "Any old ~S instances will be in a bad way.
+ ;; I hope you know what you're doing..."
+ (register-layout new-layout
+ :invalidate nil
+ :destruct-layout old-layout))
(clobber-it ()
- :report "Smash current layout, preserving old code."
- (warn "Any old ~S instances will be in a bad way.~@
- I hope you know what you're doing..."
- name)
- (register-layout new-layout :invalidate nil
- :destruct-layout old-layout))))
+ ;; FIXME: deprecated 2002-10-16, and since it's only interactive
+ ;; hackery instead of a supported feature, can probably be deleted
+ ;; in early 2003
+ :report "(deprecated synonym for RECKLESSLY-CONTINUE)"
+ (register-layout new-layout
+ :invalidate nil
+ :destruct-layout old-layout))))
(values))
;;; This is called when we are about to define a structure class. It
(res)))
\f
-;;;; slot accessors for raw slots
-
-;;; Return info about how to read/write a slot in the value stored in
-;;; OBJECT. This is also used by constructors (since we can't safely
-;;; use the accessor function, since some slots are read-only). If
-;;; supplied, DATA is a variable holding the raw-data vector.
-;;;
-;;; returned values:
-;;; 1. accessor function name (SETFable)
-;;; 2. index to pass to accessor.
-;;; 3. object form to pass to accessor
-(defun slot-accessor-form (defstruct slot object &optional data)
- (let ((rtype (dsd-raw-type slot)))
- (values
- (ecase rtype
- (single-float '%raw-ref-single)
- (double-float '%raw-ref-double)
- #!+long-float
- (long-float '%raw-ref-long)
- (complex-single-float '%raw-ref-complex-single)
- (complex-double-float '%raw-ref-complex-double)
- #!+long-float
- (complex-long-float '%raw-ref-complex-long)
- (unsigned-byte 'aref)
- ((t) '%instance-ref))
- (case rtype
- #!+long-float
- (complex-long-float
- (truncate (dsd-index slot) #!+x86 6 #!+sparc 8))
- #!+long-float
- (long-float
- (truncate (dsd-index slot) #!+x86 3 #!+sparc 4))
- (double-float
- (ash (dsd-index slot) -1))
- (complex-double-float
- (ash (dsd-index slot) -2))
- (complex-single-float
- (ash (dsd-index slot) -1))
- (t
- (dsd-index slot)))
- (cond
- ((eq rtype t) object)
- (data)
- (t
- `(truly-the (simple-array (unsigned-byte 32) (*))
- (%instance-ref ,object ,(dd-raw-index defstruct))))))))
-\f
;;; These functions are called to actually make a constructor after we
;;; have processed the arglist. The correct variant (according to the
;;; DD-TYPE) should be called. The function is defined with the
;;; various weird places, whereas STRUCTURE structures have
;;; a LAYOUT slot.
;;; * We really want to use LIST to make list structures, instead of
-;;; MAKE-LIST/(SETF ELT).
+;;; MAKE-LIST/(SETF ELT). (We can't in general use VECTOR in an
+;;; analogous way, since VECTOR makes a SIMPLE-VECTOR and vector-typed
+;;; structures can have arbitrary subtypes of VECTOR, not necessarily
+;;; SIMPLE-VECTOR.)
;;; * STRUCTURE structures can have raw slots that must also be
-;;; allocated and indirectly referenced. We use SLOT-ACCESSOR-FORM
-;;; to compute how to set the slots, which deals with raw slots.
+;;; allocated and indirectly referenced.
(defun create-vector-constructor (dd cons-name arglist vars types values)
(let ((temp (gensym))
(etype (dd-element-type dd)))
`(defun ,cons-name ,arglist
- (declare ,@(mapcar #'(lambda (var type) `(type (and ,type ,etype) ,var))
+ (declare ,@(mapcar (lambda (var type) `(type (and ,type ,etype) ,var))
vars types))
(let ((,temp (make-array ,(dd-length dd)
:element-type ',(dd-element-type dd))))
- ,@(mapcar #'(lambda (x)
- `(setf (aref ,temp ,(cdr x)) ',(car x)))
+ ,@(mapcar (lambda (x)
+ `(setf (aref ,temp ,(cdr x)) ',(car x)))
(find-name-indices dd))
- ,@(mapcar #'(lambda (dsd value)
- `(setf (aref ,temp ,(dsd-index dsd)) ,value))
+ ,@(mapcar (lambda (dsd value)
+ `(setf (aref ,temp ,(dsd-index dsd)) ,value))
(dd-slots dd) values)
,temp))))
(defun create-list-constructor (dd cons-name arglist vars types values)
(setf (elt vals (dsd-index dsd)) val))
`(defun ,cons-name ,arglist
- (declare ,@(mapcar #'(lambda (var type) `(type ,type ,var))
- vars types))
+ (declare ,@(mapcar (lambda (var type) `(type ,type ,var)) vars types))
(list ,@vals))))
(defun create-structure-constructor (dd cons-name arglist vars types values)
- (let* ((temp (gensym))
- (raw-index (dd-raw-index dd))
- (n-raw-data (when raw-index (gensym))))
+ (let* ((instance (gensym "INSTANCE"))
+ (raw-index (dd-raw-index dd)))
`(defun ,cons-name ,arglist
- (declare ,@(mapcar #'(lambda (var type) `(type ,type ,var))
+ (declare ,@(mapcar (lambda (var type) `(type ,type ,var))
vars types))
- (let ((,temp (truly-the ,(dd-name dd)
- (%make-instance ,(dd-length dd))))
- ,@(when n-raw-data
- `((,n-raw-data
- (make-array ,(dd-raw-length dd)
- :element-type '(unsigned-byte 32))))))
- (setf (%instance-layout ,temp)
- (%delayed-get-compiler-layout ,(dd-name dd)))
- ,@(when n-raw-data
- `((setf (%instance-ref ,temp ,raw-index) ,n-raw-data)))
+ (let ((,instance (truly-the ,(dd-name dd)
+ (%make-instance-with-layout
+ (%delayed-get-compiler-layout ,(dd-name dd))))))
+ ,@(when raw-index
+ `((setf (%instance-ref ,instance ,raw-index)
+ (make-array ,(dd-raw-length dd)
+ :element-type '(unsigned-byte 32)))))
,@(mapcar (lambda (dsd value)
- (multiple-value-bind (accessor index data)
- (slot-accessor-form dd dsd temp n-raw-data)
- `(setf (,accessor ,data ,index) ,value)))
+ ;; (Note that we can't in general use the
+ ;; ordinary named slot setter function here
+ ;; because the slot might be :READ-ONLY, so we
+ ;; whip up new LAMBDA representations of slot
+ ;; setters for the occasion.)
+ `(,(slot-setter-lambda-form dd dsd) ,value ,instance))
(dd-slots dd)
values)
- ,temp))))
+ ,instance))))
;;; Create a default (non-BOA) keyword constructor.
(defun create-keyword-constructor (defstruct creator)
;;; Given a structure and a BOA constructor spec, call CREATOR with
;;; the appropriate args to make a constructor.
(defun create-boa-constructor (defstruct boa creator)
- (multiple-value-bind (req opt restp rest keyp keys allowp aux)
- (sb!kernel:parse-lambda-list (second boa))
+ (multiple-value-bind (req opt restp rest keyp keys allowp auxp aux)
+ (parse-lambda-list (second boa))
(collect ((arglist)
(vars)
(types))
(dolist (arg opt)
(cond ((consp arg)
(destructuring-bind
- (name &optional (def (nth-value 1 (get-slot name))))
+ ;; FIXME: this shares some logic (though not
+ ;; code) with the &key case below (and it
+ ;; looks confusing) -- factor out the logic
+ ;; if possible. - CSR, 2002-04-19
+ (name
+ &optional
+ (def (nth-value 1 (get-slot name)))
+ (supplied-test nil supplied-test-p))
arg
- (arglist `(,name ,def))
+ (arglist `(,name ,def ,@(if supplied-test-p `(,supplied-test) nil)))
(vars name)
(types (get-slot name))))
(t
(arglist '&key)
(dolist (key keys)
(if (consp key)
- (destructuring-bind (wot &optional (def nil def-p)) key
+ (destructuring-bind (wot
+ &optional
+ (def nil def-p)
+ (supplied-test nil supplied-test-p))
+ key
(let ((name (if (consp wot)
(destructuring-bind (key var) wot
(declare (ignore key))
var)
wot)))
- (multiple-value-bind (type slot-def) (get-slot name)
- (arglist `(,wot ,(if def-p def slot-def)))
+ (multiple-value-bind (type slot-def)
+ (get-slot name)
+ (arglist `(,wot ,(if def-p def slot-def)
+ ,@(if supplied-test-p `(,supplied-test) nil)))
(vars name)
(types type))))
(do-default key))))
(when allowp (arglist '&allow-other-keys))
- (when aux
+ (when auxp
(arglist '&aux)
(dolist (arg aux)
(let* ((arg (if (consp arg) arg (list arg)))
(funcall creator defstruct (first boa)
(arglist) (vars) (types)
- (mapcar #'(lambda (slot)
- (or (find (dsd-name slot) (vars) :test #'string=)
- (dsd-default slot)))
+ (mapcar (lambda (slot)
+ (or (find (dsd-name slot) (vars) :test #'string=)
+ (dsd-default slot)))
(dd-slots defstruct))))))
;;; Grovel the constructor options, and decide what constructors (if
:metaclass-name metaclass-name
:metaclass-constructor metaclass-constructor
:dd-type dd-type))
- (conc-name (concatenate 'string (symbol-name class-name) "-"))
(dd-slots (dd-slots dd))
(dd-length (1+ (length slot-names)))
(object-gensym (gensym "OBJECT"))
(let ((dsd (find (symbol-name slot-name) dd-slots
:key #'dsd-%name
:test #'string=)))
+ ;; KLUDGE: bug 117 bogowarning. Neither
+ ;; DECLAREing the type nor TRULY-THE cut
+ ;; the mustard -- it still gives warnings.
+ (enforce-type dsd defstruct-slot-description)
`(setf (,(dsd-accessor-name dsd) ,object-gensym)
- ,slot-name)))
+ ,slot-name)))
slot-names)
,object-gensym))