Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 ÿ// Copyright 2009 The Go Authors. All rights reserved.ÿ | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 ÿ// Use of this source code is governed by a BSD-styleÿ | 2 // Use of this source code is governed by a BSD-style |
3 ÿ// license that can be found in the LICENSE file.ÿ | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 ÿ// This file implements printing of AST nodes; specificallyÿ | 5 // This file implements printing of AST nodes; specifically |
6 ÿ// expressions, statements, declarations, and files. It usesÿ | 6 // expressions, statements, declarations, and files. It uses |
7 ÿ// the print functionality implemented in printer.go.ÿ | 7 // the print functionality implemented in printer.go. |
8 | 8 |
9 package printer | 9 package printer |
10 | 10 |
11 import ( | 11 import ( |
12 "bytes" | 12 "bytes" |
13 "go/ast" | 13 "go/ast" |
14 "go/token" | 14 "go/token" |
15 ) | 15 ) |
16 | 16 |
17 | 17 |
18 ÿ// Other formatting issues:ÿ | 18 // Other formatting issues: |
19 ÿ// - better comment formatting for /*-style comments at the end of a line (e.g. a declaration)ÿ | 19 // - better comment formatting for /*-style comments at the end of a line (e.g. a declaration) |
20 ÿ// when the comment spans multiple lines; if such a comment is just two lines , formatting isÿ | 20 // when the comment spans multiple lines; if such a comment is just two lines, formatting is |
21 ÿ// not idempotentÿ | 21 // not idempotent |
22 ÿ// - formatting of expression listsÿ | 22 // - formatting of expression lists |
23 ÿ// - should use blank instead of tab to separate one-line function bodies fromÿ | 23 // - should use blank instead of tab to separate one-line function bodies from |
24 ÿ// the function header unless there is a group of consecutive one-linersÿ | 24 // the function header unless there is a group of consecutive one-liners |
25 | 25 |
26 | 26 |
27 ÿ// ---------------------------------------------------------------------------- ÿ | 27 // ---------------------------------------------------------------------------- |
28 ÿ// Common AST nodes.ÿ | 28 // Common AST nodes. |
29 | 29 |
30 ÿ// Print as many newlines as necessary (but at least min newlines) to get toÿ | 30 // Print as many newlines as necessary (but at least min newlines) to get to |
31 ÿ// the current line. ws is printed before the first line break. If newSectionÿ | 31 // the current line. ws is printed before the first line break. If newSection |
32 ÿ// is set, the first line break is printed as formfeed. Returns true if anyÿ | 32 // is set, the first line break is printed as formfeed. Returns true if any |
33 ÿ// line break was printed; returns false otherwise.ÿ | 33 // line break was printed; returns false otherwise. |
34 ÿ//ÿ | 34 // |
35 ÿ// TODO(gri): linebreak may add too many lines if the next statement at "line"ÿ | 35 // TODO(gri): linebreak may add too many lines if the next statement at "line" |
36 ÿ// is preceeded by comments because the computation of n assumesÿ | 36 // is preceeded by comments because the computation of n assumes |
37 ÿ// the current position before the comment and the target positionÿ | 37 // the current position before the comment and the target position |
38 ÿ// after the comment. Thus, after interspersing such comments, theÿ | 38 // after the comment. Thus, after interspersing such comments, the |
39 ÿ// space taken up by them is not considered to reduce the number ofÿ | 39 // space taken up by them is not considered to reduce the number of |
40 ÿ// linebreaks. At the moment there is no easy way to know aboutÿ | 40 // linebreaks. At the moment there is no easy way to know about |
41 ÿ// future (not yet interspersed) comments in this function.ÿ | 41 // future (not yet interspersed) comments in this function. |
42 ÿ//ÿ | 42 // |
43 func (p *printer) linebreak(line, min int, ws whiteSpace, newSection bool) (prin tedBreak bool) { | 43 func (p *printer) linebreak(line, min int, ws whiteSpace, newSection bool) (prin tedBreak bool) { |
44 n := p.nlines(line-p.pos.Line, min) | 44 n := p.nlines(line-p.pos.Line, min) |
45 if n > 0 { | 45 if n > 0 { |
46 p.print(ws) | 46 p.print(ws) |
47 if newSection { | 47 if newSection { |
48 p.print(formfeed) | 48 p.print(formfeed) |
49 n-- | 49 n-- |
50 } | 50 } |
51 for ; n > 0; n-- { | 51 for ; n > 0; n-- { |
52 p.print(newline) | 52 p.print(newline) |
53 } | 53 } |
54 printedBreak = true | 54 printedBreak = true |
55 } | 55 } |
56 return | 56 return |
57 } | 57 } |
58 | 58 |
59 | 59 |
60 ÿ// setComment sets g as the next comment if g != nil and if node commentsÿ | 60 // setComment sets g as the next comment if g != nil and if node comments |
61 ÿ// are enabled - this mode is used when printing source code fragments suchÿ | 61 // are enabled - this mode is used when printing source code fragments such |
62 ÿ// as exports only. It assumes that there are no other pending comments toÿ | 62 // as exports only. It assumes that there are no other pending comments to |
63 ÿ// intersperse.ÿ | 63 // intersperse. |
64 func (p *printer) setComment(g *ast.CommentGroup) { | 64 func (p *printer) setComment(g *ast.CommentGroup) { |
65 if g == nil || !p.useNodeComments { | 65 if g == nil || !p.useNodeComments { |
66 return | 66 return |
67 } | 67 } |
68 if p.comments == nil { | 68 if p.comments == nil { |
69 » » ÿ// initialize p.comments lazilyÿ | 69 » » // initialize p.comments lazily |
70 p.comments = make([]*ast.CommentGroup, 1) | 70 p.comments = make([]*ast.CommentGroup, 1) |
71 } else if p.cindex < len(p.comments) { | 71 } else if p.cindex < len(p.comments) { |
72 » » ÿ// for some reason there are pending comments; thisÿ | 72 » » // for some reason there are pending comments; this |
73 » » ÿ// should never happen - handle gracefully and flushÿ | 73 » » // should never happen - handle gracefully and flush |
74 » » ÿ// all comments up to g, ignore anything after thatÿ | 74 » » // all comments up to g, ignore anything after that |
75 p.flush(p.fset.Position(g.List[0].Pos()), token.ILLEGAL) | 75 p.flush(p.fset.Position(g.List[0].Pos()), token.ILLEGAL) |
76 } | 76 } |
77 p.comments[0] = g | 77 p.comments[0] = g |
78 p.cindex = 0 | 78 p.cindex = 0 |
79 } | 79 } |
80 | 80 |
81 | 81 |
82 type exprListMode uint | 82 type exprListMode uint |
83 | 83 |
84 const ( | 84 const ( |
85 » blankStart exprListMode = 1 << iota ÿ// print a blank before a non-empty listÿ | 85 » blankStart exprListMode = 1 << iota // print a blank before a non-empty list |
86 » blankEnd ÿ// print a blank after a non-empty listÿ | 86 » blankEnd // print a blank after a non-empty l ist |
87 » commaSep ÿ// elements are separated by commas ÿ | 87 » commaSep // elements are separated by commas |
88 » commaTerm ÿ// list is optionally terminated by a commaÿ | 88 » commaTerm // list is optionally terminated by a comma |
89 » noIndent ÿ// no extra indentation in multi-li ne listsÿ | 89 » noIndent // no extra indentation in multi-lin e lists |
90 » periodSep ÿ// elements are separated by period sÿ | 90 » periodSep // elements are separated by periods |
91 ) | 91 ) |
92 | 92 |
93 | 93 |
94 ÿ// Sets multiLine to true if the identifier list spans multiple lines.ÿ | 94 // Sets multiLine to true if the identifier list spans multiple lines. |
95 ÿ// If indent is set, a multi-line identifier list is indented after theÿ | 95 // If indent is set, a multi-line identifier list is indented after the |
96 ÿ// first linebreak encountered.ÿ | 96 // first linebreak encountered. |
97 func (p *printer) identList(list []*ast.Ident, indent bool, multiLine *bool) { | 97 func (p *printer) identList(list []*ast.Ident, indent bool, multiLine *bool) { |
98 » ÿ// convert into an expression list so we can re-use exprList formatting ÿ | 98 » // convert into an expression list so we can re-use exprList formatting |
99 xlist := make([]ast.Expr, len(list)) | 99 xlist := make([]ast.Expr, len(list)) |
100 for i, x := range list { | 100 for i, x := range list { |
101 xlist[i] = x | 101 xlist[i] = x |
102 } | 102 } |
103 mode := commaSep | 103 mode := commaSep |
104 if !indent { | 104 if !indent { |
105 mode |= noIndent | 105 mode |= noIndent |
106 } | 106 } |
107 p.exprList(token.NoPos, xlist, 1, mode, multiLine, token.NoPos) | 107 p.exprList(token.NoPos, xlist, 1, mode, multiLine, token.NoPos) |
108 } | 108 } |
109 | 109 |
110 | 110 |
111 ÿ// Print a list of expressions. If the list spans multipleÿ | 111 // Print a list of expressions. If the list spans multiple |
112 ÿ// source lines, the original line breaks are respected betweenÿ | 112 // source lines, the original line breaks are respected between |
113 ÿ// expressions. Sets multiLine to true if the list spans multipleÿ | 113 // expressions. Sets multiLine to true if the list spans multiple |
114 ÿ// lines.ÿ | 114 // lines. |
115 ÿ//ÿ | 115 // |
116 ÿ// TODO(gri) Consider rewriting this to be independent of []ast.Exprÿ | 116 // TODO(gri) Consider rewriting this to be independent of []ast.Expr |
117 ÿ// so that we can use the algorithm for any kind of listÿ | 117 // so that we can use the algorithm for any kind of list |
118 ÿ// (e.g., pass list via a channel over which to range).ÿ | 118 // (e.g., pass list via a channel over which to range). |
119 func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp rListMode, multiLine *bool, next0 token.Pos) { | 119 func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp rListMode, multiLine *bool, next0 token.Pos) { |
120 if len(list) == 0 { | 120 if len(list) == 0 { |
121 return | 121 return |
122 } | 122 } |
123 | 123 |
124 if mode&blankStart != 0 { | 124 if mode&blankStart != 0 { |
125 p.print(blank) | 125 p.print(blank) |
126 } | 126 } |
127 | 127 |
128 prev := p.fset.Position(prev0) | 128 prev := p.fset.Position(prev0) |
129 next := p.fset.Position(next0) | 129 next := p.fset.Position(next0) |
130 line := p.fset.Position(list[0].Pos()).Line | 130 line := p.fset.Position(list[0].Pos()).Line |
131 endLine := p.fset.Position(list[len(list)-1].End()).Line | 131 endLine := p.fset.Position(list[len(list)-1].End()).Line |
132 | 132 |
133 if prev.IsValid() && prev.Line == line && line == endLine { | 133 if prev.IsValid() && prev.Line == line && line == endLine { |
134 » » ÿ// all list entries on a single lineÿ | 134 » » // all list entries on a single line |
135 for i, x := range list { | 135 for i, x := range list { |
136 if i > 0 { | 136 if i > 0 { |
137 if mode&commaSep != 0 { | 137 if mode&commaSep != 0 { |
138 p.print(token.COMMA) | 138 p.print(token.COMMA) |
139 } | 139 } |
140 p.print(blank) | 140 p.print(blank) |
141 } | 141 } |
142 p.expr0(x, depth, multiLine) | 142 p.expr0(x, depth, multiLine) |
143 } | 143 } |
144 if mode&blankEnd != 0 { | 144 if mode&blankEnd != 0 { |
145 p.print(blank) | 145 p.print(blank) |
146 } | 146 } |
147 return | 147 return |
148 } | 148 } |
149 | 149 |
150 » ÿ// list entries span multiple lines;ÿ | 150 » // list entries span multiple lines; |
151 » ÿ// use source code positions to guide line breaksÿ | 151 » // use source code positions to guide line breaks |
152 | 152 |
153 » ÿ// don't add extra indentation if noIndent is set;ÿ | 153 » // don't add extra indentation if noIndent is set; |
154 » ÿ// i.e., pretend that the first line is already indentedÿ | 154 » // i.e., pretend that the first line is already indented |
155 ws := ignore | 155 ws := ignore |
156 if mode&noIndent == 0 { | 156 if mode&noIndent == 0 { |
157 ws = indent | 157 ws = indent |
158 } | 158 } |
159 | 159 |
160 » ÿ// the first linebreak is always a formfeed since this section must not ÿ | 160 » // the first linebreak is always a formfeed since this section must not |
161 » ÿ// depend on any previous formattingÿ | 161 » // depend on any previous formatting |
162 » prevBreak := -1 ÿ// index of last expression that was followed by a line breakÿ | 162 » prevBreak := -1 // index of last expression that was followed by a lineb reak |
163 linebreakMin := 1 | 163 linebreakMin := 1 |
164 if mode&periodSep != 0 { | 164 if mode&periodSep != 0 { |
165 » » ÿ// Make fragments likeÿ | 165 » » // Make fragments like |
166 » » ÿ//ÿ | 166 » » // |
167 » » ÿ// a.Bar(1,ÿ | 167 » » // a.Bar(1, |
168 » » ÿ// 2).Fooÿ | 168 » » // 2).Foo |
169 » » ÿ//ÿ | 169 » » // |
170 » » ÿ// format correctly (a linebreak shouldn't be added before Foo) whenÿ | 170 » » // format correctly (a linebreak shouldn't be added before Foo) when |
171 » » ÿ// doing period-separated expr lists by setting minimum linebre ak to 0ÿ | 171 » » // doing period-separated expr lists by setting minimum linebrea k to 0 |
172 » » ÿ// lines for them.ÿ | 172 » » // lines for them. |
173 linebreakMin = 0 | 173 linebreakMin = 0 |
174 } | 174 } |
175 if prev.IsValid() && prev.Line < line && p.linebreak(line, linebreakMin, ws, true) { | 175 if prev.IsValid() && prev.Line < line && p.linebreak(line, linebreakMin, ws, true) { |
176 ws = ignore | 176 ws = ignore |
177 *multiLine = true | 177 *multiLine = true |
178 prevBreak = 0 | 178 prevBreak = 0 |
179 } | 179 } |
180 | 180 |
181 » ÿ// initialize expression/key size: a zero value indicates expr/key does n't fit on a single lineÿ | 181 » // initialize expression/key size: a zero value indicates expr/key doesn 't fit on a single line |
182 size := 0 | 182 size := 0 |
183 | 183 |
184 » ÿ// print all list elementsÿ | 184 » // print all list elements |
185 for i, x := range list { | 185 for i, x := range list { |
186 prevLine := line | 186 prevLine := line |
187 line = p.fset.Position(x.Pos()).Line | 187 line = p.fset.Position(x.Pos()).Line |
188 | 188 |
189 » » ÿ// determine if the next linebreak, if any, needs to use formfe ed:ÿ | 189 » » // determine if the next linebreak, if any, needs to use formfee d: |
190 » » ÿ// in general, use the entire node size to make the decision; f orÿ | 190 » » // in general, use the entire node size to make the decision; fo r |
191 » » ÿ// key:value expressions, use the key sizeÿ | 191 » » // key:value expressions, use the key size |
192 » » ÿ// TODO(gri) for a better result, should probably incorporate b othÿ | 192 » » // TODO(gri) for a better result, should probably incorporate bo th |
193 » » ÿ// the key and the node size into the decision proces sÿ | 193 » » // the key and the node size into the decision process |
194 useFF := true | 194 useFF := true |
195 | 195 |
196 » » ÿ// determine element size: all bets are off if we don't haveÿ | 196 » » // determine element size: all bets are off if we don't have |
197 » » ÿ// position information for the previous and next token (likely ÿ | 197 » » // position information for the previous and next token (likely |
198 » » ÿ// generated code - simply ignore the size in this case by sett ingÿ | 198 » » // generated code - simply ignore the size in this case by setti ng |
199 » » ÿ// it to 0)ÿ | 199 » » // it to 0) |
200 prevSize := size | 200 prevSize := size |
201 » » const infinity = 1e6 ÿ// larger than any source lineÿ | 201 » » const infinity = 1e6 // larger than any source line |
202 size = p.nodeSize(x, infinity) | 202 size = p.nodeSize(x, infinity) |
203 pair, isPair := x.(*ast.KeyValueExpr) | 203 pair, isPair := x.(*ast.KeyValueExpr) |
204 if size <= infinity && prev.IsValid() && next.IsValid() { | 204 if size <= infinity && prev.IsValid() && next.IsValid() { |
205 » » » ÿ// x fits on a single lineÿ | 205 » » » // x fits on a single line |
206 if isPair { | 206 if isPair { |
207 » » » » size = p.nodeSize(pair.Key, infinity) ÿ// size < = infinityÿ | 207 » » » » size = p.nodeSize(pair.Key, infinity) // size <= infinity |
208 } | 208 } |
209 } else { | 209 } else { |
210 » » » ÿ// size too large or we don't have good layout informat ionÿ | 210 » » » // size too large or we don't have good layout informati on |
211 size = 0 | 211 size = 0 |
212 } | 212 } |
213 | 213 |
214 » » ÿ// if the previous line and the current line had single-ÿ | 214 » » // if the previous line and the current line had single- |
215 » » ÿ// line-expressions and the key sizes are small or theÿ | 215 » » // line-expressions and the key sizes are small or the |
216 » » ÿ// the ratio between the key sizes does not exceed aÿ | 216 » » // the ratio between the key sizes does not exceed a |
217 » » ÿ// threshold, align columns and do not use formfeedÿ | 217 » » // threshold, align columns and do not use formfeed |
218 if prevSize > 0 && size > 0 { | 218 if prevSize > 0 && size > 0 { |
219 const smallSize = 20 | 219 const smallSize = 20 |
220 if prevSize <= smallSize && size <= smallSize { | 220 if prevSize <= smallSize && size <= smallSize { |
221 useFF = false | 221 useFF = false |
222 } else { | 222 } else { |
223 » » » » const r = 4 ÿ// thresholdÿ | 223 » » » » const r = 4 // threshold |
224 ratio := float64(size) / float64(prevSize) | 224 ratio := float64(size) / float64(prevSize) |
225 useFF = ratio <= 1/r || r <= ratio | 225 useFF = ratio <= 1/r || r <= ratio |
226 } | 226 } |
227 } | 227 } |
228 | 228 |
229 if i > 0 { | 229 if i > 0 { |
230 if mode&commaSep != 0 { | 230 if mode&commaSep != 0 { |
231 p.print(token.COMMA) | 231 p.print(token.COMMA) |
232 } | 232 } |
233 if mode&periodSep != 0 { | 233 if mode&periodSep != 0 { |
234 p.print(token.PERIOD) | 234 p.print(token.PERIOD) |
235 } | 235 } |
236 if prevLine < line && prevLine > 0 && line > 0 { | 236 if prevLine < line && prevLine > 0 && line > 0 { |
237 » » » » ÿ// lines are broken using newlines so comments remain alignedÿ | 237 » » » » // lines are broken using newlines so comments r emain aligned |
238 » » » » ÿ// unless forceFF is set or there are multiple expressions onÿ | 238 » » » » // unless forceFF is set or there are multiple e xpressions on |
239 » » » » ÿ// the same line in which case formfeed is used ÿ | 239 » » » » // the same line in which case formfeed is used |
240 if p.linebreak(line, linebreakMin, ws, useFF || prevBreak+1 < i) { | 240 if p.linebreak(line, linebreakMin, ws, useFF || prevBreak+1 < i) { |
241 ws = ignore | 241 ws = ignore |
242 *multiLine = true | 242 *multiLine = true |
243 prevBreak = i | 243 prevBreak = i |
244 } | 244 } |
245 } else if mode&periodSep == 0 { | 245 } else if mode&periodSep == 0 { |
246 p.print(blank) | 246 p.print(blank) |
247 } | 247 } |
248 » » » ÿ// period-separated list elements don't need a blankÿ | 248 » » » // period-separated list elements don't need a blank |
249 } | 249 } |
250 | 250 |
251 if isPair && size > 0 && len(list) > 1 { | 251 if isPair && size > 0 && len(list) > 1 { |
252 » » » ÿ// we have a key:value expression that fits onto one li ne andÿ | 252 » » » // we have a key:value expression that fits onto one lin e and |
253 » » » ÿ// is in a list with more then one entry: use a column for theÿ | 253 » » » // is in a list with more then one entry: use a column f or the |
254 » » » ÿ// key such that consecutive entries can align if possi bleÿ | 254 » » » // key such that consecutive entries can align if possib le |
255 p.expr(pair.Key, multiLine) | 255 p.expr(pair.Key, multiLine) |
256 p.print(pair.Colon, token.COLON, vtab) | 256 p.print(pair.Colon, token.COLON, vtab) |
257 p.expr(pair.Value, multiLine) | 257 p.expr(pair.Value, multiLine) |
258 } else { | 258 } else { |
259 p.expr0(x, depth, multiLine) | 259 p.expr0(x, depth, multiLine) |
260 } | 260 } |
261 } | 261 } |
262 | 262 |
263 if mode&commaTerm != 0 && next.IsValid() && p.pos.Line < next.Line { | 263 if mode&commaTerm != 0 && next.IsValid() && p.pos.Line < next.Line { |
264 » » ÿ// print a terminating comma if the next token is on a new line ÿ | 264 » » // print a terminating comma if the next token is on a new line |
265 p.print(token.COMMA) | 265 p.print(token.COMMA) |
266 if ws == ignore && mode&noIndent == 0 { | 266 if ws == ignore && mode&noIndent == 0 { |
267 » » » ÿ// unindent if we indentedÿ | 267 » » » // unindent if we indented |
268 p.print(unindent) | 268 p.print(unindent) |
269 } | 269 } |
270 » » p.print(formfeed) ÿ// terminating comma needs a line break to lo ok goodÿ | 270 » » p.print(formfeed) // terminating comma needs a line break to loo k good |
271 return | 271 return |
272 } | 272 } |
273 | 273 |
274 if mode&blankEnd != 0 { | 274 if mode&blankEnd != 0 { |
275 p.print(blank) | 275 p.print(blank) |
276 } | 276 } |
277 | 277 |
278 if ws == ignore && mode&noIndent == 0 { | 278 if ws == ignore && mode&noIndent == 0 { |
279 » » ÿ// unindent if we indentedÿ | 279 » » // unindent if we indented |
280 p.print(unindent) | 280 p.print(unindent) |
281 } | 281 } |
282 } | 282 } |
283 | 283 |
284 | 284 |
285 ÿ// Sets multiLine to true if the the parameter list spans multiple lines.ÿ | 285 // Sets multiLine to true if the the parameter list spans multiple lines. |
286 func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) { | 286 func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) { |
287 p.print(fields.Opening, token.LPAREN) | 287 p.print(fields.Opening, token.LPAREN) |
288 if len(fields.List) > 0 { | 288 if len(fields.List) > 0 { |
289 var prevLine, line int | 289 var prevLine, line int |
290 for i, par := range fields.List { | 290 for i, par := range fields.List { |
291 if i > 0 { | 291 if i > 0 { |
292 p.print(token.COMMA) | 292 p.print(token.COMMA) |
293 if len(par.Names) > 0 { | 293 if len(par.Names) > 0 { |
294 line = p.fset.Position(par.Names[0].Pos( )).Line | 294 line = p.fset.Position(par.Names[0].Pos( )).Line |
295 } else { | 295 } else { |
(...skipping 10 matching lines...) Expand all Loading... | |
306 p.print(blank) | 306 p.print(blank) |
307 } | 307 } |
308 p.expr(par.Type, multiLine) | 308 p.expr(par.Type, multiLine) |
309 prevLine = p.fset.Position(par.Type.Pos()).Line | 309 prevLine = p.fset.Position(par.Type.Pos()).Line |
310 } | 310 } |
311 } | 311 } |
312 p.print(fields.Closing, token.RPAREN) | 312 p.print(fields.Closing, token.RPAREN) |
313 } | 313 } |
314 | 314 |
315 | 315 |
316 ÿ// Sets multiLine to true if the signature spans multiple lines.ÿ | 316 // Sets multiLine to true if the signature spans multiple lines. |
317 func (p *printer) signature(params, result *ast.FieldList, multiLine *bool) { | 317 func (p *printer) signature(params, result *ast.FieldList, multiLine *bool) { |
318 p.parameters(params, multiLine) | 318 p.parameters(params, multiLine) |
319 n := result.NumFields() | 319 n := result.NumFields() |
320 if n > 0 { | 320 if n > 0 { |
321 p.print(blank) | 321 p.print(blank) |
322 if n == 1 && result.List[0].Names == nil { | 322 if n == 1 && result.List[0].Names == nil { |
323 » » » ÿ// single anonymous result; no ()'sÿ | 323 » » » // single anonymous result; no ()'s |
324 p.expr(result.List[0].Type, multiLine) | 324 p.expr(result.List[0].Type, multiLine) |
325 return | 325 return |
326 } | 326 } |
327 p.parameters(result, multiLine) | 327 p.parameters(result, multiLine) |
328 } | 328 } |
329 } | 329 } |
330 | 330 |
331 | 331 |
332 func identListSize(list []*ast.Ident, maxSize int) (size int) { | 332 func identListSize(list []*ast.Ident, maxSize int) (size int) { |
333 for i, x := range list { | 333 for i, x := range list { |
334 if i > 0 { | 334 if i > 0 { |
335 » » » size += 2 ÿ// ", "ÿ | 335 » » » size += 2 // ", " |
336 } | 336 } |
337 size += len(x.Name) | 337 size += len(x.Name) |
338 if size >= maxSize { | 338 if size >= maxSize { |
339 break | 339 break |
340 } | 340 } |
341 } | 341 } |
342 return | 342 return |
343 } | 343 } |
344 | 344 |
345 | 345 |
346 func (p *printer) isOneLineFieldList(list []*ast.Field) bool { | 346 func (p *printer) isOneLineFieldList(list []*ast.Field) bool { |
347 if len(list) != 1 { | 347 if len(list) != 1 { |
348 » » return false ÿ// allow only one fieldÿ | 348 » » return false // allow only one field |
349 } | 349 } |
350 f := list[0] | 350 f := list[0] |
351 if f.Tag != nil || f.Comment != nil { | 351 if f.Tag != nil || f.Comment != nil { |
352 » » return false ÿ// don't allow tags or commentsÿ | 352 » » return false // don't allow tags or comments |
353 » } | 353 » } |
354 » ÿ// only name(s) and typeÿ | 354 » // only name(s) and type |
355 » const maxSize = 30 ÿ// adjust as appropriate, this is an approximate val ueÿ | 355 » const maxSize = 30 // adjust as appropriate, this is an approximate valu e |
356 namesSize := identListSize(f.Names, maxSize) | 356 namesSize := identListSize(f.Names, maxSize) |
357 if namesSize > 0 { | 357 if namesSize > 0 { |
358 » » namesSize = 1 ÿ// blank between names and typesÿ | 358 » » namesSize = 1 // blank between names and types |
359 } | 359 } |
360 typeSize := p.nodeSize(f.Type, maxSize) | 360 typeSize := p.nodeSize(f.Type, maxSize) |
361 return namesSize+typeSize <= maxSize | 361 return namesSize+typeSize <= maxSize |
362 } | 362 } |
363 | 363 |
364 | 364 |
365 func (p *printer) setLineComment(text string) { | 365 func (p *printer) setLineComment(text string) { |
366 p.setComment(&ast.CommentGroup{[]*ast.Comment{&ast.Comment{token.NoPos, text}}}) | 366 p.setComment(&ast.CommentGroup{[]*ast.Comment{&ast.Comment{token.NoPos, text}}}) |
367 } | 367 } |
368 | 368 |
369 | 369 |
370 func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) { | 370 func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) { |
371 p.nesting++ | 371 p.nesting++ |
372 defer func() { | 372 defer func() { |
373 p.nesting-- | 373 p.nesting-- |
374 }() | 374 }() |
375 | 375 |
376 lbrace := fields.Opening | 376 lbrace := fields.Opening |
377 list := fields.List | 377 list := fields.List |
378 rbrace := fields.Closing | 378 rbrace := fields.Closing |
379 srcIsOneLine := lbrace.IsValid() && rbrace.IsValid() && p.fset.Position( lbrace).Line == p.fset.Position(rbrace).Line | 379 srcIsOneLine := lbrace.IsValid() && rbrace.IsValid() && p.fset.Position( lbrace).Line == p.fset.Position(rbrace).Line |
380 | 380 |
381 if !isIncomplete && !p.commentBefore(p.fset.Position(rbrace)) && srcIsOn eLine { | 381 if !isIncomplete && !p.commentBefore(p.fset.Position(rbrace)) && srcIsOn eLine { |
382 » » ÿ// possibly a one-line struct/interfaceÿ | 382 » » // possibly a one-line struct/interface |
383 if len(list) == 0 { | 383 if len(list) == 0 { |
384 » » » ÿ// no blank between keyword and {} in this caseÿ | 384 » » » // no blank between keyword and {} in this case |
385 p.print(lbrace, token.LBRACE, rbrace, token.RBRACE) | 385 p.print(lbrace, token.LBRACE, rbrace, token.RBRACE) |
386 return | 386 return |
387 » » } else if isStruct && p.isOneLineFieldList(list) { ÿ// for now i gnore interfacesÿ | 387 » » } else if isStruct && p.isOneLineFieldList(list) { // for now ig nore interfaces |
388 » » » ÿ// small enough - print on one lineÿ | 388 » » » // small enough - print on one line |
389 » » » ÿ// (don't use identList and ignore source line breaks)ÿ | 389 » » » // (don't use identList and ignore source line breaks) |
390 p.print(lbrace, token.LBRACE, blank) | 390 p.print(lbrace, token.LBRACE, blank) |
391 f := list[0] | 391 f := list[0] |
392 for i, x := range f.Names { | 392 for i, x := range f.Names { |
393 if i > 0 { | 393 if i > 0 { |
394 p.print(token.COMMA, blank) | 394 p.print(token.COMMA, blank) |
395 } | 395 } |
396 p.expr(x, ignoreMultiLine) | 396 p.expr(x, ignoreMultiLine) |
397 } | 397 } |
398 if len(f.Names) > 0 { | 398 if len(f.Names) > 0 { |
399 p.print(blank) | 399 p.print(blank) |
400 } | 400 } |
401 p.expr(f.Type, ignoreMultiLine) | 401 p.expr(f.Type, ignoreMultiLine) |
402 p.print(blank, rbrace, token.RBRACE) | 402 p.print(blank, rbrace, token.RBRACE) |
403 return | 403 return |
404 } | 404 } |
405 } | 405 } |
406 | 406 |
407 » ÿ// at least one entry or incompleteÿ | 407 » // at least one entry or incomplete |
408 p.print(blank, lbrace, token.LBRACE, indent, formfeed) | 408 p.print(blank, lbrace, token.LBRACE, indent, formfeed) |
409 if isStruct { | 409 if isStruct { |
410 | 410 |
411 sep := vtab | 411 sep := vtab |
412 if len(list) == 1 { | 412 if len(list) == 1 { |
413 sep = blank | 413 sep = blank |
414 } | 414 } |
415 var ml bool | 415 var ml bool |
416 for i, f := range list { | 416 for i, f := range list { |
417 if i > 0 { | 417 if i > 0 { |
418 p.linebreak(p.fset.Position(f.Pos()).Line, 1, ig nore, ml) | 418 p.linebreak(p.fset.Position(f.Pos()).Line, 1, ig nore, ml) |
419 } | 419 } |
420 ml = false | 420 ml = false |
421 extraTabs := 0 | 421 extraTabs := 0 |
422 p.setComment(f.Doc) | 422 p.setComment(f.Doc) |
423 if len(f.Names) > 0 { | 423 if len(f.Names) > 0 { |
424 » » » » ÿ// named fieldsÿ | 424 » » » » // named fields |
425 p.identList(f.Names, false, &ml) | 425 p.identList(f.Names, false, &ml) |
426 p.print(sep) | 426 p.print(sep) |
427 p.expr(f.Type, &ml) | 427 p.expr(f.Type, &ml) |
428 extraTabs = 1 | 428 extraTabs = 1 |
429 } else { | 429 } else { |
430 » » » » ÿ// anonymous fieldÿ | 430 » » » » // anonymous field |
431 p.expr(f.Type, &ml) | 431 p.expr(f.Type, &ml) |
432 extraTabs = 2 | 432 extraTabs = 2 |
433 } | 433 } |
434 if f.Tag != nil { | 434 if f.Tag != nil { |
435 if len(f.Names) > 0 && sep == vtab { | 435 if len(f.Names) > 0 && sep == vtab { |
436 p.print(sep) | 436 p.print(sep) |
437 } | 437 } |
438 p.print(sep) | 438 p.print(sep) |
439 p.expr(f.Tag, &ml) | 439 p.expr(f.Tag, &ml) |
440 extraTabs = 0 | 440 extraTabs = 0 |
441 } | 441 } |
442 if f.Comment != nil { | 442 if f.Comment != nil { |
443 for ; extraTabs > 0; extraTabs-- { | 443 for ; extraTabs > 0; extraTabs-- { |
444 p.print(sep) | 444 p.print(sep) |
445 } | 445 } |
446 p.setComment(f.Comment) | 446 p.setComment(f.Comment) |
447 } | 447 } |
448 } | 448 } |
449 if isIncomplete { | 449 if isIncomplete { |
450 if len(list) > 0 { | 450 if len(list) > 0 { |
451 p.print(formfeed) | 451 p.print(formfeed) |
452 } | 452 } |
453 » » » p.flush(p.fset.Position(rbrace), token.RBRACE) ÿ// make sure we don't loose the last line commentÿ | 453 » » » p.flush(p.fset.Position(rbrace), token.RBRACE) // make s ure we don't loose the last line comment |
454 p.setLineComment("// contains unexported fields") | 454 p.setLineComment("// contains unexported fields") |
455 } | 455 } |
456 | 456 |
457 » } else { ÿ// interfaceÿ | 457 » } else { // interface |
458 | 458 |
459 var ml bool | 459 var ml bool |
460 for i, f := range list { | 460 for i, f := range list { |
461 if i > 0 { | 461 if i > 0 { |
462 p.linebreak(p.fset.Position(f.Pos()).Line, 1, ig nore, ml) | 462 p.linebreak(p.fset.Position(f.Pos()).Line, 1, ig nore, ml) |
463 } | 463 } |
464 ml = false | 464 ml = false |
465 p.setComment(f.Doc) | 465 p.setComment(f.Doc) |
466 if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp { | 466 if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp { |
467 » » » » ÿ// methodÿ | 467 » » » » // method |
468 p.expr(f.Names[0], &ml) | 468 p.expr(f.Names[0], &ml) |
469 p.signature(ftyp.Params, ftyp.Results, &ml) | 469 p.signature(ftyp.Params, ftyp.Results, &ml) |
470 } else { | 470 } else { |
471 » » » » ÿ// embedded interfaceÿ | 471 » » » » // embedded interface |
472 p.expr(f.Type, &ml) | 472 p.expr(f.Type, &ml) |
473 } | 473 } |
474 p.setComment(f.Comment) | 474 p.setComment(f.Comment) |
475 } | 475 } |
476 if isIncomplete { | 476 if isIncomplete { |
477 if len(list) > 0 { | 477 if len(list) > 0 { |
478 p.print(formfeed) | 478 p.print(formfeed) |
479 } | 479 } |
480 » » » p.flush(p.fset.Position(rbrace), token.RBRACE) ÿ// make sure we don't loose the last line commentÿ | 480 » » » p.flush(p.fset.Position(rbrace), token.RBRACE) // make s ure we don't loose the last line comment |
481 p.setLineComment("// contains unexported methods") | 481 p.setLineComment("// contains unexported methods") |
482 } | 482 } |
483 | 483 |
484 } | 484 } |
485 p.print(unindent, formfeed, rbrace, token.RBRACE) | 485 p.print(unindent, formfeed, rbrace, token.RBRACE) |
486 } | 486 } |
487 | 487 |
488 | 488 |
489 ÿ// ---------------------------------------------------------------------------- ÿ | 489 // ---------------------------------------------------------------------------- |
490 ÿ// Expressionsÿ | 490 // Expressions |
491 | 491 |
492 func walkBinary(e *ast.BinaryExpr) (has4, has5 bool, maxProblem int) { | 492 func walkBinary(e *ast.BinaryExpr) (has4, has5 bool, maxProblem int) { |
493 switch e.Op.Precedence() { | 493 switch e.Op.Precedence() { |
494 case 4: | 494 case 4: |
495 has4 = true | 495 has4 = true |
496 case 5: | 496 case 5: |
497 has5 = true | 497 has5 = true |
498 } | 498 } |
499 | 499 |
500 switch l := e.X.(type) { | 500 switch l := e.X.(type) { |
501 case *ast.BinaryExpr: | 501 case *ast.BinaryExpr: |
502 if l.Op.Precedence() < e.Op.Precedence() { | 502 if l.Op.Precedence() < e.Op.Precedence() { |
503 » » » ÿ// parens will be inserted.ÿ | 503 » » » // parens will be inserted. |
504 » » » ÿ// pretend this is an *ast.ParenExpr and do nothing.ÿ | 504 » » » // pretend this is an *ast.ParenExpr and do nothing. |
505 break | 505 break |
506 } | 506 } |
507 h4, h5, mp := walkBinary(l) | 507 h4, h5, mp := walkBinary(l) |
508 has4 = has4 || h4 | 508 has4 = has4 || h4 |
509 has5 = has5 || h5 | 509 has5 = has5 || h5 |
510 if maxProblem < mp { | 510 if maxProblem < mp { |
511 maxProblem = mp | 511 maxProblem = mp |
512 } | 512 } |
513 } | 513 } |
514 | 514 |
515 switch r := e.Y.(type) { | 515 switch r := e.Y.(type) { |
516 case *ast.BinaryExpr: | 516 case *ast.BinaryExpr: |
517 if r.Op.Precedence() <= e.Op.Precedence() { | 517 if r.Op.Precedence() <= e.Op.Precedence() { |
518 » » » ÿ// parens will be inserted.ÿ | 518 » » » // parens will be inserted. |
519 » » » ÿ// pretend this is an *ast.ParenExpr and do nothing.ÿ | 519 » » » // pretend this is an *ast.ParenExpr and do nothing. |
520 break | 520 break |
521 } | 521 } |
522 h4, h5, mp := walkBinary(r) | 522 h4, h5, mp := walkBinary(r) |
523 has4 = has4 || h4 | 523 has4 = has4 || h4 |
524 has5 = has5 || h5 | 524 has5 = has5 || h5 |
525 if maxProblem < mp { | 525 if maxProblem < mp { |
526 maxProblem = mp | 526 maxProblem = mp |
527 } | 527 } |
528 | 528 |
529 case *ast.StarExpr: | 529 case *ast.StarExpr: |
530 » » if e.Op.String() == "/" { | 530 » » if e.Op == token.QUO { |
rsc
2011/03/29 03:52:20
worth a comment, as it were
if e.Op == token.QUO
gri
2011/03/29 04:44:34
Done.
| |
531 maxProblem = 5 | 531 maxProblem = 5 |
532 } | 532 } |
533 | 533 |
534 case *ast.UnaryExpr: | 534 case *ast.UnaryExpr: |
535 switch e.Op.String() + r.Op.String() { | 535 switch e.Op.String() + r.Op.String() { |
536 case "/*", "&&", "&^": | 536 case "/*", "&&", "&^": |
537 maxProblem = 5 | 537 maxProblem = 5 |
538 case "++", "--": | 538 case "++", "--": |
539 if maxProblem < 4 { | 539 if maxProblem < 4 { |
540 maxProblem = 4 | 540 maxProblem = 4 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
574 | 574 |
575 func reduceDepth(depth int) int { | 575 func reduceDepth(depth int) int { |
576 depth-- | 576 depth-- |
577 if depth < 1 { | 577 if depth < 1 { |
578 depth = 1 | 578 depth = 1 |
579 } | 579 } |
580 return depth | 580 return depth |
581 } | 581 } |
582 | 582 |
583 | 583 |
584 ÿ// Format the binary expression: decide the cutoff and then format.ÿ | 584 // Format the binary expression: decide the cutoff and then format. |
585 ÿ// Let's call depth == 1 Normal mode, and depth > 1 Compact mode.ÿ | 585 // Let's call depth == 1 Normal mode, and depth > 1 Compact mode. |
586 ÿ// (Algorithm suggestion by Russ Cox.)ÿ | 586 // (Algorithm suggestion by Russ Cox.) |
587 ÿ//ÿ | 587 // |
588 ÿ// The precedences are:ÿ | 588 // The precedences are: |
589 ÿ// 5 * / % << >> & &^ÿ | 589 //» 5 * / % << >> & &^ |
590 ÿ// 4 + - | ^ÿ | 590 //» 4 + - | ^ |
591 ÿ// 3 == != < <= > >=ÿ | 591 //» 3 == != < <= > >= |
592 ÿ// 2 &&ÿ | 592 //» 2 && |
593 ÿ// 1 ||ÿ | 593 //» 1 || |
594 ÿ//ÿ | 594 // |
595 ÿ// The only decision is whether there will be spaces around levels 4 and 5.ÿ | 595 // The only decision is whether there will be spaces around levels 4 and 5. |
596 ÿ// There are never spaces at level 6 (unary), and always spaces at levels 3 and below.ÿ | 596 // There are never spaces at level 6 (unary), and always spaces at levels 3 and below. |
597 ÿ//ÿ | 597 // |
598 ÿ// To choose the cutoff, look at the whole expression but excluding primaryÿ | 598 // To choose the cutoff, look at the whole expression but excluding primary |
599 ÿ// expressions (function calls, parenthesized exprs), and apply these rules:ÿ | 599 // expressions (function calls, parenthesized exprs), and apply these rules: |
600 ÿ//ÿ | 600 // |
601 ÿ// 1) If there is a binary operator with a right side unary operandÿ | 601 //» 1) If there is a binary operator with a right side unary operand |
602 ÿ// that would clash without a space, the cutoff must be (in order):ÿ | 602 //» that would clash without a space, the cutoff must be (in order): |
603 ÿ//ÿ | 603 // |
604 ÿ// /* 6ÿ | 604 //» » /*» 6 |
605 ÿ// && 6ÿ | 605 //» » &&» 6 |
606 ÿ// &^ 6ÿ | 606 //» » &^» 6 |
607 ÿ// ++ 5ÿ | 607 //» » ++» 5 |
608 ÿ// -- 5ÿ | 608 //» » --» 5 |
609 ÿ//ÿ | 609 // |
610 ÿ// (Comparison operators always have spaces around them.)ÿ | 610 // (Comparison operators always have spaces around them.) |
611 ÿ//ÿ | 611 // |
612 ÿ// 2) If there is a mix of level 5 and level 4 operators, then the cutoffÿ | 612 //» 2) If there is a mix of level 5 and level 4 operators, then the cutoff |
613 ÿ// is 5 (use spaces to distinguish precedence) in Normal modeÿ | 613 //» is 5 (use spaces to distinguish precedence) in Normal mode |
614 ÿ// and 4 (never use spaces) in Compact mode.ÿ | 614 //» and 4 (never use spaces) in Compact mode. |
615 ÿ//ÿ | 615 // |
616 ÿ// 3) If there are no level 4 operators or no level 5 operators, then theÿ | 616 //» 3) If there are no level 4 operators or no level 5 operators, then the |
617 ÿ// cutoff is 6 (always use spaces) in Normal modeÿ | 617 //» cutoff is 6 (always use spaces) in Normal mode |
618 ÿ// and 4 (never use spaces) in Compact mode.ÿ | 618 //» and 4 (never use spaces) in Compact mode. |
619 ÿ//ÿ | 619 // |
620 ÿ// Sets multiLine to true if the binary expression spans multiple lines.ÿ | 620 // Sets multiLine to true if the binary expression spans multiple lines. |
621 func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiL ine *bool) { | 621 func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiL ine *bool) { |
622 prec := x.Op.Precedence() | 622 prec := x.Op.Precedence() |
623 if prec < prec1 { | 623 if prec < prec1 { |
624 » » ÿ// parenthesis neededÿ | 624 » » // parenthesis needed |
625 » » ÿ// Note: The parser inserts an ast.ParenExpr node; thus this ca seÿ | 625 » » // Note: The parser inserts an ast.ParenExpr node; thus this cas e |
626 » » ÿ// can only occur if the AST is created in a different wa y.ÿ | 626 » » // can only occur if the AST is created in a different way . |
627 p.print(token.LPAREN) | 627 p.print(token.LPAREN) |
628 » » p.expr0(x, reduceDepth(depth), multiLine) ÿ// parentheses undo o ne level of depthÿ | 628 » » p.expr0(x, reduceDepth(depth), multiLine) // parentheses undo on e level of depth |
629 p.print(token.RPAREN) | 629 p.print(token.RPAREN) |
630 return | 630 return |
631 } | 631 } |
632 | 632 |
633 printBlank := prec < cutoff | 633 printBlank := prec < cutoff |
634 | 634 |
635 ws := indent | 635 ws := indent |
636 p.expr1(x.X, prec, depth+diffPrec(x.X, prec), multiLine) | 636 p.expr1(x.X, prec, depth+diffPrec(x.X, prec), multiLine) |
637 if printBlank { | 637 if printBlank { |
638 p.print(blank) | 638 p.print(blank) |
639 } | 639 } |
640 » xline := p.pos.Line ÿ// before the operator (it may be on the next line! )ÿ | 640 » xline := p.pos.Line // before the operator (it may be on the next line!) |
641 yline := p.fset.Position(x.Y.Pos()).Line | 641 yline := p.fset.Position(x.Y.Pos()).Line |
642 p.print(x.OpPos, x.Op) | 642 p.print(x.OpPos, x.Op) |
643 if xline != yline && xline > 0 && yline > 0 { | 643 if xline != yline && xline > 0 && yline > 0 { |
644 » » ÿ// at least one line break, but respect an extra empty lineÿ | 644 » » // at least one line break, but respect an extra empty line |
645 » » ÿ// in the sourceÿ | 645 » » // in the source |
646 if p.linebreak(yline, 1, ws, true) { | 646 if p.linebreak(yline, 1, ws, true) { |
647 ws = ignore | 647 ws = ignore |
648 *multiLine = true | 648 *multiLine = true |
649 » » » printBlank = false ÿ// no blank after line breakÿ | 649 » » » printBlank = false // no blank after line break |
650 } | 650 } |
651 } | 651 } |
652 if printBlank { | 652 if printBlank { |
653 p.print(blank) | 653 p.print(blank) |
654 } | 654 } |
655 p.expr1(x.Y, prec+1, depth+1, multiLine) | 655 p.expr1(x.Y, prec+1, depth+1, multiLine) |
656 if ws == ignore { | 656 if ws == ignore { |
657 p.print(unindent) | 657 p.print(unindent) |
658 } | 658 } |
659 } | 659 } |
660 | 660 |
661 | 661 |
662 func isBinary(expr ast.Expr) bool { | 662 func isBinary(expr ast.Expr) bool { |
663 _, ok := expr.(*ast.BinaryExpr) | 663 _, ok := expr.(*ast.BinaryExpr) |
664 return ok | 664 return ok |
665 } | 665 } |
666 | 666 |
667 | 667 |
668 ÿ// If the expression contains one or more selector expressions, splits it intoÿ | 668 // If the expression contains one or more selector expressions, splits it into |
669 ÿ// two expressions at the rightmost period. Writes entire expr to suffix whenÿ | 669 // two expressions at the rightmost period. Writes entire expr to suffix when |
670 ÿ// selector isn't found. Rewrites AST nodes for calls, index expressions andÿ | 670 // selector isn't found. Rewrites AST nodes for calls, index expressions and |
671 ÿ// type assertions, all of which may be found in selector chains, to make themÿ | 671 // type assertions, all of which may be found in selector chains, to make them |
672 ÿ// parts of the chain.ÿ | 672 // parts of the chain. |
673 func splitSelector(expr ast.Expr) (body, suffix ast.Expr) { | 673 func splitSelector(expr ast.Expr) (body, suffix ast.Expr) { |
674 switch x := expr.(type) { | 674 switch x := expr.(type) { |
675 case *ast.SelectorExpr: | 675 case *ast.SelectorExpr: |
676 body, suffix = x.X, x.Sel | 676 body, suffix = x.X, x.Sel |
677 return | 677 return |
678 case *ast.CallExpr: | 678 case *ast.CallExpr: |
679 body, suffix = splitSelector(x.Fun) | 679 body, suffix = splitSelector(x.Fun) |
680 if body != nil { | 680 if body != nil { |
681 suffix = &ast.CallExpr{suffix, x.Lparen, x.Args, x.Ellip sis, x.Rparen} | 681 suffix = &ast.CallExpr{suffix, x.Lparen, x.Args, x.Ellip sis, x.Rparen} |
682 return | 682 return |
(...skipping 15 matching lines...) Expand all Loading... | |
698 if body != nil { | 698 if body != nil { |
699 suffix = &ast.TypeAssertExpr{suffix, x.Type} | 699 suffix = &ast.TypeAssertExpr{suffix, x.Type} |
700 return | 700 return |
701 } | 701 } |
702 } | 702 } |
703 suffix = expr | 703 suffix = expr |
704 return | 704 return |
705 } | 705 } |
706 | 706 |
707 | 707 |
708 ÿ// Convert an expression into an expression list split at the periods ofÿ | 708 // Convert an expression into an expression list split at the periods of |
709 ÿ// selector expressions.ÿ | 709 // selector expressions. |
710 func selectorExprList(expr ast.Expr) (list []ast.Expr) { | 710 func selectorExprList(expr ast.Expr) (list []ast.Expr) { |
711 » ÿ// split expressionÿ | 711 » // split expression |
712 for expr != nil { | 712 for expr != nil { |
713 var suffix ast.Expr | 713 var suffix ast.Expr |
714 expr, suffix = splitSelector(expr) | 714 expr, suffix = splitSelector(expr) |
715 list = append(list, suffix) | 715 list = append(list, suffix) |
716 } | 716 } |
717 | 717 |
718 » ÿ// reverse listÿ | 718 » // reverse list |
719 for i, j := 0, len(list)-1; i < j; i, j = i+1, j-1 { | 719 for i, j := 0, len(list)-1; i < j; i, j = i+1, j-1 { |
720 list[i], list[j] = list[j], list[i] | 720 list[i], list[j] = list[j], list[i] |
721 } | 721 } |
722 | 722 |
723 return | 723 return |
724 } | 724 } |
725 | 725 |
726 | 726 |
727 ÿ// Sets multiLine to true if the expression spans multiple lines.ÿ | 727 // Sets multiLine to true if the expression spans multiple lines. |
728 func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) { | 728 func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) { |
729 p.print(expr.Pos()) | 729 p.print(expr.Pos()) |
730 | 730 |
731 switch x := expr.(type) { | 731 switch x := expr.(type) { |
732 case *ast.BadExpr: | 732 case *ast.BadExpr: |
733 p.print("BadExpr") | 733 p.print("BadExpr") |
734 | 734 |
735 case *ast.Ident: | 735 case *ast.Ident: |
736 p.print(x) | 736 p.print(x) |
737 | 737 |
738 case *ast.BinaryExpr: | 738 case *ast.BinaryExpr: |
739 if depth < 1 { | 739 if depth < 1 { |
740 p.internalError("depth < 1:", depth) | 740 p.internalError("depth < 1:", depth) |
741 depth = 1 | 741 depth = 1 |
742 } | 742 } |
743 p.binaryExpr(x, prec1, cutoff(x, depth), depth, multiLine) | 743 p.binaryExpr(x, prec1, cutoff(x, depth), depth, multiLine) |
744 | 744 |
745 case *ast.KeyValueExpr: | 745 case *ast.KeyValueExpr: |
746 p.expr(x.Key, multiLine) | 746 p.expr(x.Key, multiLine) |
747 p.print(x.Colon, token.COLON, blank) | 747 p.print(x.Colon, token.COLON, blank) |
748 p.expr(x.Value, multiLine) | 748 p.expr(x.Value, multiLine) |
749 | 749 |
750 case *ast.StarExpr: | 750 case *ast.StarExpr: |
751 const prec = token.UnaryPrec | 751 const prec = token.UnaryPrec |
752 if prec < prec1 { | 752 if prec < prec1 { |
753 » » » ÿ// parenthesis neededÿ | 753 » » » // parenthesis needed |
754 p.print(token.LPAREN) | 754 p.print(token.LPAREN) |
755 p.print(token.MUL) | 755 p.print(token.MUL) |
756 p.expr(x.X, multiLine) | 756 p.expr(x.X, multiLine) |
757 p.print(token.RPAREN) | 757 p.print(token.RPAREN) |
758 } else { | 758 } else { |
759 » » » ÿ// no parenthesis neededÿ | 759 » » » // no parenthesis needed |
760 p.print(token.MUL) | 760 p.print(token.MUL) |
761 p.expr(x.X, multiLine) | 761 p.expr(x.X, multiLine) |
762 } | 762 } |
763 | 763 |
764 case *ast.UnaryExpr: | 764 case *ast.UnaryExpr: |
765 const prec = token.UnaryPrec | 765 const prec = token.UnaryPrec |
766 if prec < prec1 { | 766 if prec < prec1 { |
767 » » » ÿ// parenthesis neededÿ | 767 » » » // parenthesis needed |
768 p.print(token.LPAREN) | 768 p.print(token.LPAREN) |
769 p.expr(x, multiLine) | 769 p.expr(x, multiLine) |
770 p.print(token.RPAREN) | 770 p.print(token.RPAREN) |
771 } else { | 771 } else { |
772 » » » ÿ// no parenthesis neededÿ | 772 » » » // no parenthesis needed |
773 p.print(x.Op) | 773 p.print(x.Op) |
774 if x.Op == token.RANGE { | 774 if x.Op == token.RANGE { |
775 » » » » ÿ// TODO(gri) Remove this code if it cannot be r eached.ÿ | 775 » » » » // TODO(gri) Remove this code if it cannot be re ached. |
776 p.print(blank) | 776 p.print(blank) |
777 } | 777 } |
778 p.expr1(x.X, prec, depth, multiLine) | 778 p.expr1(x.X, prec, depth, multiLine) |
779 } | 779 } |
780 | 780 |
781 case *ast.BasicLit: | 781 case *ast.BasicLit: |
782 p.print(x) | 782 p.print(x) |
783 | 783 |
784 case *ast.FuncLit: | 784 case *ast.FuncLit: |
785 p.expr(x.Type, multiLine) | 785 p.expr(x.Type, multiLine) |
786 p.funcBody(x.Body, p.distance(x.Type.Pos(), p.pos), true, multiL ine) | 786 p.funcBody(x.Body, p.distance(x.Type.Pos(), p.pos), true, multiL ine) |
787 | 787 |
788 case *ast.ParenExpr: | 788 case *ast.ParenExpr: |
789 if _, hasParens := x.X.(*ast.ParenExpr); hasParens { | 789 if _, hasParens := x.X.(*ast.ParenExpr); hasParens { |
790 » » » ÿ// don't print parentheses around an already parenthesi zed expressionÿ | 790 » » » // don't print parentheses around an already parenthesiz ed expression |
791 » » » ÿ// TODO(gri) consider making this more general and inco rporate precedence levelsÿ | 791 » » » // TODO(gri) consider making this more general and incor porate precedence levels |
792 » » » p.expr0(x.X, reduceDepth(depth), multiLine) ÿ// parenthe ses undo one level of depthÿ | 792 » » » p.expr0(x.X, reduceDepth(depth), multiLine) // parenthes es undo one level of depth |
793 } else { | 793 } else { |
794 p.print(token.LPAREN) | 794 p.print(token.LPAREN) |
795 » » » p.expr0(x.X, reduceDepth(depth), multiLine) ÿ// parenthe ses undo one level of depthÿ | 795 » » » p.expr0(x.X, reduceDepth(depth), multiLine) // parenthes es undo one level of depth |
796 p.print(x.Rparen, token.RPAREN) | 796 p.print(x.Rparen, token.RPAREN) |
797 } | 797 } |
798 | 798 |
799 case *ast.SelectorExpr: | 799 case *ast.SelectorExpr: |
800 parts := selectorExprList(expr) | 800 parts := selectorExprList(expr) |
801 p.exprList(token.NoPos, parts, depth, periodSep, multiLine, toke n.NoPos) | 801 p.exprList(token.NoPos, parts, depth, periodSep, multiLine, toke n.NoPos) |
802 | 802 |
803 case *ast.TypeAssertExpr: | 803 case *ast.TypeAssertExpr: |
804 p.expr1(x.X, token.HighestPrec, depth, multiLine) | 804 p.expr1(x.X, token.HighestPrec, depth, multiLine) |
805 p.print(token.PERIOD, token.LPAREN) | 805 p.print(token.PERIOD, token.LPAREN) |
806 if x.Type != nil { | 806 if x.Type != nil { |
807 p.expr(x.Type, multiLine) | 807 p.expr(x.Type, multiLine) |
808 } else { | 808 } else { |
809 p.print(token.TYPE) | 809 p.print(token.TYPE) |
810 } | 810 } |
811 p.print(token.RPAREN) | 811 p.print(token.RPAREN) |
812 | 812 |
813 case *ast.IndexExpr: | 813 case *ast.IndexExpr: |
814 » » ÿ// TODO(gri): should treat[] like parentheses and undo one leve l of depthÿ | 814 » » // TODO(gri): should treat[] like parentheses and undo one level of depth |
815 p.expr1(x.X, token.HighestPrec, 1, multiLine) | 815 p.expr1(x.X, token.HighestPrec, 1, multiLine) |
816 p.print(x.Lbrack, token.LBRACK) | 816 p.print(x.Lbrack, token.LBRACK) |
817 p.expr0(x.Index, depth+1, multiLine) | 817 p.expr0(x.Index, depth+1, multiLine) |
818 p.print(x.Rbrack, token.RBRACK) | 818 p.print(x.Rbrack, token.RBRACK) |
819 | 819 |
820 case *ast.SliceExpr: | 820 case *ast.SliceExpr: |
821 » » ÿ// TODO(gri): should treat[] like parentheses and undo one leve l of depthÿ | 821 » » // TODO(gri): should treat[] like parentheses and undo one level of depth |
822 p.expr1(x.X, token.HighestPrec, 1, multiLine) | 822 p.expr1(x.X, token.HighestPrec, 1, multiLine) |
823 p.print(x.Lbrack, token.LBRACK) | 823 p.print(x.Lbrack, token.LBRACK) |
824 if x.Low != nil { | 824 if x.Low != nil { |
825 p.expr0(x.Low, depth+1, multiLine) | 825 p.expr0(x.Low, depth+1, multiLine) |
826 } | 826 } |
827 » » ÿ// blanks around ":" if both sides exist and either side is a b inary expressionÿ | 827 » » // blanks around ":" if both sides exist and either side is a bi nary expression |
828 if depth <= 1 && x.Low != nil && x.High != nil && (isBinary(x.Lo w) || isBinary(x.High)) { | 828 if depth <= 1 && x.Low != nil && x.High != nil && (isBinary(x.Lo w) || isBinary(x.High)) { |
829 p.print(blank, token.COLON, blank) | 829 p.print(blank, token.COLON, blank) |
830 } else { | 830 } else { |
831 p.print(token.COLON) | 831 p.print(token.COLON) |
832 } | 832 } |
833 if x.High != nil { | 833 if x.High != nil { |
834 p.expr0(x.High, depth+1, multiLine) | 834 p.expr0(x.High, depth+1, multiLine) |
835 } | 835 } |
836 p.print(x.Rbrack, token.RBRACK) | 836 p.print(x.Rbrack, token.RBRACK) |
837 | 837 |
838 case *ast.CallExpr: | 838 case *ast.CallExpr: |
839 if len(x.Args) > 1 { | 839 if len(x.Args) > 1 { |
840 depth++ | 840 depth++ |
841 } | 841 } |
842 p.expr1(x.Fun, token.HighestPrec, depth, multiLine) | 842 p.expr1(x.Fun, token.HighestPrec, depth, multiLine) |
843 p.print(x.Lparen, token.LPAREN) | 843 p.print(x.Lparen, token.LPAREN) |
844 p.exprList(x.Lparen, x.Args, depth, commaSep|commaTerm, multiLin e, x.Rparen) | 844 p.exprList(x.Lparen, x.Args, depth, commaSep|commaTerm, multiLin e, x.Rparen) |
845 if x.Ellipsis.IsValid() { | 845 if x.Ellipsis.IsValid() { |
846 p.print(x.Ellipsis, token.ELLIPSIS) | 846 p.print(x.Ellipsis, token.ELLIPSIS) |
847 } | 847 } |
848 p.print(x.Rparen, token.RPAREN) | 848 p.print(x.Rparen, token.RPAREN) |
849 | 849 |
850 case *ast.CompositeLit: | 850 case *ast.CompositeLit: |
851 » » ÿ// composite literal elements that are composite literals thems elves may have the type omittedÿ | 851 » » // composite literal elements that are composite literals themse lves may have the type omitted |
852 if x.Type != nil { | 852 if x.Type != nil { |
853 p.expr1(x.Type, token.HighestPrec, depth, multiLine) | 853 p.expr1(x.Type, token.HighestPrec, depth, multiLine) |
854 } | 854 } |
855 p.print(x.Lbrace, token.LBRACE) | 855 p.print(x.Lbrace, token.LBRACE) |
856 p.exprList(x.Lbrace, x.Elts, 1, commaSep|commaTerm, multiLine, x .Rbrace) | 856 p.exprList(x.Lbrace, x.Elts, 1, commaSep|commaTerm, multiLine, x .Rbrace) |
857 » » ÿ// do not insert extra line breaks because of comments beforeÿ | 857 » » // do not insert extra line breaks because of comments before |
858 » » ÿ// the closing '}' as it might break the code if there is noÿ | 858 » » // the closing '}' as it might break the code if there is no |
859 » » ÿ// trailing ','ÿ | 859 » » // trailing ',' |
860 p.print(noExtraLinebreak, x.Rbrace, token.RBRACE, noExtraLinebre ak) | 860 p.print(noExtraLinebreak, x.Rbrace, token.RBRACE, noExtraLinebre ak) |
861 | 861 |
862 case *ast.Ellipsis: | 862 case *ast.Ellipsis: |
863 p.print(token.ELLIPSIS) | 863 p.print(token.ELLIPSIS) |
864 if x.Elt != nil { | 864 if x.Elt != nil { |
865 p.expr(x.Elt, multiLine) | 865 p.expr(x.Elt, multiLine) |
866 } | 866 } |
867 | 867 |
868 case *ast.ArrayType: | 868 case *ast.ArrayType: |
869 p.print(token.LBRACK) | 869 p.print(token.LBRACK) |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
909 | 909 |
910 return | 910 return |
911 } | 911 } |
912 | 912 |
913 | 913 |
914 func (p *printer) expr0(x ast.Expr, depth int, multiLine *bool) { | 914 func (p *printer) expr0(x ast.Expr, depth int, multiLine *bool) { |
915 p.expr1(x, token.LowestPrec, depth, multiLine) | 915 p.expr1(x, token.LowestPrec, depth, multiLine) |
916 } | 916 } |
917 | 917 |
918 | 918 |
919 ÿ// Sets multiLine to true if the expression spans multiple lines.ÿ | 919 // Sets multiLine to true if the expression spans multiple lines. |
920 func (p *printer) expr(x ast.Expr, multiLine *bool) { | 920 func (p *printer) expr(x ast.Expr, multiLine *bool) { |
921 const depth = 1 | 921 const depth = 1 |
922 p.expr1(x, token.LowestPrec, depth, multiLine) | 922 p.expr1(x, token.LowestPrec, depth, multiLine) |
923 } | 923 } |
924 | 924 |
925 | 925 |
926 ÿ// ---------------------------------------------------------------------------- ÿ | 926 // ---------------------------------------------------------------------------- |
927 ÿ// Statementsÿ | 927 // Statements |
928 | 928 |
929 ÿ// Print the statement list indented, but without a newline after the last stat ement.ÿ | 929 // Print the statement list indented, but without a newline after the last state ment. |
930 ÿ// Extra line breaks between statements in the source are respected but at most oneÿ | 930 // Extra line breaks between statements in the source are respected but at most one |
931 ÿ// empty line is printed between statements.ÿ | 931 // empty line is printed between statements. |
932 func (p *printer) stmtList(list []ast.Stmt, _indent int, nextIsRBrace bool) { | 932 func (p *printer) stmtList(list []ast.Stmt, _indent int, nextIsRBrace bool) { |
933 » ÿ// TODO(gri): fix _indent codeÿ | 933 » // TODO(gri): fix _indent code |
934 if _indent > 0 { | 934 if _indent > 0 { |
935 p.print(indent) | 935 p.print(indent) |
936 } | 936 } |
937 var multiLine bool | 937 var multiLine bool |
938 for i, s := range list { | 938 for i, s := range list { |
939 » » ÿ// _indent == 0 only for lists of switch/select case clauses;ÿ | 939 » » // _indent == 0 only for lists of switch/select case clauses; |
940 » » ÿ// in those cases each clause is a new sectionÿ | 940 » » // in those cases each clause is a new section |
941 p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, i == 0 || _indent == 0 || multiLine) | 941 p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, i == 0 || _indent == 0 || multiLine) |
942 multiLine = false | 942 multiLine = false |
943 p.stmt(s, nextIsRBrace && i == len(list)-1, &multiLine) | 943 p.stmt(s, nextIsRBrace && i == len(list)-1, &multiLine) |
944 } | 944 } |
945 if _indent > 0 { | 945 if _indent > 0 { |
946 p.print(unindent) | 946 p.print(unindent) |
947 } | 947 } |
948 } | 948 } |
949 | 949 |
950 | 950 |
951 ÿ// block prints an *ast.BlockStmt; it always spans at least two lines.ÿ | 951 // block prints an *ast.BlockStmt; it always spans at least two lines. |
952 func (p *printer) block(s *ast.BlockStmt, indent int) { | 952 func (p *printer) block(s *ast.BlockStmt, indent int) { |
953 p.print(s.Pos(), token.LBRACE) | 953 p.print(s.Pos(), token.LBRACE) |
954 p.stmtList(s.List, indent, true) | 954 p.stmtList(s.List, indent, true) |
955 p.linebreak(p.fset.Position(s.Rbrace).Line, 1, ignore, true) | 955 p.linebreak(p.fset.Position(s.Rbrace).Line, 1, ignore, true) |
956 p.print(s.Rbrace, token.RBRACE) | 956 p.print(s.Rbrace, token.RBRACE) |
957 } | 957 } |
958 | 958 |
959 | 959 |
960 func isTypeName(x ast.Expr) bool { | 960 func isTypeName(x ast.Expr) bool { |
961 switch t := x.(type) { | 961 switch t := x.(type) { |
962 case *ast.Ident: | 962 case *ast.Ident: |
963 return true | 963 return true |
964 case *ast.SelectorExpr: | 964 case *ast.SelectorExpr: |
965 return isTypeName(t.X) | 965 return isTypeName(t.X) |
966 } | 966 } |
967 return false | 967 return false |
968 } | 968 } |
969 | 969 |
970 | 970 |
971 func stripParens(x ast.Expr) ast.Expr { | 971 func stripParens(x ast.Expr) ast.Expr { |
972 if px, strip := x.(*ast.ParenExpr); strip { | 972 if px, strip := x.(*ast.ParenExpr); strip { |
973 » » ÿ// parentheses must not be stripped if there are anyÿ | 973 » » // parentheses must not be stripped if there are any |
974 » » ÿ// unparenthesized composite literals starting withÿ | 974 » » // unparenthesized composite literals starting with |
975 » » ÿ// a type nameÿ | 975 » » // a type name |
976 ast.Inspect(px.X, func(node ast.Node) bool { | 976 ast.Inspect(px.X, func(node ast.Node) bool { |
977 switch x := node.(type) { | 977 switch x := node.(type) { |
978 case *ast.ParenExpr: | 978 case *ast.ParenExpr: |
979 » » » » ÿ// parentheses protect enclosed composite liter alsÿ | 979 » » » » // parentheses protect enclosed composite litera ls |
980 return false | 980 return false |
981 case *ast.CompositeLit: | 981 case *ast.CompositeLit: |
982 if isTypeName(x.Type) { | 982 if isTypeName(x.Type) { |
983 » » » » » strip = false ÿ// do not strip parenthes esÿ | 983 » » » » » strip = false // do not strip parenthese s |
984 } | 984 } |
985 return false | 985 return false |
986 } | 986 } |
987 » » » ÿ// in all other cases, keep inspectingÿ | 987 » » » // in all other cases, keep inspecting |
988 return true | 988 return true |
989 }) | 989 }) |
990 if strip { | 990 if strip { |
991 return stripParens(px.X) | 991 return stripParens(px.X) |
992 } | 992 } |
993 } | 993 } |
994 return x | 994 return x |
995 } | 995 } |
996 | 996 |
997 | 997 |
998 func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, po st ast.Stmt) { | 998 func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, po st ast.Stmt) { |
999 p.print(blank) | 999 p.print(blank) |
1000 needsBlank := false | 1000 needsBlank := false |
1001 if init == nil && post == nil { | 1001 if init == nil && post == nil { |
1002 » » ÿ// no semicolons requiredÿ | 1002 » » // no semicolons required |
1003 if expr != nil { | 1003 if expr != nil { |
1004 p.expr(stripParens(expr), ignoreMultiLine) | 1004 p.expr(stripParens(expr), ignoreMultiLine) |
1005 needsBlank = true | 1005 needsBlank = true |
1006 } | 1006 } |
1007 } else { | 1007 } else { |
1008 » » ÿ// all semicolons requiredÿ | 1008 » » // all semicolons required |
1009 » » ÿ// (they are not separators, print them explicitly)ÿ | 1009 » » // (they are not separators, print them explicitly) |
1010 if init != nil { | 1010 if init != nil { |
1011 p.stmt(init, false, ignoreMultiLine) | 1011 p.stmt(init, false, ignoreMultiLine) |
1012 } | 1012 } |
1013 p.print(token.SEMICOLON, blank) | 1013 p.print(token.SEMICOLON, blank) |
1014 if expr != nil { | 1014 if expr != nil { |
1015 p.expr(stripParens(expr), ignoreMultiLine) | 1015 p.expr(stripParens(expr), ignoreMultiLine) |
1016 needsBlank = true | 1016 needsBlank = true |
1017 } | 1017 } |
1018 if isForStmt { | 1018 if isForStmt { |
1019 p.print(token.SEMICOLON, blank) | 1019 p.print(token.SEMICOLON, blank) |
1020 needsBlank = false | 1020 needsBlank = false |
1021 if post != nil { | 1021 if post != nil { |
1022 p.stmt(post, false, ignoreMultiLine) | 1022 p.stmt(post, false, ignoreMultiLine) |
1023 needsBlank = true | 1023 needsBlank = true |
1024 } | 1024 } |
1025 } | 1025 } |
1026 } | 1026 } |
1027 if needsBlank { | 1027 if needsBlank { |
1028 p.print(blank) | 1028 p.print(blank) |
1029 } | 1029 } |
1030 } | 1030 } |
1031 | 1031 |
1032 | 1032 |
1033 ÿ// Sets multiLine to true if the statements spans multiple lines.ÿ | 1033 // Sets multiLine to true if the statements spans multiple lines. |
1034 func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) { | 1034 func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) { |
1035 p.print(stmt.Pos()) | 1035 p.print(stmt.Pos()) |
1036 | 1036 |
1037 switch s := stmt.(type) { | 1037 switch s := stmt.(type) { |
1038 case *ast.BadStmt: | 1038 case *ast.BadStmt: |
1039 p.print("BadStmt") | 1039 p.print("BadStmt") |
1040 | 1040 |
1041 case *ast.DeclStmt: | 1041 case *ast.DeclStmt: |
1042 p.decl(s.Decl, multiLine) | 1042 p.decl(s.Decl, multiLine) |
1043 | 1043 |
1044 case *ast.EmptyStmt: | 1044 case *ast.EmptyStmt: |
1045 » » ÿ// nothing to doÿ | 1045 » » // nothing to do |
1046 | 1046 |
1047 case *ast.LabeledStmt: | 1047 case *ast.LabeledStmt: |
1048 » » ÿ// a "correcting" unindent immediately following a line breakÿ | 1048 » » // a "correcting" unindent immediately following a line break |
1049 » » ÿ// is applied before the line break if there is no commentÿ | 1049 » » // is applied before the line break if there is no comment |
1050 » » ÿ// between (see writeWhitespace)ÿ | 1050 » » // between (see writeWhitespace) |
1051 p.print(unindent) | 1051 p.print(unindent) |
1052 p.expr(s.Label, multiLine) | 1052 p.expr(s.Label, multiLine) |
1053 p.print(s.Colon, token.COLON, indent) | 1053 p.print(s.Colon, token.COLON, indent) |
1054 if e, isEmpty := s.Stmt.(*ast.EmptyStmt); isEmpty { | 1054 if e, isEmpty := s.Stmt.(*ast.EmptyStmt); isEmpty { |
1055 if !nextIsRBrace { | 1055 if !nextIsRBrace { |
1056 p.print(newline, e.Pos(), token.SEMICOLON) | 1056 p.print(newline, e.Pos(), token.SEMICOLON) |
1057 break | 1057 break |
1058 } | 1058 } |
1059 } else { | 1059 } else { |
1060 p.linebreak(p.fset.Position(s.Stmt.Pos()).Line, 1, ignor e, true) | 1060 p.linebreak(p.fset.Position(s.Stmt.Pos()).Line, 1, ignor e, true) |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1191 *multiLine = true | 1191 *multiLine = true |
1192 | 1192 |
1193 default: | 1193 default: |
1194 panic("unreachable") | 1194 panic("unreachable") |
1195 } | 1195 } |
1196 | 1196 |
1197 return | 1197 return |
1198 } | 1198 } |
1199 | 1199 |
1200 | 1200 |
1201 ÿ// ---------------------------------------------------------------------------- ÿ | 1201 // ---------------------------------------------------------------------------- |
1202 ÿ// Declarationsÿ | 1202 // Declarations |
1203 | 1203 |
1204 ÿ// The parameter n is the number of specs in the group. If doIndent is set,ÿ | 1204 // The parameter n is the number of specs in the group. If doIndent is set, |
1205 ÿ// multi-line identifier lists in the spec are indented when the firstÿ | 1205 // multi-line identifier lists in the spec are indented when the first |
1206 ÿ// linebreak is encountered.ÿ | 1206 // linebreak is encountered. |
1207 ÿ// Sets multiLine to true if the spec spans multiple lines.ÿ | 1207 // Sets multiLine to true if the spec spans multiple lines. |
1208 ÿ//ÿ | 1208 // |
1209 func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) { | 1209 func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) { |
1210 switch s := spec.(type) { | 1210 switch s := spec.(type) { |
1211 case *ast.ImportSpec: | 1211 case *ast.ImportSpec: |
1212 p.setComment(s.Doc) | 1212 p.setComment(s.Doc) |
1213 if s.Name != nil { | 1213 if s.Name != nil { |
1214 p.expr(s.Name, multiLine) | 1214 p.expr(s.Name, multiLine) |
1215 p.print(vtab) | 1215 p.print(vtab) |
1216 } | 1216 } |
1217 p.expr(s.Path, multiLine) | 1217 p.expr(s.Path, multiLine) |
1218 p.setComment(s.Comment) | 1218 p.setComment(s.Comment) |
1219 | 1219 |
1220 case *ast.ValueSpec: | 1220 case *ast.ValueSpec: |
1221 p.setComment(s.Doc) | 1221 p.setComment(s.Doc) |
1222 » » p.identList(s.Names, doIndent, multiLine) ÿ// always presentÿ | 1222 » » p.identList(s.Names, doIndent, multiLine) // always present |
1223 if n == 1 { | 1223 if n == 1 { |
1224 if s.Type != nil { | 1224 if s.Type != nil { |
1225 p.print(blank) | 1225 p.print(blank) |
1226 p.expr(s.Type, multiLine) | 1226 p.expr(s.Type, multiLine) |
1227 } | 1227 } |
1228 if s.Values != nil { | 1228 if s.Values != nil { |
1229 p.print(blank, token.ASSIGN) | 1229 p.print(blank, token.ASSIGN) |
1230 p.exprList(token.NoPos, s.Values, 1, blankStart| commaSep, multiLine, token.NoPos) | 1230 p.exprList(token.NoPos, s.Values, 1, blankStart| commaSep, multiLine, token.NoPos) |
1231 } | 1231 } |
1232 p.setComment(s.Comment) | 1232 p.setComment(s.Comment) |
(...skipping 28 matching lines...) Expand all Loading... | |
1261 } | 1261 } |
1262 p.expr(s.Type, multiLine) | 1262 p.expr(s.Type, multiLine) |
1263 p.setComment(s.Comment) | 1263 p.setComment(s.Comment) |
1264 | 1264 |
1265 default: | 1265 default: |
1266 panic("unreachable") | 1266 panic("unreachable") |
1267 } | 1267 } |
1268 } | 1268 } |
1269 | 1269 |
1270 | 1270 |
1271 ÿ// Sets multiLine to true if the declaration spans multiple lines.ÿ | 1271 // Sets multiLine to true if the declaration spans multiple lines. |
1272 func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) { | 1272 func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) { |
1273 p.setComment(d.Doc) | 1273 p.setComment(d.Doc) |
1274 p.print(d.Pos(), d.Tok, blank) | 1274 p.print(d.Pos(), d.Tok, blank) |
1275 | 1275 |
1276 if d.Lparen.IsValid() { | 1276 if d.Lparen.IsValid() { |
1277 » » ÿ// group of parenthesized declarationsÿ | 1277 » » // group of parenthesized declarations |
1278 p.print(d.Lparen, token.LPAREN) | 1278 p.print(d.Lparen, token.LPAREN) |
1279 if len(d.Specs) > 0 { | 1279 if len(d.Specs) > 0 { |
1280 p.print(indent, formfeed) | 1280 p.print(indent, formfeed) |
1281 var ml bool | 1281 var ml bool |
1282 for i, s := range d.Specs { | 1282 for i, s := range d.Specs { |
1283 if i > 0 { | 1283 if i > 0 { |
1284 p.linebreak(p.fset.Position(s.Pos()).Lin e, 1, ignore, ml) | 1284 p.linebreak(p.fset.Position(s.Pos()).Lin e, 1, ignore, ml) |
1285 } | 1285 } |
1286 ml = false | 1286 ml = false |
1287 p.spec(s, len(d.Specs), false, &ml) | 1287 p.spec(s, len(d.Specs), false, &ml) |
1288 } | 1288 } |
1289 p.print(unindent, formfeed) | 1289 p.print(unindent, formfeed) |
1290 *multiLine = true | 1290 *multiLine = true |
1291 } | 1291 } |
1292 p.print(d.Rparen, token.RPAREN) | 1292 p.print(d.Rparen, token.RPAREN) |
1293 | 1293 |
1294 } else { | 1294 } else { |
1295 » » ÿ// single declarationÿ | 1295 » » // single declaration |
1296 p.spec(d.Specs[0], 1, true, multiLine) | 1296 p.spec(d.Specs[0], 1, true, multiLine) |
1297 } | 1297 } |
1298 } | 1298 } |
1299 | 1299 |
1300 | 1300 |
1301 ÿ// nodeSize determines the size of n in chars after formatting.ÿ | 1301 // nodeSize determines the size of n in chars after formatting. |
1302 ÿ// The result is <= maxSize if the node fits on one line with atÿ | 1302 // The result is <= maxSize if the node fits on one line with at |
1303 ÿ// most maxSize chars and the formatted output doesn't containÿ | 1303 // most maxSize chars and the formatted output doesn't contain |
1304 ÿ// any control chars. Otherwise, the result is > maxSize.ÿ | 1304 // any control chars. Otherwise, the result is > maxSize. |
1305 ÿ//ÿ | 1305 // |
1306 func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) { | 1306 func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) { |
1307 » ÿ// nodeSize invokes the printer, which may invoke nodeSizeÿ | 1307 » // nodeSize invokes the printer, which may invoke nodeSize |
1308 » ÿ// recursively. For deep composite literal nests, this canÿ | 1308 » // recursively. For deep composite literal nests, this can |
1309 » ÿ// lead to an exponential algorithm. Remember previousÿ | 1309 » // lead to an exponential algorithm. Remember previous |
1310 » ÿ// results to prune the recursion (was issue 1628).ÿ | 1310 » // results to prune the recursion (was issue 1628). |
1311 if size, found := p.nodeSizes[n]; found { | 1311 if size, found := p.nodeSizes[n]; found { |
1312 return size | 1312 return size |
1313 } | 1313 } |
1314 | 1314 |
1315 » size = maxSize + 1 ÿ// assume n doesn't fitÿ | 1315 » size = maxSize + 1 // assume n doesn't fit |
1316 p.nodeSizes[n] = size | 1316 p.nodeSizes[n] = size |
1317 | 1317 |
1318 » ÿ// nodeSize computation must be indendent of particularÿ | 1318 » // nodeSize computation must be indendent of particular |
1319 » ÿ// style so that we always get the same decision; printÿ | 1319 » // style so that we always get the same decision; print |
1320 » ÿ// in RawFormatÿ | 1320 » // in RawFormat |
1321 cfg := Config{Mode: RawFormat} | 1321 cfg := Config{Mode: RawFormat} |
1322 var buf bytes.Buffer | 1322 var buf bytes.Buffer |
1323 if _, err := cfg.fprint(&buf, p.fset, n, p.nodeSizes); err != nil { | 1323 if _, err := cfg.fprint(&buf, p.fset, n, p.nodeSizes); err != nil { |
1324 return | 1324 return |
1325 } | 1325 } |
1326 if buf.Len() <= maxSize { | 1326 if buf.Len() <= maxSize { |
1327 for _, ch := range buf.Bytes() { | 1327 for _, ch := range buf.Bytes() { |
1328 if ch < ' ' { | 1328 if ch < ' ' { |
1329 return | 1329 return |
1330 } | 1330 } |
1331 } | 1331 } |
1332 » » size = buf.Len() ÿ// n fitsÿ | 1332 » » size = buf.Len() // n fits |
1333 p.nodeSizes[n] = size | 1333 p.nodeSizes[n] = size |
1334 } | 1334 } |
1335 return | 1335 return |
1336 } | 1336 } |
1337 | 1337 |
1338 | 1338 |
1339 func (p *printer) isOneLineFunc(b *ast.BlockStmt, headerSize int) bool { | 1339 func (p *printer) isOneLineFunc(b *ast.BlockStmt, headerSize int) bool { |
1340 pos1 := b.Pos() | 1340 pos1 := b.Pos() |
1341 pos2 := b.Rbrace | 1341 pos2 := b.Rbrace |
1342 if pos1.IsValid() && pos2.IsValid() && p.fset.Position(pos1).Line != p.f set.Position(pos2).Line { | 1342 if pos1.IsValid() && pos2.IsValid() && p.fset.Position(pos1).Line != p.f set.Position(pos2).Line { |
1343 » » ÿ// opening and closing brace are on different lines - don't mak e it a one-linerÿ | 1343 » » // opening and closing brace are on different lines - don't make it a one-liner |
1344 return false | 1344 return false |
1345 } | 1345 } |
1346 if len(b.List) > 5 || p.commentBefore(p.fset.Position(pos2)) { | 1346 if len(b.List) > 5 || p.commentBefore(p.fset.Position(pos2)) { |
1347 » » ÿ// too many statements or there is a comment inside - don't mak e it a one-linerÿ | 1347 » » // too many statements or there is a comment inside - don't make it a one-liner |
1348 return false | 1348 return false |
1349 } | 1349 } |
1350 » ÿ// otherwise, estimate body sizeÿ | 1350 » // otherwise, estimate body size |
1351 const maxSize = 100 | 1351 const maxSize = 100 |
1352 bodySize := 0 | 1352 bodySize := 0 |
1353 for i, s := range b.List { | 1353 for i, s := range b.List { |
1354 if i > 0 { | 1354 if i > 0 { |
1355 » » » bodySize += 2 ÿ// space for a semicolon and blankÿ | 1355 » » » bodySize += 2 // space for a semicolon and blank |
1356 } | 1356 } |
1357 bodySize += p.nodeSize(s, maxSize) | 1357 bodySize += p.nodeSize(s, maxSize) |
1358 } | 1358 } |
1359 return headerSize+bodySize <= maxSize | 1359 return headerSize+bodySize <= maxSize |
1360 } | 1360 } |
1361 | 1361 |
1362 | 1362 |
1363 ÿ// Sets multiLine to true if the function body spans multiple lines.ÿ | 1363 // Sets multiLine to true if the function body spans multiple lines. |
1364 func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLi ne *bool) { | 1364 func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLi ne *bool) { |
1365 if b == nil { | 1365 if b == nil { |
1366 return | 1366 return |
1367 } | 1367 } |
1368 | 1368 |
1369 p.nesting++ | 1369 p.nesting++ |
1370 defer func() { | 1370 defer func() { |
1371 p.nesting-- | 1371 p.nesting-- |
1372 }() | 1372 }() |
1373 | 1373 |
(...skipping 16 matching lines...) Expand all Loading... | |
1390 p.print(b.Rbrace, token.RBRACE) | 1390 p.print(b.Rbrace, token.RBRACE) |
1391 return | 1391 return |
1392 } | 1392 } |
1393 | 1393 |
1394 p.print(blank) | 1394 p.print(blank) |
1395 p.block(b, 1) | 1395 p.block(b, 1) |
1396 *multiLine = true | 1396 *multiLine = true |
1397 } | 1397 } |
1398 | 1398 |
1399 | 1399 |
1400 ÿ// distance returns the column difference between from and to if bothÿ | 1400 // distance returns the column difference between from and to if both |
1401 ÿ// are on the same line; if they are on different lines (or unknown)ÿ | 1401 // are on the same line; if they are on different lines (or unknown) |
1402 ÿ// the result is infinity.ÿ | 1402 // the result is infinity. |
1403 func (p *printer) distance(from0 token.Pos, to token.Position) int { | 1403 func (p *printer) distance(from0 token.Pos, to token.Position) int { |
1404 from := p.fset.Position(from0) | 1404 from := p.fset.Position(from0) |
1405 if from.IsValid() && to.IsValid() && from.Line == to.Line { | 1405 if from.IsValid() && to.IsValid() && from.Line == to.Line { |
1406 return to.Column - from.Column | 1406 return to.Column - from.Column |
1407 } | 1407 } |
1408 return infinity | 1408 return infinity |
1409 } | 1409 } |
1410 | 1410 |
1411 | 1411 |
1412 ÿ// Sets multiLine to true if the declaration spans multiple lines.ÿ | 1412 // Sets multiLine to true if the declaration spans multiple lines. |
1413 func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) { | 1413 func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) { |
1414 p.setComment(d.Doc) | 1414 p.setComment(d.Doc) |
1415 p.print(d.Pos(), token.FUNC, blank) | 1415 p.print(d.Pos(), token.FUNC, blank) |
1416 if d.Recv != nil { | 1416 if d.Recv != nil { |
1417 » » p.parameters(d.Recv, multiLine) ÿ// method: print receiverÿ | 1417 » » p.parameters(d.Recv, multiLine) // method: print receiver |
1418 p.print(blank) | 1418 p.print(blank) |
1419 } | 1419 } |
1420 p.expr(d.Name, multiLine) | 1420 p.expr(d.Name, multiLine) |
1421 p.signature(d.Type.Params, d.Type.Results, multiLine) | 1421 p.signature(d.Type.Params, d.Type.Results, multiLine) |
1422 p.funcBody(d.Body, p.distance(d.Pos(), p.pos), false, multiLine) | 1422 p.funcBody(d.Body, p.distance(d.Pos(), p.pos), false, multiLine) |
1423 } | 1423 } |
1424 | 1424 |
1425 | 1425 |
1426 ÿ// Sets multiLine to true if the declaration spans multiple lines.ÿ | 1426 // Sets multiLine to true if the declaration spans multiple lines. |
1427 func (p *printer) decl(decl ast.Decl, multiLine *bool) { | 1427 func (p *printer) decl(decl ast.Decl, multiLine *bool) { |
1428 switch d := decl.(type) { | 1428 switch d := decl.(type) { |
1429 case *ast.BadDecl: | 1429 case *ast.BadDecl: |
1430 p.print(d.Pos(), "BadDecl") | 1430 p.print(d.Pos(), "BadDecl") |
1431 case *ast.GenDecl: | 1431 case *ast.GenDecl: |
1432 p.genDecl(d, multiLine) | 1432 p.genDecl(d, multiLine) |
1433 case *ast.FuncDecl: | 1433 case *ast.FuncDecl: |
1434 p.funcDecl(d, multiLine) | 1434 p.funcDecl(d, multiLine) |
1435 default: | 1435 default: |
1436 panic("unreachable") | 1436 panic("unreachable") |
1437 } | 1437 } |
1438 } | 1438 } |
1439 | 1439 |
1440 | 1440 |
1441 ÿ// ---------------------------------------------------------------------------- ÿ | 1441 // ---------------------------------------------------------------------------- |
1442 ÿ// Filesÿ | 1442 // Files |
1443 | 1443 |
1444 func declToken(decl ast.Decl) (tok token.Token) { | 1444 func declToken(decl ast.Decl) (tok token.Token) { |
1445 tok = token.ILLEGAL | 1445 tok = token.ILLEGAL |
1446 switch d := decl.(type) { | 1446 switch d := decl.(type) { |
1447 case *ast.GenDecl: | 1447 case *ast.GenDecl: |
1448 tok = d.Tok | 1448 tok = d.Tok |
1449 case *ast.FuncDecl: | 1449 case *ast.FuncDecl: |
1450 tok = token.FUNC | 1450 tok = token.FUNC |
1451 } | 1451 } |
1452 return | 1452 return |
1453 } | 1453 } |
1454 | 1454 |
1455 | 1455 |
1456 func (p *printer) file(src *ast.File) { | 1456 func (p *printer) file(src *ast.File) { |
1457 p.setComment(src.Doc) | 1457 p.setComment(src.Doc) |
1458 p.print(src.Pos(), token.PACKAGE, blank) | 1458 p.print(src.Pos(), token.PACKAGE, blank) |
1459 p.expr(src.Name, ignoreMultiLine) | 1459 p.expr(src.Name, ignoreMultiLine) |
1460 | 1460 |
1461 if len(src.Decls) > 0 { | 1461 if len(src.Decls) > 0 { |
1462 tok := token.ILLEGAL | 1462 tok := token.ILLEGAL |
1463 for _, d := range src.Decls { | 1463 for _, d := range src.Decls { |
1464 prev := tok | 1464 prev := tok |
1465 tok = declToken(d) | 1465 tok = declToken(d) |
1466 » » » ÿ// if the declaration token changed (e.g., from CONST t o TYPE)ÿ | 1466 » » » // if the declaration token changed (e.g., from CONST to TYPE) |
1467 » » » ÿ// print an empty line between top-level declarationsÿ | 1467 » » » // print an empty line between top-level declarations |
1468 min := 1 | 1468 min := 1 |
1469 if prev != tok { | 1469 if prev != tok { |
1470 min = 2 | 1470 min = 2 |
1471 } | 1471 } |
1472 p.linebreak(p.fset.Position(d.Pos()).Line, min, ignore, false) | 1472 p.linebreak(p.fset.Position(d.Pos()).Line, min, ignore, false) |
1473 p.decl(d, ignoreMultiLine) | 1473 p.decl(d, ignoreMultiLine) |
1474 } | 1474 } |
1475 } | 1475 } |
1476 | 1476 |
1477 p.print(newline) | 1477 p.print(newline) |
1478 } | 1478 } |
LEFT | RIGHT |