BSD 4_2 development
[unix-history] / usr / lib / lisp / pp.l
CommitLineData
ea3b12ee
C
1(setq rcs-pp-
2 "$Header: /usr/lib/lisp/RCS/pp.l,v 1.1 83/01/30 11:54:25 jkf Exp $")
3
4;;
5;; pp.l -[Sat Jan 29 18:27:08 1983 by jkf]-
6;;
7;; pretty printer for franz lisp
8;;
9
10(declare (macros t))
11
12(declare (special poport pparm1 pparm2 lpar rpar form linel))
13; (declare (localf $patom1 $prd1 $prdf charcnt condclosefile))
14
15; =======================================
16; pretty printer top level routine pp
17;
18;
19; calling form- (pp arg1 arg2 ... argn)
20; the args may be names of functions, atoms with associated values
21; or output descriptors.
22; if argi is:
23; an atom - it is assumed to be a function name, if there is no
24; function property associated with it,then it is assumed
25; to be an atom with a value
26; (P port)- port is the output port where the results of the
27; pretty printing will be sent.
28; poport is the default if no (P port) is given.
29; (F fname)- fname is a file name to write the results in
30; (A atmname) - means, treat this as an atom with a value, dont
31; check if it is the name of a function.
32; (E exp)- evaluate exp without printing anything
33; other - pretty-print the expression as is - no longer an error
34;
35; Also, rather than printing only a function defn or only a value, we will
36; let prettyprops decide which props to print. Finally, prettyprops will
37; follow the CMULisp format where each element is either a property
38; or a dotted pair of the form (prop . fn) where in order to print the
39; given property we call (fn id val prop). The special properties
40; function and value are used to denote those "properties" which
41; do not actually appear on the plist.
42;
43; [history of this code: originally came from Harvard Lisp, hacked to
44; work under franz at ucb, hacked to work at cmu and finally rehacked
45; to work without special cmu macros]
46
47(declare (special $outport$ $fileopen$ prettyprops))
48
49(setq prettyprops '((comment . pp-comment)
50 (function . pp-function)
51 (value . pp-value)))
52
53; printret is like print yet it returns the value printed, this is used
54; by pp
55(def printret
56 (macro ($l$)
57 `(progn (print ,@(cdr $l$)) ,(cadr $l$))))
58
59(def pp
60 (nlambda ($xlist$)
61 (prog ($gcprint $outport$ $cur$ $fileopen$ $prl$ $atm$)
62
63 (setq $gcprint nil) ; don't print
64 ; gc messages in pp.
65
66 (setq $outport$ poport) ; default port
67 ; check if more to do, if not close output file if it is
68 ; open and leave
69
70
71 toploop (cond ((null (setq $cur$ (car $xlist$)))
72 (condclosefile)
73 (terpr)
74 (return t)))
75
76 (cond ((dtpr $cur$)
77 (cond ((equal 'P (car $cur$)) ; specifying a port
78 (condclosefile) ; close file if open
79 (setq $outport$ (eval (cadr $cur$))))
80
81 ((equal 'F (car $cur$)) ; specifying a file
82 (condclosefile) ; close file if open
83 (setq $outport$ (outfile (cadr $cur$))
84 $fileopen$ t))
85
86
87 ((equal 'E (car $cur$))
88 (eval (cadr $cur$)))
89
90 (t (pp-form $cur$ $outport$))) ;-DNC inserted
91 (go botloop)))
92
93
94 (mapc (function
95 (lambda (prop)
96 (prog (printer)
97 (cond ((dtpr prop)
98 (setq printer (cdr prop))
99 (setq prop (car prop)))
100 (t (setq printer 'pp-prop)))
101 (cond ((eq 'value prop)
102 (and (boundp $cur$)
103 (apply printer
104 (list $cur$
105 (eval $cur$)
106 'value))
107 (terpr $outport$)))
108 ((eq 'function prop)
109 (and (getd $cur$)
110 (cond ((not (bcdp (getd $cur$)))
111 (apply printer
112 (list $cur$
113 (getd $cur$)
114 'function)))
115 ; restore message about
116 ; bcd since otherwise you
117 ; just get nothing and
118 ; people were complaining.
119 ; - dhl.
120 #-cmu
121 (t
122 (msg N
123 "pp: function "
124 (or $cur$)
125 " is machine coded (bcd) "))
126 )
127 (terpri $outport$)))
128 ((get $cur$ prop)
129 (apply printer
130 (list $cur$
131 (get $cur$ prop)
132 prop))
133 (terpri $outport$))))))
134 prettyprops)
135
136
137 botloop (setq $xlist$ (cdr $xlist$))
138
139 (go toploop))))
140
141(setq pparm1 50 pparm2 100)
142
143; -DNC These "prettyprinter parameters" are used to decide when we should
144; quit printing down the right margin and move back to the left -
145; Do it when the leftmargin > pparm1 and there are more than pparm2
146; more chars to print in the expression
147
148; cmu prefers dv instead of setq
149
150#+cmu
151(def pp-value (lambda (i v p)
152 (terpri $outport$)
153 (pp-form (list 'dv i v) $outport$)))
154
155#-cmu
156(def pp-value (lambda (i v p)
157 ;;(terpr $outport$) ;; pp-form does an initial terpr.
158 ;; we don't need two.
159 (pp-form `(setq ,i ',v) $outport$)))
160
161(def pp-function (lambda (i v p)
162 #+cmu (terpri $outport$)
163 ;;
164 ;; add test for traced functions and don't
165 ;; print the trace mess, just the original
166 ;; function. - dhl.
167 ;;
168 ;; this test might belong in the main pp
169 ;; loop but fits in easily here. - dhl
170 ;;
171 (cond ((and (dtpr v)
172 (dtpr (cadr v))
173 (memq (caadr v)
174 '(T-nargs T-arglist))
175 (cond ((bcdp (get i 'trace-orig-fcn))
176 #-cmu
177 (msg N
178 "pp: function "
179 (or i)
180 " is machine coded (bcd) ")
181 t)
182 (t (pp-form
183 (list 'def i
184 (get i 'trace-orig-fcn))
185 $outport$)
186 t))))
187 ; this function need to return t, but
188 ; pp-form returns nil sometimes.
189 (t (pp-form (list 'def i v) $outport$)
190 t))))
191
192(def pp-prop (lambda (i v p)
193 #+cmu (terpri $outport$)
194 (pp-form (list 'defprop i v p) $outport$)))
195
196(def condclosefile
197 (lambda nil
198 (cond ($fileopen$
199 (terpr $outport$)
200 (close $outport$)
201 (setq $fileopen$ nil)))))
202\f
203;
204; these routines are meant to be used by pp but since
205; some people insist on using them we will set $outport$ to nil
206; as the default
207(setq $outport$ nil)
208
209
210(def pp-form
211 (lexpr (n)
212 (cond ((= n 1) (setq $outport$ poport))
213 ((= n 2) (setq $outport$ (arg 2)))
214 (t (error "pp-form: wrong number of arguments: " n)))
215 (terpr $outport$)
216 ($prdf (arg 1) 0 0)))
217
218; this is for compatability with old code, will remove soon -- jkf
219(def $prpr (lambda (x) (pp-form x $outport$)))
220
221
222\f
223(declare (special rmar)) ; -DNC this used to be m - I've tried to
224 ; to fix up the pretty printer a bit. It
225 ; used to mess up regularly on (a b .c) types
226 ; of lists. Also printmacros have been added.
227
228(def $prdf
229 (lambda (l lmar rmar)
230 (prog nil
231;
232; - DNC - Here we try to fix the tendency to print a
233; thin column down the right margin by allowing it
234; to move back to the left if necessary.
235;
236 (cond ((and (>& lmar pparm1) (>& (flatc l (1+ pparm2)) pparm2))
237 (terpri $outport$)
238 (patom "; <<<<< start back on the left <<<<<" $outport$)
239 ($prdf l 5 0)
240 (terpri $outport$)
241 (patom "; >>>>> continue on the right >>>>>" $outport$)
242 (terpri $outport$)
243 (return nil)))
244 (tab lmar $outport$)
245 a (cond ((and (dtpr l)
246 (atom (car l))
247 (or (and (get (car l) 'printmacro)
248 (funcall (get (car l) 'printmacro)
249 l lmar rmar))
250 (and (get (car l) 'printmacrochar)
251 (printmacrochar (get (car l) 'printmacrochar)
252 l lmar rmar))))
253 (return nil))
254;
255; -DNC - a printmacro is a lambda (l lmar rmar)
256; attached to the atom. If it returns nil then
257; we assume it did not apply and we continue.
258; Otherwise we assume it did the job.
259;
260 ((or (not (dtpr l))
261; (*** at the moment we just punt hunks etc)
262 (and (atom (car l)) (atom (cdr l))))
263 (return (printret l $outport$)))
264 ((<& (+ rmar (flatc l (charcnt $outport$)))
265 (charcnt $outport$))
266 ;
267 ; This is just a heuristic - if print can fit it in then figure that
268; the printmacros won't hurt. Note that despite the pretentions there
269; is no guarantee that everything will fit in before rmar - for example
270; atoms (and now even hunks) are just blindly printed. - DNC
271;
272 (printaccross l lmar rmar))
273 ((and ($patom1 lpar)
274 (atom (car l))
275 (not (atom (cdr l)))
276 (not (atom (cddr l))))
277 (prog (c)
278 (printret (car l) $outport$)
279 ($patom1 '" ")
280 (setq c (nwritn $outport$))
281 a ($prd1 (cdr l) c)
282 (cond
283 ((not (atom (cdr (setq l (cdr l)))))
284 (terpr $outport$)
285 (go a)))))
286 (t
287 (prog (c)
288 (setq c (nwritn $outport$))
289 a ($prd1 l c)
290 (cond
291 ((not (atom (setq l (cdr l))))
292 (terpr $outport$)
293 (go a))))))
294 b ($patom1 rpar))))
295
296(def $prd1
297 (lambda (l n)
298 (prog nil
299 ($prdf (car l)
300 n
301 (cond ((null (setq l (cdr l))) (|1+| rmar))
302 ((atom l) (setq n nil) (plus 4 rmar (pntlen l)))
303 (t rmar)))
304 (cond
305 ((null n) ($patom1 '" . ") (return (printret l $outport$))))
306; (*** setting n is pretty disgusting)
307; (*** the last arg to $prdf is the space needed for the suffix)
308; ;Note that this is still not really right - if the prefix
309; takes several lines one would like to use the old rmar
310; until the last line where the " . mumble)" goes.
311 )))
312
313; -DNC here's the printmacro for progs - it replaces some hackery that
314; used to be in the guts of $prdf.
315
316(def printprog
317 (lambda (l lmar rmar)
318 (prog (col)
319 (cond ((cdr (last l)) (return nil)))
320 (setq col (add1 lmar))
321 (princ '|(| $outport$)
322 (princ (car l) $outport$)
323 (princ '| | $outport$)
324 (print (cadr l) $outport$)
325 (mapc '(lambda (x)
326 (cond ((atom x)
327 (tab col $outport$)
328 (print x $outport$))
329 (t ($prdf x (+ lmar 6) rmar))))
330 (cddr l))
331 (princ '|)| $outport$)
332 (return t))))
333
334(putprop 'prog 'printprog 'printmacro)
335
336;;
337;; simpler version which
338;; should look nice for lambda's also.(inside mapcar's) -dhl
339;;
340(defun print-lambda (l lmar rmar)
341 (prog (col)
342 (cond ((cdr (last l)) (return nil)))
343 (setq col (add1 lmar))
344 (princ '|(| $outport$)
345 (princ (car l) $outport$)
346 (princ '| | $outport$)
347 (print (cadr l) $outport$)
348 (let ((c (cond ((eq (car l) 'lambda)
349 8)
350 (t 9))))
351 (mapc '(lambda (x)
352 ($prdf x (+ lmar c) rmar))
353 (cddr l)))
354 (princ '|)| $outport$)
355 (terpr $outport$)
356 (tab lmar $outport$)
357 (return t)))
358
359(putprop 'lambda 'print-lambda 'printmacro)
360(putprop 'nlambda 'print-lambda 'printmacro)
361
362; Here's the printmacro for def. The original $prdf had some special code
363; for lambda and nlambda.
364
365(def printdef
366 (lambda (l lmar rmar)
367 (cond ((and (zerop lmar) ; only if we're really printing a defn
368 (zerop rmar)
369 (cadr l)
370 (atom (cadr l))
371 (dtpr (caddr l))
372 (null (cdddr l))
373 (memq (caaddr l) '(lambda nlambda macro lexpr))
374 (null (cdr (last (caddr l)))))
375 (princ '|(| $outport$)
376 (princ 'def $outport$)
377 (princ '| | $outport$)
378 (princ (cadr l) $outport$)
379 (terpri $outport$)
380 (princ '| (| $outport$)
381 (princ (caaddr l) $outport$)
382 (princ '| | $outport$)
383 (princ (cadaddr l) $outport$)
384 (terpri $outport$)
385 (mapc '(lambda (x) ($prdf x 4 0)) (cddaddr l))
386 (princ '|))| $outport$)
387 t))))
388
389(putprop 'def 'printdef 'printmacro)
390
391; There's a version of this hacked into the printer (where it don't belong!)
392; Note that it must NOT apply to things like (quote a b).
393
394;
395; adding printmacrochar so that it can be used by other read macros
396; which create things of the form (tag lisp-expr) like quote does,
397; I know this is restrictive but it is helpful in the frl source. - dhl.
398;
399;
400
401(def printmacrochar
402 (lambda (macrochar l lmar rmar)
403 (cond ((or (null (cdr l)) (cddr l)) nil)
404 (t (princ macrochar $outport$)
405 ($prdf (cadr l) (add1 lmar) rmar)
406 t))))
407
408(putprop 'quote '|'| 'printmacrochar)
409
410(def printaccross
411 (lambda (l lmar rmar)
412 (prog nil
413; (*** this is needed to make sure the printmacros are executed)
414 (princ '|(| $outport$)
415 l: (cond ((null l))
416 ((atom l) (princ '|. | $outport$) (princ l $outport$))
417 (t ($prdf (car l) (nwritn $outport$) rmar)
418 (setq l (cdr l))
419 (cond (l (princ '| | $outport$)))
420 (go l:))))))
421