X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fcode%2Fdefstruct.lisp;h=eece9616ef3f2b700677b98340b8e6e333b2e8fc;hb=d8346491af87b66677657e4b934ddeae1e749250;hp=6ce094889b48ba59a3416925482cbf8a0b981d52;hpb=986ce2596822cc0871b609346aaf592348aca596;p=sbcl.git diff --git a/src/code/defstruct.lisp b/src/code/defstruct.lisp index 6ce0948..eece961 100644 --- a/src/code/defstruct.lisp +++ b/src/code/defstruct.lisp @@ -27,10 +27,36 @@ (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) @@ -50,21 +76,25 @@ (: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) @@ -274,7 +304,10 @@ 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)))) @@ -308,14 +341,23 @@ (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)) @@ -515,7 +557,7 @@ (when offset (incf (dd-length dd) offset))))) (when (dd-include dd) - (do-dd-inclusion-stuff dd)) + (frob-dd-inclusion-stuff dd)) dd))) @@ -610,6 +652,8 @@ ;;; 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 @@ -674,7 +718,7 @@ ;;; 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 @@ -719,7 +763,7 @@ (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 @@ -777,12 +821,7 @@ ;; 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)) @@ -826,6 +865,11 @@ ,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 @@ -881,9 +925,7 @@ (%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 @@ -990,19 +1032,37 @@ (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 "~@" + '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 + "~@" + name)) + (register-layout new-layout)) + (recklessly-continue () + :report (lambda (s) + (format s + "~@" + 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 @@ -1118,53 +1178,6 @@ (res))) -;;;; 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)))))))) - ;;; 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 @@ -1176,23 +1189,25 @@ ;;; 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) @@ -1203,33 +1218,31 @@ (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) @@ -1249,8 +1262,8 @@ ;;; 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)) @@ -1276,9 +1289,16 @@ (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 @@ -1293,21 +1313,27 @@ (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))) @@ -1318,9 +1344,9 @@ (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 @@ -1446,7 +1472,6 @@ :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")) @@ -1498,8 +1523,12 @@ (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))