Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1627)

Delta Between Two Patch Sets: src/pkg/go/printer/nodes.go

Issue 4291070: code review 4291070: go/scanner: return literal as string instead of []byte (Closed)
Left Patch Set: diff -r 56b847e640f3 https://go.googlecode.com/hg/ Created 13 years ago
Right Patch Set: diff -r 4073ecdfc054 https://go.googlecode.com/hg/ Created 13 years ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
LEFTRIGHT
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
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
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
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
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
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
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
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 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b