(in-package "SB!IMPL")
(macrolet ((def (name result access src-type &optional typep)
- `(defun ,name (object ,@(if typep '(type) ()))
- (do* ((index 0 (1+ index))
- (length (length (the ,(ecase src-type
- (:list 'list)
- (:vector 'vector))
- object)))
- (result ,result)
- (in-object object))
- ((= index length) result)
- (declare (fixnum length index))
- (setf (,access result index)
- ,(ecase src-type
- (:list '(pop in-object))
- (:vector '(aref in-object index))))))))
+ `(defun ,name (object ,@(if typep '(type) ()))
+ (declare (type ,(ecase src-type
+ (:list 'list)
+ (:vector 'vector)
+ (:sequence 'sequence)) object))
+ (do* ((index 0 (1+ index))
+ (length (length object))
+ (result ,result)
+ (in-object object))
+ ((>= index length) result)
+ (declare (fixnum length index))
+ (declare (type vector result))
+ (setf (,access result index)
+ ,(ecase src-type
+ (:list '(pop in-object))
+ (:vector '(aref in-object index))
+ (:sequence '(elt in-object index))))))))
- (def list-to-simple-string* (make-string length) schar :list)
-
- (def list-to-bit-vector* (make-array length :element-type '(mod 2))
- sbit :list)
-
- (def list-to-vector* (make-sequence-of-type type length)
+ (def list-to-vector* (make-sequence type length)
aref :list t)
- (def vector-to-vector* (make-sequence-of-type type length)
+ (def vector-to-vector* (make-sequence type length)
aref :vector t)
- (def vector-to-simple-string* (make-string length) schar :vector)
-
- (def vector-to-bit-vector* (make-array length :element-type '(mod 2))
- sbit :vector))
+ (def sequence-to-vector* (make-sequence type length)
+ aref :sequence t))
(defun vector-to-list* (object)
+ (declare (type vector object))
(let ((result (list nil))
- (length (length object)))
+ (length (length object)))
(declare (fixnum length))
(do ((index 0 (1+ index))
- (splice result (cdr splice)))
- ((= index length) (cdr result))
+ (splice result (cdr splice)))
+ ((>= index length) (cdr result))
(declare (fixnum index))
(rplacd splice (list (aref object index))))))
-(defun string-to-simple-string* (object)
- (if (simple-string-p object)
- object
- (with-array-data ((data object)
- (start)
- (end (length object)))
- (declare (simple-string data))
- (subseq data start end))))
-
-(defun bit-vector-to-simple-bit-vector* (object)
- (if (simple-bit-vector-p object)
- object
- (with-array-data ((data object)
- (start)
- (end (length object)))
- (declare (simple-bit-vector data))
- (subseq data start end))))
-
(defvar *offending-datum*); FIXME: Remove after debugging COERCE.
;;; These are used both by the full DEFUN function and by various
;;; argument type is known. It might be better to do this with
;;; DEFTRANSFORMs, though.
(declaim (inline coerce-to-list))
-(declaim (inline coerce-to-simple-string coerce-to-bit-vector coerce-to-vector))
+(declaim (inline coerce-to-vector))
(defun coerce-to-fun (object)
;; (Unlike the other COERCE-TO-FOOs, this one isn't inline, because
;; it's so big and because optimizing away the outer ETYPECASE
(symbol
;; ANSI lets us return ordinary errors (non-TYPE-ERRORs) here.
(cond ((macro-function object)
- (error "~S names a macro." object))
- ((special-operator-p object)
- (error "~S is a special operator." object))
- (t (fdefinition object))))
+ (error "~S names a macro." object))
+ ((special-operator-p object)
+ (error "~S is a special operator." object))
+ (t (fdefinition object))))
(list
(case (first object)
((setf)
- (fdefinition object))
- ((lambda instance-lambda)
- ;; FIXME: If we go to a compiler-only implementation, this can
- ;; become COMPILE instead of EVAL, which seems nicer to me.
- (eval `(function ,object)))
+ (fdefinition object))
+ ((lambda)
+ ;; FIXME: If we go to a compiler-only implementation, this can
+ ;; become COMPILE instead of EVAL, which seems nicer to me.
+ (eval `(function ,object)))
(t
- (error 'simple-type-error
- :datum object
- :expected-type '(or symbol
- ;; KLUDGE: ANSI wants us to
- ;; return a TYPE-ERROR here, and
- ;; a TYPE-ERROR is supposed to
- ;; describe the expected type,
- ;; but it's not obvious how to
- ;; describe the coerceable cons
- ;; types, so we punt and just say
- ;; CONS. -- WHN 20000503
- cons)
- :format-control "~S can't be coerced to a function."
- :format-arguments (list object)))))))
+ (error 'simple-type-error
+ :datum object
+ :expected-type '(or symbol
+ ;; KLUDGE: ANSI wants us to
+ ;; return a TYPE-ERROR here, and
+ ;; a TYPE-ERROR is supposed to
+ ;; describe the expected type,
+ ;; but it's not obvious how to
+ ;; describe the coerceable cons
+ ;; types, so we punt and just say
+ ;; CONS. -- WHN 20000503
+ cons)
+ :format-control "~S can't be coerced to a function."
+ :format-arguments (list object)))))))
+
(defun coerce-to-list (object)
(etypecase object
(vector (vector-to-list* object))))
-(defun coerce-to-simple-string (object)
- (etypecase object
- (list (list-to-simple-string* object))
- (string (string-to-simple-string* object))
- (vector (vector-to-simple-string* object))))
-(defun coerce-to-bit-vector (object)
- (etypecase object
- (list (list-to-bit-vector* object))
- (vector (vector-to-bit-vector* object))))
-(defun coerce-to-simple-vector (x)
- (if (simple-vector-p x)
- x
- (replace (make-array (length x)) x)))
+
(defun coerce-to-vector (object output-type-spec)
(etypecase object
(list (list-to-vector* object output-type-spec))
#!+sb-doc
"Coerce the Object to an object of type Output-Type-Spec."
(flet ((coerce-error ()
- (/show0 "entering COERCE-ERROR")
- (error 'simple-type-error
- :format-control "~S can't be converted to type ~S."
- :format-arguments (list object output-type-spec)))
- (check-result (result)
- #!+high-security (aver (typep result output-type-spec))
- result))
+ (/show0 "entering COERCE-ERROR")
+ (error 'simple-type-error
+ :format-control "~S can't be converted to type ~S."
+ :format-arguments (list object output-type-spec)
+ :datum object
+ :expected-type output-type-spec)))
(let ((type (specifier-type output-type-spec)))
(cond
- ((%typep object output-type-spec)
- object)
- ((eq type *empty-type*)
- (coerce-error))
- ((csubtypep type (specifier-type 'character))
- (character object))
- ((csubtypep type (specifier-type 'function))
- #!+high-security
- (when (and (or (symbolp object)
- (and (listp object)
- (= (length object) 2)
- (eq (car object) 'setf)))
- (not (fboundp object)))
- (error 'simple-type-error
- :datum object
- ;; FIXME: SATISFIES FBOUNDP is a kinda bizarre broken
- ;; type specifier, since the set of values it describes
- ;; isn't in general constant in time. Maybe we could
- ;; find a better way of expressing this error? (Maybe
- ;; with the UNDEFINED-FUNCTION condition?)
- :expected-type '(satisfies fboundp)
- :format-control "~S isn't fbound."
- :format-arguments (list object)))
- #!+high-security
- (when (and (symbolp object)
- (sb!xc:macro-function object))
- (error 'simple-type-error
- :datum object
- :expected-type '(not (satisfies sb!xc:macro-function))
- :format-control "~S is a macro."
- :format-arguments (list object)))
- #!+high-security
- (when (and (symbolp object)
- (special-operator-p object))
- (error 'simple-type-error
- :datum object
- :expected-type '(not (satisfies special-operator-p))
- :format-control "~S is a special operator."
- :format-arguments (list object)))
- (eval `#',object))
- ((numberp object)
- (let ((res
- (cond
- ((csubtypep type (specifier-type 'single-float))
- (%single-float object))
- ((csubtypep type (specifier-type 'double-float))
- (%double-float object))
- #!+long-float
- ((csubtypep type (specifier-type 'long-float))
- (%long-float object))
- ((csubtypep type (specifier-type 'float))
- (%single-float object))
- ((csubtypep type (specifier-type '(complex single-float)))
- (complex (%single-float (realpart object))
- (%single-float (imagpart object))))
- ((csubtypep type (specifier-type '(complex double-float)))
- (complex (%double-float (realpart object))
- (%double-float (imagpart object))))
- #!+long-float
- ((csubtypep type (specifier-type '(complex long-float)))
- (complex (%long-float (realpart object))
- (%long-float (imagpart object))))
- ((and (typep object 'rational)
- (csubtypep type (specifier-type '(complex float))))
- ;; Perhaps somewhat surprisingly, ANSI specifies
- ;; that (COERCE FOO 'FLOAT) is a SINGLE-FLOAT, not
- ;; dispatching on *READ-DEFAULT-FLOAT-FORMAT*. By
- ;; analogy, we do the same for complex numbers. --
- ;; CSR, 2002-08-06
- (complex (%single-float object)))
- ((csubtypep type (specifier-type 'complex))
- (complex object))
- (t
- (coerce-error)))))
- ;; If RES has the wrong type, that means that rule of canonical
- ;; representation for complex rationals was invoked. According to
- ;; the Hyperspec, (coerce 7/2 'complex) returns 7/2. Thus, if the
- ;; object was a rational, there is no error here.
- (unless (or (typep res output-type-spec) (rationalp object))
- (coerce-error))
- res))
- ((csubtypep type (specifier-type 'list))
- (if (vectorp object)
- (vector-to-list* object)
- (coerce-error)))
- ((csubtypep type (specifier-type 'string))
- (check-result
- (typecase object
- (list (list-to-simple-string* object))
- (string (string-to-simple-string* object))
- (vector (vector-to-simple-string* object))
- (t
- (coerce-error)))))
- ((csubtypep type (specifier-type 'bit-vector))
- (check-result
- (typecase object
- (list (list-to-bit-vector* object))
- (vector (vector-to-bit-vector* object))
- (t
- (coerce-error)))))
- ((csubtypep type (specifier-type 'vector))
- (check-result
- (typecase object
- (list (list-to-vector* object output-type-spec))
- (vector (vector-to-vector* object output-type-spec))
- (t
- (coerce-error)))))
- (t
- (coerce-error))))))
+ ((%typep object output-type-spec)
+ object)
+ ((eq type *empty-type*)
+ (coerce-error))
+ ((type= type (specifier-type 'character))
+ (character object))
+ ((numberp object)
+ (cond
+ ((csubtypep type (specifier-type 'single-float))
+ (let ((res (%single-float object)))
+ (unless (typep res output-type-spec)
+ (coerce-error))
+ res))
+ ((csubtypep type (specifier-type 'double-float))
+ (let ((res (%double-float object)))
+ (unless (typep res output-type-spec)
+ (coerce-error))
+ res))
+ #!+long-float
+ ((csubtypep type (specifier-type 'long-float))
+ (let ((res (%long-float object)))
+ (unless (typep res output-type-spec)
+ (coerce-error))
+ res))
+ ((csubtypep type (specifier-type 'float))
+ (let ((res (%single-float object)))
+ (unless (typep res output-type-spec)
+ (coerce-error))
+ res))
+ (t
+ (let ((res
+ (cond
+ ((csubtypep type (specifier-type '(complex single-float)))
+ (complex (%single-float (realpart object))
+ (%single-float (imagpart object))))
+ ((csubtypep type (specifier-type '(complex double-float)))
+ (complex (%double-float (realpart object))
+ (%double-float (imagpart object))))
+ #!+long-float
+ ((csubtypep type (specifier-type '(complex long-float)))
+ (complex (%long-float (realpart object))
+ (%long-float (imagpart object))))
+ ((csubtypep type (specifier-type '(complex float)))
+ (complex (%single-float (realpart object))
+ (%single-float (imagpart object))))
+ ((and (typep object 'rational)
+ (csubtypep type (specifier-type '(complex float))))
+ ;; Perhaps somewhat surprisingly, ANSI specifies
+ ;; that (COERCE FOO 'FLOAT) is a SINGLE-FLOAT,
+ ;; not dispatching on
+ ;; *READ-DEFAULT-FLOAT-FORMAT*. By analogy, we
+ ;; do the same for complex numbers. -- CSR,
+ ;; 2002-08-06
+ (complex (%single-float object)))
+ ((csubtypep type (specifier-type 'complex))
+ (complex object))
+ (t
+ (coerce-error)))))
+ ;; If RES has the wrong type, that means that rule of
+ ;; canonical representation for complex rationals was
+ ;; invoked. According to the Hyperspec, (coerce 7/2
+ ;; 'complex) returns 7/2. Thus, if the object was a
+ ;; rational, there is no error here.
+ (unless (or (typep res output-type-spec)
+ (rationalp object))
+ (coerce-error))
+ res))))
+ ((csubtypep type (specifier-type 'list))
+ (if (vectorp object)
+ (cond
+ ((type= type (specifier-type 'list))
+ (vector-to-list* object))
+ ((type= type (specifier-type 'null))
+ (if (= (length object) 0)
+ 'nil
+ (sequence-type-length-mismatch-error type
+ (length object))))
+ ((cons-type-p type)
+ (multiple-value-bind (min exactp)
+ (sb!kernel::cons-type-length-info type)
+ (let ((length (length object)))
+ (if exactp
+ (unless (= length min)
+ (sequence-type-length-mismatch-error type length))
+ (unless (>= length min)
+ (sequence-type-length-mismatch-error type length)))
+ (vector-to-list* object))))
+ (t (sequence-type-too-hairy (type-specifier type))))
+ (if (sequencep object)
+ (cond
+ ((type= type (specifier-type 'list))
+ (sb!sequence:make-sequence-like
+ nil (length object) :initial-contents object))
+ ((type= type (specifier-type 'null))
+ (if (= (length object) 0)
+ 'nil
+ (sequence-type-length-mismatch-error type
+ (length object))))
+ ((cons-type-p type)
+ (multiple-value-bind (min exactp)
+ (sb!kernel::cons-type-length-info type)
+ (let ((length (length object)))
+ (if exactp
+ (unless (= length min)
+ (sequence-type-length-mismatch-error type length))
+ (unless (>= length min)
+ (sequence-type-length-mismatch-error type length)))
+ (sb!sequence:make-sequence-like
+ nil length :initial-contents object))))
+ (t (sequence-type-too-hairy (type-specifier type))))
+ (coerce-error))))
+ ((csubtypep type (specifier-type 'vector))
+ (typecase object
+ ;; FOO-TO-VECTOR* go through MAKE-SEQUENCE, so length
+ ;; errors are caught there. -- CSR, 2002-10-18
+ (list (list-to-vector* object output-type-spec))
+ (vector (vector-to-vector* object output-type-spec))
+ (sequence (sequence-to-vector* object output-type-spec))
+ (t
+ (coerce-error))))
+ ((and (csubtypep type (specifier-type 'sequence))
+ (find-class output-type-spec nil))
+ (let ((class (find-class output-type-spec)))
+ (unless (sb!mop:class-finalized-p class)
+ (sb!mop:finalize-inheritance class))
+ (sb!sequence:make-sequence-like
+ (sb!mop:class-prototype class)
+ (length object) :initial-contents object)))
+ ((csubtypep type (specifier-type 'function))
+ (when (and (legal-fun-name-p object)
+ (not (fboundp object)))
+ (error 'simple-type-error
+ :datum object
+ ;; FIXME: SATISFIES FBOUNDP is a kinda bizarre broken
+ ;; type specifier, since the set of values it describes
+ ;; isn't in general constant in time. Maybe we could
+ ;; find a better way of expressing this error? (Maybe
+ ;; with the UNDEFINED-FUNCTION condition?)
+ :expected-type '(satisfies fboundp)
+ :format-control "~S isn't fbound."
+ :format-arguments (list object)))
+ (when (and (symbolp object)
+ (sb!xc:macro-function object))
+ (error 'simple-type-error
+ :datum object
+ :expected-type '(not (satisfies sb!xc:macro-function))
+ :format-control "~S is a macro."
+ :format-arguments (list object)))
+ (when (and (symbolp object)
+ (special-operator-p object))
+ (error 'simple-type-error
+ :datum object
+ :expected-type '(not (satisfies special-operator-p))
+ :format-control "~S is a special operator."
+ :format-arguments (list object)))
+ (eval `#',object))
+ (t
+ (coerce-error))))))
;;; new version, which seems as though it should be better, but which
;;; does not yet work
"Coerces the Object to an object of type Output-Type-Spec."
(flet ((coerce-error ()
(error 'simple-type-error
- :format-control "~S can't be converted to type ~S."
- :format-arguments (list object output-type-spec)))
- (check-result (result)
- #!+high-security (aver (typep result output-type-spec))
- result))
+ :format-control "~S can't be converted to type ~S."
+ :format-arguments (list object output-type-spec)))
+ (check-result (result)
+ #!+high-security (aver (typep result output-type-spec))
+ result))
(let ((type (specifier-type output-type-spec)))
(cond
- ((%typep object output-type-spec)
- object)
- ((eq type *empty-type*)
- (coerce-error))
- ((csubtypep type (specifier-type 'character))
- (character object))
- ((csubtypep type (specifier-type 'function))
- (coerce-to-fun object))
- ((numberp object)
- (let ((res
- (cond
- ((csubtypep type (specifier-type 'single-float))
- (%single-float object))
- ((csubtypep type (specifier-type 'double-float))
- (%double-float object))
- #!+long-float
- ((csubtypep type (specifier-type 'long-float))
- (%long-float object))
- ((csubtypep type (specifier-type 'float))
- (%single-float object))
- ((csubtypep type (specifier-type '(complex single-float)))
- (complex (%single-float (realpart object))
- (%single-float (imagpart object))))
- ((csubtypep type (specifier-type '(complex double-float)))
- (complex (%double-float (realpart object))
- (%double-float (imagpart object))))
- #!+long-float
- ((csubtypep type (specifier-type '(complex long-float)))
- (complex (%long-float (realpart object))
- (%long-float (imagpart object))))
- ((csubtypep type (specifier-type 'complex))
- (complex object))
- (t
- (coerce-error)))))
- ;; If RES has the wrong type, that means that rule of
- ;; canonical representation for complex rationals was
- ;; invoked. According to the ANSI spec, (COERCE 7/2
- ;; 'COMPLEX) returns 7/2. Thus, if the object was a
- ;; rational, there is no error here.
- (unless (or (typep res output-type-spec) (rationalp object))
- (coerce-error))
- res))
- ((csubtypep type (specifier-type 'list))
- (coerce-to-list object))
- ((csubtypep type (specifier-type 'string))
- (check-result (coerce-to-simple-string object)))
- ((csubtypep type (specifier-type 'bit-vector))
- (check-result (coerce-to-bit-vector object)))
- ((csubtypep type (specifier-type 'vector))
- (check-result (coerce-to-vector object output-type-spec)))
- (t
- (coerce-error))))))
+ ((%typep object output-type-spec)
+ object)
+ ((eq type *empty-type*)
+ (coerce-error))
+ ((csubtypep type (specifier-type 'character))
+ (character object))
+ ((csubtypep type (specifier-type 'function))
+ (coerce-to-fun object))
+ ((numberp object)
+ (let ((res
+ (cond
+ ((csubtypep type (specifier-type 'single-float))
+ (%single-float object))
+ ((csubtypep type (specifier-type 'double-float))
+ (%double-float object))
+ #!+long-float
+ ((csubtypep type (specifier-type 'long-float))
+ (%long-float object))
+ ((csubtypep type (specifier-type 'float))
+ (%single-float object))
+ ((csubtypep type (specifier-type '(complex single-float)))
+ (complex (%single-float (realpart object))
+ (%single-float (imagpart object))))
+ ((csubtypep type (specifier-type '(complex double-float)))
+ (complex (%double-float (realpart object))
+ (%double-float (imagpart object))))
+ #!+long-float
+ ((csubtypep type (specifier-type '(complex long-float)))
+ (complex (%long-float (realpart object))
+ (%long-float (imagpart object))))
+ ((csubtypep type (specifier-type 'complex))
+ (complex object))
+ (t
+ (coerce-error)))))
+ ;; If RES has the wrong type, that means that rule of
+ ;; canonical representation for complex rationals was
+ ;; invoked. According to the ANSI spec, (COERCE 7/2
+ ;; 'COMPLEX) returns 7/2. Thus, if the object was a
+ ;; rational, there is no error here.
+ (unless (or (typep res output-type-spec) (rationalp object))
+ (coerce-error))
+ res))
+ ((csubtypep type (specifier-type 'list))
+ (coerce-to-list object))
+ ((csubtypep type (specifier-type 'string))
+ (check-result (coerce-to-simple-string object)))
+ ((csubtypep type (specifier-type 'bit-vector))
+ (check-result (coerce-to-bit-vector object)))
+ ((csubtypep type (specifier-type 'vector))
+ (check-result (coerce-to-vector object output-type-spec)))
+ (t
+ (coerce-error))))))