2828// side. The paper then describes various performance improvements that reduce
2929// the search space of the best function such that it can complete in O(n)
3030// instead of O(n^2) time, where n is the number of nodes.
31+ //
32+ // For example code with SQL to experiment further, refer to
33+ // https://github.com/knz/prettier/
34+ //
3135package pretty
3236
3337import (
3438 "fmt"
3539)
3640
37- // Doc represents a document as described by the referenced paper.
41+ // Doc represents a document as described by the type "DOC" in the
42+ // referenced paper. This is the abstract representation constructed
43+ // by the pretty-printing code.
3844type Doc interface {
39- // All Docs can uniquely convert themselves into a string so they can be
40- // memoized during better calculation.
41- String () string
4245 isDoc ()
4346}
4447
@@ -48,81 +51,70 @@ func (nilDoc) isDoc() {}
4851func (concat ) isDoc () {}
4952func (nest ) isDoc () {}
5053func (union ) isDoc () {}
51- func (textX ) isDoc () {}
52- func (lineX ) isDoc () {}
53-
54- func (d text ) String () string { return fmt .Sprintf ("(%q)" , string (d )) }
55- func (line ) String () string { return "LINE" }
56- func (nilDoc ) String () string { return "NIL" }
57- func (d concat ) String () string { return fmt .Sprintf ("(%s :<> %s)" , d .a , d .b ) }
58- func (d nest ) String () string { return fmt .Sprintf ("(NEST %d %s)" , d .n , d .d ) }
59- func (d union ) String () string { return fmt .Sprintf ("(%s :<|> %s)" , d .x , d .y ) }
60- func (d textX ) String () string { return fmt .Sprintf ("(%q TEXTX %s)" , d .s , d .d ) }
61- func (d lineX ) String () string { return fmt .Sprintf ("(%q LINEX %s)" , d .s , d .d ) }
6254
55+ //
56+ // Implementations of Doc ("DOC" in paper).
57+ //
58+
59+ // nilDoc represents NIL :: DOC -- the empty doc.
6360type nilDoc struct {}
6461
65- // Nil is the empty Doc .
62+ // Nil is the NIL constructor .
6663var Nil nilDoc
6764
65+ // text represents (TEXT s) :: DOC -- a simple text string.
6866type text string
6967
70- // Text creates a string Doc .
68+ // Text is the TEXT constructor .
7169func Text (s string ) Doc {
7270 return text (s )
7371}
7472
73+ // line represents LINE :: DOC -- a "soft line" that can be flattened to a space.
7574type line struct {}
7675
77- // Line is either a newline or a space if flattened onto a single line .
76+ // Line is the LINE constructor .
7877var Line line
7978
79+ // concat represents (DOC <> DOC) :: DOC -- the concatenation of two docs.
8080type concat struct {
8181 a , b Doc
8282}
8383
84- // fnNotNil runs returns fn(a, b). nil (the Go value) is converted to Nil (the
85- // Doc). If either Doc is Nil, the other Doc is returned without invoking fn.
86- func concatFn (a , b Doc , fn func (Doc , Doc ) Doc ) Doc {
87- if a == nil {
88- a = Nil
89- }
90- if b == nil {
91- b = Nil
92- }
93- if a == Nil {
94- return b
95- }
96- if b == Nil {
97- return a
98- }
99- return fn (a , b )
84+ // Concat is the <> constructor.
85+ // This uses simplifyNil to avoid actually inserting NIL docs
86+ // in the abstract tree.
87+ func Concat (a , b Doc ) Doc {
88+ return simplifyNil (a , b , func (a , b Doc ) Doc { return concat {a , b } })
10089}
10190
102- // Concat concatenates two Docs.
103- func Concat (a , b Doc ) Doc {
104- return concatFn (a , b , func (a , b Doc ) Doc {
105- return concat {a , b }
106- })
91+ // nest represents (NEST Int DOC) :: DOC -- nesting a doc "under" another.
92+ // NEST indents d by s at effective length n. len(s) does not have to be
93+ // n. This allows s to be a tab character and n can be a tab width.
94+ type nest struct {
95+ n int
96+ s string
97+ d Doc
10798}
10899
109- // Fill concatenates a list of docs with spaces if possible,
110- // otherwise with newlines.
111- // See linked paper pp 14-15.
112- // func Fill(d ...Doc) Doc {
113- // switch len(d) {
114- // case 0:
115- // return Nil
116- // case 1:
117- // return d[0]
118- // default:
119- // rest := Fill(d[1:]...)
120- // return union{
121- // ConcatSpace(flatten(d[0]), rest),
122- // ConcatLine(d[0], rest),
123- // }
124- // }
125- // }
100+ // Nest is the NEST constructor.
101+ func Nest (n int , s string , d Doc ) Doc {
102+ return nest {n , s , d }
103+ }
104+
105+ // union represents (DOC <|> DOC) :: DOC -- the union of two docs.
106+ // <|> is really the union of two sets of layouts. x and y must flatten to the
107+ // same layout. Additionally, no first line of a document in x is shorter
108+ // than some first line of a document in y; or, equivalently, every first
109+ // line in x is at least as long as every first line in y.
110+ //
111+ // The main use of the union is via the Group operator defined below.
112+ //
113+ // We do not provide a public constructor as this type is not
114+ // exported.
115+ type union struct {
116+ x , y Doc
117+ }
126118
127119// Group will format d on one line if possible.
128120func Group (d Doc ) Doc {
@@ -149,35 +141,3 @@ func flatten(d Doc) Doc {
149141 panic (fmt .Errorf ("unknown type: %T" , d ))
150142 }
151143}
152-
153- type nest struct {
154- n int
155- s string
156- d Doc
157- }
158-
159- // Nest indents d by s at effective length n. len(s) does not have to be
160- // n. This allows s to be a tab character and n can be a tab width.
161- func Nest (n int , s string , d Doc ) Doc {
162- return nest {n , s , d }
163- }
164-
165- // Doc types below are not directly accessible to users.
166-
167- // union is the union of two sets of layouts. x and y must flatten to the
168- // same layout. Additionally, no first line of a document in x is shorter
169- // than some first line of a document in y; or, equivalently, every first
170- // line in x is at least as long as every first line in y.
171- type union struct {
172- x , y Doc
173- }
174-
175- type textX struct {
176- s string
177- d Doc
178- }
179-
180- type lineX struct {
181- s string
182- d Doc
183- }
0 commit comments