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 {
3945 // All Docs can uniquely convert themselves into a string so they can be
4046 // memoized during better calculation.
@@ -48,81 +54,77 @@ func (nilDoc) isDoc() {}
4854func (concat ) isDoc () {}
4955func (nest ) isDoc () {}
5056func (union ) isDoc () {}
51- func (textX ) isDoc () {}
52- func (lineX ) isDoc () {}
5357
54- func (d text ) String () string { return fmt .Sprintf ("(%q)" , string (d )) }
58+ func (d text ) String () string { return fmt .Sprintf ("(TEXT %q)" , string (d )) }
5559func (line ) String () string { return "LINE" }
5660func (nilDoc ) String () string { return "NIL" }
5761func (d concat ) String () string { return fmt .Sprintf ("(%s :<> %s)" , d .a , d .b ) }
5862func (d nest ) String () string { return fmt .Sprintf ("(NEST %d %s)" , d .n , d .d ) }
5963func (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 ) }
6264
65+ //
66+ // Implementations of Doc ("DOC" in paper).
67+ //
68+
69+ // nilDoc represents NIL :: DOC -- the empty doc.
6370type nilDoc struct {}
6471
65- // Nil is the empty Doc .
72+ // Nil is the NIL constructor .
6673var Nil nilDoc
6774
75+ // text represents (TEXT s) :: DOC -- a simple text string.
6876type text string
6977
70- // Text creates a string Doc .
78+ // Text is the TEXT constructor .
7179func Text (s string ) Doc {
7280 return text (s )
7381}
7482
83+ // line represents LINE :: DOC -- a "soft line" that can be flattened to a space.
7584type line struct {}
7685
77- // Line is either a newline or a space if flattened onto a single line .
86+ // Line is the LINE constructor .
7887var Line line
7988
89+ // concat represents (DOC <> DOC) :: DOC -- the concatenation of two docs.
8090type concat struct {
8191 a , b Doc
8292}
8393
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 )
94+ // Concat is the <> constructor.
95+ // This uses simplifyNil to avoid actually inserting NIL docs
96+ // in the abstract tree.
97+ func Concat (a , b Doc ) Doc {
98+ return simplifyNil (a , b , func (a , b Doc ) Doc { return concat {a , b } })
10099}
101100
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- })
101+ // nest represents (NEST Int DOC) :: DOC -- nesting a doc "under" another.
102+ // NEST indents d by s at effective length n. len(s) does not have to be
103+ // n. This allows s to be a tab character and n can be a tab width.
104+ type nest struct {
105+ n int
106+ s string
107+ d Doc
107108}
108109
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- // }
110+ // Nest is the NEST constructor.
111+ func Nest (n int , s string , d Doc ) Doc {
112+ return nest {n , s , d }
113+ }
114+
115+ // union represents (DOC <|> DOC) :: DOC -- the union of two docs.
116+ // <|> is really the union of two sets of layouts. x and y must flatten to the
117+ // same layout. Additionally, no first line of a document in x is shorter
118+ // than some first line of a document in y; or, equivalently, every first
119+ // line in x is at least as long as every first line in y.
120+ //
121+ // The main use of the union is via the Group operator defined below.
122+ //
123+ // We do not provide a public constructor as this type is not
124+ // exported.
125+ type union struct {
126+ x , y Doc
127+ }
126128
127129// Group will format d on one line if possible.
128130func Group (d Doc ) Doc {
@@ -149,35 +151,3 @@ func flatten(d Doc) Doc {
149151 panic (fmt .Errorf ("unknown type: %T" , d ))
150152 }
151153}
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