(funcall (formatter "~:<~^~W~^~3I ~_~W~^ ~_~W~^~1I~@{ ~_~W~}~:>")
stream list))
+(defun pprint-prog2 (stream list &rest noise)
+ (declare (ignore noise))
+ (funcall (formatter "~:<~^~W~^~3I ~:_~W~^ ~_~W~^~1I~@{ ~_~W~}~:>")
+ stream list))
+
(defun pprint-quote (stream list &rest noise)
(declare (ignore noise))
(if (and (consp list)
:for :while :until :repeat :always :never :thereis
))
+(defun pprint-extended-loop-clauses (stream clauses)
+ (pprint-logical-block (stream clauses :prefix "" :suffix "")
+ (output-object (pprint-pop) stream)
+ (pprint-exit-if-list-exhausted)
+ (write-char #\space stream)
+ (loop for thing = (pprint-pop)
+ when (and (symbolp thing)
+ (member thing *loop-seperating-clauses* :test #'string=))
+ do (pprint-newline :mandatory stream)
+ do (output-object thing stream)
+ do (pprint-exit-if-list-exhausted)
+ do (write-char #\space stream))))
+
+(defun pprint-simple-loop-clauses (stream clauses)
+ (pprint-logical-block (stream clauses :prefix "" :suffix "")
+ (output-object (pprint-pop) stream)
+ (pprint-exit-if-list-exhausted)
+ (write-char #\space stream)
+ (loop for thing = (pprint-pop) do
+ (when (consp thing)
+ (pprint-newline :mandatory stream))
+ (output-object thing stream)
+ (pprint-exit-if-list-exhausted)
+ (write-char #\space stream))))
+
(defun pprint-loop (stream list &rest noise)
(declare (ignore noise))
(destructuring-bind (loop-symbol . clauses) list
(write-char #\( stream)
(output-object loop-symbol stream)
- (when clauses
- (write-char #\space stream)
- (pprint-logical-block (stream clauses :prefix "" :suffix "")
- (output-object (pprint-pop) stream)
- (pprint-exit-if-list-exhausted)
- (write-char #\space stream)
- (loop for thing = (pprint-pop)
- when (and (symbolp thing)
- (member thing *loop-seperating-clauses* :test #'string=))
- do (pprint-newline :mandatory stream)
- do (output-object thing stream)
- do (pprint-exit-if-list-exhausted)
- do (write-char #\space stream))))
+ (cond ((null clauses))
+ ((symbolp (car clauses))
+ (write-char #\space stream)
+ (pprint-extended-loop-clauses stream clauses))
+ (t
+ (write-char #\space stream)
+ (pprint-simple-loop-clauses stream clauses)))
(write-char #\) stream)))
+(defun pprint-if (stream list &rest noise)
+ (declare (ignore noise))
+ ;; Indent after the ``predicate'' form, and the ``then'' form.
+ (funcall (formatter "~:<~^~W~^ ~:_~:I~W~^ ~:@_~:I~@{~W~^ ~:@_~}~:>")
+ stream
+ list))
+
(defun pprint-fun-call (stream list &rest noise)
(declare (ignore noise))
(funcall (formatter "~:<~^~W~^ ~:_~:I~@{~W~^ ~:_~}~:>")
(defun pprint-data-list (stream list &rest noise)
(declare (ignore noise))
(funcall (formatter "~:<~@{~W~^ ~:_~}~:>") stream list))
+
+;;; Returns an Emacs-style indent spec: an integer N, meaning indent
+;;; the first N arguments specially then indent any further arguments
+;;; like a body.
+(defun macro-indentation (name)
+ (labels ((proper-list-p (list)
+ (not (nth-value 1 (ignore-errors (list-length list)))))
+ (macro-arglist (name)
+ (%simple-fun-arglist (macro-function name)))
+ (clean-arglist (arglist)
+ "Remove &whole, &enviroment, and &aux elements from ARGLIST."
+ (cond ((null arglist) '())
+ ((member (car arglist) '(&whole &environment))
+ (clean-arglist (cddr arglist)))
+ ((eq (car arglist) '&aux)
+ '())
+ (t (cons (car arglist) (clean-arglist (cdr arglist)))))))
+ (let ((arglist (macro-arglist name)))
+ (if (proper-list-p arglist) ; guard against dotted arglists
+ (position '&body (remove '&optional (clean-arglist arglist)))
+ nil))))
+
+;;; Pretty-Print macros by looking where &BODY appears in a macro's
+;;; lambda-list.
+(defun pprint-macro-call (stream list &rest noise)
+ (declare (ignore noise))
+ (let ((indentation (and (car list) (macro-indentation (car list)))))
+ (unless indentation
+ (return-from pprint-macro-call
+ (pprint-fun-call stream list)))
+ (pprint-logical-block (stream list :prefix "(" :suffix ")")
+ (output-object (pprint-pop) stream)
+ (pprint-exit-if-list-exhausted)
+ (write-char #\space stream)
+ (loop for indent from 0 below indentation do
+ (cond
+ ;; Place the very first argument next to the macro name
+ ((zerop indent)
+ (output-object (pprint-pop) stream)
+ (pprint-exit-if-list-exhausted))
+ ;; Indent any other non-body argument by the same
+ ;; amount. It's what Emacs seems to do, too.
+ (t
+ (pprint-indent :block 3 stream)
+ (pprint-newline :mandatory stream)
+ (output-object (pprint-pop) stream)
+ (pprint-exit-if-list-exhausted))))
+ ;; Indent back for the body.
+ (pprint-indent :block 1 stream)
+ (pprint-newline :mandatory stream)
+ (loop
+ (output-object (pprint-pop) stream)
+ (pprint-exit-if-list-exhausted)
+ (pprint-newline :mandatory stream)))))
\f
;;;; the interface seen by regular (ugly) printer and initialization routines
;; printing the object after all.
(output-ugly-object object stream))))
+(defun mboundp (name)
+ (and (fboundp name) (macro-function name) t))
+
(defun !pprint-cold-init ()
(/show0 "entering !PPRINT-COLD-INIT")
(setf *initial-pprint-dispatch* (make-pprint-dispatch-table))
;; printers for regular types
(/show0 "doing SET-PPRINT-DISPATCH for regular types")
(set-pprint-dispatch 'array #'pprint-array)
+ (set-pprint-dispatch '(cons (and symbol (satisfies mboundp)))
+ #'pprint-macro-call -1)
(set-pprint-dispatch '(cons (and symbol (satisfies fboundp)))
#'pprint-fun-call -1)
(set-pprint-dispatch '(cons symbol)
(tagbody pprint-tagbody)
(throw pprint-block)
(unwind-protect pprint-block)
+ (if pprint-if)
;; macros
(case pprint-case)
#+nil (handler-bind ...)
#+nil (handler-case ...)
(loop pprint-loop)
- (multiple-value-bind pprint-progv)
+ (multiple-value-bind pprint-prog2)
(multiple-value-setq pprint-block)
(pprint-logical-block pprint-block)
(print-unreadable-object pprint-block)
(prog pprint-prog)
(prog* pprint-prog)
(prog1 pprint-block)
- (prog2 pprint-progv)
+ (prog2 pprint-prog2)
(psetf pprint-setq)
(psetq pprint-setq)
#+nil (restart-bind ...)