0.7.7.40:
[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-simple-string* (make-string length) schar :list)
31
32   (def list-to-bit-vector* (make-array length :element-type '(mod 2))
33     sbit :list)
34
35   (def list-to-vector* (make-sequence-of-type type length)
36     aref :list t)
37
38   (def vector-to-vector* (make-sequence-of-type type length)
39     aref :vector t)
40
41   (def vector-to-simple-string* (make-string length) schar :vector)
42
43   (def vector-to-bit-vector* (make-array length :element-type '(mod 2))
44     sbit :vector))
45
46 (defun vector-to-list* (object)
47   (let ((result (list nil))
48         (length (length object)))
49     (declare (fixnum length))
50     (do ((index 0 (1+ index))
51          (splice result (cdr splice)))
52         ((= index length) (cdr result))
53       (declare (fixnum index))
54       (rplacd splice (list (aref object index))))))
55
56 (defun string-to-simple-string* (object)
57   (if (simple-string-p object)
58       object
59       (with-array-data ((data object)
60                         (start)
61                         (end (length object)))
62         (declare (simple-string data))
63         (subseq data start end))))
64
65 (defun bit-vector-to-simple-bit-vector* (object)
66   (if (simple-bit-vector-p object)
67       object
68       (with-array-data ((data object)
69                         (start)
70                         (end (length object)))
71         (declare (simple-bit-vector data))
72         (subseq data start end))))
73
74 (defvar *offending-datum*); FIXME: Remove after debugging COERCE.
75
76 ;;; These are used both by the full DEFUN function and by various
77 ;;; optimization transforms in the constant-OUTPUT-TYPE-SPEC case.
78 ;;;
79 ;;; Most of them are INLINE so that they can be optimized when the
80 ;;; argument type is known. It might be better to do this with
81 ;;; DEFTRANSFORMs, though.
82 (declaim (inline coerce-to-list))
83 (declaim (inline coerce-to-simple-string coerce-to-bit-vector coerce-to-vector))
84 (defun coerce-to-fun (object)
85   ;; (Unlike the other COERCE-TO-FOOs, this one isn't inline, because
86   ;; it's so big and because optimizing away the outer ETYPECASE
87   ;; doesn't seem to buy us that much anyway.)
88   (etypecase object
89     (symbol
90      ;; ANSI lets us return ordinary errors (non-TYPE-ERRORs) here.
91      (cond ((macro-function object)
92             (error "~S names a macro." object))
93            ((special-operator-p object)
94             (error "~S is a special operator." object))
95            (t (fdefinition object))))
96     (list
97      (case (first object)
98        ((setf)
99         (fdefinition object))
100        ((lambda instance-lambda)
101         ;; FIXME: If we go to a compiler-only implementation, this can
102         ;; become COMPILE instead of EVAL, which seems nicer to me.
103         (eval `(function ,object)))
104        (t
105         (error 'simple-type-error
106                :datum object
107                :expected-type '(or symbol
108                                    ;; KLUDGE: ANSI wants us to
109                                    ;; return a TYPE-ERROR here, and
110                                    ;; a TYPE-ERROR is supposed to
111                                    ;; describe the expected type,
112                                    ;; but it's not obvious how to
113                                    ;; describe the coerceable cons
114                                    ;; types, so we punt and just say
115                                    ;; CONS. -- WHN 20000503
116                                    cons)
117                :format-control "~S can't be coerced to a function."
118                :format-arguments (list object)))))))
119 (defun coerce-to-list (object)
120   (etypecase object
121     (vector (vector-to-list* object))))
122 (defun coerce-to-simple-string (object)
123   (etypecase object
124     (list (list-to-simple-string* object))
125     (string (string-to-simple-string* object))
126     (vector (vector-to-simple-string* object))))
127 (defun coerce-to-bit-vector (object)
128   (etypecase object
129     (list (list-to-bit-vector* object))
130     (vector (vector-to-bit-vector* object))))
131 (defun coerce-to-simple-vector (x)
132   (if (simple-vector-p x)
133       x
134       (replace (make-array (length x)) x)))
135 (defun coerce-to-vector (object output-type-spec)
136   (etypecase object
137     (list (list-to-vector* object output-type-spec))
138     (vector (vector-to-vector* object output-type-spec))))
139
140 ;;; old working version
141 (defun coerce (object output-type-spec)
142   #!+sb-doc
143   "Coerce the Object to an object of type Output-Type-Spec."
144   (flet ((coerce-error ()
145            (/show0 "entering COERCE-ERROR")
146            (error 'simple-type-error
147                   :format-control "~S can't be converted to type ~S."
148                   :format-arguments (list object output-type-spec)))
149          (check-result (result)
150            #!+high-security (aver (typep result output-type-spec))
151            result))
152     (let ((type (specifier-type output-type-spec)))
153       (cond
154         ((%typep object output-type-spec)
155          object)
156         ((eq type *empty-type*)
157          (coerce-error))
158         ((csubtypep type (specifier-type 'character))
159          (character object))
160         ((csubtypep type (specifier-type 'function))
161          #!+high-security
162          (when (and (or (symbolp object)
163                         (and (listp object)
164                              (= (length object) 2)
165                              (eq (car object) 'setf)))
166                     (not (fboundp object)))
167            (error 'simple-type-error
168                   :datum object
169                   ;; FIXME: SATISFIES FBOUNDP is a kinda bizarre broken
170                   ;; type specifier, since the set of values it describes
171                   ;; isn't in general constant in time. Maybe we could
172                   ;; find a better way of expressing this error? (Maybe
173                   ;; with the UNDEFINED-FUNCTION condition?)
174                   :expected-type '(satisfies fboundp)
175                :format-control "~S isn't fbound."
176                :format-arguments (list object)))
177          #!+high-security
178          (when (and (symbolp object)
179                     (sb!xc:macro-function object))
180            (error 'simple-type-error
181                   :datum object
182                   :expected-type '(not (satisfies sb!xc:macro-function))
183                   :format-control "~S is a macro."
184                   :format-arguments (list object)))
185          #!+high-security
186          (when (and (symbolp object)
187                     (special-operator-p object))
188            (error 'simple-type-error
189                   :datum object
190                   :expected-type '(not (satisfies special-operator-p))
191                   :format-control "~S is a special operator."
192                   :format-arguments (list object)))
193          (eval `#',object))
194         ((numberp object)
195          (let ((res
196                 (cond
197                   ((csubtypep type (specifier-type 'single-float))
198                    (%single-float object))
199                   ((csubtypep type (specifier-type 'double-float))
200                    (%double-float object))
201                   #!+long-float
202                   ((csubtypep type (specifier-type 'long-float))
203                    (%long-float object))
204                   ((csubtypep type (specifier-type 'float))
205                    (%single-float object))
206                   ((csubtypep type (specifier-type '(complex single-float)))
207                    (complex (%single-float (realpart object))
208                             (%single-float (imagpart object))))
209                   ((csubtypep type (specifier-type '(complex double-float)))
210                    (complex (%double-float (realpart object))
211                             (%double-float (imagpart object))))
212                   #!+long-float
213                   ((csubtypep type (specifier-type '(complex long-float)))
214                    (complex (%long-float (realpart object))
215                             (%long-float (imagpart object))))
216                   ((and (typep object 'rational)
217                         (csubtypep type (specifier-type '(complex float))))
218                    ;; Perhaps somewhat surprisingly, ANSI specifies
219                    ;; that (COERCE FOO 'FLOAT) is a SINGLE-FLOAT, not
220                    ;; dispatching on *READ-DEFAULT-FLOAT-FORMAT*.  By
221                    ;; analogy, we do the same for complex numbers. --
222                    ;; CSR, 2002-08-06
223                    (complex (%single-float object)))
224                   ((csubtypep type (specifier-type 'complex))
225                    (complex object))
226                   (t
227                    (coerce-error)))))
228            ;; If RES has the wrong type, that means that rule of canonical
229            ;; representation for complex rationals was invoked. According to
230            ;; the Hyperspec, (coerce 7/2 'complex) returns 7/2. Thus, if the
231            ;; object was a rational, there is no error here.
232            (unless (or (typep res output-type-spec) (rationalp object))
233              (coerce-error))
234            res))
235         ((csubtypep type (specifier-type 'list))
236          (if (vectorp object)
237              (vector-to-list* object)
238              (coerce-error)))
239         ((csubtypep type (specifier-type 'string))
240          (check-result
241           (typecase object
242             (list (list-to-simple-string* object))
243             (string (string-to-simple-string* object))
244             (vector (vector-to-simple-string* object))
245             (t
246              (coerce-error)))))
247         ((csubtypep type (specifier-type 'bit-vector))
248          (check-result
249           (typecase object
250             (list (list-to-bit-vector* object))
251             (vector (vector-to-bit-vector* object))
252             (t
253              (coerce-error)))))
254         ((csubtypep type (specifier-type 'vector))
255          (check-result
256           (typecase object
257             (list (list-to-vector* object output-type-spec))
258             (vector (vector-to-vector* object output-type-spec))
259             (t
260              (coerce-error)))))
261         (t
262          (coerce-error))))))
263
264 ;;; new version, which seems as though it should be better, but which
265 ;;; does not yet work
266 #+nil
267 (defun coerce (object output-type-spec)
268   #!+sb-doc
269   "Coerces the Object to an object of type Output-Type-Spec."
270   (flet ((coerce-error ()
271            (error 'simple-type-error
272                   :format-control "~S can't be converted to type ~S."
273                   :format-arguments (list object output-type-spec)))
274          (check-result (result)
275            #!+high-security (aver (typep result output-type-spec))
276            result))
277     (let ((type (specifier-type output-type-spec)))
278       (cond
279         ((%typep object output-type-spec)
280          object)
281         ((eq type *empty-type*)
282          (coerce-error))
283         ((csubtypep type (specifier-type 'character))
284          (character object))
285         ((csubtypep type (specifier-type 'function))
286          (coerce-to-fun object))
287         ((numberp object)
288          (let ((res
289                 (cond
290                   ((csubtypep type (specifier-type 'single-float))
291                    (%single-float object))
292                   ((csubtypep type (specifier-type 'double-float))
293                    (%double-float object))
294                   #!+long-float
295                   ((csubtypep type (specifier-type 'long-float))
296                    (%long-float object))
297                   ((csubtypep type (specifier-type 'float))
298                    (%single-float object))
299                   ((csubtypep type (specifier-type '(complex single-float)))
300                    (complex (%single-float (realpart object))
301                             (%single-float (imagpart object))))
302                   ((csubtypep type (specifier-type '(complex double-float)))
303                    (complex (%double-float (realpart object))
304                             (%double-float (imagpart object))))
305                   #!+long-float
306                   ((csubtypep type (specifier-type '(complex long-float)))
307                    (complex (%long-float (realpart object))
308                             (%long-float (imagpart object))))
309                   ((csubtypep type (specifier-type 'complex))
310                    (complex object))
311                   (t
312                    (coerce-error)))))
313            ;; If RES has the wrong type, that means that rule of
314            ;; canonical representation for complex rationals was
315            ;; invoked. According to the ANSI spec, (COERCE 7/2
316            ;; 'COMPLEX) returns 7/2. Thus, if the object was a
317            ;; rational, there is no error here.
318            (unless (or (typep res output-type-spec) (rationalp object))
319              (coerce-error))
320            res))
321         ((csubtypep type (specifier-type 'list))
322          (coerce-to-list object))
323         ((csubtypep type (specifier-type 'string))
324          (check-result (coerce-to-simple-string object)))
325         ((csubtypep type (specifier-type 'bit-vector))
326          (check-result (coerce-to-bit-vector object)))
327         ((csubtypep type (specifier-type 'vector))
328          (check-result (coerce-to-vector object output-type-spec)))
329         (t
330          (coerce-error))))))