1 ;;;; that part of DEFSTRUCT implementation which is needed not just
2 ;;;; in the target Lisp but also in the cross-compilation host
4 ;;;; This software is part of the SBCL system. See the README file for
7 ;;;; This software is derived from the CMU CL system, which was
8 ;;;; written at Carnegie Mellon University and released into the
9 ;;;; public domain. The software is in the public domain and is
10 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
11 ;;;; files for more information.
13 (in-package "SB!KERNEL")
15 (/show0 "code/defstruct.lisp 15")
19 ;;; Return the compiler layout for NAME. (The class referred to by
20 ;;; NAME must be a structure-like class.)
21 (defun compiler-layout-or-lose (name)
22 (let ((res (info :type :compiler-layout name)))
24 (error "Class is not yet defined or was undefined: ~S" name))
25 ((not (typep (layout-info res) 'defstruct-description))
26 (error "Class is not a structure class: ~S" name))
29 ;;; Delay looking for compiler-layout until the constructor is being
30 ;;; compiled, since it doesn't exist until after the EVAL-WHEN
31 ;;; (COMPILE) stuff is compiled. (Or, in the oddball case when
32 ;;; DEFSTRUCT is executing in a non-toplevel context, the
33 ;;; compiler-layout still doesn't exist at compilation time, and we
34 ;;; delay still further.)
35 (sb!xc:defmacro %delayed-get-compiler-layout (name)
36 (let ((layout (info :type :compiler-layout name)))
38 ;; ordinary case: When the DEFSTRUCT is at top level,
39 ;; then EVAL-WHEN (COMPILE) stuff will have set up the
40 ;; layout for us to use.
41 (unless (typep (layout-info layout) 'defstruct-description)
42 (error "Class is not a structure class: ~S" name))
45 ;; KLUDGE: In the case that DEFSTRUCT is not at top-level
46 ;; the layout doesn't exist at compile time. In that case
47 ;; we laboriously look it up at run time. This code will
48 ;; run on every constructor call and will likely be quite
49 ;; slow, so if anyone cares about performance of
50 ;; non-toplevel DEFSTRUCTs, it should be rewritten to be
51 ;; cleverer. -- WHN 2002-10-23
53 "implementation limitation: ~
54 Non-toplevel DEFSTRUCT constructors are slow.")
55 (let ((layout (gensym "LAYOUT")))
56 `(let ((,layout (info :type :compiler-layout ',name)))
57 (unless (typep (layout-info ,layout) 'defstruct-description)
58 (error "Class is not a structure class: ~S" ',name))
61 ;;; Get layout right away.
62 (sb!xc:defmacro compile-time-find-layout (name)
65 ;;; re. %DELAYED-GET-COMPILER-LAYOUT and COMPILE-TIME-FIND-LAYOUT, above..
67 ;;; FIXME: Perhaps both should be defined with DEFMACRO-MUNDANELY?
68 ;;; FIXME: Do we really need both? If so, their names and implementations
69 ;;; should probably be tweaked to be more parallel.
71 ;;;; DEFSTRUCT-DESCRIPTION
73 ;;; The DEFSTRUCT-DESCRIPTION structure holds compile-time information
74 ;;; about a structure type.
75 (def!struct (defstruct-description
77 (:make-load-form-fun just-dump-it-normally)
78 #-sb-xc-host (:pure t)
79 (:constructor make-defstruct-description
81 (conc-name (symbolicate name "-"))
82 (copier-name (symbolicate "COPY-" name))
83 (predicate-name (symbolicate name "-P")))))
84 ;; name of the structure
85 (name (missing-arg) :type symbol :read-only t)
86 ;; documentation on the structure
87 (doc nil :type (or string null))
88 ;; prefix for slot names. If NIL, none.
89 (conc-name nil :type (or symbol null))
90 ;; the name of the primary standard keyword constructor, or NIL if none
91 (default-constructor nil :type (or symbol null))
92 ;; all the explicit :CONSTRUCTOR specs, with name defaulted
93 (constructors () :type list)
94 ;; name of copying function
95 (copier-name nil :type (or symbol null))
96 ;; name of type predicate
97 (predicate-name nil :type (or symbol null))
98 ;; the arguments to the :INCLUDE option, or NIL if no included
100 (include nil :type list)
101 ;; properties used to define structure-like classes with an
102 ;; arbitrary superclass and that may not have STRUCTURE-CLASS as the
103 ;; metaclass. Syntax is:
104 ;; (superclass-name metaclass-name metaclass-constructor)
105 (alternate-metaclass nil :type list)
106 ;; a list of DEFSTRUCT-SLOT-DESCRIPTION objects for all slots
107 ;; (including included ones)
108 (slots () :type list)
109 ;; a list of (NAME . INDEX) pairs for accessors of included structures
110 (inherited-accessor-alist () :type list)
111 ;; number of elements we've allocated (See also RAW-LENGTH.)
112 (length 0 :type index)
113 ;; General kind of implementation.
114 (type 'structure :type (member structure vector list
115 funcallable-structure))
117 ;; The next three slots are for :TYPE'd structures (which aren't
118 ;; classes, DD-CLASS-P = NIL)
120 ;; vector element type
122 ;; T if :NAMED was explicitly specified, NIL otherwise
123 (named nil :type boolean)
124 ;; any INITIAL-OFFSET option on this direct type
125 (offset nil :type (or index null))
127 ;; the argument to the PRINT-FUNCTION option, or NIL if a
128 ;; PRINT-FUNCTION option was given with no argument, or 0 if no
129 ;; PRINT-FUNCTION option was given
130 (print-function 0 :type (or cons symbol (member 0)))
131 ;; the argument to the PRINT-OBJECT option, or NIL if a PRINT-OBJECT
132 ;; option was given with no argument, or 0 if no PRINT-OBJECT option
134 (print-object 0 :type (or cons symbol (member 0)))
135 ;; the index of the raw data vector and the number of words in it,
136 ;; or NIL and 0 if not allocated (either because this structure
137 ;; has no raw slots, or because we're still parsing it and haven't
138 ;; run across any raw slots yet)
139 (raw-index nil :type (or index null))
140 (raw-length 0 :type index)
141 ;; the value of the :PURE option, or :UNSPECIFIED. This is only
142 ;; meaningful if DD-CLASS-P = T.
143 (pure :unspecified :type (member t nil :substructure :unspecified)))
144 (def!method print-object ((x defstruct-description) stream)
145 (print-unreadable-object (x stream :type t)
146 (prin1 (dd-name x) stream)))
148 ;;; Does DD describe a structure with a class?
149 (defun dd-class-p (dd)
151 '(structure funcallable-structure)))
153 ;;; a type name which can be used when declaring things which operate
154 ;;; on structure instances
155 (defun dd-declarable-type (dd)
157 ;; Native classes are known to the type system, and we can
158 ;; declare them as types.
160 ;; Structures layered on :TYPE LIST or :TYPE VECTOR aren't part
161 ;; of the type system, so all we can declare is the underlying
162 ;; LIST or VECTOR type.
165 (defun dd-layout-or-lose (dd)
166 (compiler-layout-or-lose (dd-name dd)))
168 ;;;; DEFSTRUCT-SLOT-DESCRIPTION
170 ;;; A DEFSTRUCT-SLOT-DESCRIPTION holds compile-time information about
171 ;;; a structure slot.
172 (def!struct (defstruct-slot-description
173 (:make-load-form-fun just-dump-it-normally)
176 #-sb-xc-host (:pure t))
177 ;; string name of slot
179 ;; its position in the implementation sequence
180 (index (missing-arg) :type fixnum)
181 ;; the name of the accessor function
183 ;; (CMU CL had extra complexity here ("..or NIL if this accessor has
184 ;; the same name as an inherited accessor (which we don't want to
185 ;; shadow)") but that behavior doesn't seem to be specified by (or
186 ;; even particularly consistent with) ANSI, so it's gone in SBCL.)
188 default ; default value expression
189 (type t) ; declared type specifier
190 ;; If this object does not describe a raw slot, this value is T.
192 ;; If this object describes a raw slot, this value is the type of the
193 ;; value that the raw slot holds. Mostly. (KLUDGE: If the raw slot has
194 ;; type (UNSIGNED-BYTE 32), the value here is UNSIGNED-BYTE, not
195 ;; (UNSIGNED-BYTE 32).)
196 (raw-type t :type (member t single-float double-float
197 #!+long-float long-float
198 complex-single-float complex-double-float
199 #!+long-float complex-long-float
201 (read-only nil :type (member t nil)))
202 (def!method print-object ((x defstruct-slot-description) stream)
203 (print-unreadable-object (x stream :type t)
204 (prin1 (dsd-name x) stream)))
206 ;;; Return the name of a defstruct slot as a symbol. We store it as a
207 ;;; string to avoid creating lots of worthless symbols at load time.
208 (defun dsd-name (dsd)
209 (intern (string (dsd-%name dsd))
210 (if (dsd-accessor-name dsd)
211 (symbol-package (dsd-accessor-name dsd))
214 ;;;; typed (non-class) structures
216 ;;; Return a type specifier we can use for testing :TYPE'd structures.
217 (defun dd-lisp-type (defstruct)
218 (ecase (dd-type defstruct)
220 (vector `(simple-array ,(dd-element-type defstruct) (*)))))
222 ;;;; shared machinery for inline and out-of-line slot accessor functions
224 (eval-when (:compile-toplevel :load-toplevel :execute)
226 ;; information about how a slot of a given DSD-RAW-TYPE is to be accessed
227 (defstruct raw-slot-data
228 ;; the raw slot type, or T for a non-raw slot
230 ;; (Raw slots are allocated in the raw slots array in a vector which
231 ;; the GC doesn't need to scavenge. Non-raw slots are in the
232 ;; ordinary place you'd expect, directly indexed off the instance
234 (raw-type (missing-arg) :type (or symbol cons) :read-only t)
235 ;; What operator is used (on the raw data vector) to access a slot
237 (accessor-name (missing-arg) :type symbol :read-only t)
238 ;; How many words are each value of this type? (This is used to
239 ;; rescale the offset into the raw data vector.)
240 (n-words (missing-arg) :type (and index (integer 1)) :read-only t))
242 (defvar *raw-slot-data-list*
244 ;; The compiler thinks that the raw data vector is a vector of
245 ;; word-sized unsigned bytes, so if the slot we want to access
246 ;; actually *is* an unsigned byte, it'll access the slot for us
247 ;; even if we don't lie to it at all, just let it use normal AREF.
248 (make-raw-slot-data :raw-type 'unsigned-byte
251 ;; In the other cases, we lie to the compiler, making it use
252 ;; some low-level AREFish access in order to pun the hapless
253 ;; bits into some other-than-unsigned-byte meaning.
255 ;; "A lie can travel halfway round the world while the truth is
256 ;; putting on its shoes." -- Mark Twain
257 (make-raw-slot-data :raw-type 'single-float
258 :accessor-name '%raw-ref-single
260 (make-raw-slot-data :raw-type 'double-float
261 :accessor-name '%raw-ref-double
263 (make-raw-slot-data :raw-type 'complex-single-float
264 :accessor-name '%raw-ref-complex-single
266 (make-raw-slot-data :raw-type 'complex-double-float
267 :accessor-name '%raw-ref-complex-double
270 (make-raw-slot-data :raw-type long-float
271 :accessor-name '%raw-ref-long
272 :n-words #!+x86 3 #!+sparc 4)
274 (make-raw-slot-data :raw-type complex-long-float
275 :accessor-name '%raw-ref-complex-long
276 :n-words #!+x86 6 #!+sparc 8))))
278 ;;;; the legendary DEFSTRUCT macro itself (both CL:DEFSTRUCT and its
279 ;;;; close personal friend SB!XC:DEFSTRUCT)
281 ;;; Return a list of forms to install PRINT and MAKE-LOAD-FORM funs,
282 ;;; mentioning them in the expansion so that they can be compiled.
283 (defun class-method-definitions (defstruct)
284 (let ((name (dd-name defstruct)))
286 ;; KLUDGE: There's a FIND-CLASS DEFTRANSFORM for constant
287 ;; class names which creates fast but non-cold-loadable,
288 ;; non-compact code. In this context, we'd rather have
289 ;; compact, cold-loadable code. -- WHN 19990928
290 (declare (notinline sb!xc:find-class))
291 ,@(let ((pf (dd-print-function defstruct))
292 (po (dd-print-object defstruct))
295 ;; Giving empty :PRINT-OBJECT or :PRINT-FUNCTION options
296 ;; leaves PO or PF equal to NIL. The user-level effect is
297 ;; to generate a PRINT-OBJECT method specialized for the type,
298 ;; implementing the default #S structure-printing behavior.
299 (when (or (eq pf nil) (eq po nil))
300 (setf pf '(default-structure-print)
302 (flet (;; Given an arg from a :PRINT-OBJECT or :PRINT-FUNCTION
303 ;; option, return the value to pass as an arg to FUNCTION.
305 (destructuring-bind (fun-name) oarg
307 (cond ((not (eql pf 0))
308 `((def!method print-object ((,x ,name) ,s)
309 (funcall #',(farg pf)
312 *current-level-in-print*))))
314 `((def!method print-object ((,x ,name) ,s)
315 (funcall #',(farg po) ,x ,s))))
317 ,@(let ((pure (dd-pure defstruct)))
319 `((setf (layout-pure (class-layout
320 (sb!xc:find-class ',name)))
322 ((eq pure :substructure)
323 `((setf (layout-pure (class-layout
324 (sb!xc:find-class ',name)))
326 ,@(let ((def-con (dd-default-constructor defstruct)))
327 (when (and def-con (not (dd-alternate-metaclass defstruct)))
328 `((setf (structure-class-constructor (sb!xc:find-class ',name))
331 ;;; shared logic for CL:DEFSTRUCT and SB!XC:DEFSTRUCT
332 (defmacro !expander-for-defstruct (name-and-options
334 expanding-into-code-for-xc-host-p)
335 `(let ((name-and-options ,name-and-options)
336 (slot-descriptions ,slot-descriptions)
337 (expanding-into-code-for-xc-host-p
338 ,expanding-into-code-for-xc-host-p))
339 (let* ((dd (parse-defstruct-name-and-options-and-slot-descriptions
344 (let ((inherits (inherits-for-structure dd)))
346 ;; Note we intentionally call %DEFSTRUCT first, and
347 ;; especially before %COMPILER-DEFSTRUCT. %DEFSTRUCT
348 ;; has the tests (and resulting CERROR) for collisions
349 ;; with LAYOUTs which already exist in the runtime. If
350 ;; there are any collisions, we want the user's
351 ;; response to CERROR to control what happens.
352 ;; Especially, if the user responds to the collision
353 ;; with ABORT, we don't want %COMPILER-DEFSTRUCT to
354 ;; modify the definition of the class.
355 (%defstruct ',dd ',inherits)
356 (eval-when (:compile-toplevel :load-toplevel :execute)
357 (%compiler-defstruct ',dd ',inherits))
358 ,@(unless expanding-into-code-for-xc-host-p
359 (append ;; FIXME: We've inherited from CMU CL nonparallel
360 ;; code for creating copiers for typed and untyped
361 ;; structures. This should be fixed.
362 ;(copier-definition dd)
363 (constructor-definitions dd)
364 (class-method-definitions dd)))
367 (eval-when (:compile-toplevel :load-toplevel :execute)
368 (setf (info :typed-structure :info ',name) ',dd))
369 ,@(unless expanding-into-code-for-xc-host-p
370 (append (typed-accessor-definitions dd)
371 (typed-predicate-definitions dd)
372 (typed-copier-definitions dd)
373 (constructor-definitions dd)))
376 (sb!xc:defmacro defstruct (name-and-options &rest slot-descriptions)
378 "DEFSTRUCT {Name | (Name Option*)} {Slot | (Slot [Default] {Key Value}*)}
379 Define the structure type Name. Instances are created by MAKE-<name>,
380 which takes &KEY arguments allowing initial slot values to the specified.
381 A SETF'able function <name>-<slot> is defined for each slot to read and
382 write slot values. <name>-p is a type predicate.
384 Popular DEFSTRUCT options (see manual for others):
388 Specify the name for the constructor or predicate.
390 (:CONSTRUCTOR Name Lambda-List)
391 Specify the name and arguments for a BOA constructor
392 (which is more efficient when keyword syntax isn't necessary.)
394 (:INCLUDE Supertype Slot-Spec*)
395 Make this type a subtype of the structure type Supertype. The optional
396 Slot-Specs override inherited slot options.
401 Asserts that the value of this slot is always of the specified type.
404 If true, no setter function is defined for this slot."
405 (!expander-for-defstruct name-and-options slot-descriptions nil))
407 (defmacro sb!xc:defstruct (name-and-options &rest slot-descriptions)
409 "Cause information about a target structure to be built into the
411 (!expander-for-defstruct name-and-options slot-descriptions t))
413 ;;;; functions to generate code for various parts of DEFSTRUCT definitions
415 ;;; First, a helper to determine whether a name names an inherited
417 (defun accessor-inherited-data (name defstruct)
418 (assoc name (dd-inherited-accessor-alist defstruct) :test #'eq))
420 ;;; Return a list of forms which create a predicate function for a
422 (defun typed-predicate-definitions (defstruct)
423 (let ((name (dd-name defstruct))
424 (predicate-name (dd-predicate-name defstruct))
426 (when (and predicate-name (dd-named defstruct))
427 (let ((ltype (dd-lisp-type defstruct)))
428 `((defun ,predicate-name (,argname)
429 (and (typep ,argname ',ltype)
430 (eq (elt (the ,ltype ,argname)
431 ,(cdr (car (last (find-name-indices defstruct)))))
434 ;;; Return a list of forms to create a copier function of a typed DEFSTRUCT.
435 (defun typed-copier-definitions (defstruct)
436 (when (dd-copier-name defstruct)
437 `((setf (fdefinition ',(dd-copier-name defstruct)) #'copy-seq)
438 (declaim (ftype function ,(dd-copier-name defstruct))))))
440 ;;; Return a list of function definitions for accessing and setting
441 ;;; the slots of a typed DEFSTRUCT. The functions are proclaimed to be
442 ;;; inline, and the types of their arguments and results are declared
443 ;;; as well. We count on the compiler to do clever things with ELT.
444 (defun typed-accessor-definitions (defstruct)
446 (let ((ltype (dd-lisp-type defstruct)))
447 (dolist (slot (dd-slots defstruct))
448 (let ((name (dsd-accessor-name slot))
449 (index (dsd-index slot))
450 (slot-type `(and ,(dsd-type slot)
451 ,(dd-element-type defstruct))))
452 (let ((inherited (accessor-inherited-data name defstruct)))
455 (stuff `(proclaim '(inline ,name (setf ,name))))
456 ;; FIXME: The arguments in the next two DEFUNs should
457 ;; be gensyms. (Otherwise e.g. if NEW-VALUE happened to
458 ;; be the name of a special variable, things could get
460 (stuff `(defun ,name (structure)
461 (declare (type ,ltype structure))
462 (the ,slot-type (elt structure ,index))))
463 (unless (dsd-read-only slot)
465 `(defun (setf ,name) (new-value structure)
466 (declare (type ,ltype structure) (type ,slot-type new-value))
467 (setf (elt structure ,index) new-value)))))
468 ((not (= (cdr inherited) index))
469 (style-warn "~@<Non-overwritten accessor ~S does not access ~
470 slot with name ~S (accessing an inherited slot ~
471 instead).~:@>" name (dsd-%name slot))))))))
476 (defun require-no-print-options-so-far (defstruct)
477 (unless (and (eql (dd-print-function defstruct) 0)
478 (eql (dd-print-object defstruct) 0))
479 (error "No more than one of the following options may be specified:
480 :PRINT-FUNCTION, :PRINT-OBJECT, :TYPE")))
482 ;;; Parse a single DEFSTRUCT option and store the results in DD.
483 (defun parse-1-dd-option (option dd)
484 (let ((args (rest option))
488 (destructuring-bind (&optional conc-name) args
489 (setf (dd-conc-name dd)
490 (if (symbolp conc-name)
492 (make-symbol (string conc-name))))))
494 (destructuring-bind (&optional (cname (symbolicate "MAKE-" name))
497 (push (cons cname stuff) (dd-constructors dd))))
499 (destructuring-bind (&optional (copier (symbolicate "COPY-" name)))
501 (setf (dd-copier-name dd) copier)))
503 (destructuring-bind (&optional (predicate-name (symbolicate name "-P")))
505 (setf (dd-predicate-name dd) predicate-name)))
507 (when (dd-include dd)
508 (error "more than one :INCLUDE option"))
509 (setf (dd-include dd) args))
511 (require-no-print-options-so-far dd)
512 (setf (dd-print-function dd)
513 (the (or symbol cons) args)))
515 (require-no-print-options-so-far dd)
516 (setf (dd-print-object dd)
517 (the (or symbol cons) args)))
519 (destructuring-bind (type) args
520 (cond ((member type '(list vector))
521 (setf (dd-element-type dd) t)
522 (setf (dd-type dd) type))
523 ((and (consp type) (eq (first type) 'vector))
524 (destructuring-bind (vector vtype) type
525 (declare (ignore vector))
526 (setf (dd-element-type dd) vtype)
527 (setf (dd-type dd) 'vector)))
529 (error "~S is a bad :TYPE for DEFSTRUCT." type)))))
531 (error "The DEFSTRUCT option :NAMED takes no arguments."))
533 (destructuring-bind (offset) args
534 (setf (dd-offset dd) offset)))
536 (destructuring-bind (fun) args
537 (setf (dd-pure dd) fun)))
538 (t (error "unknown DEFSTRUCT option:~% ~S" option)))))
540 ;;; Given name and options, return a DD holding that info.
541 (defun parse-defstruct-name-and-options (name-and-options)
542 (destructuring-bind (name &rest options) name-and-options
543 (aver name) ; A null name doesn't seem to make sense here.
544 (let ((dd (make-defstruct-description name)))
545 (dolist (option options)
546 (cond ((eq option :named)
547 (setf (dd-named dd) t))
549 (parse-1-dd-option option dd))
550 ((member option '(:conc-name :constructor :copier :predicate))
551 (parse-1-dd-option (list option) dd))
553 (error "unrecognized DEFSTRUCT option: ~S" option))))
558 (error ":OFFSET can't be specified unless :TYPE is specified."))
559 (unless (dd-include dd)
560 ;; FIXME: It'd be cleaner to treat no-:INCLUDE as defaulting
561 ;; to :INCLUDE STRUCTURE-OBJECT, and then let the general-case
562 ;; (INCF (DD-LENGTH DD) (DD-LENGTH included-DD)) logic take
563 ;; care of this. (Except that the :TYPE VECTOR and :TYPE
564 ;; LIST cases, with their :NAMED and un-:NAMED flavors,
565 ;; make that messy, alas.)
566 (incf (dd-length dd))))
568 (require-no-print-options-so-far dd)
570 (incf (dd-length dd)))
571 (let ((offset (dd-offset dd)))
572 (when offset (incf (dd-length dd) offset)))))
574 (when (dd-include dd)
575 (frob-dd-inclusion-stuff dd))
579 ;;; Given name and options and slot descriptions (and possibly doc
580 ;;; string at the head of slot descriptions) return a DD holding that
582 (defun parse-defstruct-name-and-options-and-slot-descriptions
583 (name-and-options slot-descriptions)
584 (let ((result (parse-defstruct-name-and-options (if (atom name-and-options)
585 (list name-and-options)
587 (when (stringp (car slot-descriptions))
588 (setf (dd-doc result) (pop slot-descriptions)))
589 (dolist (slot-description slot-descriptions)
590 (allocate-1-slot result (parse-1-dsd result slot-description)))
593 ;;;; stuff to parse slot descriptions
595 ;;; Parse a slot description for DEFSTRUCT, add it to the description
596 ;;; and return it. If supplied, SLOT is a pre-initialized DSD
597 ;;; that we modify to get the new slot. This is supplied when handling
599 (defun parse-1-dsd (defstruct spec &optional
600 (slot (make-defstruct-slot-description :%name ""
603 (multiple-value-bind (name default default-p type type-p read-only ro-p)
608 &optional (default nil default-p)
609 &key (type nil type-p) (read-only nil ro-p))
613 (uncross type) type-p
616 (when (keywordp spec)
617 (style-warn "Keyword slot name indicates probable syntax ~
618 error in DEFSTRUCT: ~S."
622 (when (find name (dd-slots defstruct) :test #'string= :key #'dsd-%name)
623 (error 'simple-program-error
624 :format-control "duplicate slot name ~S"
625 :format-arguments (list name)))
626 (setf (dsd-%name slot) (string name))
627 (setf (dd-slots defstruct) (nconc (dd-slots defstruct) (list slot)))
629 (let ((accessor-name (if (dd-conc-name defstruct)
630 (symbolicate (dd-conc-name defstruct) name)
632 (predicate-name (dd-predicate-name defstruct)))
633 (setf (dsd-accessor-name slot) accessor-name)
634 (when (eql accessor-name predicate-name)
635 ;; Some adventurous soul has named a slot so that its accessor
636 ;; collides with the structure type predicate. ANSI doesn't
637 ;; specify what to do in this case. As of 2001-09-04, Martin
638 ;; Atzmueller reports that CLISP and Lispworks both give
639 ;; priority to the slot accessor, so that the predicate is
640 ;; overwritten. We might as well do the same (as well as
641 ;; signalling a warning).
643 "~@<The structure accessor name ~S is the same as the name of the ~
644 structure type predicate. ANSI doesn't specify what to do in ~
645 this case. We'll overwrite the type predicate with the slot ~
646 accessor, but you can't rely on this behavior, so it'd be wise to ~
647 remove the ambiguity in your code.~@:>"
649 (setf (dd-predicate-name defstruct) nil))
651 (when (and (fboundp accessor-name)
652 (not (accessor-inherited-data accessor-name defstruct)))
653 (style-warn "redefining ~S in DEFSTRUCT" accessor-name)))
656 (setf (dsd-default slot) default))
658 (setf (dsd-type slot)
659 (if (eq (dsd-type slot) t)
661 `(and ,(dsd-type slot) ,type))))
664 (setf (dsd-read-only slot) t)
665 (when (dsd-read-only slot)
666 (error "Slot ~S is :READ-ONLY in parent and must be :READ-ONLY in subtype ~S."
671 ;;; When a value of type TYPE is stored in a structure, should it be
672 ;;; stored in a raw slot? Return (VALUES RAW? RAW-TYPE WORDS), where
673 ;;; RAW? is true if TYPE should be stored in a raw slot.
674 ;;; RAW-TYPE is the raw slot type, or NIL if no raw slot.
675 ;;; WORDS is the number of words in the raw slot, or NIL if no raw slot.
677 ;;; FIXME: This should use the data in *RAW-SLOT-DATA-LIST*.
678 (defun structure-raw-slot-type-and-size (type)
680 (;; FIXME: For now we suppress raw slots, since there are various
681 ;; issues about the way that the cross-compiler handles them.
682 (not (boundp '*dummy-placeholder-to-stop-compiler-warnings*))
683 (values nil nil nil))
684 ((and (sb!xc:subtypep type '(unsigned-byte 32))
685 (multiple-value-bind (fixnum? fixnum-certain?)
686 (sb!xc:subtypep type 'fixnum)
687 ;; (The extra test for FIXNUM-CERTAIN? here is
688 ;; intended for bootstrapping the system. In
689 ;; particular, in sbcl-0.6.2, we set up LAYOUT before
690 ;; FIXNUM is defined, and so could bogusly end up
691 ;; putting INDEX-typed values into raw slots if we
692 ;; didn't test FIXNUM-CERTAIN?.)
693 (and (not fixnum?) fixnum-certain?)))
694 (values t 'unsigned-byte 1))
695 ((sb!xc:subtypep type 'single-float)
696 (values t 'single-float 1))
697 ((sb!xc:subtypep type 'double-float)
698 (values t 'double-float 2))
700 ((sb!xc:subtypep type 'long-float)
701 (values t 'long-float #!+x86 3 #!+sparc 4))
702 ((sb!xc:subtypep type '(complex single-float))
703 (values t 'complex-single-float 2))
704 ((sb!xc:subtypep type '(complex double-float))
705 (values t 'complex-double-float 4))
707 ((sb!xc:subtypep type '(complex long-float))
708 (values t 'complex-long-float #!+x86 6 #!+sparc 8))
710 (values nil nil nil))))
712 ;;; Allocate storage for a DSD in DD. This is where we decide whether
713 ;;; a slot is raw or not. If raw, and we haven't allocated a raw-index
714 ;;; yet for the raw data vector, then do it. Raw objects are aligned
715 ;;; on the unit of their size.
716 (defun allocate-1-slot (dd dsd)
717 (multiple-value-bind (raw? raw-type words)
718 (if (eq (dd-type dd) 'structure)
719 (structure-raw-slot-type-and-size (dsd-type dsd))
720 (values nil nil nil))
722 (setf (dsd-index dsd) (dd-length dd))
723 (incf (dd-length dd)))
725 (unless (dd-raw-index dd)
726 (setf (dd-raw-index dd) (dd-length dd))
727 (incf (dd-length dd)))
728 (let ((off (rem (dd-raw-length dd) words)))
730 (incf (dd-raw-length dd) (- words off))))
731 (setf (dsd-raw-type dsd) raw-type)
732 (setf (dsd-index dsd) (dd-raw-length dd))
733 (incf (dd-raw-length dd) words))))
736 (defun typed-structure-info-or-lose (name)
737 (or (info :typed-structure :info name)
738 (error ":TYPE'd DEFSTRUCT ~S not found for inclusion." name)))
740 ;;; Process any included slots pretty much like they were specified.
741 ;;; Also inherit various other attributes.
742 (defun frob-dd-inclusion-stuff (dd)
743 (destructuring-bind (included-name &rest modified-slots) (dd-include dd)
744 (let* ((type (dd-type dd))
747 (layout-info (compiler-layout-or-lose included-name))
748 (typed-structure-info-or-lose included-name))))
750 ;; checks on legality
751 (unless (and (eq type (dd-type included-structure))
752 (type= (specifier-type (dd-element-type included-structure))
753 (specifier-type (dd-element-type dd))))
754 (error ":TYPE option mismatch between structures ~S and ~S"
755 (dd-name dd) included-name))
756 (let ((included-class (sb!xc:find-class included-name nil)))
758 ;; It's not particularly well-defined to :INCLUDE any of the
759 ;; CMU CL INSTANCE weirdosities like CONDITION or
760 ;; GENERIC-FUNCTION, and it's certainly not ANSI-compliant.
761 (let* ((included-layout (class-layout included-class))
762 (included-dd (layout-info included-layout)))
763 (when (and (dd-alternate-metaclass included-dd)
764 ;; As of sbcl-0.pre7.73, anyway, STRUCTURE-OBJECT
765 ;; is represented with an ALTERNATE-METACLASS. But
766 ;; it's specifically OK to :INCLUDE (and PCL does)
767 ;; so in this one case, it's OK to include
768 ;; something with :ALTERNATE-METACLASS after all.
769 (not (eql included-name 'structure-object)))
770 (error "can't :INCLUDE class ~S (has alternate metaclass)"
773 (incf (dd-length dd) (dd-length included-structure))
774 (when (dd-class-p dd)
775 (let ((mc (rest (dd-alternate-metaclass included-structure))))
776 (when (and mc (not (dd-alternate-metaclass dd)))
777 (setf (dd-alternate-metaclass dd)
778 (cons included-name mc))))
779 (when (eq (dd-pure dd) :unspecified)
780 (setf (dd-pure dd) (dd-pure included-structure)))
781 (setf (dd-raw-index dd) (dd-raw-index included-structure))
782 (setf (dd-raw-length dd) (dd-raw-length included-structure)))
784 (setf (dd-inherited-accessor-alist dd)
785 (dd-inherited-accessor-alist included-structure))
786 (dolist (included-slot (dd-slots included-structure))
787 (let* ((included-name (dsd-name included-slot))
788 (modified (or (find included-name modified-slots
789 :key (lambda (x) (if (atom x) x (car x)))
792 ;; We stash away an alist of accessors to parents' slots
793 ;; that have already been created to avoid conflicts later
794 ;; so that structures with :INCLUDE and :CONC-NAME (and
795 ;; other edge cases) can work as specified.
796 (when (dsd-accessor-name included-slot)
797 ;; the "oldest" (i.e. highest up the tree of inheritance)
798 ;; will prevail, so don't push new ones on if they
800 (pushnew (cons (dsd-accessor-name included-slot)
801 (dsd-index included-slot))
802 (dd-inherited-accessor-alist dd)
803 :test #'eq :key #'car))
806 (copy-structure included-slot)))))))
808 ;;;; various helper functions for setting up DEFSTRUCTs
810 ;;; This function is called at macroexpand time to compute the INHERITS
811 ;;; vector for a structure type definition.
812 (defun inherits-for-structure (info)
813 (declare (type defstruct-description info))
814 (let* ((include (dd-include info))
815 (superclass-opt (dd-alternate-metaclass info))
818 (compiler-layout-or-lose (first include))
819 (class-layout (sb!xc:find-class
820 (or (first superclass-opt)
821 'structure-object))))))
822 (if (eq (dd-name info) 'ansi-stream)
823 ;; a hack to add the CL:STREAM class as a mixin for ANSI-STREAMs
824 (concatenate 'simple-vector
825 (layout-inherits super)
827 (class-layout (sb!xc:find-class 'stream))))
828 (concatenate 'simple-vector
829 (layout-inherits super)
832 ;;; Do miscellaneous (LOAD EVAL) time actions for the structure
833 ;;; described by DD. Create the class and LAYOUT, checking for
834 ;;; incompatible redefinition. Define those functions which are
835 ;;; sufficiently stereotyped that we can implement them as standard
837 (defun %defstruct (dd inherits)
838 (declare (type defstruct-description dd))
840 ;; We set up LAYOUTs even in the cross-compilation host.
841 (multiple-value-bind (class layout old-layout)
842 (ensure-structure-class dd inherits "current" "new")
843 (cond ((not old-layout)
844 (unless (eq (class-layout class) layout)
845 (register-layout layout)))
847 (let ((old-dd (layout-info old-layout)))
848 (when (defstruct-description-p old-dd)
849 (dolist (slot (dd-slots old-dd))
850 (fmakunbound (dsd-accessor-name slot))
851 (unless (dsd-read-only slot)
852 (fmakunbound `(setf ,(dsd-accessor-name slot)))))))
853 (%redefine-defstruct class old-layout layout)
854 (setq layout (class-layout class))))
855 (setf (sb!xc:find-class (dd-name dd)) class)
857 ;; Various other operations only make sense on the target SBCL.
859 (%target-defstruct dd layout))
863 ;;; Return a form describing the writable place used for this slot
864 ;;; in the instance named INSTANCE-NAME.
865 (defun %accessor-place-form (dd dsd instance-name)
866 (let (;; the operator that we'll use to access a typed slot or, in
867 ;; the case of a raw slot, to read the vector of raw slots
868 (ref (ecase (dd-type dd)
869 (structure '%instance-ref)
870 (list 'nth-but-with-sane-arg-order)
872 (raw-type (dsd-raw-type dsd)))
873 (if (eq raw-type t) ; if not raw slot
874 `(,ref ,instance-name ,(dsd-index dsd))
875 (let* ((raw-slot-data (find raw-type *raw-slot-data-list*
876 :key #'raw-slot-data-raw-type
878 (raw-slot-accessor (raw-slot-data-accessor-name raw-slot-data))
879 (raw-n-words (raw-slot-data-n-words raw-slot-data)))
880 (multiple-value-bind (scaled-dsd-index misalignment)
881 (floor (dsd-index dsd) raw-n-words)
882 (aver (zerop misalignment))
883 `(,raw-slot-accessor (,ref ,instance-name ,(dd-raw-index dd))
884 ,scaled-dsd-index))))))
886 ;;; Return inline expansion designators (i.e. values suitable for
887 ;;; (INFO :FUNCTION :INLINE-EXPANSION-DESIGNATOR ..)) for the reader
888 ;;; and writer functions of the slot described by DSD.
889 (defun slot-accessor-inline-expansion-designators (dd dsd)
890 (let ((instance-type-decl `(declare (type ,(dd-name dd) instance)))
891 (accessor-place-form (%accessor-place-form dd dsd 'instance))
892 (dsd-type (dsd-type dsd)))
896 (truly-the ,dsd-type ,accessor-place-form)))
898 `(lambda (new-value instance)
899 (declare (type ,dsd-type new-value))
901 (setf ,accessor-place-form new-value))))))
903 ;;; Return a LAMBDA form which can be used to set a slot.
904 (defun slot-setter-lambda-form (dd dsd)
905 (funcall (nth-value 1
906 (slot-accessor-inline-expansion-designators dd dsd))))
908 ;;; core compile-time setup of any class with a LAYOUT, used even by
909 ;;; !DEFSTRUCT-WITH-ALTERNATE-METACLASS weirdosities
910 (defun %compiler-set-up-layout (dd
912 ;; Several special cases (STRUCTURE-OBJECT
913 ;; itself, and structures with alternate
914 ;; metaclasses) call this function directly,
915 ;; and they're all at the base of the
916 ;; instance class structure, so this is
918 (inherits (vector (find-layout t)
919 (find-layout 'instance))))
921 (multiple-value-bind (class layout old-layout)
922 (multiple-value-bind (clayout clayout-p)
923 (info :type :compiler-layout (dd-name dd))
924 (ensure-structure-class dd
926 (if clayout-p "previously compiled" "current")
928 :compiler-layout clayout))
930 (undefine-structure (layout-class old-layout))
931 (when (and (class-subclasses class)
932 (not (eq layout old-layout)))
934 (dohash (class layout (class-subclasses class))
935 (declare (ignore layout))
936 (undefine-structure class)
937 (subs (class-proper-name class)))
939 (warn "removing old subclasses of ~S:~% ~S"
940 (sb!xc:class-name class)
943 (unless (eq (class-layout class) layout)
944 (register-layout layout :invalidate nil))
945 (setf (sb!xc:find-class (dd-name dd)) class)))
947 ;; At this point the class should be set up in the INFO database.
948 ;; But the logic that enforces this is a little tangled and
949 ;; scattered, so it's not obvious, so let's check.
950 (aver (sb!xc:find-class (dd-name dd) nil))
952 (setf (info :type :compiler-layout (dd-name dd)) layout))
956 ;;; Do (COMPILE LOAD EVAL)-time actions for the normal (not
957 ;;; ALTERNATE-LAYOUT) DEFSTRUCT described by DD.
958 (defun %compiler-defstruct (dd inherits)
959 (declare (type defstruct-description dd))
961 (%compiler-set-up-layout dd inherits)
963 (let* ((dtype (dd-declarable-type dd)))
965 (let ((copier-name (dd-copier-name dd)))
967 (sb!xc:proclaim `(ftype (function (,dtype) ,dtype) ,copier-name))))
969 (let ((predicate-name (dd-predicate-name dd)))
971 (sb!xc:proclaim `(ftype (function (t) t) ,predicate-name))
972 ;; Provide inline expansion (or not).
974 ((structure funcallable-structure)
975 ;; Let the predicate be inlined.
976 (setf (info :function :inline-expansion-designator predicate-name)
979 ;; This dead simple definition works because the
980 ;; type system knows how to generate inline type
981 ;; tests for instances.
982 (typep x ',(dd-name dd))))
983 (info :function :inlinep predicate-name)
986 ;; Just punt. We could provide inline expansions for :TYPE
987 ;; LIST and :TYPE VECTOR predicates too, but it'd be a
988 ;; little messier and we don't bother. (Does anyway use
989 ;; typed DEFSTRUCTs at all, let alone for high
993 (dolist (dsd (dd-slots dd))
994 (let* ((accessor-name (dsd-accessor-name dsd))
995 (dsd-type (dsd-type dsd)))
997 (let ((inherited (accessor-inherited-data accessor-name dd)))
1000 (multiple-value-bind (reader-designator writer-designator)
1001 (slot-accessor-inline-expansion-designators dd dsd)
1002 (sb!xc:proclaim `(ftype (function (,dtype) ,dsd-type)
1004 (setf (info :function :inline-expansion-designator
1007 (info :function :inlinep accessor-name)
1009 (unless (dsd-read-only dsd)
1010 (let ((setf-accessor-name `(setf ,accessor-name)))
1012 `(ftype (function (,dsd-type ,dtype) ,dsd-type)
1013 ,setf-accessor-name))
1014 (setf (info :function
1015 :inline-expansion-designator
1018 (info :function :inlinep setf-accessor-name)
1020 ((not (= (cdr inherited) (dsd-index dsd)))
1021 (style-warn "~@<Non-overwritten accessor ~S does not access ~
1022 slot with name ~S (accessing an inherited slot ~
1025 (dsd-%name dsd)))))))))
1028 ;;;; redefinition stuff
1030 ;;; Compare the slots of OLD and NEW, returning 3 lists of slot names:
1031 ;;; 1. Slots which have moved,
1032 ;;; 2. Slots whose type has changed,
1033 ;;; 3. Deleted slots.
1034 (defun compare-slots (old new)
1035 (let* ((oslots (dd-slots old))
1036 (nslots (dd-slots new))
1037 (onames (mapcar #'dsd-name oslots))
1038 (nnames (mapcar #'dsd-name nslots)))
1041 (dolist (name (intersection onames nnames))
1042 (let ((os (find name oslots :key #'dsd-name))
1043 (ns (find name nslots :key #'dsd-name)))
1044 (unless (subtypep (dsd-type ns) (dsd-type os))
1046 (unless (and (= (dsd-index os) (dsd-index ns))
1047 (eq (dsd-raw-type os) (dsd-raw-type ns)))
1051 (set-difference onames nnames)))))
1053 ;;; If we are redefining a structure with different slots than in the
1054 ;;; currently loaded version, give a warning and return true.
1055 (defun redefine-structure-warning (class old new)
1056 (declare (type defstruct-description old new)
1057 (type sb!xc:class class)
1059 (let ((name (dd-name new)))
1060 (multiple-value-bind (moved retyped deleted) (compare-slots old new)
1061 (when (or moved retyped deleted)
1063 "incompatibly redefining slots of structure class ~S~@
1064 Make sure any uses of affected accessors are recompiled:~@
1065 ~@[ These slots were moved to new positions:~% ~S~%~]~
1066 ~@[ These slots have new incompatible types:~% ~S~%~]~
1067 ~@[ These slots were deleted:~% ~S~%~]"
1068 name moved retyped deleted)
1071 ;;; This function is called when we are incompatibly redefining a
1072 ;;; structure CLASS to have the specified NEW-LAYOUT. We signal an
1073 ;;; error with some proceed options and return the layout that should
1075 (defun %redefine-defstruct (class old-layout new-layout)
1076 (declare (type sb!xc:class class) (type layout old-layout new-layout))
1077 (let ((name (class-proper-name class)))
1079 (error "~@<attempt to redefine the ~S class ~S incompatibly with the current definition~:@>"
1085 "~@<Use the new definition of ~S, invalidating ~
1086 already-loaded code and instances.~@:>"
1088 (register-layout new-layout))
1089 (recklessly-continue ()
1092 "~@<Use the new definition of ~S as if it were ~
1093 compatible, allowing old accessors to use new ~
1094 instances and allowing new accessors to use old ~
1097 ;; classic CMU CL warning: "Any old ~S instances will be in a bad way.
1098 ;; I hope you know what you're doing..."
1099 (register-layout new-layout
1101 :destruct-layout old-layout))
1103 ;; FIXME: deprecated 2002-10-16, and since it's only interactive
1104 ;; hackery instead of a supported feature, can probably be deleted
1106 :report "(deprecated synonym for RECKLESSLY-CONTINUE)"
1107 (register-layout new-layout
1109 :destruct-layout old-layout))))
1112 ;;; This is called when we are about to define a structure class. It
1113 ;;; returns a (possibly new) class object and the layout which should
1114 ;;; be used for the new definition (may be the current layout, and
1115 ;;; also might be an uninstalled forward referenced layout.) The third
1116 ;;; value is true if this is an incompatible redefinition, in which
1117 ;;; case it is the old layout.
1118 (defun ensure-structure-class (info inherits old-context new-context
1119 &key compiler-layout)
1120 (multiple-value-bind (class old-layout)
1124 (class 'sb!xc:structure-class)
1125 (constructor 'make-structure-class))
1126 (dd-alternate-metaclass info)
1127 (declare (ignore name))
1128 (insured-find-class (dd-name info)
1129 (if (eq class 'sb!xc:structure-class)
1131 (typep x 'sb!xc:structure-class))
1133 (sb!xc:typep x (sb!xc:find-class class))))
1134 (fdefinition constructor)))
1135 (setf (class-direct-superclasses class)
1136 (if (eq (dd-name info) 'ansi-stream)
1137 ;; a hack to add CL:STREAM as a superclass mixin to ANSI-STREAMs
1138 (list (layout-class (svref inherits (1- (length inherits))))
1139 (layout-class (svref inherits (- (length inherits) 2))))
1140 (list (layout-class (svref inherits (1- (length inherits)))))))
1141 (let ((new-layout (make-layout :class class
1143 :depthoid (length inherits)
1144 :length (dd-length info)
1146 (old-layout (or compiler-layout old-layout)))
1149 (values class new-layout nil))
1150 (;; This clause corresponds to an assertion in REDEFINE-LAYOUT-WARNING
1151 ;; of classic CMU CL. I moved it out to here because it was only
1152 ;; exercised in this code path anyway. -- WHN 19990510
1153 (not (eq (layout-class new-layout) (layout-class old-layout)))
1154 (error "shouldn't happen: weird state of OLD-LAYOUT?"))
1155 ((not *type-system-initialized*)
1156 (setf (layout-info old-layout) info)
1157 (values class old-layout nil))
1158 ((redefine-layout-warning old-context
1161 (layout-length new-layout)
1162 (layout-inherits new-layout)
1163 (layout-depthoid new-layout))
1164 (values class new-layout old-layout))
1166 (let ((old-info (layout-info old-layout)))
1168 ((or defstruct-description)
1169 (cond ((redefine-structure-warning class old-info info)
1170 (values class new-layout old-layout))
1172 (setf (layout-info old-layout) info)
1173 (values class old-layout nil))))
1175 (setf (layout-info old-layout) info)
1176 (values class old-layout nil))
1178 (error "shouldn't happen! strange thing in LAYOUT-INFO:~% ~S"
1180 (values class new-layout old-layout)))))))))
1182 ;;; Blow away all the compiler info for the structure CLASS. Iterate
1183 ;;; over this type, clearing the compiler structure type info, and
1184 ;;; undefining all the associated functions.
1185 (defun undefine-structure (class)
1186 (let ((info (layout-info (class-layout class))))
1187 (when (defstruct-description-p info)
1188 (let ((type (dd-name info)))
1189 (remhash type *typecheckfuns*)
1190 (setf (info :type :compiler-layout type) nil)
1191 (undefine-fun-name (dd-copier-name info))
1192 (undefine-fun-name (dd-predicate-name info))
1193 (dolist (slot (dd-slots info))
1194 (let ((fun (dsd-accessor-name slot)))
1195 (unless (accessor-inherited-data fun info)
1196 (undefine-fun-name fun)
1197 (unless (dsd-read-only slot)
1198 (undefine-fun-name `(setf ,fun)))))))
1199 ;; Clear out the SPECIFIER-TYPE cache so that subsequent
1200 ;; references are unknown types.
1201 (values-specifier-type-cache-clear)))
1204 ;;; Return a list of pairs (name . index). Used for :TYPE'd
1205 ;;; constructors to find all the names that we have to splice in &
1206 ;;; where. Note that these types don't have a layout, so we can't look
1207 ;;; at LAYOUT-INHERITS.
1208 (defun find-name-indices (defstruct)
1211 (do ((info defstruct
1212 (typed-structure-info-or-lose (first (dd-include info)))))
1213 ((not (dd-include info))
1218 (dolist (info infos)
1219 (incf i (or (dd-offset info) 0))
1220 (when (dd-named info)
1221 (res (cons (dd-name info) i)))
1222 (setq i (dd-length info)))))
1226 ;;; These functions are called to actually make a constructor after we
1227 ;;; have processed the arglist. The correct variant (according to the
1228 ;;; DD-TYPE) should be called. The function is defined with the
1229 ;;; specified name and arglist. VARS and TYPES are used for argument
1230 ;;; type declarations. VALUES are the values for the slots (in order.)
1232 ;;; This is split three ways because:
1233 ;;; * LIST & VECTOR structures need "name" symbols stuck in at
1234 ;;; various weird places, whereas STRUCTURE structures have
1236 ;;; * We really want to use LIST to make list structures, instead of
1237 ;;; MAKE-LIST/(SETF ELT). (We can't in general use VECTOR in an
1238 ;;; analogous way, since VECTOR makes a SIMPLE-VECTOR and vector-typed
1239 ;;; structures can have arbitrary subtypes of VECTOR, not necessarily
1241 ;;; * STRUCTURE structures can have raw slots that must also be
1242 ;;; allocated and indirectly referenced.
1243 (defun create-vector-constructor (dd cons-name arglist vars types values)
1244 (let ((temp (gensym))
1245 (etype (dd-element-type dd)))
1246 `(defun ,cons-name ,arglist
1247 (declare ,@(mapcar (lambda (var type) `(type (and ,type ,etype) ,var))
1249 (let ((,temp (make-array ,(dd-length dd)
1250 :element-type ',(dd-element-type dd))))
1251 ,@(mapcar (lambda (x)
1252 `(setf (aref ,temp ,(cdr x)) ',(car x)))
1253 (find-name-indices dd))
1254 ,@(mapcar (lambda (dsd value)
1255 `(setf (aref ,temp ,(dsd-index dsd)) ,value))
1256 (dd-slots dd) values)
1258 (defun create-list-constructor (dd cons-name arglist vars types values)
1259 (let ((vals (make-list (dd-length dd) :initial-element nil)))
1260 (dolist (x (find-name-indices dd))
1261 (setf (elt vals (cdr x)) `',(car x)))
1262 (loop for dsd in (dd-slots dd) and val in values do
1263 (setf (elt vals (dsd-index dsd)) val))
1265 `(defun ,cons-name ,arglist
1266 (declare ,@(mapcar (lambda (var type) `(type ,type ,var)) vars types))
1268 (defun create-structure-constructor (dd cons-name arglist vars types values)
1269 (let* ((instance (gensym "INSTANCE"))
1270 (raw-index (dd-raw-index dd)))
1271 `(defun ,cons-name ,arglist
1272 (declare ,@(mapcar (lambda (var type) `(type ,type ,var))
1274 (let ((,instance (truly-the ,(dd-name dd)
1275 (%make-instance-with-layout
1276 (%delayed-get-compiler-layout ,(dd-name dd))))))
1278 `((setf (%instance-ref ,instance ,raw-index)
1279 (make-array ,(dd-raw-length dd)
1280 :element-type '(unsigned-byte 32)))))
1281 ,@(mapcar (lambda (dsd value)
1282 ;; (Note that we can't in general use the
1283 ;; ordinary named slot setter function here
1284 ;; because the slot might be :READ-ONLY, so we
1285 ;; whip up new LAMBDA representations of slot
1286 ;; setters for the occasion.)
1287 `(,(slot-setter-lambda-form dd dsd) ,value ,instance))
1292 ;;; Create a default (non-BOA) keyword constructor.
1293 (defun create-keyword-constructor (defstruct creator)
1294 (declare (type function creator))
1295 (collect ((arglist (list '&key))
1298 (dolist (slot (dd-slots defstruct))
1299 (let ((dum (gensym))
1300 (name (dsd-name slot)))
1301 (arglist `((,(keywordicate name) ,dum) ,(dsd-default slot)))
1302 (types (dsd-type slot))
1305 defstruct (dd-default-constructor defstruct)
1306 (arglist) (vals) (types) (vals))))
1308 ;;; Given a structure and a BOA constructor spec, call CREATOR with
1309 ;;; the appropriate args to make a constructor.
1310 (defun create-boa-constructor (defstruct boa creator)
1311 (declare (type function creator))
1312 (multiple-value-bind (req opt restp rest keyp keys allowp auxp aux)
1313 (parse-lambda-list (second boa))
1317 (labels ((get-slot (name)
1318 (let ((res (find name (dd-slots defstruct)
1322 (values (dsd-type res) (dsd-default res))
1325 (multiple-value-bind (type default) (get-slot arg)
1326 (arglist `(,arg ,default))
1332 (types (get-slot arg)))
1335 (arglist '&optional)
1339 ;; FIXME: this shares some logic (though not
1340 ;; code) with the &key case below (and it
1341 ;; looks confusing) -- factor out the logic
1342 ;; if possible. - CSR, 2002-04-19
1345 (def (nth-value 1 (get-slot name)))
1346 (supplied-test nil supplied-test-p))
1348 (arglist `(,name ,def ,@(if supplied-test-p `(,supplied-test) nil)))
1350 (types (get-slot name))))
1352 (do-default arg)))))
1355 (arglist '&rest rest)
1363 (destructuring-bind (wot
1366 (supplied-test nil supplied-test-p))
1368 (let ((name (if (consp wot)
1369 (destructuring-bind (key var) wot
1370 (declare (ignore key))
1373 (multiple-value-bind (type slot-def)
1375 (arglist `(,wot ,(if def-p def slot-def)
1376 ,@(if supplied-test-p `(,supplied-test) nil)))
1381 (when allowp (arglist '&allow-other-keys))
1386 (let* ((arg (if (consp arg) arg (list arg)))
1390 (types (get-slot var))))))
1392 (funcall creator defstruct (first boa)
1393 (arglist) (vars) (types)
1394 (mapcar (lambda (slot)
1395 (or (find (dsd-name slot) (vars) :test #'string=)
1396 (dsd-default slot)))
1397 (dd-slots defstruct))))))
1399 ;;; Grovel the constructor options, and decide what constructors (if
1401 (defun constructor-definitions (defstruct)
1402 (let ((no-constructors nil)
1405 (creator (ecase (dd-type defstruct)
1406 (structure #'create-structure-constructor)
1407 (vector #'create-vector-constructor)
1408 (list #'create-list-constructor))))
1409 (dolist (constructor (dd-constructors defstruct))
1410 (destructuring-bind (name &optional (boa-ll nil boa-p)) constructor
1411 (declare (ignore boa-ll))
1412 (cond ((not name) (setq no-constructors t))
1413 (boa-p (push constructor boas))
1414 (t (push name defaults)))))
1416 (when no-constructors
1417 (when (or defaults boas)
1418 (error "(:CONSTRUCTOR NIL) combined with other :CONSTRUCTORs"))
1419 (return-from constructor-definitions ()))
1421 (unless (or defaults boas)
1422 (push (symbolicate "MAKE-" (dd-name defstruct)) defaults))
1426 (let ((cname (first defaults)))
1427 (setf (dd-default-constructor defstruct) cname)
1428 (res (create-keyword-constructor defstruct creator))
1429 (dolist (other-name (rest defaults))
1430 (res `(setf (fdefinition ',other-name) (fdefinition ',cname)))
1431 (res `(declaim (ftype function ',other-name))))))
1434 (res (create-boa-constructor defstruct boa creator)))
1438 ;;;; instances with ALTERNATE-METACLASS
1440 ;;;; The CMU CL support for structures with ALTERNATE-METACLASS was a
1441 ;;;; fairly general extension embedded in the main DEFSTRUCT code, and
1442 ;;;; the result was an fairly impressive mess as ALTERNATE-METACLASS
1443 ;;;; extension mixed with ANSI CL generality (e.g. :TYPE and :INCLUDE)
1444 ;;;; and CMU CL implementation hairiness (esp. raw slots). This SBCL
1445 ;;;; version is much less ambitious, noticing that ALTERNATE-METACLASS
1446 ;;;; is only used to implement CONDITION, STANDARD-INSTANCE, and
1447 ;;;; GENERIC-FUNCTION, and defining a simple specialized
1448 ;;;; separate-from-DEFSTRUCT macro to provide only enough
1449 ;;;; functionality to support those.
1451 ;;;; KLUDGE: The defining macro here is so specialized that it's ugly
1452 ;;;; in its own way. It also violates once-and-only-once by knowing
1453 ;;;; much about structures and layouts that is already known by the
1454 ;;;; main DEFSTRUCT macro. Hopefully it will go away presently
1455 ;;;; (perhaps when CL:CLASS and SB-PCL:CLASS meet) as per FIXME below.
1456 ;;;; -- WHN 2001-10-28
1458 ;;;; FIXME: There seems to be no good reason to shoehorn CONDITION,
1459 ;;;; STANDARD-INSTANCE, and GENERIC-FUNCTION into mutated structures
1460 ;;;; instead of just implementing them as primitive objects. (This
1461 ;;;; reduced-functionality macro seems pretty close to the
1462 ;;;; functionality of DEFINE-PRIMITIVE-OBJECT..)
1464 (defun make-dd-with-alternate-metaclass (&key (class-name (missing-arg))
1465 (superclass-name (missing-arg))
1466 (metaclass-name (missing-arg))
1467 (dd-type (missing-arg))
1468 metaclass-constructor
1470 (let* ((dd (make-defstruct-description class-name))
1471 (conc-name (concatenate 'string (symbol-name class-name) "-"))
1472 (dd-slots (let ((reversed-result nil)
1473 ;; The index starts at 1 for ordinary
1474 ;; named slots because slot 0 is
1475 ;; magical, used for LAYOUT in
1476 ;; CONDITIONs or for something (?) in
1477 ;; funcallable instances.
1479 (dolist (slot-name slot-names)
1480 (push (make-defstruct-slot-description
1481 :%name (symbol-name slot-name)
1483 :accessor-name (symbolicate conc-name slot-name))
1486 (nreverse reversed-result))))
1487 (setf (dd-alternate-metaclass dd) (list superclass-name
1489 metaclass-constructor)
1490 (dd-slots dd) dd-slots
1491 (dd-length dd) (1+ (length slot-names))
1492 (dd-type dd) dd-type)
1495 (sb!xc:defmacro !defstruct-with-alternate-metaclass
1497 (slot-names (missing-arg))
1498 (boa-constructor (missing-arg))
1499 (superclass-name (missing-arg))
1500 (metaclass-name (missing-arg))
1501 (metaclass-constructor (missing-arg))
1502 (dd-type (missing-arg))
1504 (runtime-type-checks-p t))
1506 (declare (type (and list (not null)) slot-names))
1507 (declare (type (and symbol (not null))
1511 metaclass-constructor))
1512 (declare (type symbol predicate))
1513 (declare (type (member structure funcallable-structure) dd-type))
1515 (let* ((dd (make-dd-with-alternate-metaclass
1516 :class-name class-name
1517 :slot-names slot-names
1518 :superclass-name superclass-name
1519 :metaclass-name metaclass-name
1520 :metaclass-constructor metaclass-constructor
1522 (dd-slots (dd-slots dd))
1523 (dd-length (1+ (length slot-names)))
1524 (object-gensym (gensym "OBJECT"))
1525 (new-value-gensym (gensym "NEW-VALUE-"))
1526 (delayed-layout-form `(%delayed-get-compiler-layout ,class-name)))
1527 (multiple-value-bind (raw-maker-form raw-reffer-operator)
1530 (values `(let ((,object-gensym (%make-instance ,dd-length)))
1531 (setf (%instance-layout ,object-gensym)
1532 ,delayed-layout-form)
1535 (funcallable-structure
1536 (values `(%make-funcallable-instance ,dd-length
1537 ,delayed-layout-form)
1538 '%funcallable-instance-info)))
1541 (eval-when (:compile-toplevel :load-toplevel :execute)
1542 (%compiler-set-up-layout ',dd))
1544 ;; slot readers and writers
1545 (declaim (inline ,@(mapcar #'dsd-accessor-name dd-slots)))
1546 ,@(mapcar (lambda (dsd)
1547 `(defun ,(dsd-accessor-name dsd) (,object-gensym)
1548 ,@(when runtime-type-checks-p
1549 `((declare (type ,class-name ,object-gensym))))
1550 (,raw-reffer-operator ,object-gensym
1553 (declaim (inline ,@(mapcar (lambda (dsd)
1554 `(setf ,(dsd-accessor-name dsd)))
1556 ,@(mapcar (lambda (dsd)
1557 `(defun (setf ,(dsd-accessor-name dsd)) (,new-value-gensym
1559 ,@(when runtime-type-checks-p
1560 `((declare (type ,class-name ,object-gensym))))
1561 (setf (,raw-reffer-operator ,object-gensym
1563 ,new-value-gensym)))
1567 (defun ,boa-constructor ,slot-names
1568 (let ((,object-gensym ,raw-maker-form))
1569 ,@(mapcar (lambda (slot-name)
1570 (let ((dsd (find (symbol-name slot-name) dd-slots
1573 ;; KLUDGE: bug 117 bogowarning. Neither
1574 ;; DECLAREing the type nor TRULY-THE cut
1575 ;; the mustard -- it still gives warnings.
1576 (enforce-type dsd defstruct-slot-description)
1577 `(setf (,(dsd-accessor-name dsd) ,object-gensym)
1584 ;; Just delegate to the compiler's type optimization
1585 ;; code, which knows how to generate inline type tests
1586 ;; for the whole CMU CL INSTANCE menagerie.
1587 `(defun ,predicate (,object-gensym)
1588 (typep ,object-gensym ',class-name)))))))
1590 ;;;; finalizing bootstrapping
1592 ;;; Set up DD and LAYOUT for STRUCTURE-OBJECT class itself.
1594 ;;; Ordinary structure classes effectively :INCLUDE STRUCTURE-OBJECT
1595 ;;; when they have no explicit :INCLUDEs, so (1) it needs to be set up
1596 ;;; before we can define ordinary structure classes, and (2) it's
1597 ;;; special enough (and simple enough) that we just build it by hand
1598 ;;; instead of trying to generalize the ordinary DEFSTRUCT code.
1599 (defun !set-up-structure-object-class ()
1600 (let ((dd (make-defstruct-description 'structure-object)))
1602 ;; Note: This has an ALTERNATE-METACLASS only because of blind
1603 ;; clueless imitation of the CMU CL code -- dunno if or why it's
1605 (dd-alternate-metaclass dd) '(instance)
1608 (dd-type dd) 'structure)
1609 (%compiler-set-up-layout dd)))
1610 (!set-up-structure-object-class)
1612 ;;; early structure predeclarations: Set up DD and LAYOUT for ordinary
1613 ;;; (non-ALTERNATE-METACLASS) structures which are needed early.
1615 '#.(sb-cold:read-from-file
1616 "src/code/early-defstruct-args.lisp-expr"))
1617 (let* ((dd (parse-defstruct-name-and-options-and-slot-descriptions
1620 (inherits (inherits-for-structure dd)))
1621 (%compiler-defstruct dd inherits)))
1623 (/show0 "code/defstruct.lisp end of file")