Commit | Line | Data |
---|---|---|
a482f2cc MV |
1 | ;;;; -*-scheme-*- |
2 | ;;;; | |
3 | ;;;; Copyright (C) 2001 Free Software Foundation, Inc. | |
4 | ;;;; | |
5 | ;;;; This program is free software; you can redistribute it and/or modify | |
6 | ;;;; it under the terms of the GNU General Public License as published by | |
7 | ;;;; the Free Software Foundation; either version 2, or (at your option) | |
8 | ;;;; any later version. | |
9 | ;;;; | |
10 | ;;;; This program is distributed in the hope that it will be useful, | |
11 | ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | ;;;; GNU General Public License for more details. | |
14 | ;;;; | |
15 | ;;;; You should have received a copy of the GNU General Public License | |
16 | ;;;; along with this software; see the file COPYING. If not, write to | |
17 | ;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |
18 | ;;;; Boston, MA 02111-1307 USA | |
19 | ;;;; | |
20 | ;;;; As a special exception, the Free Software Foundation gives permission | |
21 | ;;;; for additional uses of the text contained in its release of GUILE. | |
22 | ;;;; | |
23 | ;;;; The exception is that, if you link the GUILE library with other files | |
24 | ;;;; to produce an executable, this does not by itself cause the | |
25 | ;;;; resulting executable to be covered by the GNU General Public License. | |
26 | ;;;; Your use of that executable is in no way restricted on account of | |
27 | ;;;; linking the GUILE library code into it. | |
28 | ;;;; | |
29 | ;;;; This exception does not however invalidate any other reasons why | |
30 | ;;;; the executable file might be covered by the GNU General Public License. | |
31 | ;;;; | |
32 | ;;;; This exception applies only to the code released by the | |
33 | ;;;; Free Software Foundation under the name GUILE. If you copy | |
34 | ;;;; code from other Free Software Foundation releases into a copy of | |
35 | ;;;; GUILE, as the General Public License permits, the exception does | |
36 | ;;;; not apply to the code that you add in this way. To avoid misleading | |
37 | ;;;; anyone as to the status of such modified files, you must delete | |
38 | ;;;; this exception notice from them. | |
39 | ;;;; | |
40 | ;;;; If you write modifications of your own for GUILE, it is your choice | |
41 | ;;;; whether to permit this exception to apply to your modifications. | |
42 | ;;;; If you do not wish that, delete this exception notice. | |
43 | ;;;; | |
1a179b03 MD |
44 | (define-module (ice-9 pretty-print) |
45 | :export (pretty-print)) | |
b337528f MV |
46 | |
47 | ;; From SLIB. | |
48 | ||
49 | ;;"genwrite.scm" generic write used by pretty-print and truncated-print. | |
50 | ;; Copyright (c) 1991, Marc Feeley | |
51 | ;; Author: Marc Feeley (feeley@iro.umontreal.ca) | |
52 | ;; Distribution restrictions: none | |
53 | ||
54 | (define genwrite:newline-str (make-string 1 #\newline)) | |
55 | ||
56 | (define (generic-write obj display? width output) | |
57 | ||
58 | (define (read-macro? l) | |
59 | (define (length1? l) (and (pair? l) (null? (cdr l)))) | |
60 | (let ((head (car l)) (tail (cdr l))) | |
61 | (case head | |
62 | ((quote quasiquote unquote unquote-splicing) (length1? tail)) | |
63 | (else #f)))) | |
64 | ||
65 | (define (read-macro-body l) | |
66 | (cadr l)) | |
67 | ||
68 | (define (read-macro-prefix l) | |
69 | (let ((head (car l)) (tail (cdr l))) | |
70 | (case head | |
71 | ((quote) "'") | |
72 | ((quasiquote) "`") | |
73 | ((unquote) ",") | |
74 | ((unquote-splicing) ",@")))) | |
75 | ||
76 | (define (out str col) | |
77 | (and col (output str) (+ col (string-length str)))) | |
78 | ||
79 | (define (wr obj col) | |
80 | ||
81 | (define (wr-expr expr col) | |
82 | (if (read-macro? expr) | |
83 | (wr (read-macro-body expr) (out (read-macro-prefix expr) col)) | |
84 | (wr-lst expr col))) | |
85 | ||
86 | (define (wr-lst l col) | |
87 | (if (pair? l) | |
88 | (let loop ((l (cdr l)) | |
89 | (col (and col (wr (car l) (out "(" col))))) | |
90 | (cond ((not col) col) | |
91 | ((pair? l) | |
92 | (loop (cdr l) (wr (car l) (out " " col)))) | |
93 | ((null? l) (out ")" col)) | |
94 | (else (out ")" (wr l (out " . " col)))))) | |
95 | (out "()" col))) | |
96 | ||
97 | (cond ((pair? obj) (wr-expr obj col)) | |
98 | ((null? obj) (wr-lst obj col)) | |
99 | ((vector? obj) (wr-lst (vector->list obj) (out "#" col))) | |
100 | ((boolean? obj) (out (if obj "#t" "#f") col)) | |
101 | ((number? obj) (out (number->string obj) col)) | |
102 | ((symbol? obj) (out (symbol->string obj) col)) | |
103 | ((procedure? obj) (out "#[procedure]" col)) | |
104 | ((string? obj) (if display? | |
105 | (out obj col) | |
106 | (let loop ((i 0) (j 0) (col (out "\"" col))) | |
107 | (if (and col (< j (string-length obj))) | |
108 | (let ((c (string-ref obj j))) | |
109 | (if (or (char=? c #\\) | |
110 | (char=? c #\")) | |
111 | (loop j | |
112 | (+ j 1) | |
113 | (out "\\" | |
114 | (out (substring obj i j) | |
115 | col))) | |
116 | (loop i (+ j 1) col))) | |
117 | (out "\"" | |
118 | (out (substring obj i j) col)))))) | |
119 | ((char? obj) (if display? | |
120 | (out (make-string 1 obj) col) | |
121 | (out (case obj | |
122 | ((#\space) "space") | |
123 | ((#\newline) "newline") | |
124 | (else (make-string 1 obj))) | |
125 | (out "#\\" col)))) | |
269ce439 | 126 | (else (out (object->string obj) col)))) |
b337528f MV |
127 | |
128 | (define (pp obj col) | |
129 | ||
130 | (define (spaces n col) | |
131 | (if (> n 0) | |
132 | (if (> n 7) | |
133 | (spaces (- n 8) (out " " col)) | |
134 | (out (substring " " 0 n) col)) | |
135 | col)) | |
136 | ||
137 | (define (indent to col) | |
138 | (and col | |
139 | (if (< to col) | |
140 | (and (out genwrite:newline-str col) (spaces to 0)) | |
141 | (spaces (- to col) col)))) | |
142 | ||
143 | (define (pr obj col extra pp-pair) | |
144 | (if (or (pair? obj) (vector? obj)) ; may have to split on multiple lines | |
145 | (let ((result '()) | |
146 | (left (min (+ (- (- width col) extra) 1) max-expr-width))) | |
147 | (generic-write obj display? #f | |
148 | (lambda (str) | |
149 | (set! result (cons str result)) | |
150 | (set! left (- left (string-length str))) | |
151 | (> left 0))) | |
152 | (if (> left 0) ; all can be printed on one line | |
153 | (out (reverse-string-append result) col) | |
154 | (if (pair? obj) | |
155 | (pp-pair obj col extra) | |
156 | (pp-list (vector->list obj) (out "#" col) extra pp-expr)))) | |
157 | (wr obj col))) | |
158 | ||
159 | (define (pp-expr expr col extra) | |
160 | (if (read-macro? expr) | |
161 | (pr (read-macro-body expr) | |
162 | (out (read-macro-prefix expr) col) | |
163 | extra | |
164 | pp-expr) | |
165 | (let ((head (car expr))) | |
166 | (if (symbol? head) | |
167 | (let ((proc (style head))) | |
168 | (if proc | |
169 | (proc expr col extra) | |
170 | (if (> (string-length (symbol->string head)) | |
171 | max-call-head-width) | |
172 | (pp-general expr col extra #f #f #f pp-expr) | |
173 | (pp-call expr col extra pp-expr)))) | |
174 | (pp-list expr col extra pp-expr))))) | |
175 | ||
176 | ; (head item1 | |
177 | ; item2 | |
178 | ; item3) | |
179 | (define (pp-call expr col extra pp-item) | |
180 | (let ((col* (wr (car expr) (out "(" col)))) | |
181 | (and col | |
182 | (pp-down (cdr expr) col* (+ col* 1) extra pp-item)))) | |
183 | ||
184 | ; (item1 | |
185 | ; item2 | |
186 | ; item3) | |
187 | (define (pp-list l col extra pp-item) | |
188 | (let ((col (out "(" col))) | |
189 | (pp-down l col col extra pp-item))) | |
190 | ||
191 | (define (pp-down l col1 col2 extra pp-item) | |
192 | (let loop ((l l) (col col1)) | |
193 | (and col | |
194 | (cond ((pair? l) | |
195 | (let ((rest (cdr l))) | |
196 | (let ((extra (if (null? rest) (+ extra 1) 0))) | |
197 | (loop rest | |
198 | (pr (car l) (indent col2 col) extra pp-item))))) | |
199 | ((null? l) | |
200 | (out ")" col)) | |
201 | (else | |
202 | (out ")" | |
203 | (pr l | |
204 | (indent col2 (out "." (indent col2 col))) | |
205 | (+ extra 1) | |
206 | pp-item))))))) | |
207 | ||
208 | (define (pp-general expr col extra named? pp-1 pp-2 pp-3) | |
209 | ||
210 | (define (tail1 rest col1 col2 col3) | |
211 | (if (and pp-1 (pair? rest)) | |
212 | (let* ((val1 (car rest)) | |
213 | (rest (cdr rest)) | |
214 | (extra (if (null? rest) (+ extra 1) 0))) | |
215 | (tail2 rest col1 (pr val1 (indent col3 col2) extra pp-1) col3)) | |
216 | (tail2 rest col1 col2 col3))) | |
217 | ||
218 | (define (tail2 rest col1 col2 col3) | |
219 | (if (and pp-2 (pair? rest)) | |
220 | (let* ((val1 (car rest)) | |
221 | (rest (cdr rest)) | |
222 | (extra (if (null? rest) (+ extra 1) 0))) | |
223 | (tail3 rest col1 (pr val1 (indent col3 col2) extra pp-2))) | |
224 | (tail3 rest col1 col2))) | |
225 | ||
226 | (define (tail3 rest col1 col2) | |
227 | (pp-down rest col2 col1 extra pp-3)) | |
228 | ||
229 | (let* ((head (car expr)) | |
230 | (rest (cdr expr)) | |
231 | (col* (wr head (out "(" col)))) | |
232 | (if (and named? (pair? rest)) | |
233 | (let* ((name (car rest)) | |
234 | (rest (cdr rest)) | |
235 | (col** (wr name (out " " col*)))) | |
236 | (tail1 rest (+ col indent-general) col** (+ col** 1))) | |
237 | (tail1 rest (+ col indent-general) col* (+ col* 1))))) | |
238 | ||
239 | (define (pp-expr-list l col extra) | |
240 | (pp-list l col extra pp-expr)) | |
241 | ||
242 | (define (pp-LAMBDA expr col extra) | |
243 | (pp-general expr col extra #f pp-expr-list #f pp-expr)) | |
244 | ||
245 | (define (pp-IF expr col extra) | |
246 | (pp-general expr col extra #f pp-expr #f pp-expr)) | |
247 | ||
248 | (define (pp-COND expr col extra) | |
249 | (pp-call expr col extra pp-expr-list)) | |
250 | ||
251 | (define (pp-CASE expr col extra) | |
252 | (pp-general expr col extra #f pp-expr #f pp-expr-list)) | |
253 | ||
254 | (define (pp-AND expr col extra) | |
255 | (pp-call expr col extra pp-expr)) | |
256 | ||
257 | (define (pp-LET expr col extra) | |
258 | (let* ((rest (cdr expr)) | |
259 | (named? (and (pair? rest) (symbol? (car rest))))) | |
260 | (pp-general expr col extra named? pp-expr-list #f pp-expr))) | |
261 | ||
262 | (define (pp-BEGIN expr col extra) | |
263 | (pp-general expr col extra #f #f #f pp-expr)) | |
264 | ||
265 | (define (pp-DO expr col extra) | |
266 | (pp-general expr col extra #f pp-expr-list pp-expr-list pp-expr)) | |
267 | ||
268 | ; define formatting style (change these to suit your style) | |
269 | ||
270 | (define indent-general 2) | |
271 | ||
272 | (define max-call-head-width 5) | |
273 | ||
274 | (define max-expr-width 50) | |
275 | ||
276 | (define (style head) | |
277 | (case head | |
278 | ((lambda let* letrec define) pp-LAMBDA) | |
279 | ((if set!) pp-IF) | |
280 | ((cond) pp-COND) | |
281 | ((case) pp-CASE) | |
282 | ((and or) pp-AND) | |
283 | ((let) pp-LET) | |
284 | ((begin) pp-BEGIN) | |
285 | ((do) pp-DO) | |
286 | (else #f))) | |
287 | ||
288 | (pr obj col 0 pp-expr)) | |
289 | ||
290 | (if width | |
291 | (out genwrite:newline-str (pp obj 0)) | |
21a10205 MV |
292 | (wr obj 0)) |
293 | ;; Return `unspecified' | |
294 | (if #f #f)) | |
b337528f MV |
295 | |
296 | ; (reverse-string-append l) = (apply string-append (reverse l)) | |
297 | ||
298 | (define (reverse-string-append l) | |
299 | ||
300 | (define (rev-string-append l i) | |
301 | (if (pair? l) | |
302 | (let* ((str (car l)) | |
303 | (len (string-length str)) | |
304 | (result (rev-string-append (cdr l) (+ i len)))) | |
305 | (let loop ((j 0) (k (- (- (string-length result) i) len))) | |
306 | (if (< j len) | |
307 | (begin | |
308 | (string-set! result k (string-ref str j)) | |
309 | (loop (+ j 1) (+ k 1))) | |
310 | result))) | |
311 | (make-string i))) | |
312 | ||
313 | (rev-string-append l 0)) | |
314 | ||
315 | ;"pp.scm" Pretty-Print | |
316 | (define (pretty-print obj . opt) | |
317 | (let ((port (if (pair? opt) (car opt) (current-output-port)))) | |
318 | (generic-write obj #f 79 | |
319 | (lambda (s) (display s port) #t)))) | |
320 |