0.7.12.17:
[sbcl.git] / src / code / reader.lisp
index c97cae9..41226cb 100644 (file)
      RIGHTDIGIT ; saw "[sign] {digit}* dot {digit}+"
       (ouch-read-buffer char)
       (setq char (read-char stream nil nil))
-      (unless char (return (make-float)))
+      (unless char (return (make-float stream)))
       (case (char-class char attribute-table)
        (#.+char-attr-constituent-digit+ (go RIGHTDIGIT))
        (#.+char-attr-constituent-expt+ (go EXPONENT))
        (#.+char-attr-delimiter+
         (unread-char char stream)
-        (return (make-float)))
+        (return (make-float stream)))
        (#.+char-attr-escape+ (go ESCAPE))
        (#.+char-attr-multiple-escape+ (go MULT-ESCAPE))
        (#.+char-attr-package-delimiter+ (go COLON))
      EXPTDIGIT ; got to EXPONENT, saw "[sign] {digit}+"
       (ouch-read-buffer char)
       (setq char (read-char stream nil nil))
-      (unless char (return (make-float)))
+      (unless char (return (make-float stream)))
       (case (char-class char attribute-table)
        (#.+char-attr-constituent-digit+ (go EXPTDIGIT))
        (#.+char-attr-delimiter+
         (unread-char char stream)
-        (return (make-float)))
+        (return (make-float stream)))
        (#.+char-attr-escape+ (go ESCAPE))
        (#.+char-attr-multiple-escape+ (go MULT-ESCAPE))
        (#.+char-attr-package-delimiter+ (go COLON))
      RATIODIGIT ; saw "[sign] {digit}+ slash {digit}+"
       (ouch-read-buffer char)
       (setq char (read-char stream nil nil))
-      (unless char (return (make-ratio)))
+      (unless char (return (make-ratio stream)))
       (case (char-class2 char attribute-table)
        (#.+char-attr-constituent-digit+ (go RATIODIGIT))
        (#.+char-attr-delimiter+
         (unread-char char stream)
-        (return (make-ratio)))
+        (return (make-ratio stream)))
        (#.+char-attr-escape+ (go ESCAPE))
        (#.+char-attr-multiple-escape+ (go MULT-ESCAPE))
        (#.+char-attr-package-delimiter+ (go COLON))
                                 (the index (* num base))))))))
        (setq number (+ num (* number base-power)))))))
 
-(defun make-float ()
+(defun make-float (stream)
   ;; Assume that the contents of *read-buffer* are a legal float, with nothing
   ;; else after it.
   (read-unwind-read-buffer)
     (cond ((eofp char)
           ;; If not, we've read the whole number.
           (let ((num (make-float-aux number divisor
-                                     *read-default-float-format*)))
+                                     *read-default-float-format*
+                                     stream)))
             (return-from make-float (if negative-fraction (- num) num))))
          ((exponent-letterp char)
           (setq float-char char)
                                  (#\D 'double-float)
                                  (#\L 'long-float)))
                  num)
-            ;; toy@rtp.ericsson.se: We need to watch out if the
+            ;; Raymond Toy writes: We need to watch out if the
             ;; exponent is too small or too large. We add enough to
             ;; EXPONENT to make it within range and scale NUMBER
             ;; appropriately. This should avoid any unnecessary
             ;; underflow or overflow problems.
             (multiple-value-bind (min-expo max-expo)
-                ;; FIXME: These #. forms are broken w.r.t.
-                ;; cross-compilation portability. Maybe expressions
-                ;; like
-                ;;   (LOG SB!XC:MOST-POSITIVE-SHORT-FLOAT 10s0)
-                ;; could be used instead? Or perhaps some sort of
-                ;; load-time-form magic?
+                ;; FIXME: These forms are broken w.r.t.
+                ;; cross-compilation portability, as the
+                ;; cross-compiler will call the host's LOG function
+                ;; while attempting to constant-fold. Maybe some sort
+                ;; of load-time-form magic could be used instead?
                 (case float-format
                   (short-float
                    (values
-                    #.(log least-positive-normalized-short-float 10s0)
-                    #.(log most-positive-short-float 10s0)))
+                    (log sb!xc:least-positive-normalized-short-float 10s0)
+                    (log sb!xc:most-positive-short-float 10s0)))
                   (single-float
                    (values
-                    #.(log least-positive-normalized-single-float 10f0)
-                    #.(log most-positive-single-float 10f0)))
+                    (log sb!xc:least-positive-normalized-single-float 10f0)
+                    (log sb!xc:most-positive-single-float 10f0)))
                   (double-float
                    (values
-                    #.(log least-positive-normalized-double-float 10d0)
-                    #.(log most-positive-double-float 10d0)))
+                    (log sb!xc:least-positive-normalized-double-float 10d0)
+                    (log sb!xc:most-positive-double-float 10d0)))
                   (long-float
                    (values
-                    #.(log least-positive-normalized-long-float 10L0)
-                    #.(log most-positive-long-float 10L0))))
+                    (log sb!xc:least-positive-normalized-long-float 10L0)
+                    (log sb!xc:most-positive-long-float 10L0))))
               (let ((correction (cond ((<= exponent min-expo)
                                        (ceiling (- min-expo exponent)))
                                       ((>= exponent max-expo)
                                        0))))
                 (incf exponent correction)
                 (setf number (/ number (expt 10 correction)))
-                (setq num (make-float-aux number divisor float-format))
+                (setq num (make-float-aux number divisor float-format stream))
                 (setq num (* num (expt 10 exponent)))
                 (return-from make-float (if negative-fraction
                                             (- num)
          ;; should never happen
          (t (bug "bad fallthrough in floating point reader")))))
 
-(defun make-float-aux (number divisor float-format)
-  (coerce (/ number divisor) float-format))
+(defun make-float-aux (number divisor float-format stream)
+  (handler-case
+      (coerce (/ number divisor) float-format)
+    (type-error (c)
+      (error 'reader-impossible-number-error
+            :error c :stream stream
+            :format-control "failed to build float"))))
 
-(defun make-ratio ()
+(defun make-ratio (stream)
   ;; Assume *READ-BUFFER* contains a legal ratio. Build the number from
   ;; the string.
   ;;
          (dig ()))
         ((or (eofp ch) (not (setq dig (digit-char-p ch *read-base*)))))
         (setq denominator (+ (* denominator *read-base*) dig)))
-    (let ((num (/ numerator denominator)))
+    (let ((num (handler-case
+                  (/ numerator denominator)
+                (arithmetic-error (c)
+                  (error 'reader-impossible-number-error
+                         :error c :stream stream
+                         :format-control "failed to build ratio")))))
       (if negative-number (- num) num))))
 \f
 ;;;; cruft for dispatch macros
    and the lisp object built by the reader is returned. Macro chars
    will take effect."
   (declare (string string))
+  
   (with-array-data ((string string)
                    (start start)
-                   (end (or end (length string))))
+                   (end (%check-vector-sequence-bounds string start end)))
     (unless *read-from-string-spares*
       (push (internal-make-string-input-stream "" 0 0)
            *read-from-string-spares*))
   (default to the beginning and end of the string)  It skips over
   whitespace characters and then tries to parse an integer. The
   radix parameter must be between 2 and 36."
-  (with-array-data ((string string)
-                   (start start)
-                   (end (or end (length string))))
-    (let ((index (do ((i start (1+ i)))
-                    ((= i end)
-                     (if junk-allowed
-                         (return-from parse-integer (values nil end))
-                         (error "no non-whitespace characters in number")))
-                  (declare (fixnum i))
-                  (unless (whitespacep (char string i)) (return i))))
-         (minusp nil)
-         (found-digit nil)
-         (result 0))
-      (declare (fixnum index))
-      (let ((char (char string index)))
-       (cond ((char= char #\-)
-              (setq minusp t)
-              (incf index))
-             ((char= char #\+)
-              (incf index))))
-      (loop
-       (when (= index end) (return nil))
-       (let* ((char (char string index))
-              (weight (digit-char-p char radix)))
-         (cond (weight
-                (setq result (+ weight (* result radix))
-                      found-digit t))
-               (junk-allowed (return nil))
-               ((whitespacep char)
-                (do ((jndex (1+ index) (1+ jndex)))
-                    ((= jndex end))
-                  (declare (fixnum jndex))
-                  (unless (whitespacep (char string jndex))
-                    (error "junk in string ~S" string)))
-                (return nil))
-               (t
-                (error "junk in string ~S" string))))
-       (incf index))
-      (values
-       (if found-digit
-          (if minusp (- result) result)
-          (if junk-allowed
-              nil
-              (error "no digits in string ~S" string)))
-       index))))
+  (macrolet ((parse-error (format-control)
+              `(error 'simple-parse-error
+                      :format-control ,format-control
+                      :format-arguments (list string))))
+    (with-array-data ((string string)
+                     (start start)
+                     (end (%check-vector-sequence-bounds string start end)))
+      (let ((index (do ((i start (1+ i)))
+                      ((= i end)
+                       (if junk-allowed
+                           (return-from parse-integer (values nil end))
+                           (parse-error "no non-whitespace characters in string ~S.")))
+                    (declare (fixnum i))
+                    (unless (whitespacep (char string i)) (return i))))
+           (minusp nil)
+           (found-digit nil)
+           (result 0))
+       (declare (fixnum index))
+       (let ((char (char string index)))
+         (cond ((char= char #\-)
+                (setq minusp t)
+                (incf index))
+               ((char= char #\+)
+                (incf index))))
+       (loop
+        (when (= index end) (return nil))
+        (let* ((char (char string index))
+               (weight (digit-char-p char radix)))
+          (cond (weight
+                 (setq result (+ weight (* result radix))
+                       found-digit t))
+                (junk-allowed (return nil))
+                ((whitespacep char)
+                 (do ((jndex (1+ index) (1+ jndex)))
+                     ((= jndex end))
+                   (declare (fixnum jndex))
+                   (unless (whitespacep (char string jndex))
+                     (parse-error "junk in string ~S")))
+                 (return nil))
+                (t
+                 (parse-error "junk in string ~S"))))
+        (incf index))
+       (values
+        (if found-digit
+            (if minusp (- result) result)
+            (if junk-allowed
+                nil
+                (parse-error "no digits in string ~S")))
+        index)))))
 \f
 ;;;; reader initialization code