BSD 4_3 development
[unix-history] / usr / lib / lisp / pp.l
(setq rcs-pp-
"$Header: /usr/lib/lisp/RCS/pp.l,v 1.2 83/08/15 22:27:54 jkf Exp $")
;;
;; pp.l -[Mon Aug 15 10:52:13 1983 by jkf]-
;;
;; pretty printer for franz lisp
;;
(declare (macros t))
(declare (special poport pparm1 pparm2 lpar rpar form linel))
; (declare (localf $patom1 $prd1 $prdf charcnt condclosefile))
; =======================================
; pretty printer top level routine pp
;
;
; calling form- (pp arg1 arg2 ... argn)
; the args may be names of functions, atoms with associated values
; or output descriptors.
; if argi is:
; an atom - it is assumed to be a function name, if there is no
; function property associated with it,then it is assumed
; to be an atom with a value
; (P port)- port is the output port where the results of the
; pretty printing will be sent.
; poport is the default if no (P port) is given.
; (F fname)- fname is a file name to write the results in
; (A atmname) - means, treat this as an atom with a value, dont
; check if it is the name of a function.
; (E exp)- evaluate exp without printing anything
; other - pretty-print the expression as is - no longer an error
;
; Also, rather than printing only a function defn or only a value, we will
; let prettyprops decide which props to print. Finally, prettyprops will
; follow the CMULisp format where each element is either a property
; or a dotted pair of the form (prop . fn) where in order to print the
; given property we call (fn id val prop). The special properties
; function and value are used to denote those "properties" which
; do not actually appear on the plist.
;
; [history of this code: originally came from Harvard Lisp, hacked to
; work under franz at ucb, hacked to work at cmu and finally rehacked
; to work without special cmu macros]
(declare (special $outport$ $fileopen$ prettyprops))
(setq prettyprops '((comment . pp-comment)
(function . pp-function)
(value . pp-value)))
; printret is like print yet it returns the value printed, this is used
; by pp
(def printret
(macro ($l$)
`(progn (print ,@(cdr $l$)) ,(cadr $l$))))
(def pp
(nlambda ($xlist$)
(prog ($gcprint $outport$ $cur$ $fileopen$ $prl$ $atm$)
(setq $gcprint nil) ; don't print
; gc messages in pp.
(setq $outport$ poport) ; default port
; check if more to do, if not close output file if it is
; open and leave
toploop (cond ((null (setq $cur$ (car $xlist$)))
(condclosefile)
(terpr)
(return t)))
(cond ((dtpr $cur$)
(cond ((equal 'P (car $cur$)) ; specifying a port
(condclosefile) ; close file if open
(setq $outport$ (eval (cadr $cur$))))
((equal 'F (car $cur$)) ; specifying a file
(condclosefile) ; close file if open
(setq $outport$ (outfile (cadr $cur$))
$fileopen$ t))
((equal 'E (car $cur$))
(eval (cadr $cur$)))
(t (pp-form $cur$ $outport$))) ;-DNC inserted
(go botloop)))
(mapc (function
(lambda (prop)
(prog (printer)
(cond ((dtpr prop)
(setq printer (cdr prop))
(setq prop (car prop)))
(t (setq printer 'pp-prop)))
(cond ((eq 'value prop)
(and (boundp $cur$)
(apply printer
(list $cur$
(eval $cur$)
'value))
(terpr $outport$)))
((eq 'function prop)
(and (getd $cur$)
(cond ((not (bcdp (getd $cur$)))
(apply printer
(list $cur$
(getd $cur$)
'function)))
; restore message about
; bcd since otherwise you
; just get nothing and
; people were complaining.
; - dhl.
#-cmu
(t
(msg N
"pp: function "
(or $cur$)
" is machine coded (bcd) "))
)
(terpri $outport$)))
((get $cur$ prop)
(apply printer
(list $cur$
(get $cur$ prop)
prop))
(terpri $outport$))))))
prettyprops)
botloop (setq $xlist$ (cdr $xlist$))
(go toploop))))
(setq pparm1 50 pparm2 100)
; -DNC These "prettyprinter parameters" are used to decide when we should
; quit printing down the right margin and move back to the left -
; Do it when the leftmargin > pparm1 and there are more than pparm2
; more chars to print in the expression
; cmu prefers dv instead of setq
#+cmu
(def pp-value (lambda (i v p)
(terpri $outport$)
(pp-form (list 'dv i v) $outport$)))
#-cmu
(def pp-value (lambda (i v p)
;;(terpr $outport$) ;; pp-form does an initial terpr.
;; we don't need two.
(pp-form `(setq ,i ',v) $outport$)))
(def pp-function (lambda (i v p)
#+cmu (terpri $outport$)
;;
;; add test for traced functions and don't
;; print the trace mess, just the original
;; function. - dhl.
;;
;; this test might belong in the main pp
;; loop but fits in easily here. - dhl
;;
(cond ((and (dtpr v)
(dtpr (cadr v))
(memq (caadr v)
'(T-nargs T-arglist))
(cond ((bcdp (get i 'trace-orig-fcn))
#-cmu
(msg N
"pp: function "
(or i)
" is machine coded (bcd) ")
t)
(t (pp-form
(list 'def i
(get i 'trace-orig-fcn))
$outport$)
t))))
; this function need to return t, but
; pp-form returns nil sometimes.
(t (pp-form (list 'def i v) $outport$)
t))))
(def pp-prop (lambda (i v p)
#+cmu (terpri $outport$)
(pp-form (list 'defprop i v p) $outport$)))
(def condclosefile
(lambda nil
(cond ($fileopen$
(terpr $outport$)
(close $outport$)
(setq $fileopen$ nil)))))
\f
;
; these routines are meant to be used by pp but since
; some people insist on using them we will set $outport$ to nil
; as the default
(setq $outport$ nil)
(defun pp-form (value &optional ($outport$ poport oport-p) (lmar 0))
($prdf value lmar 0))
; this is for compatability with old code, will remove soon -- jkf
(def $prpr (lambda (x) (pp-form x $outport$)))
\f
(declare (special rmar)) ; -DNC this used to be m - I've tried to
; to fix up the pretty printer a bit. It
; used to mess up regularly on (a b .c) types
; of lists. Also printmacros have been added.
(def $prdf
(lambda (l lmar rmar)
(prog nil
;
; - DNC - Here we try to fix the tendency to print a
; thin column down the right margin by allowing it
; to move back to the left if necessary.
;
(cond ((and (>& lmar pparm1) (>& (flatc l (1+ pparm2)) pparm2))
(terpri $outport$)
(patom "; <<<<< start back on the left <<<<<" $outport$)
($prdf l 5 0)
(terpri $outport$)
(patom "; >>>>> continue on the right >>>>>" $outport$)
(terpri $outport$)
(return nil)))
(tab lmar $outport$)
a (cond ((and (dtpr l)
(atom (car l))
(or (and (get (car l) 'printmacro)
(funcall (get (car l) 'printmacro)
l lmar rmar))
(and (get (car l) 'printmacrochar)
(printmacrochar (get (car l) 'printmacrochar)
l lmar rmar))))
(return nil))
;
; -DNC - a printmacro is a lambda (l lmar rmar)
; attached to the atom. If it returns nil then
; we assume it did not apply and we continue.
; Otherwise we assume it did the job.
;
((or (not (dtpr l))
; (*** at the moment we just punt hunks etc)
(and (atom (car l)) (atom (cdr l))))
(return (printret l $outport$)))
((<& (+ rmar (flatc l (charcnt $outport$)))
(charcnt $outport$))
;
; This is just a heuristic - if print can fit it in then figure that
; the printmacros won't hurt. Note that despite the pretentions there
; is no guarantee that everything will fit in before rmar - for example
; atoms (and now even hunks) are just blindly printed. - DNC
;
(printaccross l lmar rmar))
((and ($patom1 lpar)
(atom (car l))
(not (atom (cdr l)))
(not (atom (cddr l))))
(prog (c)
(printret (car l) $outport$)
($patom1 '" ")
(setq c (nwritn $outport$))
a ($prd1 (cdr l) c)
(cond
((not (atom (cdr (setq l (cdr l)))))
(terpr $outport$)
(go a)))))
(t
(prog (c)
(setq c (nwritn $outport$))
a ($prd1 l c)
(cond
((not (atom (setq l (cdr l))))
(terpr $outport$)
(go a))))))
b ($patom1 rpar))))
(def $prd1
(lambda (l n)
(prog nil
($prdf (car l)
n
(cond ((null (setq l (cdr l))) (|1+| rmar))
((atom l) (setq n nil) (plus 4 rmar (pntlen l)))
(t rmar)))
(cond
((null n) ($patom1 '" . ") (return (printret l $outport$))))
; (*** setting n is pretty disgusting)
; (*** the last arg to $prdf is the space needed for the suffix)
; ;Note that this is still not really right - if the prefix
; takes several lines one would like to use the old rmar
; until the last line where the " . mumble)" goes.
)))
; -DNC here's the printmacro for progs - it replaces some hackery that
; used to be in the guts of $prdf.
(def printprog
(lambda (l lmar rmar)
(prog (col)
(cond ((cdr (last l)) (return nil)))
(setq col (add1 lmar))
(princ '|(| $outport$)
(princ (car l) $outport$)
(princ '| | $outport$)
(print (cadr l) $outport$)
(mapc '(lambda (x)
(cond ((atom x)
(tab col $outport$)
(print x $outport$))
(t ($prdf x (+ lmar 6) rmar))))
(cddr l))
(princ '|)| $outport$)
(return t))))
(putprop 'prog 'printprog 'printmacro)
;;
;; simpler version which
;; should look nice for lambda's also.(inside mapcar's) -dhl
;;
(defun print-lambda (l lmar rmar)
(prog (col)
(cond ((cdr (last l)) (return nil)))
(setq col (add1 lmar))
(princ '|(| $outport$)
(princ (car l) $outport$)
(princ '| | $outport$)
(print (cadr l) $outport$)
(let ((c (cond ((eq (car l) 'lambda)
8)
(t 9))))
(mapc '(lambda (x)
($prdf x (+ lmar c) rmar))
(cddr l)))
(princ '|)| $outport$)
(terpr $outport$)
(tab lmar $outport$)
(return t)))
(putprop 'lambda 'print-lambda 'printmacro)
(putprop 'nlambda 'print-lambda 'printmacro)
; Here's the printmacro for def. The original $prdf had some special code
; for lambda and nlambda.
(def printdef
(lambda (l lmar rmar)
(cond ((and (zerop lmar) ; only if we're really printing a defn
(zerop rmar)
(cadr l)
(atom (cadr l))
(dtpr (caddr l))
(null (cdddr l))
(memq (caaddr l) '(lambda nlambda macro lexpr))
(null (cdr (last (caddr l)))))
(princ '|(| $outport$)
(princ 'def $outport$)
(princ '| | $outport$)
(princ (cadr l) $outport$)
(terpri $outport$)
(princ '| (| $outport$)
(princ (caaddr l) $outport$)
(princ '| | $outport$)
(princ (cadaddr l) $outport$)
(terpri $outport$)
(mapc '(lambda (x) ($prdf x 4 0)) (cddaddr l))
(princ '|))| $outport$)
t))))
(putprop 'def 'printdef 'printmacro)
; There's a version of this hacked into the printer (where it don't belong!)
; Note that it must NOT apply to things like (quote a b).
;
; adding printmacrochar so that it can be used by other read macros
; which create things of the form (tag lisp-expr) like quote does,
; I know this is restrictive but it is helpful in the frl source. - dhl.
;
;
(def printmacrochar
(lambda (macrochar l lmar rmar)
(cond ((or (null (cdr l)) (cddr l)) nil)
(t (princ macrochar $outport$)
($prdf (cadr l) (add1 lmar) rmar)
t))))
(putprop 'quote '|'| 'printmacrochar)
(def printaccross
(lambda (l lmar rmar)
(prog nil
; (*** this is needed to make sure the printmacros are executed)
(princ '|(| $outport$)
l: (cond ((null l))
((atom l) (princ '|. | $outport$) (princ l $outport$))
(t ($prdf (car l) (nwritn $outport$) rmar)
(setq l (cdr l))
(cond (l (princ '| | $outport$)))
(go l:))))))