(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))))) ; ; 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$))) (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:))))))