1
2
3
4
5
6
7
8
9 package printer
10
11 import (
12 "bytes"
13 "go/ast"
14 "go/token"
15 )
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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
58
59
60
61 func (p *printer) setComment(g *ast.CommentGroup) {
62 if g == nil || !p.useNodeComments {
63 return
64 }
65 if p.comments == nil {
66
67 p.comments = make([]*ast.CommentGroup, 1)
68 } else if p.cindex < len(p.comments) {
69
70
71
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
82 blankEnd
83 commaSep
84 commaTerm
85 noIndent
86 periodSep
87 )
88
89
90
91
92 func (p *printer) identList(list []*ast.Ident, indent bool, multiLine *bool) {
93
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
106
107
108
109
110
111
112
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
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
145
146
147
148
149 ws := ignore
150 if mode&noIndent == 0 {
151 ws = indent
152 }
153
154
155
156 prevBreak := -1
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
164 size := 0
165
166
167 for i, x := range list {
168 prevLine := line
169 line = p.fset.Position(x.Pos()).Line
170
171
172
173
174
175
176 useFF := true
177
178
179
180
181
182 prevSize := size
183 const infinity = 1e6
184 size = p.nodeSize(x, infinity)
185 pair, isPair := x.(*ast.KeyValueExpr)
186 if size <= infinity && prev.IsValid() && next.IsValid() {
187
188 if isPair {
189 size = p.nodeSize(pair.Key, infinity)
190 }
191 } else {
192
193 size = 0
194 }
195
196
197
198
199
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
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
219 if prevLine < line && prevLine > 0 && line > 0 {
220
221
222
223 if p.linebreak(line, 0, ws, useFF || prevBreak+1 < i) {
224 ws = ignore
225 *multiLine = true
226 prevBreak = i
227 needsBlank = false
228 }
229 }
230 if needsBlank {
231 p.print(blank)
232 }
233 }
234
235 if isPair && size > 0 && len(list) > 1 {
236
237
238
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
249 p.print(token.COMMA)
250 if ws == ignore && mode&noIndent == 0 {
251
252 p.print(unindent)
253 }
254 p.print(formfeed)
255 return
256 }
257
258 if mode&blankEnd != 0 {
259 p.print(blank)
260 }
261
262 if ws == ignore && mode&noIndent == 0 {
263
264 p.print(unindent)
265 }
266 }
267
268
269 func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) {
270 p.print(fields.Opening, token.LPAREN)
271 if len(fields.List) > 0 {
272 var prevLine, line int
273 for i, par := range fields.List {
274 if i > 0 {
275 p.print(token.COMMA)
276 if len(par.Names) > 0 {
277 line = p.fset.Position(par.Names[0].Pos()).Line
278 } else {
279 line = p.fset.Position(par.Type.Pos()).Line
280 }
281 if 0 < prevLine && prevLine < line && p.linebreak(line, 0, ignore, true) {
282 *multiLine = true
283 } else {
284 p.print(blank)
285 }
286 }
287 if len(par.Names) > 0 {
288 p.identList(par.Names, false, multiLine)
289 p.print(blank)
290 }
291 p.expr(par.Type, multiLine)
292 prevLine = p.fset.Position(par.Type.Pos()).Line
293 }
294 }
295 p.print(fields.Closing, token.RPAREN)
296 }
297
298
299 func (p *printer) signature(params, result *ast.FieldList, multiLine *bool) {
300 p.parameters(params, multiLine)
301 n := result.NumFields()
302 if n > 0 {
303 p.print(blank)
304 if n == 1 && result.List[0].Names == nil {
305
306 p.expr(result.List[0].Type, multiLine)
307 return
308 }
309 p.parameters(result, multiLine)
310 }
311 }
312
313 func identListSize(list []*ast.Ident, maxSize int) (size int) {
314 for i, x := range list {
315 if i > 0 {
316 size += 2
317 }
318 size += len(x.Name)
319 if size >= maxSize {
320 break
321 }
322 }
323 return
324 }
325
326 func (p *printer) isOneLineFieldList(list []*ast.Field) bool {
327 if len(list) != 1 {
328 return false
329 }
330 f := list[0]
331 if f.Tag != nil || f.Comment != nil {
332 return false
333 }
334
335 const maxSize = 30
336 namesSize := identListSize(f.Names, maxSize)
337 if namesSize > 0 {
338 namesSize = 1
339 }
340 typeSize := p.nodeSize(f.Type, maxSize)
341 return namesSize+typeSize <= maxSize
342 }
343
344 func (p *printer) setLineComment(text string) {
345 p.setComment(&ast.CommentGroup{[]*ast.Comment{&ast.Comment{token.NoPos, text}}})
346 }
347
348 func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) {
349 lbrace := fields.Opening
350 list := fields.List
351 rbrace := fields.Closing
352 srcIsOneLine := lbrace.IsValid() && rbrace.IsValid() && p.fset.Position(lbrace).Line == p.fset.Position(rbrace).Line
353
354 if !isIncomplete && !p.commentBefore(p.fset.Position(rbrace)) && srcIsOneLine {
355
356 if len(list) == 0 {
357
358 p.print(lbrace, token.LBRACE, rbrace, token.RBRACE)
359 return
360 } else if isStruct && p.isOneLineFieldList(list) {
361
362
363 p.print(lbrace, token.LBRACE, blank)
364 f := list[0]
365 for i, x := range f.Names {
366 if i > 0 {
367 p.print(token.COMMA, blank)
368 }
369 p.expr(x, ignoreMultiLine)
370 }
371 if len(f.Names) > 0 {
372 p.print(blank)
373 }
374 p.expr(f.Type, ignoreMultiLine)
375 p.print(blank, rbrace, token.RBRACE)
376 return
377 }
378 }
379
380
381 p.print(blank, lbrace, token.LBRACE, indent, formfeed)
382 if isStruct {
383
384 sep := vtab
385 if len(list) == 1 {
386 sep = blank
387 }
388 var ml bool
389 for i, f := range list {
390 if i > 0 {
391 p.linebreak(p.fset.Position(f.Pos()).Line, 1, ignore, ml)
392 }
393 ml = false
394 extraTabs := 0
395 p.setComment(f.Doc)
396 if len(f.Names) > 0 {
397
398 p.identList(f.Names, false, &ml)
399 p.print(sep)
400 p.expr(f.Type, &ml)
401 extraTabs = 1
402 } else {
403
404 p.expr(f.Type, &ml)
405 extraTabs = 2
406 }
407 if f.Tag != nil {
408 if len(f.Names) > 0 && sep == vtab {
409 p.print(sep)
410 }
411 p.print(sep)
412 p.expr(f.Tag, &ml)
413 extraTabs = 0
414 }
415 if f.Comment != nil {
416 for ; extraTabs > 0; extraTabs-- {
417 p.print(sep)
418 }
419 p.setComment(f.Comment)
420 }
421 }
422 if isIncomplete {
423 if len(list) > 0 {
424 p.print(formfeed)
425 }
426 p.flush(p.fset.Position(rbrace), token.RBRACE)
427 p.setLineComment("// contains filtered or unexported fields")
428 }
429
430 } else {
431
432 var ml bool
433 for i, f := range list {
434 if i > 0 {
435 p.linebreak(p.fset.Position(f.Pos()).Line, 1, ignore, ml)
436 }
437 ml = false
438 p.setComment(f.Doc)
439 if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
440
441 p.expr(f.Names[0], &ml)
442 p.signature(ftyp.Params, ftyp.Results, &ml)
443 } else {
444
445 p.expr(f.Type, &ml)
446 }
447 p.setComment(f.Comment)
448 }
449 if isIncomplete {
450 if len(list) > 0 {
451 p.print(formfeed)
452 }
453 p.flush(p.fset.Position(rbrace), token.RBRACE)
454 p.setLineComment("// contains filtered or unexported methods")
455 }
456
457 }
458 p.print(unindent, formfeed, rbrace, token.RBRACE)
459 }
460
461
462
463
464 func walkBinary(e *ast.BinaryExpr) (has4, has5 bool, maxProblem int) {
465 switch e.Op.Precedence() {
466 case 4:
467 has4 = true
468 case 5:
469 has5 = true
470 }
471
472 switch l := e.X.(type) {
473 case *ast.BinaryExpr:
474 if l.Op.Precedence() < e.Op.Precedence() {
475
476
477 break
478 }
479 h4, h5, mp := walkBinary(l)
480 has4 = has4 || h4
481 has5 = has5 || h5
482 if maxProblem < mp {
483 maxProblem = mp
484 }
485 }
486
487 switch r := e.Y.(type) {
488 case *ast.BinaryExpr:
489 if r.Op.Precedence() <= e.Op.Precedence() {
490
491
492 break
493 }
494 h4, h5, mp := walkBinary(r)
495 has4 = has4 || h4
496 has5 = has5 || h5
497 if maxProblem < mp {
498 maxProblem = mp
499 }
500
501 case *ast.StarExpr:
502 if e.Op == token.QUO {
503 maxProblem = 5
504 }
505
506 case *ast.UnaryExpr:
507 switch e.Op.String() + r.Op.String() {
508 case "/*", "&&", "&^":
509 maxProblem = 5
510 case "++", "--":
511 if maxProblem < 4 {
512 maxProblem = 4
513 }
514 }
515 }
516 return
517 }
518
519 func cutoff(e *ast.BinaryExpr, depth int) int {
520 has4, has5, maxProblem := walkBinary(e)
521 if maxProblem > 0 {
522 return maxProblem + 1
523 }
524 if has4 && has5 {
525 if depth == 1 {
526 return 5
527 }
528 return 4
529 }
530 if depth == 1 {
531 return 6
532 }
533 return 4
534 }
535
536 func diffPrec(expr ast.Expr, prec int) int {
537 x, ok := expr.(*ast.BinaryExpr)
538 if !ok || prec != x.Op.Precedence() {
539 return 1
540 }
541 return 0
542 }
543
544 func reduceDepth(depth int) int {
545 depth--
546 if depth < 1 {
547 depth = 1
548 }
549 return depth
550 }
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589 func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiLine *bool) {
590 prec := x.Op.Precedence()
591 if prec < prec1 {
592
593
594
595 p.print(token.LPAREN)
596 p.expr0(x, reduceDepth(depth), multiLine)
597 p.print(token.RPAREN)
598 return
599 }
600
601 printBlank := prec < cutoff
602
603 ws := indent
604 p.expr1(x.X, prec, depth+diffPrec(x.X, prec), multiLine)
605 if printBlank {
606 p.print(blank)
607 }
608 xline := p.pos.Line
609 yline := p.fset.Position(x.Y.Pos()).Line
610 p.print(x.OpPos, x.Op)
611 if xline != yline && xline > 0 && yline > 0 {
612
613
614 if p.linebreak(yline, 1, ws, true) {
615 ws = ignore
616 *multiLine = true
617 printBlank = false
618 }
619 }
620 if printBlank {
621 p.print(blank)
622 }
623 p.expr1(x.Y, prec+1, depth+1, multiLine)
624 if ws == ignore {
625 p.print(unindent)
626 }
627 }
628
629 func isBinary(expr ast.Expr) bool {
630 _, ok := expr.(*ast.BinaryExpr)
631 return ok
632 }
633
634
635
636
637
638
639 func splitSelector(expr ast.Expr) (body, suffix ast.Expr) {
640 switch x := expr.(type) {
641 case *ast.SelectorExpr:
642 body, suffix = x.X, x.Sel
643 return
644 case *ast.CallExpr:
645 body, suffix = splitSelector(x.Fun)
646 if body != nil {
647 suffix = &ast.CallExpr{suffix, x.Lparen, x.Args, x.Ellipsis, x.Rparen}
648 return
649 }
650 case *ast.IndexExpr:
651 body, suffix = splitSelector(x.X)
652 if body != nil {
653 suffix = &ast.IndexExpr{suffix, x.Lbrack, x.Index, x.Rbrack}
654 return
655 }
656 case *ast.SliceExpr:
657 body, suffix = splitSelector(x.X)
658 if body != nil {
659 suffix = &ast.SliceExpr{suffix, x.Lbrack, x.Low, x.High, x.Rbrack}
660 return
661 }
662 case *ast.TypeAssertExpr:
663 body, suffix = splitSelector(x.X)
664 if body != nil {
665 suffix = &ast.TypeAssertExpr{suffix, x.Type}
666 return
667 }
668 }
669 suffix = expr
670 return
671 }
672
673
674
675 func selectorExprList(expr ast.Expr) (list []ast.Expr) {
676
677 for expr != nil {
678 var suffix ast.Expr
679 expr, suffix = splitSelector(expr)
680 list = append(list, suffix)
681 }
682
683
684 for i, j := 0, len(list)-1; i < j; i, j = i+1, j-1 {
685 list[i], list[j] = list[j], list[i]
686 }
687
688 return
689 }
690
691
692 func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
693 p.print(expr.Pos())
694
695 switch x := expr.(type) {
696 case *ast.BadExpr:
697 p.print("BadExpr")
698
699 case *ast.Ident:
700 p.print(x)
701
702 case *ast.BinaryExpr:
703 if depth < 1 {
704 p.internalError("depth < 1:", depth)
705 depth = 1
706 }
707 p.binaryExpr(x, prec1, cutoff(x, depth), depth, multiLine)
708
709 case *ast.KeyValueExpr:
710 p.expr(x.Key, multiLine)
711 p.print(x.Colon, token.COLON, blank)
712 p.expr(x.Value, multiLine)
713
714 case *ast.StarExpr:
715 const prec = token.UnaryPrec
716 if prec < prec1 {
717
718 p.print(token.LPAREN)
719 p.print(token.MUL)
720 p.expr(x.X, multiLine)
721 p.print(token.RPAREN)
722 } else {
723
724 p.print(token.MUL)
725 p.expr(x.X, multiLine)
726 }
727
728 case *ast.UnaryExpr:
729 const prec = token.UnaryPrec
730 if prec < prec1 {
731
732 p.print(token.LPAREN)
733 p.expr(x, multiLine)
734 p.print(token.RPAREN)
735 } else {
736
737 p.print(x.Op)
738 if x.Op == token.RANGE {
739
740 p.print(blank)
741 }
742 p.expr1(x.X, prec, depth, multiLine)
743 }
744
745 case *ast.BasicLit:
746 p.print(x)
747
748 case *ast.FuncLit:
749 p.expr(x.Type, multiLine)
750 p.funcBody(x.Body, p.distance(x.Type.Pos(), p.pos), true, multiLine)
751
752 case *ast.ParenExpr:
753 if _, hasParens := x.X.(*ast.ParenExpr); hasParens {
754
755
756 p.expr0(x.X, reduceDepth(depth), multiLine)
757 } else {
758 p.print(token.LPAREN)
759 p.expr0(x.X, reduceDepth(depth), multiLine)
760 p.print(x.Rparen, token.RPAREN)
761 }
762
763 case *ast.SelectorExpr:
764 parts := selectorExprList(expr)
765 p.exprList(token.NoPos, parts, depth, periodSep, multiLine, token.NoPos)
766
767 case *ast.TypeAssertExpr:
768 p.expr1(x.X, token.HighestPrec, depth, multiLine)
769 p.print(token.PERIOD, token.LPAREN)
770 if x.Type != nil {
771 p.expr(x.Type, multiLine)
772 } else {
773 p.print(token.TYPE)
774 }
775 p.print(token.RPAREN)
776
777 case *ast.IndexExpr:
778
779 p.expr1(x.X, token.HighestPrec, 1, multiLine)
780 p.print(x.Lbrack, token.LBRACK)
781 p.expr0(x.Index, depth+1, multiLine)
782 p.print(x.Rbrack, token.RBRACK)
783
784 case *ast.SliceExpr:
785
786 p.expr1(x.X, token.HighestPrec, 1, multiLine)
787 p.print(x.Lbrack, token.LBRACK)
788 if x.Low != nil {
789 p.expr0(x.Low, depth+1, multiLine)
790 }
791
792 if depth <= 1 && x.Low != nil && x.High != nil && (isBinary(x.Low) || isBinary(x.High)) {
793 p.print(blank, token.COLON, blank)
794 } else {
795 p.print(token.COLON)
796 }
797 if x.High != nil {
798 p.expr0(x.High, depth+1, multiLine)
799 }
800 p.print(x.Rbrack, token.RBRACK)
801
802 case *ast.CallExpr:
803 if len(x.Args) > 1 {
804 depth++
805 }
806 p.expr1(x.Fun, token.HighestPrec, depth, multiLine)
807 p.print(x.Lparen, token.LPAREN)
808 p.exprList(x.Lparen, x.Args, depth, commaSep|commaTerm, multiLine, x.Rparen)
809 if x.Ellipsis.IsValid() {
810 p.print(x.Ellipsis, token.ELLIPSIS)
811 }
812 p.print(x.Rparen, token.RPAREN)
813
814 case *ast.CompositeLit:
815
816 if x.Type != nil {
817 p.expr1(x.Type, token.HighestPrec, depth, multiLine)
818 }
819 p.print(x.Lbrace, token.LBRACE)
820 p.exprList(x.Lbrace, x.Elts, 1, commaSep|commaTerm, multiLine, x.Rbrace)
821
822
823
824 p.print(noExtraLinebreak, x.Rbrace, token.RBRACE, noExtraLinebreak)
825
826 case *ast.Ellipsis:
827 p.print(token.ELLIPSIS)
828 if x.Elt != nil {
829 p.expr(x.Elt, multiLine)
830 }
831
832 case *ast.ArrayType:
833 p.print(token.LBRACK)
834 if x.Len != nil {
835 p.expr(x.Len, multiLine)
836 }
837 p.print(token.RBRACK)
838 p.expr(x.Elt, multiLine)
839
840 case *ast.StructType:
841 p.print(token.STRUCT)
842 p.fieldList(x.Fields, true, x.Incomplete)
843
844 case *ast.FuncType:
845 p.print(token.FUNC)
846 p.signature(x.Params, x.Results, multiLine)
847
848 case *ast.InterfaceType:
849 p.print(token.INTERFACE)
850 p.fieldList(x.Methods, false, x.Incomplete)
851
852 case *ast.MapType:
853 p.print(token.MAP, token.LBRACK)
854 p.expr(x.Key, multiLine)
855 p.print(token.RBRACK)
856 p.expr(x.Value, multiLine)
857
858 case *ast.ChanType:
859 switch x.Dir {
860 case ast.SEND | ast.RECV:
861 p.print(token.CHAN)
862 case ast.RECV:
863 p.print(token.ARROW, token.CHAN)
864 case ast.SEND:
865 p.print(token.CHAN, token.ARROW)
866 }
867 p.print(blank)
868 p.expr(x.Value, multiLine)
869
870 default:
871 panic("unreachable")
872 }
873
874 return
875 }
876
877 func (p *printer) expr0(x ast.Expr, depth int, multiLine *bool) {
878 p.expr1(x, token.LowestPrec, depth, multiLine)
879 }
880
881
882 func (p *printer) expr(x ast.Expr, multiLine *bool) {
883 const depth = 1
884 p.expr1(x, token.LowestPrec, depth, multiLine)
885 }
886
887
888
889
890
891
892
893 func (p *printer) stmtList(list []ast.Stmt, _indent int, nextIsRBrace bool) {
894
895 if _indent > 0 {
896 p.print(indent)
897 }
898 var multiLine bool
899 for i, s := range list {
900
901
902 p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, i == 0 || _indent == 0 || multiLine)
903 multiLine = false
904 p.stmt(s, nextIsRBrace && i == len(list)-1, &multiLine)
905 }
906 if _indent > 0 {
907 p.print(unindent)
908 }
909 }
910
911
912 func (p *printer) block(s *ast.BlockStmt, indent int) {
913 p.print(s.Pos(), token.LBRACE)
914 p.stmtList(s.List, indent, true)
915 p.linebreak(p.fset.Position(s.Rbrace).Line, 1, ignore, true)
916 p.print(s.Rbrace, token.RBRACE)
917 }
918
919 func isTypeName(x ast.Expr) bool {
920 switch t := x.(type) {
921 case *ast.Ident:
922 return true
923 case *ast.SelectorExpr:
924 return isTypeName(t.X)
925 }
926 return false
927 }
928
929 func stripParens(x ast.Expr) ast.Expr {
930 if px, strip := x.(*ast.ParenExpr); strip {
931
932
933
934 ast.Inspect(px.X, func(node ast.Node) bool {
935 switch x := node.(type) {
936 case *ast.ParenExpr:
937
938 return false
939 case *ast.CompositeLit:
940 if isTypeName(x.Type) {
941 strip = false
942 }
943 return false
944 }
945
946 return true
947 })
948 if strip {
949 return stripParens(px.X)
950 }
951 }
952 return x
953 }
954
955 func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, post ast.Stmt) {
956 p.print(blank)
957 needsBlank := false
958 if init == nil && post == nil {
959
960 if expr != nil {
961 p.expr(stripParens(expr), ignoreMultiLine)
962 needsBlank = true
963 }
964 } else {
965
966
967 if init != nil {
968 p.stmt(init, false, ignoreMultiLine)
969 }
970 p.print(token.SEMICOLON, blank)
971 if expr != nil {
972 p.expr(stripParens(expr), ignoreMultiLine)
973 needsBlank = true
974 }
975 if isForStmt {
976 p.print(token.SEMICOLON, blank)
977 needsBlank = false
978 if post != nil {
979 p.stmt(post, false, ignoreMultiLine)
980 needsBlank = true
981 }
982 }
983 }
984 if needsBlank {
985 p.print(blank)
986 }
987 }
988
989
990 func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
991 p.print(stmt.Pos())
992
993 switch s := stmt.(type) {
994 case *ast.BadStmt:
995 p.print("BadStmt")
996
997 case *ast.DeclStmt:
998 p.decl(s.Decl, multiLine)
999
1000 case *ast.EmptyStmt:
1001
1002
1003 case *ast.LabeledStmt:
1004
1005
1006
1007 p.print(unindent)
1008 p.expr(s.Label, multiLine)
1009 p.print(s.Colon, token.COLON, indent)
1010 if e, isEmpty := s.Stmt.(*ast.EmptyStmt); isEmpty {
1011 if !nextIsRBrace {
1012 p.print(newline, e.Pos(), token.SEMICOLON)
1013 break
1014 }
1015 } else {
1016 p.linebreak(p.fset.Position(s.Stmt.Pos()).Line, 1, ignore, true)
1017 }
1018 p.stmt(s.Stmt, nextIsRBrace, multiLine)
1019
1020 case *ast.ExprStmt:
1021 const depth = 1
1022 p.expr0(s.X, depth, multiLine)
1023
1024 case *ast.SendStmt:
1025 const depth = 1
1026 p.expr0(s.Chan, depth, multiLine)
1027 p.print(blank, s.Arrow, token.ARROW, blank)
1028 p.expr0(s.Value, depth, multiLine)
1029
1030 case *ast.IncDecStmt:
1031 const depth = 1
1032 p.expr0(s.X, depth+1, multiLine)
1033 p.print(s.TokPos, s.Tok)
1034
1035 case *ast.AssignStmt:
1036 var depth = 1
1037 if len(s.Lhs) > 1 && len(s.Rhs) > 1 {
1038 depth++
1039 }
1040 p.exprList(s.Pos(), s.Lhs, depth, commaSep, multiLine, s.TokPos)
1041 p.print(blank, s.TokPos, s.Tok)
1042 p.exprList(s.TokPos, s.Rhs, depth, blankStart|commaSep, multiLine, token.NoPos)
1043
1044 case *ast.GoStmt:
1045 p.print(token.GO, blank)
1046 p.expr(s.Call, multiLine)
1047
1048 case *ast.DeferStmt:
1049 p.print(token.DEFER, blank)
1050 p.expr(s.Call, multiLine)
1051
1052 case *ast.ReturnStmt:
1053 p.print(token.RETURN)
1054 if s.Results != nil {
1055 p.exprList(s.Pos(), s.Results, 1, blankStart|commaSep, multiLine, token.NoPos)
1056 }
1057
1058 case *ast.BranchStmt:
1059 p.print(s.Tok)
1060 if s.Label != nil {
1061 p.print(blank)
1062 p.expr(s.Label, multiLine)
1063 }
1064
1065 case *ast.BlockStmt:
1066 p.block(s, 1)
1067 *multiLine = true
1068
1069 case *ast.IfStmt:
1070 p.print(token.IF)
1071 p.controlClause(false, s.Init, s.Cond, nil)
1072 p.block(s.Body, 1)
1073 *multiLine = true
1074 if s.Else != nil {
1075 p.print(blank, token.ELSE, blank)
1076 switch s.Else.(type) {
1077 case *ast.BlockStmt, *ast.IfStmt:
1078 p.stmt(s.Else, nextIsRBrace, ignoreMultiLine)
1079 default:
1080 p.print(token.LBRACE, indent, formfeed)
1081 p.stmt(s.Else, true, ignoreMultiLine)
1082 p.print(unindent, formfeed, token.RBRACE)
1083 }
1084 }
1085
1086 case *ast.CaseClause:
1087 if s.List != nil {
1088 p.print(token.CASE)
1089 p.exprList(s.Pos(), s.List, 1, blankStart|commaSep, multiLine, s.Colon)
1090 } else {
1091 p.print(token.DEFAULT)
1092 }
1093 p.print(s.Colon, token.COLON)
1094 p.stmtList(s.Body, 1, nextIsRBrace)
1095
1096 case *ast.SwitchStmt:
1097 p.print(token.SWITCH)
1098 p.controlClause(false, s.Init, s.Tag, nil)
1099 p.block(s.Body, 0)
1100 *multiLine = true
1101
1102 case *ast.TypeSwitchStmt:
1103 p.print(token.SWITCH)
1104 if s.Init != nil {
1105 p.print(blank)
1106 p.stmt(s.Init, false, ignoreMultiLine)
1107 p.print(token.SEMICOLON)
1108 }
1109 p.print(blank)
1110 p.stmt(s.Assign, false, ignoreMultiLine)
1111 p.print(blank)
1112 p.block(s.Body, 0)
1113 *multiLine = true
1114
1115 case *ast.CommClause:
1116 if s.Comm != nil {
1117 p.print(token.CASE, blank)
1118 p.stmt(s.Comm, false, ignoreMultiLine)
1119 } else {
1120 p.print(token.DEFAULT)
1121 }
1122 p.print(s.Colon, token.COLON)
1123 p.stmtList(s.Body, 1, nextIsRBrace)
1124
1125 case *ast.SelectStmt:
1126 p.print(token.SELECT, blank)
1127 body := s.Body
1128 if len(body.List) == 0 && !p.commentBefore(p.fset.Position(body.Rbrace)) {
1129
1130 p.print(body.Lbrace, token.LBRACE, body.Rbrace, token.RBRACE)
1131 } else {
1132 p.block(body, 0)
1133 *multiLine = true
1134 }
1135
1136 case *ast.ForStmt:
1137 p.print(token.FOR)
1138 p.controlClause(true, s.Init, s.Cond, s.Post)
1139 p.block(s.Body, 1)
1140 *multiLine = true
1141
1142 case *ast.RangeStmt:
1143 p.print(token.FOR, blank)
1144 p.expr(s.Key, multiLine)
1145 if s.Value != nil {
1146 p.print(token.COMMA, blank)
1147 p.expr(s.Value, multiLine)
1148 }
1149 p.print(blank, s.TokPos, s.Tok, blank, token.RANGE, blank)
1150 p.expr(stripParens(s.X), multiLine)
1151 p.print(blank)
1152 p.block(s.Body, 1)
1153 *multiLine = true
1154
1155 default:
1156 panic("unreachable")
1157 }
1158
1159 return
1160 }
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190 func keepTypeColumn(specs []ast.Spec) []bool {
1191 m := make([]bool, len(specs))
1192
1193 populate := func(i, j int, keepType bool) {
1194 if keepType {
1195 for ; i < j; i++ {
1196 m[i] = true
1197 }
1198 }
1199 }
1200
1201 i0 := -1
1202 var keepType bool
1203 for i, s := range specs {
1204 t := s.(*ast.ValueSpec)
1205 if t.Values != nil {
1206 if i0 < 0 {
1207
1208 i0 = i
1209 keepType = false
1210 }
1211 } else {
1212 if i0 >= 0 {
1213
1214 populate(i0, i, keepType)
1215 i0 = -1
1216 }
1217 }
1218 if t.Type != nil {
1219 keepType = true
1220 }
1221 }
1222 if i0 >= 0 {
1223
1224 populate(i0, len(specs), keepType)
1225 }
1226
1227 return m
1228 }
1229
1230 func (p *printer) valueSpec(s *ast.ValueSpec, keepType, doIndent bool, multiLine *bool) {
1231 p.setComment(s.Doc)
1232 p.identList(s.Names, doIndent, multiLine)
1233 extraTabs := 3
1234 if s.Type != nil || keepType {
1235 p.print(vtab)
1236 extraTabs--
1237 }
1238 if s.Type != nil {
1239 p.expr(s.Type, multiLine)
1240 }
1241 if s.Values != nil {
1242 p.print(vtab, token.ASSIGN)
1243 p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiLine, token.NoPos)
1244 extraTabs--
1245 }
1246 if s.Comment != nil {
1247 for ; extraTabs > 0; extraTabs-- {
1248 p.print(vtab)
1249 }
1250 p.setComment(s.Comment)
1251 }
1252 }
1253
1254
1255
1256
1257
1258
1259 func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) {
1260 switch s := spec.(type) {
1261 case *ast.ImportSpec:
1262 p.setComment(s.Doc)
1263 if s.Name != nil {
1264 p.expr(s.Name, multiLine)
1265 p.print(blank)
1266 }
1267 p.expr(s.Path, multiLine)
1268 p.setComment(s.Comment)
1269
1270 case *ast.ValueSpec:
1271 if n != 1 {
1272 p.internalError("expected n = 1; got", n)
1273 }
1274 p.setComment(s.Doc)
1275 p.identList(s.Names, doIndent, multiLine)
1276 if s.Type != nil {
1277 p.print(blank)
1278 p.expr(s.Type, multiLine)
1279 }
1280 if s.Values != nil {
1281 p.print(blank, token.ASSIGN)
1282 p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiLine, token.NoPos)
1283 }
1284 p.setComment(s.Comment)
1285
1286 case *ast.TypeSpec:
1287 p.setComment(s.Doc)
1288 p.expr(s.Name, multiLine)
1289 if n == 1 {
1290 p.print(blank)
1291 } else {
1292 p.print(vtab)
1293 }
1294 p.expr(s.Type, multiLine)
1295 p.setComment(s.Comment)
1296
1297 default:
1298 panic("unreachable")
1299 }
1300 }
1301
1302
1303 func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) {
1304 p.setComment(d.Doc)
1305 p.print(d.Pos(), d.Tok, blank)
1306
1307 if d.Lparen.IsValid() {
1308
1309 p.print(d.Lparen, token.LPAREN)
1310 if n := len(d.Specs); n > 0 {
1311 p.print(indent, formfeed)
1312 if n > 1 && (d.Tok == token.CONST || d.Tok == token.VAR) {
1313
1314
1315 keepType := keepTypeColumn(d.Specs)
1316 var ml bool
1317 for i, s := range d.Specs {
1318 if i > 0 {
1319 p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, ml)
1320 }
1321 ml = false
1322 p.valueSpec(s.(*ast.ValueSpec), keepType[i], false, &ml)
1323 }
1324 } else {
1325 var ml bool
1326 for i, s := range d.Specs {
1327 if i > 0 {
1328 p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, ml)
1329 }
1330 ml = false
1331 p.spec(s, n, false, &ml)
1332 }
1333 }
1334 p.print(unindent, formfeed)
1335 *multiLine = true
1336 }
1337 p.print(d.Rparen, token.RPAREN)
1338
1339 } else {
1340
1341 p.spec(d.Specs[0], 1, true, multiLine)
1342 }
1343 }
1344
1345
1346
1347
1348
1349
1350 func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) {
1351
1352
1353
1354
1355 if size, found := p.nodeSizes[n]; found {
1356 return size
1357 }
1358
1359 size = maxSize + 1
1360 p.nodeSizes[n] = size
1361
1362
1363
1364
1365 cfg := Config{Mode: RawFormat}
1366 var buf bytes.Buffer
1367 if _, err := cfg.fprint(&buf, p.fset, n, p.nodeSizes); err != nil {
1368 return
1369 }
1370 if buf.Len() <= maxSize {
1371 for _, ch := range buf.Bytes() {
1372 if ch < ' ' {
1373 return
1374 }
1375 }
1376 size = buf.Len()
1377 p.nodeSizes[n] = size
1378 }
1379 return
1380 }
1381
1382 func (p *printer) isOneLineFunc(b *ast.BlockStmt, headerSize int) bool {
1383 pos1 := b.Pos()
1384 pos2 := b.Rbrace
1385 if pos1.IsValid() && pos2.IsValid() && p.fset.Position(pos1).Line != p.fset.Position(pos2).Line {
1386
1387 return false
1388 }
1389 if len(b.List) > 5 || p.commentBefore(p.fset.Position(pos2)) {
1390
1391 return false
1392 }
1393
1394 const maxSize = 100
1395 bodySize := 0
1396 for i, s := range b.List {
1397 if i > 0 {
1398 bodySize += 2
1399 }
1400 bodySize += p.nodeSize(s, maxSize)
1401 }
1402 return headerSize+bodySize <= maxSize
1403 }
1404
1405
1406 func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLine *bool) {
1407 if b == nil {
1408 return
1409 }
1410
1411 if p.isOneLineFunc(b, headerSize) {
1412 sep := vtab
1413 if isLit {
1414 sep = blank
1415 }
1416 p.print(sep, b.Lbrace, token.LBRACE)
1417 if len(b.List) > 0 {
1418 p.print(blank)
1419 for i, s := range b.List {
1420 if i > 0 {
1421 p.print(token.SEMICOLON, blank)
1422 }
1423 p.stmt(s, i == len(b.List)-1, ignoreMultiLine)
1424 }
1425 p.print(blank)
1426 }
1427 p.print(b.Rbrace, token.RBRACE)
1428 return
1429 }
1430
1431 p.print(blank)
1432 p.block(b, 1)
1433 *multiLine = true
1434 }
1435
1436
1437
1438
1439 func (p *printer) distance(from0 token.Pos, to token.Position) int {
1440 from := p.fset.Position(from0)
1441 if from.IsValid() && to.IsValid() && from.Line == to.Line {
1442 return to.Column - from.Column
1443 }
1444 return infinity
1445 }
1446
1447
1448 func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) {
1449 p.setComment(d.Doc)
1450 p.print(d.Pos(), token.FUNC, blank)
1451 if d.Recv != nil {
1452 p.parameters(d.Recv, multiLine)
1453 p.print(blank)
1454 }
1455 p.expr(d.Name, multiLine)
1456 p.signature(d.Type.Params, d.Type.Results, multiLine)
1457 p.funcBody(d.Body, p.distance(d.Pos(), p.pos), false, multiLine)
1458 }
1459
1460
1461 func (p *printer) decl(decl ast.Decl, multiLine *bool) {
1462 switch d := decl.(type) {
1463 case *ast.BadDecl:
1464 p.print(d.Pos(), "BadDecl")
1465 case *ast.GenDecl:
1466 p.genDecl(d, multiLine)
1467 case *ast.FuncDecl:
1468 p.funcDecl(d, multiLine)
1469 default:
1470 panic("unreachable")
1471 }
1472 }
1473
1474
1475
1476
1477 func declToken(decl ast.Decl) (tok token.Token) {
1478 tok = token.ILLEGAL
1479 switch d := decl.(type) {
1480 case *ast.GenDecl:
1481 tok = d.Tok
1482 case *ast.FuncDecl:
1483 tok = token.FUNC
1484 }
1485 return
1486 }
1487
1488 func (p *printer) file(src *ast.File) {
1489 p.setComment(src.Doc)
1490 p.print(src.Pos(), token.PACKAGE, blank)
1491 p.expr(src.Name, ignoreMultiLine)
1492
1493 if len(src.Decls) > 0 {
1494 tok := token.ILLEGAL
1495 for _, d := range src.Decls {
1496 prev := tok
1497 tok = declToken(d)
1498
1499
1500 min := 1
1501 if prev != tok {
1502 min = 2
1503 }
1504 p.linebreak(p.fset.Position(d.Pos()).Line, min, ignore, false)
1505 p.decl(d, ignoreMultiLine)
1506 }
1507 }
1508
1509 p.print(newline)
1510 }