factor/library/syntax/prettyprint.factor

358 lines
8.2 KiB
Factor
Raw Normal View History

2006-01-03 20:04:46 -05:00
! Copyright (C) 2003, 2006 Slava Pestov.
2006-05-15 01:01:47 -04:00
! See http://factorcode.org/license.txt for BSD license.
2004-07-16 02:26:21 -04:00
IN: prettyprint
2006-05-17 14:55:46 -04:00
USING: alien arrays generic hashtables io kernel math
namespaces parser sequences strings styles vectors words ;
2004-07-16 02:26:21 -04:00
2005-08-21 01:17:37 -04:00
! State
2005-12-17 14:52:27 -05:00
SYMBOL: position
2005-08-21 01:17:37 -04:00
SYMBOL: last-newline
2005-02-09 20:57:19 -05:00
SYMBOL: recursion-check
2005-08-21 01:17:37 -04:00
SYMBOL: line-count
SYMBOL: end-printing
2006-01-03 20:04:46 -05:00
SYMBOL: indent
SYMBOL: pprinter-stack
2005-08-21 01:17:37 -04:00
! Configuration
SYMBOL: tab-size
2005-08-21 01:17:37 -04:00
SYMBOL: margin
SYMBOL: nesting-limit
SYMBOL: length-limit
SYMBOL: line-limit
SYMBOL: string-limit
2005-08-21 01:17:37 -04:00
! Special trick to highlight a word in a quotation
SYMBOL: hilite-quotation
SYMBOL: hilite-index
SYMBOL: hilite-next?
2005-08-21 01:17:37 -04:00
global [
4 tab-size set
2005-08-21 01:17:37 -04:00
64 margin set
2005-12-17 14:52:27 -05:00
0 position set
2005-08-21 01:17:37 -04:00
0 indent set
0 last-newline set
1 line-count set
string-limit off
2005-08-21 01:17:37 -04:00
] bind
GENERIC: pprint-section*
TUPLE: section start end nl-after? indent style ;
2005-08-21 01:17:37 -04:00
C: section ( style length -- section )
2005-12-17 14:52:27 -05:00
>r position [ dup rot + dup ] change r>
2005-08-21 01:17:37 -04:00
[ set-section-end ] keep
[ set-section-start ] keep
[ set-section-style ] keep
0 over set-section-indent ;
2005-08-21 01:17:37 -04:00
: line-limit? ( -- ? )
line-limit get dup [ line-count get <= ] when ;
2005-12-24 18:29:31 -05:00
: do-indent indent get CHAR: \s <string> write ;
: fresh-line ( n -- )
dup last-newline get = [
drop
] [
last-newline set
2005-09-14 00:37:50 -04:00
line-limit? [ "..." write end-printing get continue ] when
line-count inc
terpri do-indent
2005-09-24 15:21:17 -04:00
] if ;
2005-08-21 01:17:37 -04:00
TUPLE: text string ;
2005-08-21 01:17:37 -04:00
C: text ( string style -- section )
[ >r over length 1+ <section> r> set-delegate ] keep
2005-08-21 01:17:37 -04:00
[ set-text-string ] keep ;
M: text pprint-section*
dup text-string swap section-style format ;
2005-08-21 01:17:37 -04:00
TUPLE: block sections ;
C: block ( style -- block )
[ >r 0 <section> r> set-delegate ] keep
V{ } clone over set-block-sections
t over set-section-nl-after?
tab-size get over set-section-indent ;
2006-01-03 20:04:46 -05:00
: pprinter-block pprinter-stack get peek ;
: block-empty? ( section -- ? )
2005-09-24 15:21:17 -04:00
dup block? [ block-sections empty? ] [ drop f ] if ;
2005-08-21 01:17:37 -04:00
2006-01-03 20:04:46 -05:00
: add-section ( section -- )
dup block-empty?
[ drop ] [ pprinter-block block-sections push ] if ;
2005-08-21 01:17:37 -04:00
: styled-text ( string style -- ) <text> add-section ;
: text ( string -- ) H{ } styled-text ;
2005-11-29 23:49:59 -05:00
: <indent ( section -- ) section-indent indent [ + ] change ;
: indent> ( section -- ) section-indent indent [ swap - ] change ;
: inset-section ( section -- )
dup <indent
dup section-start fresh-line dup pprint-section*
dup indent>
dup section-nl-after?
2005-09-24 15:21:17 -04:00
[ section-end fresh-line ] [ drop ] if ;
: section-fits? ( section -- ? )
2006-01-28 15:49:31 -05:00
margin get dup zero? [
2drop t
] [
line-limit? pick block? and [
2drop t
] [
>r section-end last-newline get - indent get + r> <=
] if
] if ;
2005-08-21 01:17:37 -04:00
: pprint-section ( section -- )
dup section-fits? [ pprint-section* ] [ inset-section ] if ;
2005-08-21 01:17:37 -04:00
2005-08-29 01:00:55 -04:00
TUPLE: newline ;
2005-08-21 01:17:37 -04:00
C: newline ( -- section )
H{ } 0 <section> over set-delegate ;
2005-08-21 01:17:37 -04:00
M: newline pprint-section*
section-start fresh-line ;
2006-01-03 20:04:46 -05:00
: newline ( -- ) <newline> add-section ;
2005-09-01 02:01:51 -04:00
: advance ( section -- )
2005-09-01 02:15:29 -04:00
dup newline? [
drop
] [
2005-12-28 20:25:17 -05:00
section-start last-newline get = [ bl ] unless
2005-09-24 15:21:17 -04:00
] if ;
2005-09-01 02:01:51 -04:00
: <style section-style stdio [ <nested-style-stream> ] change ;
: style> stdio [ delegate ] change ;
M: block pprint-section*
dup <style
2005-09-01 01:20:43 -04:00
f swap block-sections [
2005-09-01 02:01:51 -04:00
over [ dup advance ] when pprint-section drop t
] each drop
style> ;
2005-07-27 01:46:06 -04:00
: <block ( style -- ) <block> pprinter-stack get push ;
2004-11-25 21:08:09 -05:00
2005-12-17 14:52:27 -05:00
: end-block ( block -- ) position get swap set-section-end ;
2005-02-09 20:57:19 -05:00
2005-08-29 01:00:55 -04:00
: (block>) ( -- )
2006-01-03 20:04:46 -05:00
pprinter-stack get pop dup end-block add-section ;
2006-01-03 20:04:46 -05:00
: last-block? ( -- ? ) pprinter-stack get length 1 = ;
2005-08-29 01:00:55 -04:00
2006-01-03 17:43:29 -05:00
: block> ( -- ) last-block? [ (block>) ] unless ;
2005-08-29 01:00:55 -04:00
: block; ( -- )
2006-01-03 20:04:46 -05:00
pprinter-block f swap set-section-nl-after? block> ;
2005-08-21 01:17:37 -04:00
2005-08-29 01:00:55 -04:00
: end-blocks ( -- ) last-block? [ (block>) end-blocks ] unless ;
2006-01-03 20:04:46 -05:00
: do-pprint ( -- )
[ end-printing set pprinter-block pprint-section ] callcc0 ;
2005-08-21 01:17:37 -04:00
GENERIC: pprint* ( obj -- )
2006-01-06 22:42:07 -05:00
: word-style ( word -- style )
2006-05-19 15:29:22 -04:00
[
dup presented set
parsing? [ bold font-style set ] when
] make-hash ;
2006-01-06 22:42:07 -05:00
2005-08-21 23:35:50 -04:00
: pprint-word ( obj -- )
dup word-name swap word-style styled-text ;
2005-04-13 20:44:06 -04:00
M: object pprint*
"( unprintable object: " swap class word-name " )" append3
text ;
M: real pprint* number>string text ;
: ch>ascii-escape ( ch -- esc )
H{
2005-11-28 02:23:36 -05:00
{ CHAR: \e "\\e" }
{ CHAR: \n "\\n" }
{ CHAR: \r "\\r" }
{ CHAR: \t "\\t" }
{ CHAR: \0 "\\0" }
{ CHAR: \\ "\\\\" }
{ CHAR: \" "\\\"" }
} hash ;
: ch>unicode-escape ( ch -- esc )
>hex 4 CHAR: 0 pad-left "\\u" swap append ;
2005-11-19 04:09:30 -05:00
: unparse-ch ( ch -- )
dup quotable? [
,
] [
2005-09-24 15:21:17 -04:00
dup ch>ascii-escape [ ] [ ch>unicode-escape ] ?if %
] if ;
: do-string-limit ( string -- string )
string-limit get [
dup length margin get > [
margin get 3 - head "..." append
] when
] when ;
: pprint-string ( string prefix -- )
2005-08-25 15:27:38 -04:00
[ % [ unparse-ch ] each CHAR: " , ] "" make
do-string-limit text ;
M: string pprint* "\"" pprint-string ;
M: sbuf pprint* "SBUF\" " pprint-string ;
2005-02-09 20:57:19 -05:00
M: word pprint*
2005-09-22 16:21:36 -04:00
dup "pprint-close" word-prop [ block> ] when
2005-08-29 01:00:55 -04:00
dup pprint-word
"pprint-open" word-prop [ H{ } <block ] when ;
2006-06-26 03:08:54 -04:00
M: f pprint* drop \ f pprint-word ;
M: dll pprint* dll-path "DLL\" " pprint-string ;
2005-02-09 20:57:19 -05:00
2005-08-21 01:17:37 -04:00
: nesting-limit? ( -- ? )
2006-01-03 20:04:46 -05:00
nesting-limit get dup [ pprinter-stack get length < ] when ;
2005-08-21 01:17:37 -04:00
2006-01-03 20:04:46 -05:00
: check-recursion ( obj quot -- )
2005-08-21 01:17:37 -04:00
nesting-limit? [
2drop "#" text
2005-02-09 20:57:19 -05:00
] [
2005-08-07 00:00:57 -04:00
over recursion-check get memq? [
2drop "&" text
2005-08-07 00:00:57 -04:00
] [
over recursion-check get push
2005-08-07 00:00:57 -04:00
call
recursion-check get pop*
2005-09-24 15:21:17 -04:00
] if
] if ; inline
2005-02-09 20:57:19 -05:00
2005-08-21 01:17:37 -04:00
: length-limit? ( seq -- seq ? )
length-limit get dup
[ over length over > [ head t ] [ drop f ] if ]
2005-09-24 15:21:17 -04:00
[ drop f ] if ;
2005-08-29 01:00:55 -04:00
: pprint-element ( object -- )
dup parsing? [ \ POSTPONE: pprint-word ] when pprint* ;
2006-08-12 16:57:49 -04:00
: hilite-style ( -- hash )
H{
{ background { 0.9 0.9 0.9 1 } }
{ highlight t }
} ;
: pprint-hilite ( object n -- )
hilite-index get = [
2006-08-12 16:57:49 -04:00
hilite-style <block pprint-element block>
] [
pprint-element
] if ;
2005-08-21 01:17:37 -04:00
: pprint-elements ( seq -- )
length-limit? >r dup hilite-quotation get eq? [
dup length [ pprint-hilite ] 2each
] [
[ pprint-element ] each
] if r> [ "..." text ] when ;
2005-08-21 01:17:37 -04:00
: pprint-sequence ( seq start end -- )
2005-08-29 01:00:55 -04:00
swap pprint* swap pprint-elements pprint* ;
M: complex pprint*
>rect 2array \ C{ \ } pprint-sequence ;
2005-08-21 01:17:37 -04:00
M: quotation pprint*
2006-05-15 01:01:47 -04:00
[ \ [ \ ] pprint-sequence ] check-recursion ;
2004-07-19 16:10:18 -04:00
M: array pprint*
[ \ { \ } pprint-sequence ] check-recursion ;
M: vector pprint*
[ \ V{ \ } pprint-sequence ] check-recursion ;
2004-11-25 20:37:05 -05:00
M: hashtable pprint*
[ hash>alist \ H{ \ } pprint-sequence ] check-recursion ;
2004-11-25 20:37:05 -05:00
M: tuple pprint*
2005-09-01 01:20:43 -04:00
[
\ T{ pprint*
tuple>array dup first pprint*
H{ } <block 1 tail-slice pprint-elements
\ } pprint*
2005-09-01 01:20:43 -04:00
] check-recursion ;
2004-07-16 02:26:21 -04:00
M: alien pprint*
dup expired? [
drop "( alien expired )"
] [
2005-08-29 01:00:55 -04:00
\ ALIEN: pprint-word alien-address number>string
] if text ;
2005-04-10 18:58:30 -04:00
M: wrapper pprint*
dup wrapped word? [
2005-08-29 01:00:55 -04:00
\ \ pprint-word wrapped pprint-word
] [
wrapped 1array \ W{ \ } pprint-sequence
2005-09-24 15:21:17 -04:00
] if ;
2005-09-05 20:36:10 -04:00
: with-pprint ( quot -- )
2005-02-09 20:57:19 -05:00
[
V{ } clone recursion-check set
H{ } <block> f ?push pprinter-stack set
2006-01-03 20:04:46 -05:00
call end-blocks do-pprint
2005-09-05 20:36:10 -04:00
] with-scope ; inline
: pprint ( object -- ) [ pprint* ] with-pprint ;
2005-08-21 01:17:37 -04:00
: . ( obj -- )
H{
{ length-limit 1000 }
{ nesting-limit 10 }
} clone [ pprint ] bind terpri ;
2004-07-16 02:26:21 -04:00
: unparse ( object -- str ) [ pprint ] string-out ;
2005-08-21 14:40:12 -04:00
: pprint-short ( object -- string )
2006-01-05 00:33:12 -05:00
H{
{ line-limit 1 }
{ length-limit 15 }
{ nesting-limit 2 }
{ string-limit t }
} clone [ pprint ] bind ;
2005-08-21 14:40:12 -04:00
: short. ( object -- ) pprint-short terpri ;
2005-09-25 22:25:54 -04:00
: unparse-short ( object -- string ) [ pprint-short ] string-out ;
: .b >bin print ;
: .o >oct print ;
: .h >hex print ;
2005-08-29 01:00:55 -04:00
2005-11-06 19:14:35 -05:00
: define-open t "pprint-open" set-word-prop ;
: define-close t "pprint-close" set-word-prop ;
{
2006-05-15 01:01:47 -04:00
POSTPONE: [
POSTPONE: { POSTPONE: V{ POSTPONE: H{
POSTPONE: W{
2005-11-06 19:14:35 -05:00
} [ define-open ] each
{
2006-05-15 01:01:47 -04:00
POSTPONE: ] POSTPONE: }
2005-11-06 19:14:35 -05:00
} [ define-close ] each