dfd208d1cb616531d45db4ae6ca9ba85065fb881
[sbcl.git] / src / code / coerce.lisp
1 ;;;; COERCE and related code
2
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
11
12 (in-package "SB!IMPL")
13
14 (macrolet ((def (name result access src-type &optional typep)
15              `(defun ,name (object ,@(if typep '(type) ()))
16                 (do* ((index 0 (1+ index))
17                       (length (length (the ,(ecase src-type
18                                               (:list 'list)
19                                               (:vector 'vector))
20                                            object)))
21                       (result ,result)
22                       (in-object object))
23                      ((= index length) result)
24                   (declare (fixnum length index))
25                   (setf (,access result index)
26                         ,(ecase src-type
27                            (:list '(pop in-object))
28                            (:vector '(aref in-object index))))))))
29
30   (def list-to-vector* (make-sequence type length)
31     aref :list t)
32
33   (def vector-to-vector* (make-sequence type length)
34     aref :vector t))
35
36 (defun vector-to-list* (object)
37   (let ((result (list nil))
38         (length (length object)))
39     (declare (fixnum length))
40     (do ((index 0 (1+ index))
41          (splice result (cdr splice)))
42         ((= index length) (cdr result))
43       (declare (fixnum index))
44       (rplacd splice (list (aref object index))))))
45
46 (defvar *offending-datum*); FIXME: Remove after debugging COERCE.
47
48 ;;; These are used both by the full DEFUN function and by various
49 ;;; optimization transforms in the constant-OUTPUT-TYPE-SPEC case.
50 ;;;
51 ;;; Most of them are INLINE so that they can be optimized when the
52 ;;; argument type is known. It might be better to do this with
53 ;;; DEFTRANSFORMs, though.
54 (declaim (inline coerce-to-list))
55 (declaim (inline coerce-to-vector))
56 (defun coerce-to-fun (object)
57   ;; (Unlike the other COERCE-TO-FOOs, this one isn't inline, because
58   ;; it's so big and because optimizing away the outer ETYPECASE
59   ;; doesn't seem to buy us that much anyway.)
60   (etypecase object
61     (symbol
62      ;; ANSI lets us return ordinary errors (non-TYPE-ERRORs) here.
63      (cond ((macro-function object)
64             (error "~S names a macro." object))
65            ((special-operator-p object)
66             (error "~S is a special operator." object))
67            (t (fdefinition object))))
68     (list
69      (case (first object)
70        ((setf)
71         (fdefinition object))
72        ((lambda instance-lambda)
73         ;; FIXME: If we go to a compiler-only implementation, this can
74         ;; become COMPILE instead of EVAL, which seems nicer to me.
75         (eval `(function ,object)))
76        (t
77         (error 'simple-type-error
78                :datum object
79                :expected-type '(or symbol
80                                    ;; KLUDGE: ANSI wants us to
81                                    ;; return a TYPE-ERROR here, and
82                                    ;; a TYPE-ERROR is supposed to
83                                    ;; describe the expected type,
84                                    ;; but it's not obvious how to
85                                    ;; describe the coerceable cons
86                                    ;; types, so we punt and just say
87                                    ;; CONS. -- WHN 20000503
88                                    cons)
89                :format-control "~S can't be coerced to a function."
90                :format-arguments (list object)))))))
91
92 (defun coerce-to-list (object)
93   (etypecase object
94     (vector (vector-to-list* object))))
95
96 (defun coerce-to-vector (object output-type-spec)
97   (etypecase object
98     (list (list-to-vector* object output-type-spec))
99     (vector (vector-to-vector* object output-type-spec))))
100
101 ;;; old working version
102 (defun coerce (object output-type-spec)
103   #!+sb-doc
104   "Coerce the Object to an object of type Output-Type-Spec."
105   (flet ((coerce-error ()
106            (/show0 "entering COERCE-ERROR")
107            (error 'simple-type-error
108                   :format-control "~S can't be converted to type ~S."
109                   :format-arguments (list object output-type-spec))))
110     (let ((type (specifier-type output-type-spec)))
111       (cond
112         ((%typep object output-type-spec)
113          object)
114         ((eq type *empty-type*)
115          (coerce-error))
116         ((csubtypep type (specifier-type 'character))
117          (character object))
118         ((csubtypep type (specifier-type 'function))
119          #!+high-security
120          (when (and (or (symbolp object)
121                         (and (listp object)
122                              (= (length object) 2)
123                              (eq (car object) 'setf)))
124                     (not (fboundp object)))
125            (error 'simple-type-error
126                   :datum object
127                   ;; FIXME: SATISFIES FBOUNDP is a kinda bizarre broken
128                   ;; type specifier, since the set of values it describes
129                   ;; isn't in general constant in time. Maybe we could
130                   ;; find a better way of expressing this error? (Maybe
131                   ;; with the UNDEFINED-FUNCTION condition?)
132                   :expected-type '(satisfies fboundp)
133                :format-control "~S isn't fbound."
134                :format-arguments (list object)))
135          #!+high-security
136          (when (and (symbolp object)
137                     (sb!xc:macro-function object))
138            (error 'simple-type-error
139                   :datum object
140                   :expected-type '(not (satisfies sb!xc:macro-function))
141                   :format-control "~S is a macro."
142                   :format-arguments (list object)))
143          #!+high-security
144          (when (and (symbolp object)
145                     (special-operator-p object))
146            (error 'simple-type-error
147                   :datum object
148                   :expected-type '(not (satisfies special-operator-p))
149                   :format-control "~S is a special operator."
150                   :format-arguments (list object)))
151          (eval `#',object))
152         ((numberp object)
153          (let ((res
154                 (cond
155                   ((csubtypep type (specifier-type 'single-float))
156                    (%single-float object))
157                   ((csubtypep type (specifier-type 'double-float))
158                    (%double-float object))
159                   #!+long-float
160                   ((csubtypep type (specifier-type 'long-float))
161                    (%long-float object))
162                   ((csubtypep type (specifier-type 'float))
163                    (%single-float object))
164                   ((csubtypep type (specifier-type '(complex single-float)))
165                    (complex (%single-float (realpart object))
166                             (%single-float (imagpart object))))
167                   ((csubtypep type (specifier-type '(complex double-float)))
168                    (complex (%double-float (realpart object))
169                             (%double-float (imagpart object))))
170                   #!+long-float
171                   ((csubtypep type (specifier-type '(complex long-float)))
172                    (complex (%long-float (realpart object))
173                             (%long-float (imagpart object))))
174                   ((and (typep object 'rational)
175                         (csubtypep type (specifier-type '(complex float))))
176                    ;; Perhaps somewhat surprisingly, ANSI specifies
177                    ;; that (COERCE FOO 'FLOAT) is a SINGLE-FLOAT, not
178                    ;; dispatching on *READ-DEFAULT-FLOAT-FORMAT*.  By
179                    ;; analogy, we do the same for complex numbers. --
180                    ;; CSR, 2002-08-06
181                    (complex (%single-float object)))
182                   ((csubtypep type (specifier-type 'complex))
183                    (complex object))
184                   (t
185                    (coerce-error)))))
186            ;; If RES has the wrong type, that means that rule of canonical
187            ;; representation for complex rationals was invoked. According to
188            ;; the Hyperspec, (coerce 7/2 'complex) returns 7/2. Thus, if the
189            ;; object was a rational, there is no error here.
190            (unless (or (typep res output-type-spec) (rationalp object))
191              (coerce-error))
192            res))
193         ((csubtypep type (specifier-type 'list))
194          (if (vectorp object)
195              (vector-to-list* object)
196              (coerce-error)))
197         ((csubtypep type (specifier-type 'vector))
198          (typecase object
199            (list (list-to-vector* object output-type-spec))
200            (vector (vector-to-vector* object output-type-spec))
201            (t
202             (coerce-error))))
203         (t
204          (coerce-error))))))
205
206 ;;; new version, which seems as though it should be better, but which
207 ;;; does not yet work
208 #+nil
209 (defun coerce (object output-type-spec)
210   #!+sb-doc
211   "Coerces the Object to an object of type Output-Type-Spec."
212   (flet ((coerce-error ()
213            (error 'simple-type-error
214                   :format-control "~S can't be converted to type ~S."
215                   :format-arguments (list object output-type-spec)))
216          (check-result (result)
217            #!+high-security (aver (typep result output-type-spec))
218            result))
219     (let ((type (specifier-type output-type-spec)))
220       (cond
221         ((%typep object output-type-spec)
222          object)
223         ((eq type *empty-type*)
224          (coerce-error))
225         ((csubtypep type (specifier-type 'character))
226          (character object))
227         ((csubtypep type (specifier-type 'function))
228          (coerce-to-fun object))
229         ((numberp object)
230          (let ((res
231                 (cond
232                   ((csubtypep type (specifier-type 'single-float))
233                    (%single-float object))
234                   ((csubtypep type (specifier-type 'double-float))
235                    (%double-float object))
236                   #!+long-float
237                   ((csubtypep type (specifier-type 'long-float))
238                    (%long-float object))
239                   ((csubtypep type (specifier-type 'float))
240                    (%single-float object))
241                   ((csubtypep type (specifier-type '(complex single-float)))
242                    (complex (%single-float (realpart object))
243                             (%single-float (imagpart object))))
244                   ((csubtypep type (specifier-type '(complex double-float)))
245                    (complex (%double-float (realpart object))
246                             (%double-float (imagpart object))))
247                   #!+long-float
248                   ((csubtypep type (specifier-type '(complex long-float)))
249                    (complex (%long-float (realpart object))
250                             (%long-float (imagpart object))))
251                   ((csubtypep type (specifier-type 'complex))
252                    (complex object))
253                   (t
254                    (coerce-error)))))
255            ;; If RES has the wrong type, that means that rule of
256            ;; canonical representation for complex rationals was
257            ;; invoked. According to the ANSI spec, (COERCE 7/2
258            ;; 'COMPLEX) returns 7/2. Thus, if the object was a
259            ;; rational, there is no error here.
260            (unless (or (typep res output-type-spec) (rationalp object))
261              (coerce-error))
262            res))
263         ((csubtypep type (specifier-type 'list))
264          (coerce-to-list object))
265         ((csubtypep type (specifier-type 'string))
266          (check-result (coerce-to-simple-string object)))
267         ((csubtypep type (specifier-type 'bit-vector))
268          (check-result (coerce-to-bit-vector object)))
269         ((csubtypep type (specifier-type 'vector))
270          (check-result (coerce-to-vector object output-type-spec)))
271         (t
272          (coerce-error))))))