OSDN Git Service

b2a48c28a733bbe4d4431927055398b7f320ce37
[pf3gnuchains/gcc-fork.git] / libgo / go / go / printer / nodes.go
1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // This file implements printing of AST nodes; specifically
6 // expressions, statements, declarations, and files. It uses
7 // the print functionality implemented in printer.go.
8
9 package printer
10
11 import (
12         "bytes"
13         "go/ast"
14         "go/token"
15 )
16
17 // Other formatting issues:
18 // - better comment formatting for /*-style comments at the end of a line (e.g. a declaration)
19 //   when the comment spans multiple lines; if such a comment is just two lines, formatting is
20 //   not idempotent
21 // - formatting of expression lists
22 // - should use blank instead of tab to separate one-line function bodies from
23 //   the function header unless there is a group of consecutive one-liners
24
25 // ----------------------------------------------------------------------------
26 // Common AST nodes.
27
28 // Print as many newlines as necessary (but at least min newlines) to get to
29 // the current line. ws is printed before the first line break. If newSection
30 // is set, the first line break is printed as formfeed. Returns true if any
31 // line break was printed; returns false otherwise.
32 //
33 // TODO(gri): linebreak may add too many lines if the next statement at "line"
34 //            is preceded by comments because the computation of n assumes
35 //            the current position before the comment and the target position
36 //            after the comment. Thus, after interspersing such comments, the
37 //            space taken up by them is not considered to reduce the number of
38 //            linebreaks. At the moment there is no easy way to know about
39 //            future (not yet interspersed) comments in this function.
40 //
41 func (p *printer) linebreak(line, min int, ws whiteSpace, newSection bool) (printedBreak bool) {
42         n := p.nlines(line-p.pos.Line, min)
43         if n > 0 {
44                 p.print(ws)
45                 if newSection {
46                         p.print(formfeed)
47                         n--
48                 }
49                 for ; n > 0; n-- {
50                         p.print(newline)
51                 }
52                 printedBreak = true
53         }
54         return
55 }
56
57 // setComment sets g as the next comment if g != nil and if node comments
58 // are enabled - this mode is used when printing source code fragments such
59 // as exports only. It assumes that there are no other pending comments to
60 // intersperse.
61 func (p *printer) setComment(g *ast.CommentGroup) {
62         if g == nil || !p.useNodeComments {
63                 return
64         }
65         if p.comments == nil {
66                 // initialize p.comments lazily
67                 p.comments = make([]*ast.CommentGroup, 1)
68         } else if p.cindex < len(p.comments) {
69                 // for some reason there are pending comments; this
70                 // should never happen - handle gracefully and flush
71                 // all comments up to g, ignore anything after that
72                 p.flush(p.fset.Position(g.List[0].Pos()), token.ILLEGAL)
73         }
74         p.comments[0] = g
75         p.cindex = 0
76 }
77
78 type exprListMode uint
79
80 const (
81         blankStart exprListMode = 1 << iota // print a blank before a non-empty list
82         blankEnd                            // print a blank after a non-empty list
83         commaSep                            // elements are separated by commas
84         commaTerm                           // list is optionally terminated by a comma
85         noIndent                            // no extra indentation in multi-line lists
86         periodSep                           // elements are separated by periods
87 )
88
89 // Sets multiLine to true if the identifier list spans multiple lines.
90 // If indent is set, a multi-line identifier list is indented after the
91 // first linebreak encountered.
92 func (p *printer) identList(list []*ast.Ident, indent bool, multiLine *bool) {
93         // convert into an expression list so we can re-use exprList formatting
94         xlist := make([]ast.Expr, len(list))
95         for i, x := range list {
96                 xlist[i] = x
97         }
98         mode := commaSep
99         if !indent {
100                 mode |= noIndent
101         }
102         p.exprList(token.NoPos, xlist, 1, mode, multiLine, token.NoPos)
103 }
104
105 // Print a list of expressions. If the list spans multiple
106 // source lines, the original line breaks are respected between
107 // expressions. Sets multiLine to true if the list spans multiple
108 // lines.
109 //
110 // TODO(gri) Consider rewriting this to be independent of []ast.Expr
111 //           so that we can use the algorithm for any kind of list
112 //           (e.g., pass list via a channel over which to range).
113 func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exprListMode, multiLine *bool, next0 token.Pos) {
114         if len(list) == 0 {
115                 return
116         }
117
118         if mode&blankStart != 0 {
119                 p.print(blank)
120         }
121
122         prev := p.fset.Position(prev0)
123         next := p.fset.Position(next0)
124         line := p.fset.Position(list[0].Pos()).Line
125         endLine := p.fset.Position(list[len(list)-1].End()).Line
126
127         if prev.IsValid() && prev.Line == line && line == endLine {
128                 // all list entries on a single line
129                 for i, x := range list {
130                         if i > 0 {
131                                 if mode&commaSep != 0 {
132                                         p.print(token.COMMA)
133                                 }
134                                 p.print(blank)
135                         }
136                         p.expr0(x, depth, multiLine)
137                 }
138                 if mode&blankEnd != 0 {
139                         p.print(blank)
140                 }
141                 return
142         }
143
144         // list entries span multiple lines;
145         // use source code positions to guide line breaks
146
147         // don't add extra indentation if noIndent is set;
148         // i.e., pretend that the first line is already indented
149         ws := ignore
150         if mode&noIndent == 0 {
151                 ws = indent
152         }
153
154         // the first linebreak is always a formfeed since this section must not
155         // depend on any previous formatting
156         prevBreak := -1 // index of last expression that was followed by a linebreak
157         if prev.IsValid() && prev.Line < line && p.linebreak(line, 0, ws, true) {
158                 ws = ignore
159                 *multiLine = true
160                 prevBreak = 0
161         }
162
163         // initialize expression/key size: a zero value indicates expr/key doesn't fit on a single line
164         size := 0
165
166         // print all list elements
167         for i, x := range list {
168                 prevLine := line
169                 line = p.fset.Position(x.Pos()).Line
170
171                 // determine if the next linebreak, if any, needs to use formfeed:
172                 // in general, use the entire node size to make the decision; for
173                 // key:value expressions, use the key size
174                 // TODO(gri) for a better result, should probably incorporate both
175                 //           the key and the node size into the decision process
176                 useFF := true
177
178                 // determine element size: all bets are off if we don't have
179                 // position information for the previous and next token (likely
180                 // generated code - simply ignore the size in this case by setting
181                 // it to 0)
182                 prevSize := size
183                 const infinity = 1e6 // larger than any source line
184                 size = p.nodeSize(x, infinity)
185                 pair, isPair := x.(*ast.KeyValueExpr)
186                 if size <= infinity && prev.IsValid() && next.IsValid() {
187                         // x fits on a single line
188                         if isPair {
189                                 size = p.nodeSize(pair.Key, infinity) // size <= infinity
190                         }
191                 } else {
192                         // size too large or we don't have good layout information
193                         size = 0
194                 }
195
196                 // if the previous line and the current line had single-
197                 // line-expressions and the key sizes are small or the
198                 // the ratio between the key sizes does not exceed a
199                 // threshold, align columns and do not use formfeed
200                 if prevSize > 0 && size > 0 {
201                         const smallSize = 20
202                         if prevSize <= smallSize && size <= smallSize {
203                                 useFF = false
204                         } else {
205                                 const r = 4 // threshold
206                                 ratio := float64(size) / float64(prevSize)
207                                 useFF = ratio <= 1/r || r <= ratio
208                         }
209                 }
210
211                 if i > 0 {
212                         switch {
213                         case mode&commaSep != 0:
214                                 p.print(token.COMMA)
215                         case mode&periodSep != 0:
216                                 p.print(token.PERIOD)
217                         }
218                         needsBlank := mode&periodSep == 0 // period-separated list elements don't need a blank
219                         if prevLine < line && prevLine > 0 && line > 0 {
220                                 // lines are broken using newlines so comments remain aligned
221                                 // unless forceFF is set or there are multiple expressions on
222                                 // the same line in which case formfeed is used
223                                 if p.linebreak(line, 0, ws, useFF || prevBreak+1 < i) {
224                                         ws = ignore
225                                         *multiLine = true
226                                         prevBreak = i
227                                         needsBlank = false // we got a line break instead
228                                 }
229                         }
230                         if needsBlank {
231                                 p.print(blank)
232                         }
233                 }
234
235                 if isPair && size > 0 && len(list) > 1 {
236                         // we have a key:value expression that fits onto one line and
237                         // is in a list with more then one entry: use a column for the
238                         // key such that consecutive entries can align if possible
239                         p.expr(pair.Key, multiLine)
240                         p.print(pair.Colon, token.COLON, vtab)
241                         p.expr(pair.Value, multiLine)
242                 } else {
243                         p.expr0(x, depth, multiLine)
244                 }
245         }
246
247         if mode&commaTerm != 0 && next.IsValid() && p.pos.Line < next.Line {
248                 // print a terminating comma if the next token is on a new line
249                 p.print(token.COMMA)
250                 if ws == ignore && mode&noIndent == 0 {
251                         // unindent if we indented
252                         p.print(unindent)
253                 }
254                 p.print(formfeed) // terminating comma needs a line break to look good
255                 return
256         }
257
258         if mode&blankEnd != 0 {
259                 p.print(blank)
260         }
261
262         if ws == ignore && mode&noIndent == 0 {
263                 // unindent if we indented
264                 p.print(unindent)
265         }
266 }
267
268 // Sets multiLine to true if the the parameter list spans multiple lines.
269 func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) {
270         p.print(fields.Opening, token.LPAREN)
271         if len(fields.List) > 0 {
272                 ws := indent
273                 var prevLine, line int
274                 for i, par := range fields.List {
275                         if i > 0 {
276                                 p.print(token.COMMA)
277                                 if len(par.Names) > 0 {
278                                         line = p.fset.Position(par.Names[0].Pos()).Line
279                                 } else {
280                                         line = p.fset.Position(par.Type.Pos()).Line
281                                 }
282                                 if 0 < prevLine && prevLine < line && p.linebreak(line, 0, ws, true) {
283                                         ws = ignore
284                                         *multiLine = true
285                                 } else {
286                                         p.print(blank)
287                                 }
288                         }
289                         if len(par.Names) > 0 {
290                                 // Very subtle: If we indented before (ws == ignore), identList
291                                 // won't indent again. If we didn't (ws == indent), identList will
292                                 // indent if the identList spans multiple lines, and it will outdent
293                                 // again at the end (and still ws == indent). Thus, a subsequent indent
294                                 // by a linebreak call after a type, or in the next multi-line identList
295                                 // will do the right thing.
296                                 p.identList(par.Names, ws == indent, multiLine)
297                                 p.print(blank)
298                         }
299                         p.expr(par.Type, multiLine)
300                         prevLine = p.fset.Position(par.Type.Pos()).Line
301                 }
302                 if ws == ignore {
303                         // unindent if we indented
304                         p.print(unindent)
305                 }
306         }
307         p.print(fields.Closing, token.RPAREN)
308 }
309
310 // Sets multiLine to true if the signature spans multiple lines.
311 func (p *printer) signature(params, result *ast.FieldList, multiLine *bool) {
312         p.parameters(params, multiLine)
313         n := result.NumFields()
314         if n > 0 {
315                 p.print(blank)
316                 if n == 1 && result.List[0].Names == nil {
317                         // single anonymous result; no ()'s
318                         p.expr(result.List[0].Type, multiLine)
319                         return
320                 }
321                 p.parameters(result, multiLine)
322         }
323 }
324
325 func identListSize(list []*ast.Ident, maxSize int) (size int) {
326         for i, x := range list {
327                 if i > 0 {
328                         size += 2 // ", "
329                 }
330                 size += len(x.Name)
331                 if size >= maxSize {
332                         break
333                 }
334         }
335         return
336 }
337
338 func (p *printer) isOneLineFieldList(list []*ast.Field) bool {
339         if len(list) != 1 {
340                 return false // allow only one field
341         }
342         f := list[0]
343         if f.Tag != nil || f.Comment != nil {
344                 return false // don't allow tags or comments
345         }
346         // only name(s) and type
347         const maxSize = 30 // adjust as appropriate, this is an approximate value
348         namesSize := identListSize(f.Names, maxSize)
349         if namesSize > 0 {
350                 namesSize = 1 // blank between names and types
351         }
352         typeSize := p.nodeSize(f.Type, maxSize)
353         return namesSize+typeSize <= maxSize
354 }
355
356 func (p *printer) setLineComment(text string) {
357         p.setComment(&ast.CommentGroup{[]*ast.Comment{{token.NoPos, text}}})
358 }
359
360 func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) {
361         lbrace := fields.Opening
362         list := fields.List
363         rbrace := fields.Closing
364         srcIsOneLine := lbrace.IsValid() && rbrace.IsValid() && p.fset.Position(lbrace).Line == p.fset.Position(rbrace).Line
365
366         if !isIncomplete && !p.commentBefore(p.fset.Position(rbrace)) && srcIsOneLine {
367                 // possibly a one-line struct/interface
368                 if len(list) == 0 {
369                         // no blank between keyword and {} in this case
370                         p.print(lbrace, token.LBRACE, rbrace, token.RBRACE)
371                         return
372                 } else if isStruct && p.isOneLineFieldList(list) { // for now ignore interfaces
373                         // small enough - print on one line
374                         // (don't use identList and ignore source line breaks)
375                         p.print(lbrace, token.LBRACE, blank)
376                         f := list[0]
377                         for i, x := range f.Names {
378                                 if i > 0 {
379                                         p.print(token.COMMA, blank)
380                                 }
381                                 p.expr(x, ignoreMultiLine)
382                         }
383                         if len(f.Names) > 0 {
384                                 p.print(blank)
385                         }
386                         p.expr(f.Type, ignoreMultiLine)
387                         p.print(blank, rbrace, token.RBRACE)
388                         return
389                 }
390         }
391
392         // at least one entry or incomplete
393         p.print(blank, lbrace, token.LBRACE, indent, formfeed)
394         if isStruct {
395
396                 sep := vtab
397                 if len(list) == 1 {
398                         sep = blank
399                 }
400                 var ml bool
401                 for i, f := range list {
402                         if i > 0 {
403                                 p.linebreak(p.fset.Position(f.Pos()).Line, 1, ignore, ml)
404                         }
405                         ml = false
406                         extraTabs := 0
407                         p.setComment(f.Doc)
408                         if len(f.Names) > 0 {
409                                 // named fields
410                                 p.identList(f.Names, false, &ml)
411                                 p.print(sep)
412                                 p.expr(f.Type, &ml)
413                                 extraTabs = 1
414                         } else {
415                                 // anonymous field
416                                 p.expr(f.Type, &ml)
417                                 extraTabs = 2
418                         }
419                         if f.Tag != nil {
420                                 if len(f.Names) > 0 && sep == vtab {
421                                         p.print(sep)
422                                 }
423                                 p.print(sep)
424                                 p.expr(f.Tag, &ml)
425                                 extraTabs = 0
426                         }
427                         if f.Comment != nil {
428                                 for ; extraTabs > 0; extraTabs-- {
429                                         p.print(sep)
430                                 }
431                                 p.setComment(f.Comment)
432                         }
433                 }
434                 if isIncomplete {
435                         if len(list) > 0 {
436                                 p.print(formfeed)
437                         }
438                         p.flush(p.fset.Position(rbrace), token.RBRACE) // make sure we don't lose the last line comment
439                         p.setLineComment("// contains filtered or unexported fields")
440                 }
441
442         } else { // interface
443
444                 var ml bool
445                 for i, f := range list {
446                         if i > 0 {
447                                 p.linebreak(p.fset.Position(f.Pos()).Line, 1, ignore, ml)
448                         }
449                         ml = false
450                         p.setComment(f.Doc)
451                         if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
452                                 // method
453                                 p.expr(f.Names[0], &ml)
454                                 p.signature(ftyp.Params, ftyp.Results, &ml)
455                         } else {
456                                 // embedded interface
457                                 p.expr(f.Type, &ml)
458                         }
459                         p.setComment(f.Comment)
460                 }
461                 if isIncomplete {
462                         if len(list) > 0 {
463                                 p.print(formfeed)
464                         }
465                         p.flush(p.fset.Position(rbrace), token.RBRACE) // make sure we don't lose the last line comment
466                         p.setLineComment("// contains filtered or unexported methods")
467                 }
468
469         }
470         p.print(unindent, formfeed, rbrace, token.RBRACE)
471 }
472
473 // ----------------------------------------------------------------------------
474 // Expressions
475
476 func walkBinary(e *ast.BinaryExpr) (has4, has5 bool, maxProblem int) {
477         switch e.Op.Precedence() {
478         case 4:
479                 has4 = true
480         case 5:
481                 has5 = true
482         }
483
484         switch l := e.X.(type) {
485         case *ast.BinaryExpr:
486                 if l.Op.Precedence() < e.Op.Precedence() {
487                         // parens will be inserted.
488                         // pretend this is an *ast.ParenExpr and do nothing.
489                         break
490                 }
491                 h4, h5, mp := walkBinary(l)
492                 has4 = has4 || h4
493                 has5 = has5 || h5
494                 if maxProblem < mp {
495                         maxProblem = mp
496                 }
497         }
498
499         switch r := e.Y.(type) {
500         case *ast.BinaryExpr:
501                 if r.Op.Precedence() <= e.Op.Precedence() {
502                         // parens will be inserted.
503                         // pretend this is an *ast.ParenExpr and do nothing.
504                         break
505                 }
506                 h4, h5, mp := walkBinary(r)
507                 has4 = has4 || h4
508                 has5 = has5 || h5
509                 if maxProblem < mp {
510                         maxProblem = mp
511                 }
512
513         case *ast.StarExpr:
514                 if e.Op == token.QUO { // `*/`
515                         maxProblem = 5
516                 }
517
518         case *ast.UnaryExpr:
519                 switch e.Op.String() + r.Op.String() {
520                 case "/*", "&&", "&^":
521                         maxProblem = 5
522                 case "++", "--":
523                         if maxProblem < 4 {
524                                 maxProblem = 4
525                         }
526                 }
527         }
528         return
529 }
530
531 func cutoff(e *ast.BinaryExpr, depth int) int {
532         has4, has5, maxProblem := walkBinary(e)
533         if maxProblem > 0 {
534                 return maxProblem + 1
535         }
536         if has4 && has5 {
537                 if depth == 1 {
538                         return 5
539                 }
540                 return 4
541         }
542         if depth == 1 {
543                 return 6
544         }
545         return 4
546 }
547
548 func diffPrec(expr ast.Expr, prec int) int {
549         x, ok := expr.(*ast.BinaryExpr)
550         if !ok || prec != x.Op.Precedence() {
551                 return 1
552         }
553         return 0
554 }
555
556 func reduceDepth(depth int) int {
557         depth--
558         if depth < 1 {
559                 depth = 1
560         }
561         return depth
562 }
563
564 // Format the binary expression: decide the cutoff and then format.
565 // Let's call depth == 1 Normal mode, and depth > 1 Compact mode.
566 // (Algorithm suggestion by Russ Cox.)
567 //
568 // The precedences are:
569 //      5             *  /  %  <<  >>  &  &^
570 //      4             +  -  |  ^
571 //      3             ==  !=  <  <=  >  >=
572 //      2             &&
573 //      1             ||
574 //
575 // The only decision is whether there will be spaces around levels 4 and 5.
576 // There are never spaces at level 6 (unary), and always spaces at levels 3 and below.
577 //
578 // To choose the cutoff, look at the whole expression but excluding primary
579 // expressions (function calls, parenthesized exprs), and apply these rules:
580 //
581 //      1) If there is a binary operator with a right side unary operand
582 //         that would clash without a space, the cutoff must be (in order):
583 //
584 //              /*      6
585 //              &&      6
586 //              &^      6
587 //              ++      5
588 //              --      5
589 //
590 //         (Comparison operators always have spaces around them.)
591 //
592 //      2) If there is a mix of level 5 and level 4 operators, then the cutoff
593 //         is 5 (use spaces to distinguish precedence) in Normal mode
594 //         and 4 (never use spaces) in Compact mode.
595 //
596 //      3) If there are no level 4 operators or no level 5 operators, then the
597 //         cutoff is 6 (always use spaces) in Normal mode
598 //         and 4 (never use spaces) in Compact mode.
599 //
600 // Sets multiLine to true if the binary expression spans multiple lines.
601 func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiLine *bool) {
602         prec := x.Op.Precedence()
603         if prec < prec1 {
604                 // parenthesis needed
605                 // Note: The parser inserts an ast.ParenExpr node; thus this case
606                 //       can only occur if the AST is created in a different way.
607                 p.print(token.LPAREN)
608                 p.expr0(x, reduceDepth(depth), multiLine) // parentheses undo one level of depth
609                 p.print(token.RPAREN)
610                 return
611         }
612
613         printBlank := prec < cutoff
614
615         ws := indent
616         p.expr1(x.X, prec, depth+diffPrec(x.X, prec), multiLine)
617         if printBlank {
618                 p.print(blank)
619         }
620         xline := p.pos.Line // before the operator (it may be on the next line!)
621         yline := p.fset.Position(x.Y.Pos()).Line
622         p.print(x.OpPos, x.Op)
623         if xline != yline && xline > 0 && yline > 0 {
624                 // at least one line break, but respect an extra empty line
625                 // in the source
626                 if p.linebreak(yline, 1, ws, true) {
627                         ws = ignore
628                         *multiLine = true
629                         printBlank = false // no blank after line break
630                 }
631         }
632         if printBlank {
633                 p.print(blank)
634         }
635         p.expr1(x.Y, prec+1, depth+1, multiLine)
636         if ws == ignore {
637                 p.print(unindent)
638         }
639 }
640
641 func isBinary(expr ast.Expr) bool {
642         _, ok := expr.(*ast.BinaryExpr)
643         return ok
644 }
645
646 // If the expression contains one or more selector expressions, splits it into
647 // two expressions at the rightmost period. Writes entire expr to suffix when
648 // selector isn't found. Rewrites AST nodes for calls, index expressions and
649 // type assertions, all of which may be found in selector chains, to make them
650 // parts of the chain.
651 func splitSelector(expr ast.Expr) (body, suffix ast.Expr) {
652         switch x := expr.(type) {
653         case *ast.SelectorExpr:
654                 body, suffix = x.X, x.Sel
655                 return
656         case *ast.CallExpr:
657                 body, suffix = splitSelector(x.Fun)
658                 if body != nil {
659                         suffix = &ast.CallExpr{suffix, x.Lparen, x.Args, x.Ellipsis, x.Rparen}
660                         return
661                 }
662         case *ast.IndexExpr:
663                 body, suffix = splitSelector(x.X)
664                 if body != nil {
665                         suffix = &ast.IndexExpr{suffix, x.Lbrack, x.Index, x.Rbrack}
666                         return
667                 }
668         case *ast.SliceExpr:
669                 body, suffix = splitSelector(x.X)
670                 if body != nil {
671                         suffix = &ast.SliceExpr{suffix, x.Lbrack, x.Low, x.High, x.Rbrack}
672                         return
673                 }
674         case *ast.TypeAssertExpr:
675                 body, suffix = splitSelector(x.X)
676                 if body != nil {
677                         suffix = &ast.TypeAssertExpr{suffix, x.Type}
678                         return
679                 }
680         }
681         suffix = expr
682         return
683 }
684
685 // Convert an expression into an expression list split at the periods of
686 // selector expressions.
687 func selectorExprList(expr ast.Expr) (list []ast.Expr) {
688         // split expression
689         for expr != nil {
690                 var suffix ast.Expr
691                 expr, suffix = splitSelector(expr)
692                 list = append(list, suffix)
693         }
694
695         // reverse list
696         for i, j := 0, len(list)-1; i < j; i, j = i+1, j-1 {
697                 list[i], list[j] = list[j], list[i]
698         }
699
700         return
701 }
702
703 // Sets multiLine to true if the expression spans multiple lines.
704 func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
705         p.print(expr.Pos())
706
707         switch x := expr.(type) {
708         case *ast.BadExpr:
709                 p.print("BadExpr")
710
711         case *ast.Ident:
712                 p.print(x)
713
714         case *ast.BinaryExpr:
715                 if depth < 1 {
716                         p.internalError("depth < 1:", depth)
717                         depth = 1
718                 }
719                 p.binaryExpr(x, prec1, cutoff(x, depth), depth, multiLine)
720
721         case *ast.KeyValueExpr:
722                 p.expr(x.Key, multiLine)
723                 p.print(x.Colon, token.COLON, blank)
724                 p.expr(x.Value, multiLine)
725
726         case *ast.StarExpr:
727                 const prec = token.UnaryPrec
728                 if prec < prec1 {
729                         // parenthesis needed
730                         p.print(token.LPAREN)
731                         p.print(token.MUL)
732                         p.expr(x.X, multiLine)
733                         p.print(token.RPAREN)
734                 } else {
735                         // no parenthesis needed
736                         p.print(token.MUL)
737                         p.expr(x.X, multiLine)
738                 }
739
740         case *ast.UnaryExpr:
741                 const prec = token.UnaryPrec
742                 if prec < prec1 {
743                         // parenthesis needed
744                         p.print(token.LPAREN)
745                         p.expr(x, multiLine)
746                         p.print(token.RPAREN)
747                 } else {
748                         // no parenthesis needed
749                         p.print(x.Op)
750                         if x.Op == token.RANGE {
751                                 // TODO(gri) Remove this code if it cannot be reached.
752                                 p.print(blank)
753                         }
754                         p.expr1(x.X, prec, depth, multiLine)
755                 }
756
757         case *ast.BasicLit:
758                 p.print(x)
759
760         case *ast.FuncLit:
761                 p.expr(x.Type, multiLine)
762                 p.funcBody(x.Body, p.distance(x.Type.Pos(), p.pos), true, multiLine)
763
764         case *ast.ParenExpr:
765                 if _, hasParens := x.X.(*ast.ParenExpr); hasParens {
766                         // don't print parentheses around an already parenthesized expression
767                         // TODO(gri) consider making this more general and incorporate precedence levels
768                         p.expr0(x.X, reduceDepth(depth), multiLine) // parentheses undo one level of depth
769                 } else {
770                         p.print(token.LPAREN)
771                         p.expr0(x.X, reduceDepth(depth), multiLine) // parentheses undo one level of depth
772                         p.print(x.Rparen, token.RPAREN)
773                 }
774
775         case *ast.SelectorExpr:
776                 parts := selectorExprList(expr)
777                 p.exprList(token.NoPos, parts, depth, periodSep, multiLine, token.NoPos)
778
779         case *ast.TypeAssertExpr:
780                 p.expr1(x.X, token.HighestPrec, depth, multiLine)
781                 p.print(token.PERIOD, token.LPAREN)
782                 if x.Type != nil {
783                         p.expr(x.Type, multiLine)
784                 } else {
785                         p.print(token.TYPE)
786                 }
787                 p.print(token.RPAREN)
788
789         case *ast.IndexExpr:
790                 // TODO(gri): should treat[] like parentheses and undo one level of depth
791                 p.expr1(x.X, token.HighestPrec, 1, multiLine)
792                 p.print(x.Lbrack, token.LBRACK)
793                 p.expr0(x.Index, depth+1, multiLine)
794                 p.print(x.Rbrack, token.RBRACK)
795
796         case *ast.SliceExpr:
797                 // TODO(gri): should treat[] like parentheses and undo one level of depth
798                 p.expr1(x.X, token.HighestPrec, 1, multiLine)
799                 p.print(x.Lbrack, token.LBRACK)
800                 if x.Low != nil {
801                         p.expr0(x.Low, depth+1, multiLine)
802                 }
803                 // blanks around ":" if both sides exist and either side is a binary expression
804                 if depth <= 1 && x.Low != nil && x.High != nil && (isBinary(x.Low) || isBinary(x.High)) {
805                         p.print(blank, token.COLON, blank)
806                 } else {
807                         p.print(token.COLON)
808                 }
809                 if x.High != nil {
810                         p.expr0(x.High, depth+1, multiLine)
811                 }
812                 p.print(x.Rbrack, token.RBRACK)
813
814         case *ast.CallExpr:
815                 if len(x.Args) > 1 {
816                         depth++
817                 }
818                 p.expr1(x.Fun, token.HighestPrec, depth, multiLine)
819                 p.print(x.Lparen, token.LPAREN)
820                 p.exprList(x.Lparen, x.Args, depth, commaSep|commaTerm, multiLine, x.Rparen)
821                 if x.Ellipsis.IsValid() {
822                         p.print(x.Ellipsis, token.ELLIPSIS)
823                 }
824                 p.print(x.Rparen, token.RPAREN)
825
826         case *ast.CompositeLit:
827                 // composite literal elements that are composite literals themselves may have the type omitted
828                 if x.Type != nil {
829                         p.expr1(x.Type, token.HighestPrec, depth, multiLine)
830                 }
831                 p.print(x.Lbrace, token.LBRACE)
832                 p.exprList(x.Lbrace, x.Elts, 1, commaSep|commaTerm, multiLine, x.Rbrace)
833                 // do not insert extra line breaks because of comments before
834                 // the closing '}' as it might break the code if there is no
835                 // trailing ','
836                 p.print(noExtraLinebreak, x.Rbrace, token.RBRACE, noExtraLinebreak)
837
838         case *ast.Ellipsis:
839                 p.print(token.ELLIPSIS)
840                 if x.Elt != nil {
841                         p.expr(x.Elt, multiLine)
842                 }
843
844         case *ast.ArrayType:
845                 p.print(token.LBRACK)
846                 if x.Len != nil {
847                         p.expr(x.Len, multiLine)
848                 }
849                 p.print(token.RBRACK)
850                 p.expr(x.Elt, multiLine)
851
852         case *ast.StructType:
853                 p.print(token.STRUCT)
854                 p.fieldList(x.Fields, true, x.Incomplete)
855
856         case *ast.FuncType:
857                 p.print(token.FUNC)
858                 p.signature(x.Params, x.Results, multiLine)
859
860         case *ast.InterfaceType:
861                 p.print(token.INTERFACE)
862                 p.fieldList(x.Methods, false, x.Incomplete)
863
864         case *ast.MapType:
865                 p.print(token.MAP, token.LBRACK)
866                 p.expr(x.Key, multiLine)
867                 p.print(token.RBRACK)
868                 p.expr(x.Value, multiLine)
869
870         case *ast.ChanType:
871                 switch x.Dir {
872                 case ast.SEND | ast.RECV:
873                         p.print(token.CHAN)
874                 case ast.RECV:
875                         p.print(token.ARROW, token.CHAN)
876                 case ast.SEND:
877                         p.print(token.CHAN, token.ARROW)
878                 }
879                 p.print(blank)
880                 p.expr(x.Value, multiLine)
881
882         default:
883                 panic("unreachable")
884         }
885
886         return
887 }
888
889 func (p *printer) expr0(x ast.Expr, depth int, multiLine *bool) {
890         p.expr1(x, token.LowestPrec, depth, multiLine)
891 }
892
893 // Sets multiLine to true if the expression spans multiple lines.
894 func (p *printer) expr(x ast.Expr, multiLine *bool) {
895         const depth = 1
896         p.expr1(x, token.LowestPrec, depth, multiLine)
897 }
898
899 // ----------------------------------------------------------------------------
900 // Statements
901
902 // Print the statement list indented, but without a newline after the last statement.
903 // Extra line breaks between statements in the source are respected but at most one
904 // empty line is printed between statements.
905 func (p *printer) stmtList(list []ast.Stmt, _indent int, nextIsRBrace bool) {
906         // TODO(gri): fix _indent code
907         if _indent > 0 {
908                 p.print(indent)
909         }
910         var multiLine bool
911         for i, s := range list {
912                 // _indent == 0 only for lists of switch/select case clauses;
913                 // in those cases each clause is a new section
914                 p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, i == 0 || _indent == 0 || multiLine)
915                 multiLine = false
916                 p.stmt(s, nextIsRBrace && i == len(list)-1, &multiLine)
917         }
918         if _indent > 0 {
919                 p.print(unindent)
920         }
921 }
922
923 // block prints an *ast.BlockStmt; it always spans at least two lines.
924 func (p *printer) block(s *ast.BlockStmt, indent int) {
925         p.print(s.Pos(), token.LBRACE)
926         p.stmtList(s.List, indent, true)
927         p.linebreak(p.fset.Position(s.Rbrace).Line, 1, ignore, true)
928         p.print(s.Rbrace, token.RBRACE)
929 }
930
931 func isTypeName(x ast.Expr) bool {
932         switch t := x.(type) {
933         case *ast.Ident:
934                 return true
935         case *ast.SelectorExpr:
936                 return isTypeName(t.X)
937         }
938         return false
939 }
940
941 func stripParens(x ast.Expr) ast.Expr {
942         if px, strip := x.(*ast.ParenExpr); strip {
943                 // parentheses must not be stripped if there are any
944                 // unparenthesized composite literals starting with
945                 // a type name
946                 ast.Inspect(px.X, func(node ast.Node) bool {
947                         switch x := node.(type) {
948                         case *ast.ParenExpr:
949                                 // parentheses protect enclosed composite literals
950                                 return false
951                         case *ast.CompositeLit:
952                                 if isTypeName(x.Type) {
953                                         strip = false // do not strip parentheses
954                                 }
955                                 return false
956                         }
957                         // in all other cases, keep inspecting
958                         return true
959                 })
960                 if strip {
961                         return stripParens(px.X)
962                 }
963         }
964         return x
965 }
966
967 func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, post ast.Stmt) {
968         p.print(blank)
969         needsBlank := false
970         if init == nil && post == nil {
971                 // no semicolons required
972                 if expr != nil {
973                         p.expr(stripParens(expr), ignoreMultiLine)
974                         needsBlank = true
975                 }
976         } else {
977                 // all semicolons required
978                 // (they are not separators, print them explicitly)
979                 if init != nil {
980                         p.stmt(init, false, ignoreMultiLine)
981                 }
982                 p.print(token.SEMICOLON, blank)
983                 if expr != nil {
984                         p.expr(stripParens(expr), ignoreMultiLine)
985                         needsBlank = true
986                 }
987                 if isForStmt {
988                         p.print(token.SEMICOLON, blank)
989                         needsBlank = false
990                         if post != nil {
991                                 p.stmt(post, false, ignoreMultiLine)
992                                 needsBlank = true
993                         }
994                 }
995         }
996         if needsBlank {
997                 p.print(blank)
998         }
999 }
1000
1001 // Sets multiLine to true if the statements spans multiple lines.
1002 func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
1003         p.print(stmt.Pos())
1004
1005         switch s := stmt.(type) {
1006         case *ast.BadStmt:
1007                 p.print("BadStmt")
1008
1009         case *ast.DeclStmt:
1010                 p.decl(s.Decl, multiLine)
1011
1012         case *ast.EmptyStmt:
1013                 // nothing to do
1014
1015         case *ast.LabeledStmt:
1016                 // a "correcting" unindent immediately following a line break
1017                 // is applied before the line break if there is no comment
1018                 // between (see writeWhitespace)
1019                 p.print(unindent)
1020                 p.expr(s.Label, multiLine)
1021                 p.print(s.Colon, token.COLON, indent)
1022                 if e, isEmpty := s.Stmt.(*ast.EmptyStmt); isEmpty {
1023                         if !nextIsRBrace {
1024                                 p.print(newline, e.Pos(), token.SEMICOLON)
1025                                 break
1026                         }
1027                 } else {
1028                         p.linebreak(p.fset.Position(s.Stmt.Pos()).Line, 1, ignore, true)
1029                 }
1030                 p.stmt(s.Stmt, nextIsRBrace, multiLine)
1031
1032         case *ast.ExprStmt:
1033                 const depth = 1
1034                 p.expr0(s.X, depth, multiLine)
1035
1036         case *ast.SendStmt:
1037                 const depth = 1
1038                 p.expr0(s.Chan, depth, multiLine)
1039                 p.print(blank, s.Arrow, token.ARROW, blank)
1040                 p.expr0(s.Value, depth, multiLine)
1041
1042         case *ast.IncDecStmt:
1043                 const depth = 1
1044                 p.expr0(s.X, depth+1, multiLine)
1045                 p.print(s.TokPos, s.Tok)
1046
1047         case *ast.AssignStmt:
1048                 var depth = 1
1049                 if len(s.Lhs) > 1 && len(s.Rhs) > 1 {
1050                         depth++
1051                 }
1052                 p.exprList(s.Pos(), s.Lhs, depth, commaSep, multiLine, s.TokPos)
1053                 p.print(blank, s.TokPos, s.Tok)
1054                 p.exprList(s.TokPos, s.Rhs, depth, blankStart|commaSep, multiLine, token.NoPos)
1055
1056         case *ast.GoStmt:
1057                 p.print(token.GO, blank)
1058                 p.expr(s.Call, multiLine)
1059
1060         case *ast.DeferStmt:
1061                 p.print(token.DEFER, blank)
1062                 p.expr(s.Call, multiLine)
1063
1064         case *ast.ReturnStmt:
1065                 p.print(token.RETURN)
1066                 if s.Results != nil {
1067                         p.exprList(s.Pos(), s.Results, 1, blankStart|commaSep, multiLine, token.NoPos)
1068                 }
1069
1070         case *ast.BranchStmt:
1071                 p.print(s.Tok)
1072                 if s.Label != nil {
1073                         p.print(blank)
1074                         p.expr(s.Label, multiLine)
1075                 }
1076
1077         case *ast.BlockStmt:
1078                 p.block(s, 1)
1079                 *multiLine = true
1080
1081         case *ast.IfStmt:
1082                 p.print(token.IF)
1083                 p.controlClause(false, s.Init, s.Cond, nil)
1084                 p.block(s.Body, 1)
1085                 *multiLine = true
1086                 if s.Else != nil {
1087                         p.print(blank, token.ELSE, blank)
1088                         switch s.Else.(type) {
1089                         case *ast.BlockStmt, *ast.IfStmt:
1090                                 p.stmt(s.Else, nextIsRBrace, ignoreMultiLine)
1091                         default:
1092                                 p.print(token.LBRACE, indent, formfeed)
1093                                 p.stmt(s.Else, true, ignoreMultiLine)
1094                                 p.print(unindent, formfeed, token.RBRACE)
1095                         }
1096                 }
1097
1098         case *ast.CaseClause:
1099                 if s.List != nil {
1100                         p.print(token.CASE)
1101                         p.exprList(s.Pos(), s.List, 1, blankStart|commaSep, multiLine, s.Colon)
1102                 } else {
1103                         p.print(token.DEFAULT)
1104                 }
1105                 p.print(s.Colon, token.COLON)
1106                 p.stmtList(s.Body, 1, nextIsRBrace)
1107
1108         case *ast.SwitchStmt:
1109                 p.print(token.SWITCH)
1110                 p.controlClause(false, s.Init, s.Tag, nil)
1111                 p.block(s.Body, 0)
1112                 *multiLine = true
1113
1114         case *ast.TypeSwitchStmt:
1115                 p.print(token.SWITCH)
1116                 if s.Init != nil {
1117                         p.print(blank)
1118                         p.stmt(s.Init, false, ignoreMultiLine)
1119                         p.print(token.SEMICOLON)
1120                 }
1121                 p.print(blank)
1122                 p.stmt(s.Assign, false, ignoreMultiLine)
1123                 p.print(blank)
1124                 p.block(s.Body, 0)
1125                 *multiLine = true
1126
1127         case *ast.CommClause:
1128                 if s.Comm != nil {
1129                         p.print(token.CASE, blank)
1130                         p.stmt(s.Comm, false, ignoreMultiLine)
1131                 } else {
1132                         p.print(token.DEFAULT)
1133                 }
1134                 p.print(s.Colon, token.COLON)
1135                 p.stmtList(s.Body, 1, nextIsRBrace)
1136
1137         case *ast.SelectStmt:
1138                 p.print(token.SELECT, blank)
1139                 body := s.Body
1140                 if len(body.List) == 0 && !p.commentBefore(p.fset.Position(body.Rbrace)) {
1141                         // print empty select statement w/o comments on one line
1142                         p.print(body.Lbrace, token.LBRACE, body.Rbrace, token.RBRACE)
1143                 } else {
1144                         p.block(body, 0)
1145                         *multiLine = true
1146                 }
1147
1148         case *ast.ForStmt:
1149                 p.print(token.FOR)
1150                 p.controlClause(true, s.Init, s.Cond, s.Post)
1151                 p.block(s.Body, 1)
1152                 *multiLine = true
1153
1154         case *ast.RangeStmt:
1155                 p.print(token.FOR, blank)
1156                 p.expr(s.Key, multiLine)
1157                 if s.Value != nil {
1158                         p.print(token.COMMA, blank)
1159                         p.expr(s.Value, multiLine)
1160                 }
1161                 p.print(blank, s.TokPos, s.Tok, blank, token.RANGE, blank)
1162                 p.expr(stripParens(s.X), multiLine)
1163                 p.print(blank)
1164                 p.block(s.Body, 1)
1165                 *multiLine = true
1166
1167         default:
1168                 panic("unreachable")
1169         }
1170
1171         return
1172 }
1173
1174 // ----------------------------------------------------------------------------
1175 // Declarations
1176
1177 // The keepTypeColumn function determines if the type column of a series of
1178 // consecutive const or var declarations must be kept, or if initialization
1179 // values (V) can be placed in the type column (T) instead. The i'th entry
1180 // in the result slice is true if the type column in spec[i] must be kept.
1181 //
1182 // For example, the declaration:
1183 //
1184 //      const (
1185 //              foobar int = 42 // comment
1186 //              x          = 7  // comment
1187 //              foo
1188 //              bar = 991
1189 //      )
1190 //
1191 // leads to the type/values matrix below. A run of value columns (V) can
1192 // be moved into the type column if there is no type for any of the values
1193 // in that column (we only move entire columns so that they align properly).
1194 //
1195 //      matrix        formatted     result
1196 //                    matrix
1197 //      T  V    ->    T  V     ->   true      there is a T and so the type
1198 //      -  V          -  V          true      column must be kept
1199 //      -  -          -  -          false
1200 //      -  V          V  -          false     V is moved into T column
1201 //
1202 func keepTypeColumn(specs []ast.Spec) []bool {
1203         m := make([]bool, len(specs))
1204
1205         populate := func(i, j int, keepType bool) {
1206                 if keepType {
1207                         for ; i < j; i++ {
1208                                 m[i] = true
1209                         }
1210                 }
1211         }
1212
1213         i0 := -1 // if i0 >= 0 we are in a run and i0 is the start of the run
1214         var keepType bool
1215         for i, s := range specs {
1216                 t := s.(*ast.ValueSpec)
1217                 if t.Values != nil {
1218                         if i0 < 0 {
1219                                 // start of a run of ValueSpecs with non-nil Values
1220                                 i0 = i
1221                                 keepType = false
1222                         }
1223                 } else {
1224                         if i0 >= 0 {
1225                                 // end of a run
1226                                 populate(i0, i, keepType)
1227                                 i0 = -1
1228                         }
1229                 }
1230                 if t.Type != nil {
1231                         keepType = true
1232                 }
1233         }
1234         if i0 >= 0 {
1235                 // end of a run
1236                 populate(i0, len(specs), keepType)
1237         }
1238
1239         return m
1240 }
1241
1242 func (p *printer) valueSpec(s *ast.ValueSpec, keepType, doIndent bool, multiLine *bool) {
1243         p.setComment(s.Doc)
1244         p.identList(s.Names, doIndent, multiLine) // always present
1245         extraTabs := 3
1246         if s.Type != nil || keepType {
1247                 p.print(vtab)
1248                 extraTabs--
1249         }
1250         if s.Type != nil {
1251                 p.expr(s.Type, multiLine)
1252         }
1253         if s.Values != nil {
1254                 p.print(vtab, token.ASSIGN)
1255                 p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiLine, token.NoPos)
1256                 extraTabs--
1257         }
1258         if s.Comment != nil {
1259                 for ; extraTabs > 0; extraTabs-- {
1260                         p.print(vtab)
1261                 }
1262                 p.setComment(s.Comment)
1263         }
1264 }
1265
1266 // The parameter n is the number of specs in the group. If doIndent is set,
1267 // multi-line identifier lists in the spec are indented when the first
1268 // linebreak is encountered.
1269 // Sets multiLine to true if the spec spans multiple lines.
1270 //
1271 func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) {
1272         switch s := spec.(type) {
1273         case *ast.ImportSpec:
1274                 p.setComment(s.Doc)
1275                 if s.Name != nil {
1276                         p.expr(s.Name, multiLine)
1277                         p.print(blank)
1278                 }
1279                 p.expr(s.Path, multiLine)
1280                 p.setComment(s.Comment)
1281                 p.print(s.EndPos)
1282
1283         case *ast.ValueSpec:
1284                 if n != 1 {
1285                         p.internalError("expected n = 1; got", n)
1286                 }
1287                 p.setComment(s.Doc)
1288                 p.identList(s.Names, doIndent, multiLine) // always present
1289                 if s.Type != nil {
1290                         p.print(blank)
1291                         p.expr(s.Type, multiLine)
1292                 }
1293                 if s.Values != nil {
1294                         p.print(blank, token.ASSIGN)
1295                         p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiLine, token.NoPos)
1296                 }
1297                 p.setComment(s.Comment)
1298
1299         case *ast.TypeSpec:
1300                 p.setComment(s.Doc)
1301                 p.expr(s.Name, multiLine)
1302                 if n == 1 {
1303                         p.print(blank)
1304                 } else {
1305                         p.print(vtab)
1306                 }
1307                 p.expr(s.Type, multiLine)
1308                 p.setComment(s.Comment)
1309
1310         default:
1311                 panic("unreachable")
1312         }
1313 }
1314
1315 // Sets multiLine to true if the declaration spans multiple lines.
1316 func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) {
1317         p.setComment(d.Doc)
1318         p.print(d.Pos(), d.Tok, blank)
1319
1320         if d.Lparen.IsValid() {
1321                 // group of parenthesized declarations
1322                 p.print(d.Lparen, token.LPAREN)
1323                 if n := len(d.Specs); n > 0 {
1324                         p.print(indent, formfeed)
1325                         if n > 1 && (d.Tok == token.CONST || d.Tok == token.VAR) {
1326                                 // two or more grouped const/var declarations:
1327                                 // determine if the type column must be kept
1328                                 keepType := keepTypeColumn(d.Specs)
1329                                 var ml bool
1330                                 for i, s := range d.Specs {
1331                                         if i > 0 {
1332                                                 p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, ml)
1333                                         }
1334                                         ml = false
1335                                         p.valueSpec(s.(*ast.ValueSpec), keepType[i], false, &ml)
1336                                 }
1337                         } else {
1338                                 var ml bool
1339                                 for i, s := range d.Specs {
1340                                         if i > 0 {
1341                                                 p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, ml)
1342                                         }
1343                                         ml = false
1344                                         p.spec(s, n, false, &ml)
1345                                 }
1346                         }
1347                         p.print(unindent, formfeed)
1348                         *multiLine = true
1349                 }
1350                 p.print(d.Rparen, token.RPAREN)
1351
1352         } else {
1353                 // single declaration
1354                 p.spec(d.Specs[0], 1, true, multiLine)
1355         }
1356 }
1357
1358 // nodeSize determines the size of n in chars after formatting.
1359 // The result is <= maxSize if the node fits on one line with at
1360 // most maxSize chars and the formatted output doesn't contain
1361 // any control chars. Otherwise, the result is > maxSize.
1362 //
1363 func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) {
1364         // nodeSize invokes the printer, which may invoke nodeSize
1365         // recursively. For deep composite literal nests, this can
1366         // lead to an exponential algorithm. Remember previous
1367         // results to prune the recursion (was issue 1628).
1368         if size, found := p.nodeSizes[n]; found {
1369                 return size
1370         }
1371
1372         size = maxSize + 1 // assume n doesn't fit
1373         p.nodeSizes[n] = size
1374
1375         // nodeSize computation must be independent of particular
1376         // style so that we always get the same decision; print
1377         // in RawFormat
1378         cfg := Config{Mode: RawFormat}
1379         var buf bytes.Buffer
1380         if err := cfg.fprint(&buf, p.fset, n, p.nodeSizes); err != nil {
1381                 return
1382         }
1383         if buf.Len() <= maxSize {
1384                 for _, ch := range buf.Bytes() {
1385                         if ch < ' ' {
1386                                 return
1387                         }
1388                 }
1389                 size = buf.Len() // n fits
1390                 p.nodeSizes[n] = size
1391         }
1392         return
1393 }
1394
1395 func (p *printer) isOneLineFunc(b *ast.BlockStmt, headerSize int) bool {
1396         pos1 := b.Pos()
1397         pos2 := b.Rbrace
1398         if pos1.IsValid() && pos2.IsValid() && p.fset.Position(pos1).Line != p.fset.Position(pos2).Line {
1399                 // opening and closing brace are on different lines - don't make it a one-liner
1400                 return false
1401         }
1402         if len(b.List) > 5 || p.commentBefore(p.fset.Position(pos2)) {
1403                 // too many statements or there is a comment inside - don't make it a one-liner
1404                 return false
1405         }
1406         // otherwise, estimate body size
1407         const maxSize = 100
1408         bodySize := 0
1409         for i, s := range b.List {
1410                 if i > 0 {
1411                         bodySize += 2 // space for a semicolon and blank
1412                 }
1413                 bodySize += p.nodeSize(s, maxSize)
1414         }
1415         return headerSize+bodySize <= maxSize
1416 }
1417
1418 // Sets multiLine to true if the function body spans multiple lines.
1419 func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLine *bool) {
1420         if b == nil {
1421                 return
1422         }
1423
1424         if p.isOneLineFunc(b, headerSize) {
1425                 sep := vtab
1426                 if isLit {
1427                         sep = blank
1428                 }
1429                 p.print(sep, b.Lbrace, token.LBRACE)
1430                 if len(b.List) > 0 {
1431                         p.print(blank)
1432                         for i, s := range b.List {
1433                                 if i > 0 {
1434                                         p.print(token.SEMICOLON, blank)
1435                                 }
1436                                 p.stmt(s, i == len(b.List)-1, ignoreMultiLine)
1437                         }
1438                         p.print(blank)
1439                 }
1440                 p.print(b.Rbrace, token.RBRACE)
1441                 return
1442         }
1443
1444         p.print(blank)
1445         p.block(b, 1)
1446         *multiLine = true
1447 }
1448
1449 // distance returns the column difference between from and to if both
1450 // are on the same line; if they are on different lines (or unknown)
1451 // the result is infinity.
1452 func (p *printer) distance(from0 token.Pos, to token.Position) int {
1453         from := p.fset.Position(from0)
1454         if from.IsValid() && to.IsValid() && from.Line == to.Line {
1455                 return to.Column - from.Column
1456         }
1457         return infinity
1458 }
1459
1460 // Sets multiLine to true if the declaration spans multiple lines.
1461 func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) {
1462         p.setComment(d.Doc)
1463         p.print(d.Pos(), token.FUNC, blank)
1464         if d.Recv != nil {
1465                 p.parameters(d.Recv, multiLine) // method: print receiver
1466                 p.print(blank)
1467         }
1468         p.expr(d.Name, multiLine)
1469         p.signature(d.Type.Params, d.Type.Results, multiLine)
1470         p.funcBody(d.Body, p.distance(d.Pos(), p.pos), false, multiLine)
1471 }
1472
1473 // Sets multiLine to true if the declaration spans multiple lines.
1474 func (p *printer) decl(decl ast.Decl, multiLine *bool) {
1475         switch d := decl.(type) {
1476         case *ast.BadDecl:
1477                 p.print(d.Pos(), "BadDecl")
1478         case *ast.GenDecl:
1479                 p.genDecl(d, multiLine)
1480         case *ast.FuncDecl:
1481                 p.funcDecl(d, multiLine)
1482         default:
1483                 panic("unreachable")
1484         }
1485 }
1486
1487 // ----------------------------------------------------------------------------
1488 // Files
1489
1490 func declToken(decl ast.Decl) (tok token.Token) {
1491         tok = token.ILLEGAL
1492         switch d := decl.(type) {
1493         case *ast.GenDecl:
1494                 tok = d.Tok
1495         case *ast.FuncDecl:
1496                 tok = token.FUNC
1497         }
1498         return
1499 }
1500
1501 func (p *printer) file(src *ast.File) {
1502         p.setComment(src.Doc)
1503         p.print(src.Pos(), token.PACKAGE, blank)
1504         p.expr(src.Name, ignoreMultiLine)
1505
1506         if len(src.Decls) > 0 {
1507                 tok := token.ILLEGAL
1508                 for _, d := range src.Decls {
1509                         prev := tok
1510                         tok = declToken(d)
1511                         // if the declaration token changed (e.g., from CONST to TYPE)
1512                         // print an empty line between top-level declarations
1513                         min := 1
1514                         if prev != tok {
1515                                 min = 2
1516                         }
1517                         p.linebreak(p.fset.Position(d.Pos()).Line, min, ignore, false)
1518                         p.decl(d, ignoreMultiLine)
1519                 }
1520         }
1521
1522         p.print(newline)
1523 }