1 ! Copyright (C) 2003, 2005 Slava Pestov.
2 ! See http://factor.sf.net/license.txt for BSD license.
4 USING: alien generic hashtables io kernel lists math namespaces
5 parser sequences strings styles vectors words ;
11 SYMBOL: recursion-check
34 TUPLE: pprinter stack ;
36 GENERIC: pprint-section*
38 TUPLE: section start end nl-after? indent ;
40 C: section ( length -- section )
41 >r column [ dup rot + dup ] change r>
42 [ set-section-end ] keep
43 [ set-section-start ] keep
44 0 over set-section-indent ;
46 : section-fits? ( section -- ? )
47 section-end last-newline get - indent get + margin get <= ;
49 : line-limit? ( -- ? )
50 line-limit get dup [ line-count get <= ] when ;
52 : do-indent indent get CHAR: \s fill write ;
55 #! n is current column position.
56 dup last-newline get = [
61 line-limit? [ "..." write end-printing get call ] when
65 TUPLE: text string style ;
67 C: text ( string style -- section )
68 pick length 1 + <section> over set-delegate
69 [ set-text-style ] keep
70 [ set-text-string ] keep ;
72 M: text pprint-section*
73 dup text-string swap text-style format ;
75 TUPLE: block sections ;
78 0 <section> over set-delegate
79 { } clone over set-block-sections
80 t over set-section-nl-after?
81 tab-size get over set-section-indent ;
83 : pprinter-block pprinter-stack peek ;
85 : block-empty? ( section -- ? )
86 dup block? [ block-sections empty? ] [ drop f ] ifte ;
88 : add-section ( section stream -- )
92 pprinter-block block-sections push
95 : text ( string style -- ) <text> pprinter get add-section ;
97 : <indent ( section -- ) section-indent indent [ + ] change ;
99 : indent> ( section -- ) section-indent indent [ swap - ] change ;
101 : inset-section ( section -- )
103 dup section-start fresh-line dup pprint-section*
105 dup section-nl-after?
106 [ section-end fresh-line ] [ drop ] ifte ;
108 : pprint-section ( section -- )
110 [ pprint-section* ] [ inset-section ] ifte ;
114 C: newline ( -- section )
115 0 <section> over set-delegate ;
117 M: newline pprint-section* ( newline -- )
118 section-start fresh-line ;
120 : advance ( section -- )
124 section-start last-newline get = [ " " write ] unless
127 M: block pprint-section* ( block -- )
128 f swap block-sections [
129 over [ dup advance ] when pprint-section drop t
132 : <block ( -- ) <block> pprinter get pprinter-stack push ;
134 : newline ( -- ) <newline> pprinter get add-section ;
136 : end-block ( block -- ) column get swap set-section-end ;
138 : pop-block ( pprinter -- ) pprinter-stack pop drop ;
141 pprinter get dup pprinter-block
142 dup end-block swap dup pop-block add-section ;
144 : last-block? ( -- ? )
145 pprinter get pprinter-stack length 1 = ;
148 #! Protect against malformed <block ... block> forms.
149 last-block? [ (block>) ] unless ;
152 pprinter get pprinter-block f swap set-section-nl-after?
155 : end-blocks ( -- ) last-block? [ (block>) end-blocks ] unless ;
157 C: pprinter ( -- stream )
158 <block> 1vector over set-pprinter-stack ;
160 : do-pprint ( pprinter -- )
163 dup pprinter-block pprint-section
167 GENERIC: pprint* ( obj -- )
169 : vocab-style ( vocab -- style )
171 [[ "syntax" [ [[ foreground [ 128 128 128 ] ]] ] ]]
172 [[ "kernel" [ [[ foreground [ 0 0 128 ] ]] ] ]]
173 [[ "sequences" [ [[ foreground [ 128 0 0 ] ]] ] ]]
174 [[ "math" [ [[ foreground [ 0 128 0 ] ]] ] ]]
175 [[ "math-internals" [ [[ foreground [ 192 0 0 ] ]] ] ]]
176 [[ "kernel-internals" [ [[ foreground [ 192 0 0 ] ]] ] ]]
177 [[ "io-internals" [ [[ foreground [ 192 0 0 ] ]] ] ]]
180 : word-style ( word -- style )
181 dup word-vocabulary vocab-style swap presented swons add ;
183 : pprint-word ( obj -- )
184 dup word-name [ "( unnamed )" ] unless*
185 swap word-style text ;
187 M: object pprint* ( obj -- )
188 "( unprintable object: " swap class word-name " )" append3
191 M: real pprint* ( obj -- ) number>string f text ;
193 : ch>ascii-escape ( ch -- esc )
200 [[ CHAR: \\ "\\\\" ]]
201 [[ CHAR: \" "\\\"" ]]
204 : ch>unicode-escape ( ch -- esc )
205 >hex 4 CHAR: 0 pad-left "\\u" swap append ;
207 : unparse-ch ( ch -- ch/str )
211 dup ch>ascii-escape [ ] [ ch>unicode-escape ] ?ifte %
214 : do-string-limit ( string -- string )
216 dup length margin get > [
217 margin get 3 - swap head "..." append
221 : pprint-string ( string prefix -- )
222 [ % [ unparse-ch ] each CHAR: " , ] "" make
223 do-string-limit f text ;
225 M: string pprint* ( str -- str ) "\"" pprint-string ;
227 M: sbuf pprint* ( str -- str ) "SBUF\" " pprint-string ;
229 M: word pprint* ( word -- )
230 dup "pprint-before-hook" word-prop call
232 "pprint-after-hook" word-prop call ;
234 M: t pprint* drop "t" f text ;
236 M: f pprint* drop "f" f text ;
238 M: dll pprint* ( obj -- str ) dll-path "DLL\" " pprint-string ;
240 : nesting-limit? ( -- ? )
241 nesting-limit get dup
242 [ pprinter get pprinter-stack length < ] when ;
244 : check-recursion ( obj quot -- indent )
245 #! We detect circular structure.
249 over recursion-check get memq? [
252 over recursion-check [ cons ] change
254 recursion-check [ cdr ] change
258 : length-limit? ( seq -- seq ? )
260 [ swap 2dup length < [ head t ] [ nip f ] ifte ]
263 : pprint-element ( object -- )
264 dup parsing? [ \ POSTPONE: pprint-word ] when pprint* ;
266 : pprint-elements ( seq -- )
268 [ pprint-element ] each
269 r> [ "... " f text ] when ;
271 : pprint-sequence ( seq start end -- )
272 swap pprint* swap pprint-elements pprint* ;
274 M: complex pprint* ( num -- )
275 >rect 2vector \ #{ \ }# pprint-sequence ;
277 M: cons pprint* ( list -- )
279 dup list? [ \ [ \ ] ] [ uncons 2vector \ [[ \ ]] ] ifte
283 M: vector pprint* ( vector -- )
284 [ \ { \ } pprint-sequence ] check-recursion ;
286 M: hashtable pprint* ( hashtable -- )
287 [ hash>alist \ {{ \ }} pprint-sequence ] check-recursion ;
289 M: tuple pprint* ( tuple -- )
292 <mirror> dup first pprint*
293 <block 1 swap tail-slice pprint-elements block>
297 M: alien pprint* ( alien -- )
299 drop "( alien expired )"
301 \ ALIEN: pprint-word alien-address number>string
304 M: wrapper pprint* ( wrapper -- )
306 \ \ pprint-word wrapped pprint-word
308 wrapped 1vector \ W[ \ ]W pprint-sequence
311 : with-pprint ( quot -- )
313 <pprinter> pprinter set call end-blocks
314 pprinter get do-pprint
315 ] with-scope ; inline
317 : pprint ( object -- ) [ pprint* ] with-pprint ;
319 : unparse ( object -- str ) [ pprint ] string-out ;
321 : . ( obj -- ) pprint terpri ;
323 : pprint-short ( object -- string )
332 : unparse-short ( object -- str ) [ pprint-short ] string-out ;
334 : short. ( object -- )
335 dup unparse-short swap write-object terpri ;
337 : sequence. ( sequence -- ) [ short. ] each ;
339 : stack. ( sequence -- ) reverse-slice sequence. ;
341 : .s datastack stack. ;
342 : .r callstack stack. ;
350 #! The word will be pretty-printed as a block opener.
351 #! Examples are [ { {{ [[ << and so on.
352 [ <block ] "pprint-after-hook" set-word-prop ;
354 : define-close ( word -- )
355 #! The word will be pretty-printed as a block closer.
356 #! Examples are ] } }} ]] >> and so on.
357 [ block> ] "pprint-before-hook" set-word-prop ;
360 { POSTPONE: [ POSTPONE: ] }
361 { POSTPONE: { POSTPONE: } }
362 { POSTPONE: {{ POSTPONE: }} }
363 { POSTPONE: [[ POSTPONE: ]] }
364 { POSTPONE: [[ POSTPONE: ]] }
365 } [ first2 define-close define-open ] each