(defvar *print-readably* nil
#!+sb-doc
- "If true, all objects will printed readably. If readable printing is
- impossible, an error will be signalled. This overrides the value of
+ "If true, all objects will be printed readably. If readable printing
+ is impossible, an error will be signalled. This overrides the value of
*PRINT-ESCAPE*.")
(defvar *print-escape* t
#!+sb-doc
"Should pretty printing be used?")
(defvar *print-base* 10.
#!+sb-doc
- "the output base for RATIONALs (including integers)")
+ "The output base for RATIONALs (including integers).")
(defvar *print-radix* nil
#!+sb-doc
"Should base be verified when printing RATIONALs?")
"Should #: prefixes be used when printing symbols with null SYMBOL-PACKAGE?")
(defvar *print-lines* nil
#!+sb-doc
- "the maximum number of lines to print per object")
+ "The maximum number of lines to print per object.")
(defvar *print-right-margin* nil
#!+sb-doc
- "the position of the right margin in ems (for pretty-printing)")
+ "The position of the right margin in ems (for pretty-printing).")
(defvar *print-miser-width* nil
#!+sb-doc
"If the remaining space between the current column and the right margin
(defvar *print-pprint-dispatch*)
#!+sb-doc
(setf (fdocumentation '*print-pprint-dispatch* 'variable)
- "the pprint-dispatch-table that controls how to pretty-print objects")
+ "The pprint-dispatch-table that controls how to pretty-print objects.")
(defmacro with-standard-io-syntax (&body body)
#!+sb-doc
((:pprint-dispatch *print-pprint-dispatch*)
*print-pprint-dispatch*))
#!+sb-doc
- "Output OBJECT to the specified stream, defaulting to *STANDARD-OUTPUT*"
+ "Output OBJECT to the specified stream, defaulting to *STANDARD-OUTPUT*."
(output-object object (out-synonym-of stream))
object)
(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
(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)
\f
;;;; support for the PRINT-UNREADABLE-OBJECT macro
+(defun read-unreadable-replacement ()
+ (format *query-io* "~@<Enter an object (evaluated): ~@:>")
+ (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
:level nil :length nil)
- (write-char #\space stream))
+ (write-char #\space stream)
+ (pprint-newline :fill stream))
(when body
- (pprint-newline :fill stream)
(funcall body))
(when identity
(when (or body (not type))
(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)
(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))
(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))
;; 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
(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)
(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)