1
2
3
4
5
6
7
8
9 package printer
10
11 import (
12 "bytes"
13 "go/ast"
14 "go/token"
15 "math"
16 "strconv"
17 "strings"
18 "unicode"
19 "unicode/utf8"
20 )
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 func (p *printer) linebreak(line, min int, ws whiteSpace, newSection bool) (nbreaks int) {
49 n := nlimit(line - p.pos.Line)
50 if n < min {
51 n = min
52 }
53 if n > 0 {
54 p.print(ws)
55 if newSection {
56 p.print(formfeed)
57 n--
58 nbreaks = 2
59 }
60 nbreaks += n
61 for ; n > 0; n-- {
62 p.print(newline)
63 }
64 }
65 return
66 }
67
68
69
70
71
72 func (p *printer) setComment(g *ast.CommentGroup) {
73 if g == nil || !p.useNodeComments {
74 return
75 }
76 if p.comments == nil {
77
78 p.comments = make([]*ast.CommentGroup, 1)
79 } else if p.cindex < len(p.comments) {
80
81
82
83 p.flush(p.posFor(g.List[0].Pos()), token.ILLEGAL)
84 p.comments = p.comments[0:1]
85
86 p.internalError("setComment found pending comments")
87 }
88 p.comments[0] = g
89 p.cindex = 0
90
91
92
93
94 if p.commentOffset == infinity {
95 p.nextComment()
96 }
97 }
98
99 type exprListMode uint
100
101 const (
102 commaTerm exprListMode = 1 << iota
103 noIndent
104 )
105
106
107
108 func (p *printer) identList(list []*ast.Ident, indent bool) {
109
110 xlist := make([]ast.Expr, len(list))
111 for i, x := range list {
112 xlist[i] = x
113 }
114 var mode exprListMode
115 if !indent {
116 mode = noIndent
117 }
118 p.exprList(token.NoPos, xlist, 1, mode, token.NoPos, false)
119 }
120
121 const filteredMsg = "contains filtered or unexported fields"
122
123
124
125
126
127
128
129
130 func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exprListMode, next0 token.Pos, isIncomplete bool) {
131 if len(list) == 0 {
132 if isIncomplete {
133 prev := p.posFor(prev0)
134 next := p.posFor(next0)
135 if prev.IsValid() && prev.Line == next.Line {
136 p.print("/* " + filteredMsg + " */")
137 } else {
138 p.print(newline)
139 p.print(indent, "// "+filteredMsg, unindent, newline)
140 }
141 }
142 return
143 }
144
145 prev := p.posFor(prev0)
146 next := p.posFor(next0)
147 line := p.lineFor(list[0].Pos())
148 endLine := p.lineFor(list[len(list)-1].End())
149
150 if prev.IsValid() && prev.Line == line && line == endLine {
151
152 for i, x := range list {
153 if i > 0 {
154
155
156 p.print(x.Pos(), token.COMMA, blank)
157 }
158 p.expr0(x, depth)
159 }
160 if isIncomplete {
161 p.print(token.COMMA, blank, "/* "+filteredMsg+" */")
162 }
163 return
164 }
165
166
167
168
169
170
171 ws := ignore
172 if mode&noIndent == 0 {
173 ws = indent
174 }
175
176
177
178 prevBreak := -1
179 if prev.IsValid() && prev.Line < line && p.linebreak(line, 0, ws, true) > 0 {
180 ws = ignore
181 prevBreak = 0
182 }
183
184
185 size := 0
186
187
188
189
190
191 lnsum := 0.0
192 count := 0
193
194
195 prevLine := prev.Line
196 for i, x := range list {
197 line = p.lineFor(x.Pos())
198
199
200
201
202
203
204 useFF := true
205
206
207
208
209
210 prevSize := size
211 const infinity = 1e6
212 size = p.nodeSize(x, infinity)
213 pair, isPair := x.(*ast.KeyValueExpr)
214 if size <= infinity && prev.IsValid() && next.IsValid() {
215
216 if isPair {
217 size = p.nodeSize(pair.Key, infinity)
218 }
219 } else {
220
221 size = 0
222 }
223
224
225
226
227
228
229 if prevSize > 0 && size > 0 {
230 const smallSize = 40
231 if count == 0 || prevSize <= smallSize && size <= smallSize {
232 useFF = false
233 } else {
234 const r = 2.5
235 geomean := math.Exp(lnsum / float64(count))
236 ratio := float64(size) / geomean
237 useFF = r*ratio <= 1 || r <= ratio
238 }
239 }
240
241 needsLinebreak := 0 < prevLine && prevLine < line
242 if i > 0 {
243
244
245
246 if !needsLinebreak {
247 p.print(x.Pos())
248 }
249 p.print(token.COMMA)
250 needsBlank := true
251 if needsLinebreak {
252
253
254
255 nbreaks := p.linebreak(line, 0, ws, useFF || prevBreak+1 < i)
256 if nbreaks > 0 {
257 ws = ignore
258 prevBreak = i
259 needsBlank = false
260 }
261
262
263
264
265 if nbreaks > 1 {
266 lnsum = 0
267 count = 0
268 }
269 }
270 if needsBlank {
271 p.print(blank)
272 }
273 }
274
275 if len(list) > 1 && isPair && size > 0 && needsLinebreak {
276
277
278
279
280
281 p.expr(pair.Key)
282 p.print(pair.Colon, token.COLON, vtab)
283 p.expr(pair.Value)
284 } else {
285 p.expr0(x, depth)
286 }
287
288 if size > 0 {
289 lnsum += math.Log(float64(size))
290 count++
291 }
292
293 prevLine = line
294 }
295
296 if mode&commaTerm != 0 && next.IsValid() && p.pos.Line < next.Line {
297
298 p.print(token.COMMA)
299 if isIncomplete {
300 p.print(newline)
301 p.print("// " + filteredMsg)
302 }
303 if ws == ignore && mode&noIndent == 0 {
304
305 p.print(unindent)
306 }
307 p.print(formfeed)
308 return
309 }
310
311 if isIncomplete {
312 p.print(token.COMMA, newline)
313 p.print("// "+filteredMsg, newline)
314 }
315
316 if ws == ignore && mode&noIndent == 0 {
317
318 p.print(unindent)
319 }
320 }
321
322 type paramMode int
323
324 const (
325 funcParam paramMode = iota
326 funcTParam
327 typeTParam
328 )
329
330 func (p *printer) parameters(fields *ast.FieldList, mode paramMode) {
331 openTok, closeTok := token.LPAREN, token.RPAREN
332 if mode != funcParam {
333 openTok, closeTok = token.LBRACK, token.RBRACK
334 }
335 p.print(fields.Opening, openTok)
336 if len(fields.List) > 0 {
337 prevLine := p.lineFor(fields.Opening)
338 ws := indent
339 for i, par := range fields.List {
340
341
342
343 parLineBeg := p.lineFor(par.Pos())
344 parLineEnd := p.lineFor(par.End())
345
346 needsLinebreak := 0 < prevLine && prevLine < parLineBeg
347 if i > 0 {
348
349
350
351 if !needsLinebreak {
352 p.print(par.Pos())
353 }
354 p.print(token.COMMA)
355 }
356
357 if needsLinebreak && p.linebreak(parLineBeg, 0, ws, true) > 0 {
358
359 ws = ignore
360 } else if i > 0 {
361 p.print(blank)
362 }
363
364 if len(par.Names) > 0 {
365
366
367
368
369
370
371 p.identList(par.Names, ws == indent)
372 p.print(blank)
373 }
374
375 p.expr(stripParensAlways(par.Type))
376 prevLine = parLineEnd
377 }
378
379
380
381 if closing := p.lineFor(fields.Closing); 0 < prevLine && prevLine < closing {
382 p.print(token.COMMA)
383 p.linebreak(closing, 0, ignore, true)
384 } else if mode == typeTParam && fields.NumFields() == 1 {
385
386
387
388
389
390
391 if t, _ := fields.List[0].Type.(*ast.StarExpr); t != nil && !isTypeLit(t.X) {
392 p.print(token.COMMA)
393 }
394 }
395
396
397 if ws == ignore {
398 p.print(unindent)
399 }
400 }
401
402 p.print(fields.Closing, closeTok)
403 }
404
405
406 func isTypeLit(x ast.Expr) bool {
407 switch x := x.(type) {
408 case *ast.ArrayType, *ast.StructType, *ast.FuncType, *ast.InterfaceType, *ast.MapType, *ast.ChanType:
409 return true
410 case *ast.StarExpr:
411
412
413 return isTypeLit(x.X)
414 case *ast.ParenExpr:
415 return isTypeLit(x.X)
416 }
417 return false
418 }
419
420 func (p *printer) signature(sig *ast.FuncType) {
421 if sig.TypeParams != nil {
422 p.parameters(sig.TypeParams, funcTParam)
423 }
424 if sig.Params != nil {
425 p.parameters(sig.Params, funcParam)
426 } else {
427 p.print(token.LPAREN, token.RPAREN)
428 }
429 res := sig.Results
430 n := res.NumFields()
431 if n > 0 {
432
433 p.print(blank)
434 if n == 1 && res.List[0].Names == nil {
435
436 p.expr(stripParensAlways(res.List[0].Type))
437 return
438 }
439 p.parameters(res, funcParam)
440 }
441 }
442
443 func identListSize(list []*ast.Ident, maxSize int) (size int) {
444 for i, x := range list {
445 if i > 0 {
446 size += len(", ")
447 }
448 size += utf8.RuneCountInString(x.Name)
449 if size >= maxSize {
450 break
451 }
452 }
453 return
454 }
455
456 func (p *printer) isOneLineFieldList(list []*ast.Field) bool {
457 if len(list) != 1 {
458 return false
459 }
460 f := list[0]
461 if f.Tag != nil || f.Comment != nil {
462 return false
463 }
464
465 const maxSize = 30
466 namesSize := identListSize(f.Names, maxSize)
467 if namesSize > 0 {
468 namesSize = 1
469 }
470 typeSize := p.nodeSize(f.Type, maxSize)
471 return namesSize+typeSize <= maxSize
472 }
473
474 func (p *printer) setLineComment(text string) {
475 p.setComment(&ast.CommentGroup{List: []*ast.Comment{{Slash: token.NoPos, Text: text}}})
476 }
477
478 func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) {
479 lbrace := fields.Opening
480 list := fields.List
481 rbrace := fields.Closing
482 hasComments := isIncomplete || p.commentBefore(p.posFor(rbrace))
483 srcIsOneLine := lbrace.IsValid() && rbrace.IsValid() && p.lineFor(lbrace) == p.lineFor(rbrace)
484
485 if !hasComments && srcIsOneLine {
486
487 if len(list) == 0 {
488
489 p.print(lbrace, token.LBRACE, rbrace, token.RBRACE)
490 return
491 } else if p.isOneLineFieldList(list) {
492
493
494 p.print(lbrace, token.LBRACE, blank)
495 f := list[0]
496 if isStruct {
497 for i, x := range f.Names {
498 if i > 0 {
499
500 p.print(token.COMMA, blank)
501 }
502 p.expr(x)
503 }
504 if len(f.Names) > 0 {
505 p.print(blank)
506 }
507 p.expr(f.Type)
508 } else {
509 if len(f.Names) > 0 {
510 name := f.Names[0]
511 p.expr(name)
512 p.signature(f.Type.(*ast.FuncType))
513 } else {
514
515 p.expr(f.Type)
516 }
517 }
518 p.print(blank, rbrace, token.RBRACE)
519 return
520 }
521 }
522
523
524 p.print(blank, lbrace, token.LBRACE, indent)
525 if hasComments || len(list) > 0 {
526 p.print(formfeed)
527 }
528
529 if isStruct {
530
531 sep := vtab
532 if len(list) == 1 {
533 sep = blank
534 }
535 var line int
536 for i, f := range list {
537 if i > 0 {
538 p.linebreak(p.lineFor(f.Pos()), 1, ignore, p.linesFrom(line) > 0)
539 }
540 extraTabs := 0
541 p.setComment(f.Doc)
542 p.recordLine(&line)
543 if len(f.Names) > 0 {
544
545 p.identList(f.Names, false)
546 p.print(sep)
547 p.expr(f.Type)
548 extraTabs = 1
549 } else {
550
551 p.expr(f.Type)
552 extraTabs = 2
553 }
554 if f.Tag != nil {
555 if len(f.Names) > 0 && sep == vtab {
556 p.print(sep)
557 }
558 p.print(sep)
559 p.expr(f.Tag)
560 extraTabs = 0
561 }
562 if f.Comment != nil {
563 for ; extraTabs > 0; extraTabs-- {
564 p.print(sep)
565 }
566 p.setComment(f.Comment)
567 }
568 }
569 if isIncomplete {
570 if len(list) > 0 {
571 p.print(formfeed)
572 }
573 p.flush(p.posFor(rbrace), token.RBRACE)
574 p.setLineComment("// " + filteredMsg)
575 }
576
577 } else {
578
579 var line int
580 var prev *ast.Ident
581 for i, f := range list {
582 var name *ast.Ident
583 if len(f.Names) > 0 {
584 name = f.Names[0]
585 }
586 if i > 0 {
587
588
589
590 min := 1
591 if prev != nil && name == prev {
592 min = 0
593 }
594 p.linebreak(p.lineFor(f.Pos()), min, ignore, p.linesFrom(line) > 0)
595 }
596 p.setComment(f.Doc)
597 p.recordLine(&line)
598 if name != nil {
599
600 p.expr(name)
601 p.signature(f.Type.(*ast.FuncType))
602 prev = nil
603 } else {
604
605 p.expr(f.Type)
606 prev = nil
607 }
608 p.setComment(f.Comment)
609 }
610 if isIncomplete {
611 if len(list) > 0 {
612 p.print(formfeed)
613 }
614 p.flush(p.posFor(rbrace), token.RBRACE)
615 p.setLineComment("// contains filtered or unexported methods")
616 }
617
618 }
619 p.print(unindent, formfeed, rbrace, token.RBRACE)
620 }
621
622
623
624
625 func walkBinary(e *ast.BinaryExpr) (has4, has5 bool, maxProblem int) {
626 switch e.Op.Precedence() {
627 case 4:
628 has4 = true
629 case 5:
630 has5 = true
631 }
632
633 switch l := e.X.(type) {
634 case *ast.BinaryExpr:
635 if l.Op.Precedence() < e.Op.Precedence() {
636
637
638 break
639 }
640 h4, h5, mp := walkBinary(l)
641 has4 = has4 || h4
642 has5 = has5 || h5
643 if maxProblem < mp {
644 maxProblem = mp
645 }
646 }
647
648 switch r := e.Y.(type) {
649 case *ast.BinaryExpr:
650 if r.Op.Precedence() <= e.Op.Precedence() {
651
652
653 break
654 }
655 h4, h5, mp := walkBinary(r)
656 has4 = has4 || h4
657 has5 = has5 || h5
658 if maxProblem < mp {
659 maxProblem = mp
660 }
661
662 case *ast.StarExpr:
663 if e.Op == token.QUO {
664 maxProblem = 5
665 }
666
667 case *ast.UnaryExpr:
668 switch e.Op.String() + r.Op.String() {
669 case "/*", "&&", "&^":
670 maxProblem = 5
671 case "++", "--":
672 if maxProblem < 4 {
673 maxProblem = 4
674 }
675 }
676 }
677 return
678 }
679
680 func cutoff(e *ast.BinaryExpr, depth int) int {
681 has4, has5, maxProblem := walkBinary(e)
682 if maxProblem > 0 {
683 return maxProblem + 1
684 }
685 if has4 && has5 {
686 if depth == 1 {
687 return 5
688 }
689 return 4
690 }
691 if depth == 1 {
692 return 6
693 }
694 return 4
695 }
696
697 func diffPrec(expr ast.Expr, prec int) int {
698 x, ok := expr.(*ast.BinaryExpr)
699 if !ok || prec != x.Op.Precedence() {
700 return 1
701 }
702 return 0
703 }
704
705 func reduceDepth(depth int) int {
706 depth--
707 if depth < 1 {
708 depth = 1
709 }
710 return depth
711 }
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749 func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int) {
750 prec := x.Op.Precedence()
751 if prec < prec1 {
752
753
754
755 p.print(token.LPAREN)
756 p.expr0(x, reduceDepth(depth))
757 p.print(token.RPAREN)
758 return
759 }
760
761 printBlank := prec < cutoff
762
763 ws := indent
764 p.expr1(x.X, prec, depth+diffPrec(x.X, prec))
765 if printBlank {
766 p.print(blank)
767 }
768 xline := p.pos.Line
769 yline := p.lineFor(x.Y.Pos())
770 p.print(x.OpPos, x.Op)
771 if xline != yline && xline > 0 && yline > 0 {
772
773
774 if p.linebreak(yline, 1, ws, true) > 0 {
775 ws = ignore
776 printBlank = false
777 }
778 }
779 if printBlank {
780 p.print(blank)
781 }
782 p.expr1(x.Y, prec+1, depth+1)
783 if ws == ignore {
784 p.print(unindent)
785 }
786 }
787
788 func isBinary(expr ast.Expr) bool {
789 _, ok := expr.(*ast.BinaryExpr)
790 return ok
791 }
792
793 func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
794 p.print(expr.Pos())
795
796 switch x := expr.(type) {
797 case *ast.BadExpr:
798 p.print("BadExpr")
799
800 case *ast.Ident:
801 p.print(x)
802
803 case *ast.BinaryExpr:
804 if depth < 1 {
805 p.internalError("depth < 1:", depth)
806 depth = 1
807 }
808 p.binaryExpr(x, prec1, cutoff(x, depth), depth)
809
810 case *ast.KeyValueExpr:
811 p.expr(x.Key)
812 p.print(x.Colon, token.COLON, blank)
813 p.expr(x.Value)
814
815 case *ast.StarExpr:
816 const prec = token.UnaryPrec
817 if prec < prec1 {
818
819 p.print(token.LPAREN)
820 p.print(token.MUL)
821 p.expr(x.X)
822 p.print(token.RPAREN)
823 } else {
824
825 p.print(token.MUL)
826 p.expr(x.X)
827 }
828
829 case *ast.UnaryExpr:
830 const prec = token.UnaryPrec
831 if prec < prec1 {
832
833 p.print(token.LPAREN)
834 p.expr(x)
835 p.print(token.RPAREN)
836 } else {
837
838 p.print(x.Op)
839 if x.Op == token.RANGE {
840
841 p.print(blank)
842 }
843 p.expr1(x.X, prec, depth)
844 }
845
846 case *ast.BasicLit:
847 if p.Config.Mode&normalizeNumbers != 0 {
848 x = normalizedNumber(x)
849 }
850 p.print(x)
851
852 case *ast.FuncLit:
853 p.print(x.Type.Pos(), token.FUNC)
854
855 startCol := p.out.Column - len("func")
856 p.signature(x.Type)
857 p.funcBody(p.distanceFrom(x.Type.Pos(), startCol), blank, x.Body)
858
859 case *ast.ParenExpr:
860 if _, hasParens := x.X.(*ast.ParenExpr); hasParens {
861
862
863 p.expr0(x.X, depth)
864 } else {
865 p.print(token.LPAREN)
866 p.expr0(x.X, reduceDepth(depth))
867 p.print(x.Rparen, token.RPAREN)
868 }
869
870 case *ast.SelectorExpr:
871 p.selectorExpr(x, depth, false)
872
873 case *ast.TypeAssertExpr:
874 p.expr1(x.X, token.HighestPrec, depth)
875 p.print(token.PERIOD, x.Lparen, token.LPAREN)
876 if x.Type != nil {
877 p.expr(x.Type)
878 } else {
879 p.print(token.TYPE)
880 }
881 p.print(x.Rparen, token.RPAREN)
882
883 case *ast.IndexExpr:
884
885 p.expr1(x.X, token.HighestPrec, 1)
886 p.print(x.Lbrack, token.LBRACK)
887 p.expr0(x.Index, depth+1)
888 p.print(x.Rbrack, token.RBRACK)
889
890 case *ast.IndexListExpr:
891
892
893 p.expr1(x.X, token.HighestPrec, 1)
894 p.print(x.Lbrack, token.LBRACK)
895 p.exprList(x.Lbrack, x.Indices, depth+1, commaTerm, x.Rbrack, false)
896 p.print(x.Rbrack, token.RBRACK)
897
898 case *ast.SliceExpr:
899
900 p.expr1(x.X, token.HighestPrec, 1)
901 p.print(x.Lbrack, token.LBRACK)
902 indices := []ast.Expr{x.Low, x.High}
903 if x.Max != nil {
904 indices = append(indices, x.Max)
905 }
906
907 var needsBlanks bool
908 if depth <= 1 {
909 var indexCount int
910 var hasBinaries bool
911 for _, x := range indices {
912 if x != nil {
913 indexCount++
914 if isBinary(x) {
915 hasBinaries = true
916 }
917 }
918 }
919 if indexCount > 1 && hasBinaries {
920 needsBlanks = true
921 }
922 }
923 for i, x := range indices {
924 if i > 0 {
925 if indices[i-1] != nil && needsBlanks {
926 p.print(blank)
927 }
928 p.print(token.COLON)
929 if x != nil && needsBlanks {
930 p.print(blank)
931 }
932 }
933 if x != nil {
934 p.expr0(x, depth+1)
935 }
936 }
937 p.print(x.Rbrack, token.RBRACK)
938
939 case *ast.CallExpr:
940 if len(x.Args) > 1 {
941 depth++
942 }
943 var wasIndented bool
944 if _, ok := x.Fun.(*ast.FuncType); ok {
945
946 p.print(token.LPAREN)
947 wasIndented = p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
948 p.print(token.RPAREN)
949 } else {
950 wasIndented = p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
951 }
952 p.print(x.Lparen, token.LPAREN)
953 if x.Ellipsis.IsValid() {
954 p.exprList(x.Lparen, x.Args, depth, 0, x.Ellipsis, false)
955 p.print(x.Ellipsis, token.ELLIPSIS)
956 if x.Rparen.IsValid() && p.lineFor(x.Ellipsis) < p.lineFor(x.Rparen) {
957 p.print(token.COMMA, formfeed)
958 }
959 } else {
960 p.exprList(x.Lparen, x.Args, depth, commaTerm, x.Rparen, false)
961 }
962 p.print(x.Rparen, token.RPAREN)
963 if wasIndented {
964 p.print(unindent)
965 }
966
967 case *ast.CompositeLit:
968
969 if x.Type != nil {
970 p.expr1(x.Type, token.HighestPrec, depth)
971 }
972 p.level++
973 p.print(x.Lbrace, token.LBRACE)
974 p.exprList(x.Lbrace, x.Elts, 1, commaTerm, x.Rbrace, x.Incomplete)
975
976
977
978 mode := noExtraLinebreak
979
980
981 if len(x.Elts) > 0 {
982 mode |= noExtraBlank
983 }
984
985
986 p.print(indent, unindent, mode, x.Rbrace, token.RBRACE, mode)
987 p.level--
988
989 case *ast.Ellipsis:
990 p.print(token.ELLIPSIS)
991 if x.Elt != nil {
992 p.expr(x.Elt)
993 }
994
995 case *ast.ArrayType:
996 p.print(token.LBRACK)
997 if x.Len != nil {
998 p.expr(x.Len)
999 }
1000 p.print(token.RBRACK)
1001 p.expr(x.Elt)
1002
1003 case *ast.StructType:
1004 p.print(token.STRUCT)
1005 p.fieldList(x.Fields, true, x.Incomplete)
1006
1007 case *ast.FuncType:
1008 p.print(token.FUNC)
1009 p.signature(x)
1010
1011 case *ast.InterfaceType:
1012 p.print(token.INTERFACE)
1013 p.fieldList(x.Methods, false, x.Incomplete)
1014
1015 case *ast.MapType:
1016 p.print(token.MAP, token.LBRACK)
1017 p.expr(x.Key)
1018 p.print(token.RBRACK)
1019 p.expr(x.Value)
1020
1021 case *ast.ChanType:
1022 switch x.Dir {
1023 case ast.SEND | ast.RECV:
1024 p.print(token.CHAN)
1025 case ast.RECV:
1026 p.print(token.ARROW, token.CHAN)
1027 case ast.SEND:
1028 p.print(token.CHAN, x.Arrow, token.ARROW)
1029 }
1030 p.print(blank)
1031 p.expr(x.Value)
1032
1033 default:
1034 panic("unreachable")
1035 }
1036 }
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046 func normalizedNumber(lit *ast.BasicLit) *ast.BasicLit {
1047 if lit.Kind != token.INT && lit.Kind != token.FLOAT && lit.Kind != token.IMAG {
1048 return lit
1049 }
1050 if len(lit.Value) < 2 {
1051 return lit
1052 }
1053
1054
1055
1056
1057 x := lit.Value
1058 switch x[:2] {
1059 default:
1060
1061 if i := strings.LastIndexByte(x, 'E'); i >= 0 {
1062 x = x[:i] + "e" + x[i+1:]
1063 break
1064 }
1065
1066 if x[len(x)-1] == 'i' && !strings.ContainsAny(x, ".e") {
1067 x = strings.TrimLeft(x, "0_")
1068 if x == "i" {
1069 x = "0i"
1070 }
1071 }
1072 case "0X":
1073 x = "0x" + x[2:]
1074
1075 if i := strings.LastIndexByte(x, 'P'); i >= 0 {
1076 x = x[:i] + "p" + x[i+1:]
1077 }
1078 case "0x":
1079
1080 i := strings.LastIndexByte(x, 'P')
1081 if i == -1 {
1082 return lit
1083 }
1084 x = x[:i] + "p" + x[i+1:]
1085 case "0O":
1086 x = "0o" + x[2:]
1087 case "0o":
1088 return lit
1089 case "0B":
1090 x = "0b" + x[2:]
1091 case "0b":
1092 return lit
1093 }
1094
1095 return &ast.BasicLit{ValuePos: lit.ValuePos, Kind: lit.Kind, Value: x}
1096 }
1097
1098 func (p *printer) possibleSelectorExpr(expr ast.Expr, prec1, depth int) bool {
1099 if x, ok := expr.(*ast.SelectorExpr); ok {
1100 return p.selectorExpr(x, depth, true)
1101 }
1102 p.expr1(expr, prec1, depth)
1103 return false
1104 }
1105
1106
1107
1108 func (p *printer) selectorExpr(x *ast.SelectorExpr, depth int, isMethod bool) bool {
1109 p.expr1(x.X, token.HighestPrec, depth)
1110 p.print(token.PERIOD)
1111 if line := p.lineFor(x.Sel.Pos()); p.pos.IsValid() && p.pos.Line < line {
1112 p.print(indent, newline, x.Sel.Pos(), x.Sel)
1113 if !isMethod {
1114 p.print(unindent)
1115 }
1116 return true
1117 }
1118 p.print(x.Sel.Pos(), x.Sel)
1119 return false
1120 }
1121
1122 func (p *printer) expr0(x ast.Expr, depth int) {
1123 p.expr1(x, token.LowestPrec, depth)
1124 }
1125
1126 func (p *printer) expr(x ast.Expr) {
1127 const depth = 1
1128 p.expr1(x, token.LowestPrec, depth)
1129 }
1130
1131
1132
1133
1134
1135
1136
1137 func (p *printer) stmtList(list []ast.Stmt, nindent int, nextIsRBrace bool) {
1138 if nindent > 0 {
1139 p.print(indent)
1140 }
1141 var line int
1142 i := 0
1143 for _, s := range list {
1144
1145 if _, isEmpty := s.(*ast.EmptyStmt); !isEmpty {
1146
1147
1148 if len(p.output) > 0 {
1149
1150
1151 p.linebreak(p.lineFor(s.Pos()), 1, ignore, i == 0 || nindent == 0 || p.linesFrom(line) > 0)
1152 }
1153 p.recordLine(&line)
1154 p.stmt(s, nextIsRBrace && i == len(list)-1)
1155
1156
1157
1158 for t := s; ; {
1159 lt, _ := t.(*ast.LabeledStmt)
1160 if lt == nil {
1161 break
1162 }
1163 line++
1164 t = lt.Stmt
1165 }
1166 i++
1167 }
1168 }
1169 if nindent > 0 {
1170 p.print(unindent)
1171 }
1172 }
1173
1174
1175 func (p *printer) block(b *ast.BlockStmt, nindent int) {
1176 p.print(b.Lbrace, token.LBRACE)
1177 p.stmtList(b.List, nindent, true)
1178 p.linebreak(p.lineFor(b.Rbrace), 1, ignore, true)
1179 p.print(b.Rbrace, token.RBRACE)
1180 }
1181
1182 func isTypeName(x ast.Expr) bool {
1183 switch t := x.(type) {
1184 case *ast.Ident:
1185 return true
1186 case *ast.SelectorExpr:
1187 return isTypeName(t.X)
1188 }
1189 return false
1190 }
1191
1192 func stripParens(x ast.Expr) ast.Expr {
1193 if px, strip := x.(*ast.ParenExpr); strip {
1194
1195
1196
1197 ast.Inspect(px.X, func(node ast.Node) bool {
1198 switch x := node.(type) {
1199 case *ast.ParenExpr:
1200
1201 return false
1202 case *ast.CompositeLit:
1203 if isTypeName(x.Type) {
1204 strip = false
1205 }
1206 return false
1207 }
1208
1209 return true
1210 })
1211 if strip {
1212 return stripParens(px.X)
1213 }
1214 }
1215 return x
1216 }
1217
1218 func stripParensAlways(x ast.Expr) ast.Expr {
1219 if x, ok := x.(*ast.ParenExpr); ok {
1220 return stripParensAlways(x.X)
1221 }
1222 return x
1223 }
1224
1225 func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, post ast.Stmt) {
1226 p.print(blank)
1227 needsBlank := false
1228 if init == nil && post == nil {
1229
1230 if expr != nil {
1231 p.expr(stripParens(expr))
1232 needsBlank = true
1233 }
1234 } else {
1235
1236
1237 if init != nil {
1238 p.stmt(init, false)
1239 }
1240 p.print(token.SEMICOLON, blank)
1241 if expr != nil {
1242 p.expr(stripParens(expr))
1243 needsBlank = true
1244 }
1245 if isForStmt {
1246 p.print(token.SEMICOLON, blank)
1247 needsBlank = false
1248 if post != nil {
1249 p.stmt(post, false)
1250 needsBlank = true
1251 }
1252 }
1253 }
1254 if needsBlank {
1255 p.print(blank)
1256 }
1257 }
1258
1259
1260
1261
1262
1263 func (p *printer) indentList(list []ast.Expr) bool {
1264
1265
1266
1267 if len(list) >= 2 {
1268 var b = p.lineFor(list[0].Pos())
1269 var e = p.lineFor(list[len(list)-1].End())
1270 if 0 < b && b < e {
1271
1272 n := 0
1273 line := b
1274 for _, x := range list {
1275 xb := p.lineFor(x.Pos())
1276 xe := p.lineFor(x.End())
1277 if line < xb {
1278
1279
1280 return true
1281 }
1282 if xb < xe {
1283
1284 n++
1285 }
1286 line = xe
1287 }
1288 return n > 1
1289 }
1290 }
1291 return false
1292 }
1293
1294 func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool) {
1295 p.print(stmt.Pos())
1296
1297 switch s := stmt.(type) {
1298 case *ast.BadStmt:
1299 p.print("BadStmt")
1300
1301 case *ast.DeclStmt:
1302 p.decl(s.Decl)
1303
1304 case *ast.EmptyStmt:
1305
1306
1307 case *ast.LabeledStmt:
1308
1309
1310
1311 p.print(unindent)
1312 p.expr(s.Label)
1313 p.print(s.Colon, token.COLON, indent)
1314 if e, isEmpty := s.Stmt.(*ast.EmptyStmt); isEmpty {
1315 if !nextIsRBrace {
1316 p.print(newline, e.Pos(), token.SEMICOLON)
1317 break
1318 }
1319 } else {
1320 p.linebreak(p.lineFor(s.Stmt.Pos()), 1, ignore, true)
1321 }
1322 p.stmt(s.Stmt, nextIsRBrace)
1323
1324 case *ast.ExprStmt:
1325 const depth = 1
1326 p.expr0(s.X, depth)
1327
1328 case *ast.SendStmt:
1329 const depth = 1
1330 p.expr0(s.Chan, depth)
1331 p.print(blank, s.Arrow, token.ARROW, blank)
1332 p.expr0(s.Value, depth)
1333
1334 case *ast.IncDecStmt:
1335 const depth = 1
1336 p.expr0(s.X, depth+1)
1337 p.print(s.TokPos, s.Tok)
1338
1339 case *ast.AssignStmt:
1340 var depth = 1
1341 if len(s.Lhs) > 1 && len(s.Rhs) > 1 {
1342 depth++
1343 }
1344 p.exprList(s.Pos(), s.Lhs, depth, 0, s.TokPos, false)
1345 p.print(blank, s.TokPos, s.Tok, blank)
1346 p.exprList(s.TokPos, s.Rhs, depth, 0, token.NoPos, false)
1347
1348 case *ast.GoStmt:
1349 p.print(token.GO, blank)
1350 p.expr(s.Call)
1351
1352 case *ast.DeferStmt:
1353 p.print(token.DEFER, blank)
1354 p.expr(s.Call)
1355
1356 case *ast.ReturnStmt:
1357 p.print(token.RETURN)
1358 if s.Results != nil {
1359 p.print(blank)
1360
1361
1362
1363
1364
1365 if p.indentList(s.Results) {
1366 p.print(indent)
1367
1368
1369 p.exprList(token.NoPos, s.Results, 1, noIndent, token.NoPos, false)
1370 p.print(unindent)
1371 } else {
1372 p.exprList(token.NoPos, s.Results, 1, 0, token.NoPos, false)
1373 }
1374 }
1375
1376 case *ast.BranchStmt:
1377 p.print(s.Tok)
1378 if s.Label != nil {
1379 p.print(blank)
1380 p.expr(s.Label)
1381 }
1382
1383 case *ast.BlockStmt:
1384 p.block(s, 1)
1385
1386 case *ast.IfStmt:
1387 p.print(token.IF)
1388 p.controlClause(false, s.Init, s.Cond, nil)
1389 p.block(s.Body, 1)
1390 if s.Else != nil {
1391 p.print(blank, token.ELSE, blank)
1392 switch s.Else.(type) {
1393 case *ast.BlockStmt, *ast.IfStmt:
1394 p.stmt(s.Else, nextIsRBrace)
1395 default:
1396
1397
1398
1399 p.print(token.LBRACE, indent, formfeed)
1400 p.stmt(s.Else, true)
1401 p.print(unindent, formfeed, token.RBRACE)
1402 }
1403 }
1404
1405 case *ast.CaseClause:
1406 if s.List != nil {
1407 p.print(token.CASE, blank)
1408 p.exprList(s.Pos(), s.List, 1, 0, s.Colon, false)
1409 } else {
1410 p.print(token.DEFAULT)
1411 }
1412 p.print(s.Colon, token.COLON)
1413 p.stmtList(s.Body, 1, nextIsRBrace)
1414
1415 case *ast.SwitchStmt:
1416 p.print(token.SWITCH)
1417 p.controlClause(false, s.Init, s.Tag, nil)
1418 p.block(s.Body, 0)
1419
1420 case *ast.TypeSwitchStmt:
1421 p.print(token.SWITCH)
1422 if s.Init != nil {
1423 p.print(blank)
1424 p.stmt(s.Init, false)
1425 p.print(token.SEMICOLON)
1426 }
1427 p.print(blank)
1428 p.stmt(s.Assign, false)
1429 p.print(blank)
1430 p.block(s.Body, 0)
1431
1432 case *ast.CommClause:
1433 if s.Comm != nil {
1434 p.print(token.CASE, blank)
1435 p.stmt(s.Comm, false)
1436 } else {
1437 p.print(token.DEFAULT)
1438 }
1439 p.print(s.Colon, token.COLON)
1440 p.stmtList(s.Body, 1, nextIsRBrace)
1441
1442 case *ast.SelectStmt:
1443 p.print(token.SELECT, blank)
1444 body := s.Body
1445 if len(body.List) == 0 && !p.commentBefore(p.posFor(body.Rbrace)) {
1446
1447 p.print(body.Lbrace, token.LBRACE, body.Rbrace, token.RBRACE)
1448 } else {
1449 p.block(body, 0)
1450 }
1451
1452 case *ast.ForStmt:
1453 p.print(token.FOR)
1454 p.controlClause(true, s.Init, s.Cond, s.Post)
1455 p.block(s.Body, 1)
1456
1457 case *ast.RangeStmt:
1458 p.print(token.FOR, blank)
1459 if s.Key != nil {
1460 p.expr(s.Key)
1461 if s.Value != nil {
1462
1463
1464 p.print(s.Value.Pos(), token.COMMA, blank)
1465 p.expr(s.Value)
1466 }
1467 p.print(blank, s.TokPos, s.Tok, blank)
1468 }
1469 p.print(token.RANGE, blank)
1470 p.expr(stripParens(s.X))
1471 p.print(blank)
1472 p.block(s.Body, 1)
1473
1474 default:
1475 panic("unreachable")
1476 }
1477 }
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507 func keepTypeColumn(specs []ast.Spec) []bool {
1508 m := make([]bool, len(specs))
1509
1510 populate := func(i, j int, keepType bool) {
1511 if keepType {
1512 for ; i < j; i++ {
1513 m[i] = true
1514 }
1515 }
1516 }
1517
1518 i0 := -1
1519 var keepType bool
1520 for i, s := range specs {
1521 t := s.(*ast.ValueSpec)
1522 if t.Values != nil {
1523 if i0 < 0 {
1524
1525 i0 = i
1526 keepType = false
1527 }
1528 } else {
1529 if i0 >= 0 {
1530
1531 populate(i0, i, keepType)
1532 i0 = -1
1533 }
1534 }
1535 if t.Type != nil {
1536 keepType = true
1537 }
1538 }
1539 if i0 >= 0 {
1540
1541 populate(i0, len(specs), keepType)
1542 }
1543
1544 return m
1545 }
1546
1547 func (p *printer) valueSpec(s *ast.ValueSpec, keepType bool) {
1548 p.setComment(s.Doc)
1549 p.identList(s.Names, false)
1550 extraTabs := 3
1551 if s.Type != nil || keepType {
1552 p.print(vtab)
1553 extraTabs--
1554 }
1555 if s.Type != nil {
1556 p.expr(s.Type)
1557 }
1558 if s.Values != nil {
1559 p.print(vtab, token.ASSIGN, blank)
1560 p.exprList(token.NoPos, s.Values, 1, 0, token.NoPos, false)
1561 extraTabs--
1562 }
1563 if s.Comment != nil {
1564 for ; extraTabs > 0; extraTabs-- {
1565 p.print(vtab)
1566 }
1567 p.setComment(s.Comment)
1568 }
1569 }
1570
1571 func sanitizeImportPath(lit *ast.BasicLit) *ast.BasicLit {
1572
1573
1574
1575
1576
1577
1578
1579
1580 if lit.Kind != token.STRING {
1581 return lit
1582 }
1583 s, err := strconv.Unquote(lit.Value)
1584 if err != nil {
1585 return lit
1586 }
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596 if s == "" {
1597 return lit
1598 }
1599 const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
1600 for _, r := range s {
1601 if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
1602 return lit
1603 }
1604 }
1605
1606
1607 s = strconv.Quote(s)
1608 if s == lit.Value {
1609 return lit
1610 }
1611 return &ast.BasicLit{ValuePos: lit.ValuePos, Kind: token.STRING, Value: s}
1612 }
1613
1614
1615
1616
1617
1618 func (p *printer) spec(spec ast.Spec, n int, doIndent bool) {
1619 switch s := spec.(type) {
1620 case *ast.ImportSpec:
1621 p.setComment(s.Doc)
1622 if s.Name != nil {
1623 p.expr(s.Name)
1624 p.print(blank)
1625 }
1626 p.expr(sanitizeImportPath(s.Path))
1627 p.setComment(s.Comment)
1628 p.print(s.EndPos)
1629
1630 case *ast.ValueSpec:
1631 if n != 1 {
1632 p.internalError("expected n = 1; got", n)
1633 }
1634 p.setComment(s.Doc)
1635 p.identList(s.Names, doIndent)
1636 if s.Type != nil {
1637 p.print(blank)
1638 p.expr(s.Type)
1639 }
1640 if s.Values != nil {
1641 p.print(blank, token.ASSIGN, blank)
1642 p.exprList(token.NoPos, s.Values, 1, 0, token.NoPos, false)
1643 }
1644 p.setComment(s.Comment)
1645
1646 case *ast.TypeSpec:
1647 p.setComment(s.Doc)
1648 p.expr(s.Name)
1649 if s.TypeParams != nil {
1650 p.parameters(s.TypeParams, typeTParam)
1651 }
1652 if n == 1 {
1653 p.print(blank)
1654 } else {
1655 p.print(vtab)
1656 }
1657 if s.Assign.IsValid() {
1658 p.print(token.ASSIGN, blank)
1659 }
1660 p.expr(s.Type)
1661 p.setComment(s.Comment)
1662
1663 default:
1664 panic("unreachable")
1665 }
1666 }
1667
1668 func (p *printer) genDecl(d *ast.GenDecl) {
1669 p.setComment(d.Doc)
1670 p.print(d.Pos(), d.Tok, blank)
1671
1672 if d.Lparen.IsValid() || len(d.Specs) > 1 {
1673
1674 p.print(d.Lparen, token.LPAREN)
1675 if n := len(d.Specs); n > 0 {
1676 p.print(indent, formfeed)
1677 if n > 1 && (d.Tok == token.CONST || d.Tok == token.VAR) {
1678
1679
1680 keepType := keepTypeColumn(d.Specs)
1681 var line int
1682 for i, s := range d.Specs {
1683 if i > 0 {
1684 p.linebreak(p.lineFor(s.Pos()), 1, ignore, p.linesFrom(line) > 0)
1685 }
1686 p.recordLine(&line)
1687 p.valueSpec(s.(*ast.ValueSpec), keepType[i])
1688 }
1689 } else {
1690 var line int
1691 for i, s := range d.Specs {
1692 if i > 0 {
1693 p.linebreak(p.lineFor(s.Pos()), 1, ignore, p.linesFrom(line) > 0)
1694 }
1695 p.recordLine(&line)
1696 p.spec(s, n, false)
1697 }
1698 }
1699 p.print(unindent, formfeed)
1700 }
1701 p.print(d.Rparen, token.RPAREN)
1702
1703 } else if len(d.Specs) > 0 {
1704
1705 p.spec(d.Specs[0], 1, true)
1706 }
1707 }
1708
1709
1710
1711
1712
1713
1714 func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) {
1715
1716
1717
1718
1719 if size, found := p.nodeSizes[n]; found {
1720 return size
1721 }
1722
1723 size = maxSize + 1
1724 p.nodeSizes[n] = size
1725
1726
1727
1728
1729 cfg := Config{Mode: RawFormat}
1730 var buf bytes.Buffer
1731 if err := cfg.fprint(&buf, p.fset, n, p.nodeSizes); err != nil {
1732 return
1733 }
1734 if buf.Len() <= maxSize {
1735 for _, ch := range buf.Bytes() {
1736 if ch < ' ' {
1737 return
1738 }
1739 }
1740 size = buf.Len()
1741 p.nodeSizes[n] = size
1742 }
1743 return
1744 }
1745
1746
1747 func (p *printer) numLines(n ast.Node) int {
1748 if from := n.Pos(); from.IsValid() {
1749 if to := n.End(); to.IsValid() {
1750 return p.lineFor(to) - p.lineFor(from) + 1
1751 }
1752 }
1753 return infinity
1754 }
1755
1756
1757 func (p *printer) bodySize(b *ast.BlockStmt, maxSize int) int {
1758 pos1 := b.Pos()
1759 pos2 := b.Rbrace
1760 if pos1.IsValid() && pos2.IsValid() && p.lineFor(pos1) != p.lineFor(pos2) {
1761
1762 return maxSize + 1
1763 }
1764 if len(b.List) > 5 {
1765
1766 return maxSize + 1
1767 }
1768
1769 bodySize := p.commentSizeBefore(p.posFor(pos2))
1770 for i, s := range b.List {
1771 if bodySize > maxSize {
1772 break
1773 }
1774 if i > 0 {
1775 bodySize += 2
1776 }
1777 bodySize += p.nodeSize(s, maxSize)
1778 }
1779 return bodySize
1780 }
1781
1782
1783
1784
1785
1786
1787
1788 func (p *printer) funcBody(headerSize int, sep whiteSpace, b *ast.BlockStmt) {
1789 if b == nil {
1790 return
1791 }
1792
1793
1794 defer func(level int) {
1795 p.level = level
1796 }(p.level)
1797 p.level = 0
1798
1799 const maxSize = 100
1800 if headerSize+p.bodySize(b, maxSize) <= maxSize {
1801 p.print(sep, b.Lbrace, token.LBRACE)
1802 if len(b.List) > 0 {
1803 p.print(blank)
1804 for i, s := range b.List {
1805 if i > 0 {
1806 p.print(token.SEMICOLON, blank)
1807 }
1808 p.stmt(s, i == len(b.List)-1)
1809 }
1810 p.print(blank)
1811 }
1812 p.print(noExtraLinebreak, b.Rbrace, token.RBRACE, noExtraLinebreak)
1813 return
1814 }
1815
1816 if sep != ignore {
1817 p.print(blank)
1818 }
1819 p.block(b, 1)
1820 }
1821
1822
1823
1824
1825 func (p *printer) distanceFrom(startPos token.Pos, startOutCol int) int {
1826 if startPos.IsValid() && p.pos.IsValid() && p.posFor(startPos).Line == p.pos.Line {
1827 return p.out.Column - startOutCol
1828 }
1829 return infinity
1830 }
1831
1832 func (p *printer) funcDecl(d *ast.FuncDecl) {
1833 p.setComment(d.Doc)
1834 p.print(d.Pos(), token.FUNC, blank)
1835
1836
1837
1838 startCol := p.out.Column - len("func ")
1839 if d.Recv != nil {
1840 p.parameters(d.Recv, funcParam)
1841 p.print(blank)
1842 }
1843 p.expr(d.Name)
1844 p.signature(d.Type)
1845 p.funcBody(p.distanceFrom(d.Pos(), startCol), vtab, d.Body)
1846 }
1847
1848 func (p *printer) decl(decl ast.Decl) {
1849 switch d := decl.(type) {
1850 case *ast.BadDecl:
1851 p.print(d.Pos(), "BadDecl")
1852 case *ast.GenDecl:
1853 p.genDecl(d)
1854 case *ast.FuncDecl:
1855 p.funcDecl(d)
1856 default:
1857 panic("unreachable")
1858 }
1859 }
1860
1861
1862
1863
1864 func declToken(decl ast.Decl) (tok token.Token) {
1865 tok = token.ILLEGAL
1866 switch d := decl.(type) {
1867 case *ast.GenDecl:
1868 tok = d.Tok
1869 case *ast.FuncDecl:
1870 tok = token.FUNC
1871 }
1872 return
1873 }
1874
1875 func (p *printer) declList(list []ast.Decl) {
1876 tok := token.ILLEGAL
1877 for _, d := range list {
1878 prev := tok
1879 tok = declToken(d)
1880
1881
1882
1883
1884
1885
1886
1887 if len(p.output) > 0 {
1888
1889
1890 min := 1
1891 if prev != tok || getDoc(d) != nil {
1892 min = 2
1893 }
1894
1895
1896 p.linebreak(p.lineFor(d.Pos()), min, ignore, tok == token.FUNC && p.numLines(d) > 1)
1897 }
1898 p.decl(d)
1899 }
1900 }
1901
1902 func (p *printer) file(src *ast.File) {
1903 p.setComment(src.Doc)
1904 p.print(src.Pos(), token.PACKAGE, blank)
1905 p.expr(src.Name)
1906 p.declList(src.Decls)
1907 p.print(newline)
1908 }
1909
View as plain text