Source file src/pkg/go/printer/nodes.go
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 func (p *printer) parameters(fields *ast.FieldList) {
323 p.print(fields.Opening, token.LPAREN)
324 if len(fields.List) > 0 {
325 prevLine := p.lineFor(fields.Opening)
326 ws := indent
327 for i, par := range fields.List {
328
329
330
331 var parLineBeg int
332 if len(par.Names) > 0 {
333 parLineBeg = p.lineFor(par.Names[0].Pos())
334 } else {
335 parLineBeg = p.lineFor(par.Type.Pos())
336 }
337 var parLineEnd = p.lineFor(par.Type.End())
338
339 needsLinebreak := 0 < prevLine && prevLine < parLineBeg
340 if i > 0 {
341
342
343
344 if !needsLinebreak {
345 p.print(par.Pos())
346 }
347 p.print(token.COMMA)
348 }
349
350 if needsLinebreak && p.linebreak(parLineBeg, 0, ws, true) > 0 {
351
352 ws = ignore
353 } else if i > 0 {
354 p.print(blank)
355 }
356
357 if len(par.Names) > 0 {
358
359
360
361
362
363
364 p.identList(par.Names, ws == indent)
365 p.print(blank)
366 }
367
368 p.expr(stripParensAlways(par.Type))
369 prevLine = parLineEnd
370 }
371
372
373 if closing := p.lineFor(fields.Closing); 0 < prevLine && prevLine < closing {
374 p.print(token.COMMA)
375 p.linebreak(closing, 0, ignore, true)
376 }
377
378 if ws == ignore {
379 p.print(unindent)
380 }
381 }
382 p.print(fields.Closing, token.RPAREN)
383 }
384
385 func (p *printer) signature(params, result *ast.FieldList) {
386 if params != nil {
387 p.parameters(params)
388 } else {
389 p.print(token.LPAREN, token.RPAREN)
390 }
391 n := result.NumFields()
392 if n > 0 {
393
394 p.print(blank)
395 if n == 1 && result.List[0].Names == nil {
396
397 p.expr(stripParensAlways(result.List[0].Type))
398 return
399 }
400 p.parameters(result)
401 }
402 }
403
404 func identListSize(list []*ast.Ident, maxSize int) (size int) {
405 for i, x := range list {
406 if i > 0 {
407 size += len(", ")
408 }
409 size += utf8.RuneCountInString(x.Name)
410 if size >= maxSize {
411 break
412 }
413 }
414 return
415 }
416
417 func (p *printer) isOneLineFieldList(list []*ast.Field) bool {
418 if len(list) != 1 {
419 return false
420 }
421 f := list[0]
422 if f.Tag != nil || f.Comment != nil {
423 return false
424 }
425
426 const maxSize = 30
427 namesSize := identListSize(f.Names, maxSize)
428 if namesSize > 0 {
429 namesSize = 1
430 }
431 typeSize := p.nodeSize(f.Type, maxSize)
432 return namesSize+typeSize <= maxSize
433 }
434
435 func (p *printer) setLineComment(text string) {
436 p.setComment(&ast.CommentGroup{List: []*ast.Comment{{Slash: token.NoPos, Text: text}}})
437 }
438
439 func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) {
440 lbrace := fields.Opening
441 list := fields.List
442 rbrace := fields.Closing
443 hasComments := isIncomplete || p.commentBefore(p.posFor(rbrace))
444 srcIsOneLine := lbrace.IsValid() && rbrace.IsValid() && p.lineFor(lbrace) == p.lineFor(rbrace)
445
446 if !hasComments && srcIsOneLine {
447
448 if len(list) == 0 {
449
450 p.print(lbrace, token.LBRACE, rbrace, token.RBRACE)
451 return
452 } else if p.isOneLineFieldList(list) {
453
454
455 p.print(lbrace, token.LBRACE, blank)
456 f := list[0]
457 if isStruct {
458 for i, x := range f.Names {
459 if i > 0 {
460
461 p.print(token.COMMA, blank)
462 }
463 p.expr(x)
464 }
465 if len(f.Names) > 0 {
466 p.print(blank)
467 }
468 p.expr(f.Type)
469 } else {
470 if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
471
472 p.expr(f.Names[0])
473 p.signature(ftyp.Params, ftyp.Results)
474 } else {
475
476 p.expr(f.Type)
477 }
478 }
479 p.print(blank, rbrace, token.RBRACE)
480 return
481 }
482 }
483
484
485 p.print(blank, lbrace, token.LBRACE, indent)
486 if hasComments || len(list) > 0 {
487 p.print(formfeed)
488 }
489
490 if isStruct {
491
492 sep := vtab
493 if len(list) == 1 {
494 sep = blank
495 }
496 var line int
497 for i, f := range list {
498 if i > 0 {
499 p.linebreak(p.lineFor(f.Pos()), 1, ignore, p.linesFrom(line) > 0)
500 }
501 extraTabs := 0
502 p.setComment(f.Doc)
503 p.recordLine(&line)
504 if len(f.Names) > 0 {
505
506 p.identList(f.Names, false)
507 p.print(sep)
508 p.expr(f.Type)
509 extraTabs = 1
510 } else {
511
512 p.expr(f.Type)
513 extraTabs = 2
514 }
515 if f.Tag != nil {
516 if len(f.Names) > 0 && sep == vtab {
517 p.print(sep)
518 }
519 p.print(sep)
520 p.expr(f.Tag)
521 extraTabs = 0
522 }
523 if f.Comment != nil {
524 for ; extraTabs > 0; extraTabs-- {
525 p.print(sep)
526 }
527 p.setComment(f.Comment)
528 }
529 }
530 if isIncomplete {
531 if len(list) > 0 {
532 p.print(formfeed)
533 }
534 p.flush(p.posFor(rbrace), token.RBRACE)
535 p.setLineComment("// " + filteredMsg)
536 }
537
538 } else {
539
540 var line int
541 for i, f := range list {
542 if i > 0 {
543 p.linebreak(p.lineFor(f.Pos()), 1, ignore, p.linesFrom(line) > 0)
544 }
545 p.setComment(f.Doc)
546 p.recordLine(&line)
547 if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
548
549 p.expr(f.Names[0])
550 p.signature(ftyp.Params, ftyp.Results)
551 } else {
552
553 p.expr(f.Type)
554 }
555 p.setComment(f.Comment)
556 }
557 if isIncomplete {
558 if len(list) > 0 {
559 p.print(formfeed)
560 }
561 p.flush(p.posFor(rbrace), token.RBRACE)
562 p.setLineComment("// contains filtered or unexported methods")
563 }
564
565 }
566 p.print(unindent, formfeed, rbrace, token.RBRACE)
567 }
568
569
570
571
572 func walkBinary(e *ast.BinaryExpr) (has4, has5 bool, maxProblem int) {
573 switch e.Op.Precedence() {
574 case 4:
575 has4 = true
576 case 5:
577 has5 = true
578 }
579
580 switch l := e.X.(type) {
581 case *ast.BinaryExpr:
582 if l.Op.Precedence() < e.Op.Precedence() {
583
584
585 break
586 }
587 h4, h5, mp := walkBinary(l)
588 has4 = has4 || h4
589 has5 = has5 || h5
590 if maxProblem < mp {
591 maxProblem = mp
592 }
593 }
594
595 switch r := e.Y.(type) {
596 case *ast.BinaryExpr:
597 if r.Op.Precedence() <= e.Op.Precedence() {
598
599
600 break
601 }
602 h4, h5, mp := walkBinary(r)
603 has4 = has4 || h4
604 has5 = has5 || h5
605 if maxProblem < mp {
606 maxProblem = mp
607 }
608
609 case *ast.StarExpr:
610 if e.Op == token.QUO {
611 maxProblem = 5
612 }
613
614 case *ast.UnaryExpr:
615 switch e.Op.String() + r.Op.String() {
616 case "/*", "&&", "&^":
617 maxProblem = 5
618 case "++", "--":
619 if maxProblem < 4 {
620 maxProblem = 4
621 }
622 }
623 }
624 return
625 }
626
627 func cutoff(e *ast.BinaryExpr, depth int) int {
628 has4, has5, maxProblem := walkBinary(e)
629 if maxProblem > 0 {
630 return maxProblem + 1
631 }
632 if has4 && has5 {
633 if depth == 1 {
634 return 5
635 }
636 return 4
637 }
638 if depth == 1 {
639 return 6
640 }
641 return 4
642 }
643
644 func diffPrec(expr ast.Expr, prec int) int {
645 x, ok := expr.(*ast.BinaryExpr)
646 if !ok || prec != x.Op.Precedence() {
647 return 1
648 }
649 return 0
650 }
651
652 func reduceDepth(depth int) int {
653 depth--
654 if depth < 1 {
655 depth = 1
656 }
657 return depth
658 }
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696 func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int) {
697 prec := x.Op.Precedence()
698 if prec < prec1 {
699
700
701
702 p.print(token.LPAREN)
703 p.expr0(x, reduceDepth(depth))
704 p.print(token.RPAREN)
705 return
706 }
707
708 printBlank := prec < cutoff
709
710 ws := indent
711 p.expr1(x.X, prec, depth+diffPrec(x.X, prec))
712 if printBlank {
713 p.print(blank)
714 }
715 xline := p.pos.Line
716 yline := p.lineFor(x.Y.Pos())
717 p.print(x.OpPos, x.Op)
718 if xline != yline && xline > 0 && yline > 0 {
719
720
721 if p.linebreak(yline, 1, ws, true) > 0 {
722 ws = ignore
723 printBlank = false
724 }
725 }
726 if printBlank {
727 p.print(blank)
728 }
729 p.expr1(x.Y, prec+1, depth+1)
730 if ws == ignore {
731 p.print(unindent)
732 }
733 }
734
735 func isBinary(expr ast.Expr) bool {
736 _, ok := expr.(*ast.BinaryExpr)
737 return ok
738 }
739
740 func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
741 p.print(expr.Pos())
742
743 switch x := expr.(type) {
744 case *ast.BadExpr:
745 p.print("BadExpr")
746
747 case *ast.Ident:
748 p.print(x)
749
750 case *ast.BinaryExpr:
751 if depth < 1 {
752 p.internalError("depth < 1:", depth)
753 depth = 1
754 }
755 p.binaryExpr(x, prec1, cutoff(x, depth), depth)
756
757 case *ast.KeyValueExpr:
758 p.expr(x.Key)
759 p.print(x.Colon, token.COLON, blank)
760 p.expr(x.Value)
761
762 case *ast.StarExpr:
763 const prec = token.UnaryPrec
764 if prec < prec1 {
765
766 p.print(token.LPAREN)
767 p.print(token.MUL)
768 p.expr(x.X)
769 p.print(token.RPAREN)
770 } else {
771
772 p.print(token.MUL)
773 p.expr(x.X)
774 }
775
776 case *ast.UnaryExpr:
777 const prec = token.UnaryPrec
778 if prec < prec1 {
779
780 p.print(token.LPAREN)
781 p.expr(x)
782 p.print(token.RPAREN)
783 } else {
784
785 p.print(x.Op)
786 if x.Op == token.RANGE {
787
788 p.print(blank)
789 }
790 p.expr1(x.X, prec, depth)
791 }
792
793 case *ast.BasicLit:
794 p.print(x)
795
796 case *ast.FuncLit:
797 p.expr(x.Type)
798 p.funcBody(p.distanceFrom(x.Type.Pos()), blank, x.Body)
799
800 case *ast.ParenExpr:
801 if _, hasParens := x.X.(*ast.ParenExpr); hasParens {
802
803
804 p.expr0(x.X, depth)
805 } else {
806 p.print(token.LPAREN)
807 p.expr0(x.X, reduceDepth(depth))
808 p.print(x.Rparen, token.RPAREN)
809 }
810
811 case *ast.SelectorExpr:
812 p.selectorExpr(x, depth, false)
813
814 case *ast.TypeAssertExpr:
815 p.expr1(x.X, token.HighestPrec, depth)
816 p.print(token.PERIOD, x.Lparen, token.LPAREN)
817 if x.Type != nil {
818 p.expr(x.Type)
819 } else {
820 p.print(token.TYPE)
821 }
822 p.print(x.Rparen, token.RPAREN)
823
824 case *ast.IndexExpr:
825
826 p.expr1(x.X, token.HighestPrec, 1)
827 p.print(x.Lbrack, token.LBRACK)
828 p.expr0(x.Index, depth+1)
829 p.print(x.Rbrack, token.RBRACK)
830
831 case *ast.SliceExpr:
832
833 p.expr1(x.X, token.HighestPrec, 1)
834 p.print(x.Lbrack, token.LBRACK)
835 indices := []ast.Expr{x.Low, x.High}
836 if x.Max != nil {
837 indices = append(indices, x.Max)
838 }
839
840 var needsBlanks bool
841 if depth <= 1 {
842 var indexCount int
843 var hasBinaries bool
844 for _, x := range indices {
845 if x != nil {
846 indexCount++
847 if isBinary(x) {
848 hasBinaries = true
849 }
850 }
851 }
852 if indexCount > 1 && hasBinaries {
853 needsBlanks = true
854 }
855 }
856 for i, x := range indices {
857 if i > 0 {
858 if indices[i-1] != nil && needsBlanks {
859 p.print(blank)
860 }
861 p.print(token.COLON)
862 if x != nil && needsBlanks {
863 p.print(blank)
864 }
865 }
866 if x != nil {
867 p.expr0(x, depth+1)
868 }
869 }
870 p.print(x.Rbrack, token.RBRACK)
871
872 case *ast.CallExpr:
873 if len(x.Args) > 1 {
874 depth++
875 }
876 var wasIndented bool
877 if _, ok := x.Fun.(*ast.FuncType); ok {
878
879 p.print(token.LPAREN)
880 wasIndented = p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
881 p.print(token.RPAREN)
882 } else {
883 wasIndented = p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
884 }
885 p.print(x.Lparen, token.LPAREN)
886 if x.Ellipsis.IsValid() {
887 p.exprList(x.Lparen, x.Args, depth, 0, x.Ellipsis, false)
888 p.print(x.Ellipsis, token.ELLIPSIS)
889 if x.Rparen.IsValid() && p.lineFor(x.Ellipsis) < p.lineFor(x.Rparen) {
890 p.print(token.COMMA, formfeed)
891 }
892 } else {
893 p.exprList(x.Lparen, x.Args, depth, commaTerm, x.Rparen, false)
894 }
895 p.print(x.Rparen, token.RPAREN)
896 if wasIndented {
897 p.print(unindent)
898 }
899
900 case *ast.CompositeLit:
901
902 if x.Type != nil {
903 p.expr1(x.Type, token.HighestPrec, depth)
904 }
905 p.level++
906 p.print(x.Lbrace, token.LBRACE)
907 p.exprList(x.Lbrace, x.Elts, 1, commaTerm, x.Rbrace, x.Incomplete)
908
909
910
911 mode := noExtraLinebreak
912
913
914 if len(x.Elts) > 0 {
915 mode |= noExtraBlank
916 }
917
918
919 p.print(indent, unindent, mode, x.Rbrace, token.RBRACE, mode)
920 p.level--
921
922 case *ast.Ellipsis:
923 p.print(token.ELLIPSIS)
924 if x.Elt != nil {
925 p.expr(x.Elt)
926 }
927
928 case *ast.ArrayType:
929 p.print(token.LBRACK)
930 if x.Len != nil {
931 p.expr(x.Len)
932 }
933 p.print(token.RBRACK)
934 p.expr(x.Elt)
935
936 case *ast.StructType:
937 p.print(token.STRUCT)
938 p.fieldList(x.Fields, true, x.Incomplete)
939
940 case *ast.FuncType:
941 p.print(token.FUNC)
942 p.signature(x.Params, x.Results)
943
944 case *ast.InterfaceType:
945 p.print(token.INTERFACE)
946 p.fieldList(x.Methods, false, x.Incomplete)
947
948 case *ast.MapType:
949 p.print(token.MAP, token.LBRACK)
950 p.expr(x.Key)
951 p.print(token.RBRACK)
952 p.expr(x.Value)
953
954 case *ast.ChanType:
955 switch x.Dir {
956 case ast.SEND | ast.RECV:
957 p.print(token.CHAN)
958 case ast.RECV:
959 p.print(token.ARROW, token.CHAN)
960 case ast.SEND:
961 p.print(token.CHAN, x.Arrow, token.ARROW)
962 }
963 p.print(blank)
964 p.expr(x.Value)
965
966 default:
967 panic("unreachable")
968 }
969 }
970
971 func (p *printer) possibleSelectorExpr(expr ast.Expr, prec1, depth int) bool {
972 if x, ok := expr.(*ast.SelectorExpr); ok {
973 return p.selectorExpr(x, depth, true)
974 }
975 p.expr1(expr, prec1, depth)
976 return false
977 }
978
979
980
981 func (p *printer) selectorExpr(x *ast.SelectorExpr, depth int, isMethod bool) bool {
982 p.expr1(x.X, token.HighestPrec, depth)
983 p.print(token.PERIOD)
984 if line := p.lineFor(x.Sel.Pos()); p.pos.IsValid() && p.pos.Line < line {
985 p.print(indent, newline, x.Sel.Pos(), x.Sel)
986 if !isMethod {
987 p.print(unindent)
988 }
989 return true
990 }
991 p.print(x.Sel.Pos(), x.Sel)
992 return false
993 }
994
995 func (p *printer) expr0(x ast.Expr, depth int) {
996 p.expr1(x, token.LowestPrec, depth)
997 }
998
999 func (p *printer) expr(x ast.Expr) {
1000 const depth = 1
1001 p.expr1(x, token.LowestPrec, depth)
1002 }
1003
1004
1005
1006
1007
1008
1009
1010 func (p *printer) stmtList(list []ast.Stmt, nindent int, nextIsRBrace bool) {
1011 if nindent > 0 {
1012 p.print(indent)
1013 }
1014 var line int
1015 i := 0
1016 for _, s := range list {
1017
1018 if _, isEmpty := s.(*ast.EmptyStmt); !isEmpty {
1019
1020
1021 if len(p.output) > 0 {
1022
1023
1024 p.linebreak(p.lineFor(s.Pos()), 1, ignore, i == 0 || nindent == 0 || p.linesFrom(line) > 0)
1025 }
1026 p.recordLine(&line)
1027 p.stmt(s, nextIsRBrace && i == len(list)-1)
1028
1029
1030
1031 for t := s; ; {
1032 lt, _ := t.(*ast.LabeledStmt)
1033 if lt == nil {
1034 break
1035 }
1036 line++
1037 t = lt.Stmt
1038 }
1039 i++
1040 }
1041 }
1042 if nindent > 0 {
1043 p.print(unindent)
1044 }
1045 }
1046
1047
1048 func (p *printer) block(b *ast.BlockStmt, nindent int) {
1049 p.print(b.Lbrace, token.LBRACE)
1050 p.stmtList(b.List, nindent, true)
1051 p.linebreak(p.lineFor(b.Rbrace), 1, ignore, true)
1052 p.print(b.Rbrace, token.RBRACE)
1053 }
1054
1055 func isTypeName(x ast.Expr) bool {
1056 switch t := x.(type) {
1057 case *ast.Ident:
1058 return true
1059 case *ast.SelectorExpr:
1060 return isTypeName(t.X)
1061 }
1062 return false
1063 }
1064
1065 func stripParens(x ast.Expr) ast.Expr {
1066 if px, strip := x.(*ast.ParenExpr); strip {
1067
1068
1069
1070 ast.Inspect(px.X, func(node ast.Node) bool {
1071 switch x := node.(type) {
1072 case *ast.ParenExpr:
1073
1074 return false
1075 case *ast.CompositeLit:
1076 if isTypeName(x.Type) {
1077 strip = false
1078 }
1079 return false
1080 }
1081
1082 return true
1083 })
1084 if strip {
1085 return stripParens(px.X)
1086 }
1087 }
1088 return x
1089 }
1090
1091 func stripParensAlways(x ast.Expr) ast.Expr {
1092 if x, ok := x.(*ast.ParenExpr); ok {
1093 return stripParensAlways(x.X)
1094 }
1095 return x
1096 }
1097
1098 func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, post ast.Stmt) {
1099 p.print(blank)
1100 needsBlank := false
1101 if init == nil && post == nil {
1102
1103 if expr != nil {
1104 p.expr(stripParens(expr))
1105 needsBlank = true
1106 }
1107 } else {
1108
1109
1110 if init != nil {
1111 p.stmt(init, false)
1112 }
1113 p.print(token.SEMICOLON, blank)
1114 if expr != nil {
1115 p.expr(stripParens(expr))
1116 needsBlank = true
1117 }
1118 if isForStmt {
1119 p.print(token.SEMICOLON, blank)
1120 needsBlank = false
1121 if post != nil {
1122 p.stmt(post, false)
1123 needsBlank = true
1124 }
1125 }
1126 }
1127 if needsBlank {
1128 p.print(blank)
1129 }
1130 }
1131
1132
1133
1134
1135
1136 func (p *printer) indentList(list []ast.Expr) bool {
1137
1138
1139
1140 if len(list) >= 2 {
1141 var b = p.lineFor(list[0].Pos())
1142 var e = p.lineFor(list[len(list)-1].End())
1143 if 0 < b && b < e {
1144
1145 n := 0
1146 line := b
1147 for _, x := range list {
1148 xb := p.lineFor(x.Pos())
1149 xe := p.lineFor(x.End())
1150 if line < xb {
1151
1152
1153 return true
1154 }
1155 if xb < xe {
1156
1157 n++
1158 }
1159 line = xe
1160 }
1161 return n > 1
1162 }
1163 }
1164 return false
1165 }
1166
1167 func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool) {
1168 p.print(stmt.Pos())
1169
1170 switch s := stmt.(type) {
1171 case *ast.BadStmt:
1172 p.print("BadStmt")
1173
1174 case *ast.DeclStmt:
1175 p.decl(s.Decl)
1176
1177 case *ast.EmptyStmt:
1178
1179
1180 case *ast.LabeledStmt:
1181
1182
1183
1184 p.print(unindent)
1185 p.expr(s.Label)
1186 p.print(s.Colon, token.COLON, indent)
1187 if e, isEmpty := s.Stmt.(*ast.EmptyStmt); isEmpty {
1188 if !nextIsRBrace {
1189 p.print(newline, e.Pos(), token.SEMICOLON)
1190 break
1191 }
1192 } else {
1193 p.linebreak(p.lineFor(s.Stmt.Pos()), 1, ignore, true)
1194 }
1195 p.stmt(s.Stmt, nextIsRBrace)
1196
1197 case *ast.ExprStmt:
1198 const depth = 1
1199 p.expr0(s.X, depth)
1200
1201 case *ast.SendStmt:
1202 const depth = 1
1203 p.expr0(s.Chan, depth)
1204 p.print(blank, s.Arrow, token.ARROW, blank)
1205 p.expr0(s.Value, depth)
1206
1207 case *ast.IncDecStmt:
1208 const depth = 1
1209 p.expr0(s.X, depth+1)
1210 p.print(s.TokPos, s.Tok)
1211
1212 case *ast.AssignStmt:
1213 var depth = 1
1214 if len(s.Lhs) > 1 && len(s.Rhs) > 1 {
1215 depth++
1216 }
1217 p.exprList(s.Pos(), s.Lhs, depth, 0, s.TokPos, false)
1218 p.print(blank, s.TokPos, s.Tok, blank)
1219 p.exprList(s.TokPos, s.Rhs, depth, 0, token.NoPos, false)
1220
1221 case *ast.GoStmt:
1222 p.print(token.GO, blank)
1223 p.expr(s.Call)
1224
1225 case *ast.DeferStmt:
1226 p.print(token.DEFER, blank)
1227 p.expr(s.Call)
1228
1229 case *ast.ReturnStmt:
1230 p.print(token.RETURN)
1231 if s.Results != nil {
1232 p.print(blank)
1233
1234
1235
1236
1237
1238 if p.indentList(s.Results) {
1239 p.print(indent)
1240 p.exprList(s.Pos(), s.Results, 1, noIndent, token.NoPos, false)
1241 p.print(unindent)
1242 } else {
1243 p.exprList(s.Pos(), s.Results, 1, 0, token.NoPos, false)
1244 }
1245 }
1246
1247 case *ast.BranchStmt:
1248 p.print(s.Tok)
1249 if s.Label != nil {
1250 p.print(blank)
1251 p.expr(s.Label)
1252 }
1253
1254 case *ast.BlockStmt:
1255 p.block(s, 1)
1256
1257 case *ast.IfStmt:
1258 p.print(token.IF)
1259 p.controlClause(false, s.Init, s.Cond, nil)
1260 p.block(s.Body, 1)
1261 if s.Else != nil {
1262 p.print(blank, token.ELSE, blank)
1263 switch s.Else.(type) {
1264 case *ast.BlockStmt, *ast.IfStmt:
1265 p.stmt(s.Else, nextIsRBrace)
1266 default:
1267
1268
1269
1270 p.print(token.LBRACE, indent, formfeed)
1271 p.stmt(s.Else, true)
1272 p.print(unindent, formfeed, token.RBRACE)
1273 }
1274 }
1275
1276 case *ast.CaseClause:
1277 if s.List != nil {
1278 p.print(token.CASE, blank)
1279 p.exprList(s.Pos(), s.List, 1, 0, s.Colon, false)
1280 } else {
1281 p.print(token.DEFAULT)
1282 }
1283 p.print(s.Colon, token.COLON)
1284 p.stmtList(s.Body, 1, nextIsRBrace)
1285
1286 case *ast.SwitchStmt:
1287 p.print(token.SWITCH)
1288 p.controlClause(false, s.Init, s.Tag, nil)
1289 p.block(s.Body, 0)
1290
1291 case *ast.TypeSwitchStmt:
1292 p.print(token.SWITCH)
1293 if s.Init != nil {
1294 p.print(blank)
1295 p.stmt(s.Init, false)
1296 p.print(token.SEMICOLON)
1297 }
1298 p.print(blank)
1299 p.stmt(s.Assign, false)
1300 p.print(blank)
1301 p.block(s.Body, 0)
1302
1303 case *ast.CommClause:
1304 if s.Comm != nil {
1305 p.print(token.CASE, blank)
1306 p.stmt(s.Comm, false)
1307 } else {
1308 p.print(token.DEFAULT)
1309 }
1310 p.print(s.Colon, token.COLON)
1311 p.stmtList(s.Body, 1, nextIsRBrace)
1312
1313 case *ast.SelectStmt:
1314 p.print(token.SELECT, blank)
1315 body := s.Body
1316 if len(body.List) == 0 && !p.commentBefore(p.posFor(body.Rbrace)) {
1317
1318 p.print(body.Lbrace, token.LBRACE, body.Rbrace, token.RBRACE)
1319 } else {
1320 p.block(body, 0)
1321 }
1322
1323 case *ast.ForStmt:
1324 p.print(token.FOR)
1325 p.controlClause(true, s.Init, s.Cond, s.Post)
1326 p.block(s.Body, 1)
1327
1328 case *ast.RangeStmt:
1329 p.print(token.FOR, blank)
1330 if s.Key != nil {
1331 p.expr(s.Key)
1332 if s.Value != nil {
1333
1334
1335 p.print(s.Value.Pos(), token.COMMA, blank)
1336 p.expr(s.Value)
1337 }
1338 p.print(blank, s.TokPos, s.Tok, blank)
1339 }
1340 p.print(token.RANGE, blank)
1341 p.expr(stripParens(s.X))
1342 p.print(blank)
1343 p.block(s.Body, 1)
1344
1345 default:
1346 panic("unreachable")
1347 }
1348 }
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378 func keepTypeColumn(specs []ast.Spec) []bool {
1379 m := make([]bool, len(specs))
1380
1381 populate := func(i, j int, keepType bool) {
1382 if keepType {
1383 for ; i < j; i++ {
1384 m[i] = true
1385 }
1386 }
1387 }
1388
1389 i0 := -1
1390 var keepType bool
1391 for i, s := range specs {
1392 t := s.(*ast.ValueSpec)
1393 if t.Values != nil {
1394 if i0 < 0 {
1395
1396 i0 = i
1397 keepType = false
1398 }
1399 } else {
1400 if i0 >= 0 {
1401
1402 populate(i0, i, keepType)
1403 i0 = -1
1404 }
1405 }
1406 if t.Type != nil {
1407 keepType = true
1408 }
1409 }
1410 if i0 >= 0 {
1411
1412 populate(i0, len(specs), keepType)
1413 }
1414
1415 return m
1416 }
1417
1418 func (p *printer) valueSpec(s *ast.ValueSpec, keepType bool) {
1419 p.setComment(s.Doc)
1420 p.identList(s.Names, false)
1421 extraTabs := 3
1422 if s.Type != nil || keepType {
1423 p.print(vtab)
1424 extraTabs--
1425 }
1426 if s.Type != nil {
1427 p.expr(s.Type)
1428 }
1429 if s.Values != nil {
1430 p.print(vtab, token.ASSIGN, blank)
1431 p.exprList(token.NoPos, s.Values, 1, 0, token.NoPos, false)
1432 extraTabs--
1433 }
1434 if s.Comment != nil {
1435 for ; extraTabs > 0; extraTabs-- {
1436 p.print(vtab)
1437 }
1438 p.setComment(s.Comment)
1439 }
1440 }
1441
1442 func sanitizeImportPath(lit *ast.BasicLit) *ast.BasicLit {
1443
1444
1445
1446
1447
1448
1449
1450
1451 if lit.Kind != token.STRING {
1452 return lit
1453 }
1454 s, err := strconv.Unquote(lit.Value)
1455 if err != nil {
1456 return lit
1457 }
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467 if s == "" {
1468 return lit
1469 }
1470 const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
1471 for _, r := range s {
1472 if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
1473 return lit
1474 }
1475 }
1476
1477
1478 s = strconv.Quote(s)
1479 if s == lit.Value {
1480 return lit
1481 }
1482 return &ast.BasicLit{ValuePos: lit.ValuePos, Kind: token.STRING, Value: s}
1483 }
1484
1485
1486
1487
1488
1489 func (p *printer) spec(spec ast.Spec, n int, doIndent bool) {
1490 switch s := spec.(type) {
1491 case *ast.ImportSpec:
1492 p.setComment(s.Doc)
1493 if s.Name != nil {
1494 p.expr(s.Name)
1495 p.print(blank)
1496 }
1497 p.expr(sanitizeImportPath(s.Path))
1498 p.setComment(s.Comment)
1499 p.print(s.EndPos)
1500
1501 case *ast.ValueSpec:
1502 if n != 1 {
1503 p.internalError("expected n = 1; got", n)
1504 }
1505 p.setComment(s.Doc)
1506 p.identList(s.Names, doIndent)
1507 if s.Type != nil {
1508 p.print(blank)
1509 p.expr(s.Type)
1510 }
1511 if s.Values != nil {
1512 p.print(blank, token.ASSIGN, blank)
1513 p.exprList(token.NoPos, s.Values, 1, 0, token.NoPos, false)
1514 }
1515 p.setComment(s.Comment)
1516
1517 case *ast.TypeSpec:
1518 p.setComment(s.Doc)
1519 p.expr(s.Name)
1520 if n == 1 {
1521 p.print(blank)
1522 } else {
1523 p.print(vtab)
1524 }
1525 if s.Assign.IsValid() {
1526 p.print(token.ASSIGN, blank)
1527 }
1528 p.expr(s.Type)
1529 p.setComment(s.Comment)
1530
1531 default:
1532 panic("unreachable")
1533 }
1534 }
1535
1536 func (p *printer) genDecl(d *ast.GenDecl) {
1537 p.setComment(d.Doc)
1538 p.print(d.Pos(), d.Tok, blank)
1539
1540 if d.Lparen.IsValid() || len(d.Specs) > 1 {
1541
1542 p.print(d.Lparen, token.LPAREN)
1543 if n := len(d.Specs); n > 0 {
1544 p.print(indent, formfeed)
1545 if n > 1 && (d.Tok == token.CONST || d.Tok == token.VAR) {
1546
1547
1548 keepType := keepTypeColumn(d.Specs)
1549 var line int
1550 for i, s := range d.Specs {
1551 if i > 0 {
1552 p.linebreak(p.lineFor(s.Pos()), 1, ignore, p.linesFrom(line) > 0)
1553 }
1554 p.recordLine(&line)
1555 p.valueSpec(s.(*ast.ValueSpec), keepType[i])
1556 }
1557 } else {
1558 var line int
1559 for i, s := range d.Specs {
1560 if i > 0 {
1561 p.linebreak(p.lineFor(s.Pos()), 1, ignore, p.linesFrom(line) > 0)
1562 }
1563 p.recordLine(&line)
1564 p.spec(s, n, false)
1565 }
1566 }
1567 p.print(unindent, formfeed)
1568 }
1569 p.print(d.Rparen, token.RPAREN)
1570
1571 } else if len(d.Specs) > 0 {
1572
1573 p.spec(d.Specs[0], 1, true)
1574 }
1575 }
1576
1577
1578
1579
1580
1581
1582 func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) {
1583
1584
1585
1586
1587 if size, found := p.nodeSizes[n]; found {
1588 return size
1589 }
1590
1591 size = maxSize + 1
1592 p.nodeSizes[n] = size
1593
1594
1595
1596
1597 cfg := Config{Mode: RawFormat}
1598 var buf bytes.Buffer
1599 if err := cfg.fprint(&buf, p.fset, n, p.nodeSizes); err != nil {
1600 return
1601 }
1602 if buf.Len() <= maxSize {
1603 for _, ch := range buf.Bytes() {
1604 if ch < ' ' {
1605 return
1606 }
1607 }
1608 size = buf.Len()
1609 p.nodeSizes[n] = size
1610 }
1611 return
1612 }
1613
1614
1615 func (p *printer) numLines(n ast.Node) int {
1616 if from := n.Pos(); from.IsValid() {
1617 if to := n.End(); to.IsValid() {
1618 return p.lineFor(to) - p.lineFor(from) + 1
1619 }
1620 }
1621 return infinity
1622 }
1623
1624
1625 func (p *printer) bodySize(b *ast.BlockStmt, maxSize int) int {
1626 pos1 := b.Pos()
1627 pos2 := b.Rbrace
1628 if pos1.IsValid() && pos2.IsValid() && p.lineFor(pos1) != p.lineFor(pos2) {
1629
1630 return maxSize + 1
1631 }
1632 if len(b.List) > 5 {
1633
1634 return maxSize + 1
1635 }
1636
1637 bodySize := p.commentSizeBefore(p.posFor(pos2))
1638 for i, s := range b.List {
1639 if bodySize > maxSize {
1640 break
1641 }
1642 if i > 0 {
1643 bodySize += 2
1644 }
1645 bodySize += p.nodeSize(s, maxSize)
1646 }
1647 return bodySize
1648 }
1649
1650
1651
1652
1653
1654
1655
1656 func (p *printer) funcBody(headerSize int, sep whiteSpace, b *ast.BlockStmt) {
1657 if b == nil {
1658 return
1659 }
1660
1661
1662 defer func(level int) {
1663 p.level = level
1664 }(p.level)
1665 p.level = 0
1666
1667 const maxSize = 100
1668 if headerSize+p.bodySize(b, maxSize) <= maxSize {
1669 p.print(sep, b.Lbrace, token.LBRACE)
1670 if len(b.List) > 0 {
1671 p.print(blank)
1672 for i, s := range b.List {
1673 if i > 0 {
1674 p.print(token.SEMICOLON, blank)
1675 }
1676 p.stmt(s, i == len(b.List)-1)
1677 }
1678 p.print(blank)
1679 }
1680 p.print(noExtraLinebreak, b.Rbrace, token.RBRACE, noExtraLinebreak)
1681 return
1682 }
1683
1684 if sep != ignore {
1685 p.print(blank)
1686 }
1687 p.block(b, 1)
1688 }
1689
1690
1691
1692
1693 func (p *printer) distanceFrom(from token.Pos) int {
1694 if from.IsValid() && p.pos.IsValid() {
1695 if f := p.posFor(from); f.Line == p.pos.Line {
1696 return p.pos.Column - f.Column
1697 }
1698 }
1699 return infinity
1700 }
1701
1702 func (p *printer) funcDecl(d *ast.FuncDecl) {
1703 p.setComment(d.Doc)
1704 p.print(d.Pos(), token.FUNC, blank)
1705 if d.Recv != nil {
1706 p.parameters(d.Recv)
1707 p.print(blank)
1708 }
1709 p.expr(d.Name)
1710 p.signature(d.Type.Params, d.Type.Results)
1711 p.funcBody(p.distanceFrom(d.Pos()), vtab, d.Body)
1712 }
1713
1714 func (p *printer) decl(decl ast.Decl) {
1715 switch d := decl.(type) {
1716 case *ast.BadDecl:
1717 p.print(d.Pos(), "BadDecl")
1718 case *ast.GenDecl:
1719 p.genDecl(d)
1720 case *ast.FuncDecl:
1721 p.funcDecl(d)
1722 default:
1723 panic("unreachable")
1724 }
1725 }
1726
1727
1728
1729
1730 func declToken(decl ast.Decl) (tok token.Token) {
1731 tok = token.ILLEGAL
1732 switch d := decl.(type) {
1733 case *ast.GenDecl:
1734 tok = d.Tok
1735 case *ast.FuncDecl:
1736 tok = token.FUNC
1737 }
1738 return
1739 }
1740
1741 func (p *printer) declList(list []ast.Decl) {
1742 tok := token.ILLEGAL
1743 for _, d := range list {
1744 prev := tok
1745 tok = declToken(d)
1746
1747
1748
1749
1750
1751
1752
1753 if len(p.output) > 0 {
1754
1755
1756 min := 1
1757 if prev != tok || getDoc(d) != nil {
1758 min = 2
1759 }
1760
1761
1762 p.linebreak(p.lineFor(d.Pos()), min, ignore, tok == token.FUNC && p.numLines(d) > 1)
1763 }
1764 p.decl(d)
1765 }
1766 }
1767
1768 func (p *printer) file(src *ast.File) {
1769 p.setComment(src.Doc)
1770 p.print(src.Pos(), token.PACKAGE, blank)
1771 p.expr(src.Name)
1772 p.declList(src.Decls)
1773 p.print(newline)
1774 }
1775
View as plain text