0.9.3.32:
[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)
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        ((instance-lambda)
77         (deprecation-warning 'instance-lambda 'lambda)
78         (eval `(function ,object)))
79        (t
80         (error 'simple-type-error
81                :datum object
82                :expected-type '(or symbol
83                                    ;; KLUDGE: ANSI wants us to
84                                    ;; return a TYPE-ERROR here, and
85                                    ;; a TYPE-ERROR is supposed to
86                                    ;; describe the expected type,
87                                    ;; but it's not obvious how to
88                                    ;; describe the coerceable cons
89                                    ;; types, so we punt and just say
90                                    ;; CONS. -- WHN 20000503
91                                    cons)
92                :format-control "~S can't be coerced to a function."
93                :format-arguments (list object)))))))
94
95 (defun coerce-to-list (object)
96   (etypecase object
97     (vector (vector-to-list* object))))
98
99 (defun coerce-to-vector (object output-type-spec)
100   (etypecase object
101     (list (list-to-vector* object output-type-spec))
102     (vector (vector-to-vector* object output-type-spec))))
103
104 ;;; old working version
105 (defun coerce (object output-type-spec)
106   #!+sb-doc
107   "Coerce the Object to an object of type Output-Type-Spec."
108   (flet ((coerce-error ()
109            (/show0 "entering COERCE-ERROR")
110            (error 'simple-type-error
111                   :format-control "~S can't be converted to type ~S."
112                   :format-arguments (list object output-type-spec)
113                   :datum object
114                   :expected-type output-type-spec)))
115     (let ((type (specifier-type output-type-spec)))
116       (cond
117         ((%typep object output-type-spec)
118          object)
119         ((eq type *empty-type*)
120          (coerce-error))
121         ((csubtypep type (specifier-type 'character))
122          (character object))
123         ((csubtypep type (specifier-type 'function))
124          (when (and (legal-fun-name-p object)
125                     (not (fboundp object)))
126            (error 'simple-type-error
127                   :datum object
128                   ;; FIXME: SATISFIES FBOUNDP is a kinda bizarre broken
129                   ;; type specifier, since the set of values it describes
130                   ;; isn't in general constant in time. Maybe we could
131                   ;; find a better way of expressing this error? (Maybe
132                   ;; with the UNDEFINED-FUNCTION condition?)
133                   :expected-type '(satisfies fboundp)
134                :format-control "~S isn't fbound."
135                :format-arguments (list object)))
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          (when (and (symbolp object)
144                     (special-operator-p object))
145            (error 'simple-type-error
146                   :datum object
147                   :expected-type '(not (satisfies special-operator-p))
148                   :format-control "~S is a special operator."
149                   :format-arguments (list object)))
150          (eval `#',object))
151         ((numberp object)
152          (cond
153            ((csubtypep type (specifier-type 'single-float))
154             (let ((res (%single-float object)))
155               (unless (typep res output-type-spec)
156                 (coerce-error))
157               res))
158            ((csubtypep type (specifier-type 'double-float))
159             (let ((res (%double-float object)))
160               (unless (typep res output-type-spec)
161                 (coerce-error))
162               res))
163            #!+long-float
164            ((csubtypep type (specifier-type 'long-float))
165             (let ((res (%long-float object)))
166               (unless (typep res output-type-spec)
167                 (coerce-error))
168               res))
169            ((csubtypep type (specifier-type 'float))
170             (let ((res (%single-float object)))
171               (unless (typep res output-type-spec)
172                 (coerce-error))
173               res))
174            (t
175             (let ((res
176                    (cond
177                      ((csubtypep type (specifier-type '(complex single-float)))
178                       (complex (%single-float (realpart object))
179                                (%single-float (imagpart object))))
180                      ((csubtypep type (specifier-type '(complex double-float)))
181                       (complex (%double-float (realpart object))
182                                (%double-float (imagpart object))))
183                      #!+long-float
184                      ((csubtypep type (specifier-type '(complex long-float)))
185                       (complex (%long-float (realpart object))
186                                (%long-float (imagpart object))))
187                      ((csubtypep type (specifier-type '(complex float)))
188                       (complex (%single-float (realpart object))
189                                (%single-float (imagpart object))))
190                      ((and (typep object 'rational)
191                            (csubtypep type (specifier-type '(complex float))))
192                       ;; Perhaps somewhat surprisingly, ANSI specifies
193                       ;; that (COERCE FOO 'FLOAT) is a SINGLE-FLOAT,
194                       ;; not dispatching on
195                       ;; *READ-DEFAULT-FLOAT-FORMAT*.  By analogy, we
196                       ;; do the same for complex numbers. -- CSR,
197                       ;; 2002-08-06
198                       (complex (%single-float object)))
199                      ((csubtypep type (specifier-type 'complex))
200                       (complex object))
201                      (t
202                       (coerce-error)))))
203               ;; If RES has the wrong type, that means that rule of
204               ;; canonical representation for complex rationals was
205               ;; invoked. According to the Hyperspec, (coerce 7/2
206               ;; 'complex) returns 7/2. Thus, if the object was a
207               ;; rational, there is no error here.
208               (unless (or (typep res output-type-spec)
209                           (rationalp object))
210                 (coerce-error))
211               res))))
212         ((csubtypep type (specifier-type 'list))
213          (if (vectorp object)
214              (cond
215                ((type= type (specifier-type 'list))
216                 (vector-to-list* object))
217                ((type= type (specifier-type 'null))
218                 (if (= (length object) 0)
219                     'nil
220                     (sequence-type-length-mismatch-error type
221                                                          (length object))))
222                ((cons-type-p type)
223                 (multiple-value-bind (min exactp)
224                     (sb!kernel::cons-type-length-info type)
225                   (let ((length (length object)))
226                     (if exactp
227                         (unless (= length min)
228                           (sequence-type-length-mismatch-error type length))
229                         (unless (>= length min)
230                           (sequence-type-length-mismatch-error type length)))
231                     (vector-to-list* object))))
232                (t (sequence-type-too-hairy (type-specifier type))))
233              (coerce-error)))
234         ((csubtypep type (specifier-type 'vector))
235          (typecase object
236            ;; FOO-TO-VECTOR* go through MAKE-SEQUENCE, so length
237            ;; errors are caught there. -- CSR, 2002-10-18
238            (list (list-to-vector* object output-type-spec))
239            (vector (vector-to-vector* object output-type-spec))
240            (t
241             (coerce-error))))
242         (t
243          (coerce-error))))))
244
245 ;;; new version, which seems as though it should be better, but which
246 ;;; does not yet work
247 #+nil
248 (defun coerce (object output-type-spec)
249   #!+sb-doc
250   "Coerces the Object to an object of type Output-Type-Spec."
251   (flet ((coerce-error ()
252            (error 'simple-type-error
253                   :format-control "~S can't be converted to type ~S."
254                   :format-arguments (list object output-type-spec)))
255          (check-result (result)
256            #!+high-security (aver (typep result output-type-spec))
257            result))
258     (let ((type (specifier-type output-type-spec)))
259       (cond
260         ((%typep object output-type-spec)
261          object)
262         ((eq type *empty-type*)
263          (coerce-error))
264         ((csubtypep type (specifier-type 'character))
265          (character object))
266         ((csubtypep type (specifier-type 'function))
267          (coerce-to-fun object))
268         ((numberp object)
269          (let ((res
270                 (cond
271                   ((csubtypep type (specifier-type 'single-float))
272                    (%single-float object))
273                   ((csubtypep type (specifier-type 'double-float))
274                    (%double-float object))
275                   #!+long-float
276                   ((csubtypep type (specifier-type 'long-float))
277                    (%long-float object))
278                   ((csubtypep type (specifier-type 'float))
279                    (%single-float object))
280                   ((csubtypep type (specifier-type '(complex single-float)))
281                    (complex (%single-float (realpart object))
282                             (%single-float (imagpart object))))
283                   ((csubtypep type (specifier-type '(complex double-float)))
284                    (complex (%double-float (realpart object))
285                             (%double-float (imagpart object))))
286                   #!+long-float
287                   ((csubtypep type (specifier-type '(complex long-float)))
288                    (complex (%long-float (realpart object))
289                             (%long-float (imagpart object))))
290                   ((csubtypep type (specifier-type 'complex))
291                    (complex object))
292                   (t
293                    (coerce-error)))))
294            ;; If RES has the wrong type, that means that rule of
295            ;; canonical representation for complex rationals was
296            ;; invoked. According to the ANSI spec, (COERCE 7/2
297            ;; 'COMPLEX) returns 7/2. Thus, if the object was a
298            ;; rational, there is no error here.
299            (unless (or (typep res output-type-spec) (rationalp object))
300              (coerce-error))
301            res))
302         ((csubtypep type (specifier-type 'list))
303          (coerce-to-list object))
304         ((csubtypep type (specifier-type 'string))
305          (check-result (coerce-to-simple-string object)))
306         ((csubtypep type (specifier-type 'bit-vector))
307          (check-result (coerce-to-bit-vector object)))
308         ((csubtypep type (specifier-type 'vector))
309          (check-result (coerce-to-vector object output-type-spec)))
310         (t
311          (coerce-error))))))