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