X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fcode%2Fprint.lisp;h=b0a4e72b31441a6dc4a17f10ec1c425a3a120f86;hb=6caf3ed5713773cb423f46bf40a29f2438c97c78;hp=4676332e4926834faa0a04c4bbb000496fa865a7;hpb=425ce8cf75122dfb7242ffbf5d726e12fae24e58;p=sbcl.git diff --git a/src/code/print.lisp b/src/code/print.lisp index 4676332..b0a4e72 100644 --- a/src/code/print.lisp +++ b/src/code/print.lisp @@ -193,9 +193,11 @@ (push (list variable value) bind))) (unless (assoc 'stream bind) (push (list 'stream '*standard-output*) bind)) - `(let ,(nreverse bind) - ,@(when ignore `((declare (ignore ,@ignore)))) - (output-object ,object stream)))) + (once-only ((object object)) + `(let ,(nreverse bind) + ,@(when ignore `((declare (ignore ,@ignore)))) + (output-object ,object (out-synonym-of stream)) + ,object)))) (defun prin1 (object &optional stream) #!+sb-doc @@ -275,9 +277,10 @@ (push variable ignore)) (push (list variable value) bind))) (if bind - `(let ,(nreverse bind) - ,@(when ignore `((declare (ignore ,@ignore)))) - (stringify-object ,object)) + (once-only ((object object)) + `(let ,(nreverse bind) + ,@(when ignore `((declare (ignore ,@ignore)))) + (stringify-object ,object))) `(stringify-object ,object)))) (defun prin1-to-string (object) @@ -305,11 +308,24 @@ ;;;; support for the PRINT-UNREADABLE-OBJECT macro +(defun read-unreadable-replacement () + (format *query-io* "~@") + (finish-output *query-io*) + (list (eval (read *query-io*)))) + ;;; guts of PRINT-UNREADABLE-OBJECT (defun %print-unreadable-object (object stream type identity body) (declare (type (or null function) body)) (when *print-readably* - (error 'print-not-readable :object object)) + (restart-case + (error 'print-not-readable :object object) + (print-unreadably () + :report "Print unreadably.") + (use-value (o) + :report "Supply an object to be printed instead." + :interactive read-unreadable-replacement + (write o :stream stream) + (return-from %print-unreadable-object nil)))) (flet ((print-description () (when type (write (type-of object) :stream stream :circle nil @@ -938,7 +954,16 @@ (load-time-value (array-element-type (make-array 0 :element-type 'character)))))) - (error 'print-not-readable :object vector)) + (restart-case + (error 'print-not-readable :object vector) + (print-unreadably () + :report "Print unreadably." + (let ((*print-readably* nil)) + (output-vector vector stream))) + (use-value (o) + :report "Supply an object to be printed instead." + :interactive read-unreadable-replacement + (write o :stream stream)))) ((or *print-escape* *print-readably*) (write-char #\" stream) (quote-string vector stream) @@ -956,7 +981,14 @@ (t (when (and *print-readably* (not (array-readably-printable-p vector))) - (error 'print-not-readable :object vector)) + (restart-case + (error 'print-not-readable :object vector) + (print-unreadably () + :report "Print unreadably.") + (use-value (o) + :report "Supply an object to be printed instead." + :interactive read-unreadable-replacement + (return-from output-vector (write o :stream stream))))) (descend-into (stream) (write-string "#(" stream) (dotimes (i (length vector)) @@ -1008,7 +1040,14 @@ (defun output-array-guts (array stream) (when (and *print-readably* (not (array-readably-printable-p array))) - (error 'print-not-readable :object array)) + (restart-case + (error 'print-not-readable :object array) + (print-unreadably () + :report "Print unreadably.") + (use-value (o) + :report "Supply an object to be printed instead." + :interactive read-unreadable-replacement + (return-from output-array-guts (write o :stream stream))))) (write-char #\# stream) (let ((*print-base* 10) (*print-radix* nil)) @@ -1274,71 +1313,68 @@ ;; FIXME: I think only FORMAT-DOLLARS calls FLONUM-TO-STRING with ;; possibly-negative X. (setf x (abs x)) - (cond ((zerop x) - ;; Zero is a special case which FLOAT-STRING cannot handle. - (if fdigits - (let ((s (make-string (1+ fdigits) :initial-element #\0))) - (setf (schar s 0) #\.) - (values s (length s) t (zerop fdigits) 0)) - (values "." 1 t t 0))) - (t - (multiple-value-bind (e string) - (if fdigits - (flonum-to-digits x (min (- (+ fdigits (or scale 0))) - (- (or fmin 0)))) - (if (and width (> width 1)) - (let ((w (multiple-value-list - (flonum-to-digits x - (max 1 - (+ (1- width) - (if (and scale (minusp scale)) - scale 0))) - t))) - (f (multiple-value-list - (flonum-to-digits x (- (+ (or fmin 0) - (if scale scale 0))))))) - (cond - ((>= (length (cadr w)) (length (cadr f))) - (values-list w)) - (t (values-list f)))) - (flonum-to-digits x))) - (let ((e (+ e (or scale 0))) - (stream (make-string-output-stream))) - (if (plusp e) - (progn - (write-string string stream :end (min (length string) - e)) - (dotimes (i (- e (length string))) - (write-char #\0 stream)) - (write-char #\. stream) - (write-string string stream :start (min (length - string) e)) - (when fdigits - (dotimes (i (- fdigits - (- (length string) - (min (length string) e)))) - (write-char #\0 stream)))) - (progn - (write-string "." stream) - (dotimes (i (- e)) - (write-char #\0 stream)) - (write-string string stream) - (when fdigits - (dotimes (i (+ fdigits e (- (length string)))) - (write-char #\0 stream))))) - (let ((string (get-output-stream-string stream))) - (values string (length string) - (char= (char string 0) #\.) - (char= (char string (1- (length string))) #\.) - (position #\. string)))))))) - -;;; implementation of figure 1 from Burger and Dybvig, 1996. As the -;;; implementation of the Dragon from Classic CMUCL (and previously in -;;; SBCL above FLONUM-TO-STRING) says: "DO NOT EVEN THINK OF -;;; ATTEMPTING TO UNDERSTAND THIS CODE WITHOUT READING THE PAPER!", -;;; and in this case we have to add that even reading the paper might -;;; not bring immediate illumination as CSR has attempted to turn -;;; idiomatic Scheme into idiomatic Lisp. + (multiple-value-bind (e string) + (if fdigits + (flonum-to-digits x (min (- (+ fdigits (or scale 0))) + (- (or fmin 0)))) + (if (and width (> width 1)) + (let ((w (multiple-value-list + (flonum-to-digits x + (max 1 + (+ (1- width) + (if (and scale (minusp scale)) + scale 0))) + t))) + (f (multiple-value-list + (flonum-to-digits x (- (+ (or fmin 0) + (if scale scale 0))))))) + (cond + ((>= (length (cadr w)) (length (cadr f))) + (values-list w)) + (t (values-list f)))) + (flonum-to-digits x))) + (let ((e (if (zerop x) + e + (+ e (or scale 0)))) + (stream (make-string-output-stream))) + (if (plusp e) + (progn + (write-string string stream :end (min (length string) e)) + (dotimes (i (- e (length string))) + (write-char #\0 stream)) + (write-char #\. stream) + (write-string string stream :start (min (length string) e)) + (when fdigits + (dotimes (i (- fdigits + (- (length string) + (min (length string) e)))) + (write-char #\0 stream)))) + (progn + (write-string "." stream) + (dotimes (i (- e)) + (write-char #\0 stream)) + (write-string string stream :end (when fdigits + (min (length string) + (max (or fmin 0) + (+ fdigits e))))) + (when fdigits + (dotimes (i (+ fdigits e (- (length string)))) + (write-char #\0 stream))))) + (let ((string (get-output-stream-string stream))) + (values string (length string) + (char= (char string 0) #\.) + (char= (char string (1- (length string))) #\.) + (position #\. string)))))) + +;;; implementation of figure 1 from Burger and Dybvig, 1996. It is +;;; extended in order to handle rounding. +;;; +;;; As the implementation of the Dragon from Classic CMUCL (and +;;; previously in SBCL above FLONUM-TO-STRING) says: "DO NOT EVEN +;;; THINK OF ATTEMPTING TO UNDERSTAND THIS CODE WITHOUT READING THE +;;; PAPER!", and in this case we have to add that even reading the +;;; paper might not bring immediate illumination as CSR has attempted +;;; to turn idiomatic Scheme into idiomatic Lisp. ;;; ;;; FIXME: figure 1 from Burger and Dybvig is the unoptimized ;;; algorithm, noticeably slow at finding the exponent. Figure 2 has @@ -1381,9 +1417,10 @@ (r r (* r print-base)) (m+ m+ (* m+ print-base)) (m- m- (* m- print-base))) - ((not (or (< (* (+ r m+) print-base) s) - (and (not high-ok) - (= (* (+ r m+) print-base) s)))) + ((not (and (plusp (- r m-)) ; Extension to handle zero + (or (< (* (+ r m+) print-base) s) + (and (not high-ok) + (= (* (+ r m+) print-base) s))))) (values k (generate r s m+ m-))))))) (generate (r s m+ m-) (let (d tc1 tc2) @@ -1559,7 +1596,16 @@ (cond (*read-eval* (write-string "#." stream)) (*print-readably* - (error 'print-not-readable :object x)) + (restart-case + (error 'print-not-readable :object x) + (print-unreadably () + :report "Print unreadably." + (let ((*print-readably* nil)) + (output-float-infinity x stream))) + (use-value (o) + :report "Supply an object to be printed instead." + :interactive read-unreadable-replacement + (write o :stream stream)))) (t (write-string "#<" stream))) (write-string "SB-EXT:" stream)