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
1315 func (p *printer) indentList(list []ast.Expr) bool {
1316
1317
1318
1319 if len(list) >= 2 {
1320 var b = p.lineFor(list[0].Pos())
1321 var e = p.lineFor(list[len(list)-1].End())
1322 if 0 < b && b < e {
1323
1324 n := 0
1325 line := b
1326 for _, x := range list {
1327 xb := p.lineFor(x.Pos())
1328 xe := p.lineFor(x.End())
1329 if line < xb {
1330
1331
1332 return true
1333 }
1334 if xb < xe {
1335
1336 n++
1337 }
1338 line = xe
1339 }
1340 return n > 1
1341 }
1342 }
1343 return false
1344 }
1345
1346 func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool) {
1347 p.setPos(stmt.Pos())
1348
1349 switch s := stmt.(type) {
1350 case *ast.BadStmt:
1351 p.print("BadStmt")
1352
1353 case *ast.DeclStmt:
1354 p.decl(s.Decl)
1355
1356 case *ast.EmptyStmt:
1357
1358
1359 case *ast.LabeledStmt:
1360
1361
1362
1363 p.print(unindent)
1364 p.expr(s.Label)
1365 p.setPos(s.Colon)
1366 p.print(token.COLON, indent)
1367 if e, isEmpty := s.Stmt.(*ast.EmptyStmt); isEmpty {
1368 if !nextIsRBrace {
1369 p.print(newline)
1370 p.setPos(e.Pos())
1371 p.print(token.SEMICOLON)
1372 break
1373 }
1374 } else {
1375 p.linebreak(p.lineFor(s.Stmt.Pos()), 1, ignore, true)
1376 }
1377 p.stmt(s.Stmt, nextIsRBrace)
1378
1379 case *ast.ExprStmt:
1380 const depth = 1
1381 p.expr0(s.X, depth)
1382
1383 case *ast.SendStmt:
1384 const depth = 1
1385 p.expr0(s.Chan, depth)
1386 p.print(blank)
1387 p.setPos(s.Arrow)
1388 p.print(token.ARROW, blank)
1389 p.expr0(s.Value, depth)
1390
1391 case *ast.IncDecStmt:
1392 const depth = 1
1393 p.expr0(s.X, depth+1)
1394 p.setPos(s.TokPos)
1395 p.print(s.Tok)
1396
1397 case *ast.AssignStmt:
1398 var depth = 1
1399 if len(s.Lhs) > 1 && len(s.Rhs) > 1 {
1400 depth++
1401 }
1402 p.exprList(s.Pos(), s.Lhs, depth, 0, s.TokPos, false)
1403 p.print(blank)
1404 p.setPos(s.TokPos)
1405 p.print(s.Tok, blank)
1406 p.exprList(s.TokPos, s.Rhs, depth, 0, token.NoPos, false)
1407
1408 case *ast.GoStmt:
1409 p.print(token.GO, blank)
1410 p.expr(s.Call)
1411
1412 case *ast.DeferStmt:
1413 p.print(token.DEFER, blank)
1414 p.expr(s.Call)
1415
1416 case *ast.ReturnStmt:
1417 p.print(token.RETURN)
1418 if s.Results != nil {
1419 p.print(blank)
1420
1421
1422
1423
1424
1425 if p.indentList(s.Results) {
1426 p.print(indent)
1427
1428
1429 p.exprList(token.NoPos, s.Results, 1, noIndent, token.NoPos, false)
1430 p.print(unindent)
1431 } else {
1432 p.exprList(token.NoPos, s.Results, 1, 0, token.NoPos, false)
1433 }
1434 }
1435
1436 case *ast.BranchStmt:
1437 p.print(s.Tok)
1438 if s.Label != nil {
1439 p.print(blank)
1440 p.expr(s.Label)
1441 }
1442
1443 case *ast.BlockStmt:
1444 p.block(s, 1)
1445
1446 case *ast.IfStmt:
1447 p.print(token.IF)
1448 p.controlClause(false, s.Init, s.Cond, nil)
1449 p.block(s.Body, 1)
1450 if s.Else != nil {
1451 p.print(blank, token.ELSE, blank)
1452 switch s.Else.(type) {
1453 case *ast.BlockStmt, *ast.IfStmt:
1454 p.stmt(s.Else, nextIsRBrace)
1455 default:
1456
1457
1458
1459 p.print(token.LBRACE, indent, formfeed)
1460 p.stmt(s.Else, true)
1461 p.print(unindent, formfeed, token.RBRACE)
1462 }
1463 }
1464
1465 case *ast.CaseClause:
1466 if s.List != nil {
1467 p.print(token.CASE, blank)
1468 p.exprList(s.Pos(), s.List, 1, 0, s.Colon, false)
1469 } else {
1470 p.print(token.DEFAULT)
1471 }
1472 p.setPos(s.Colon)
1473 p.print(token.COLON)
1474 p.stmtList(s.Body, 1, nextIsRBrace)
1475
1476 case *ast.SwitchStmt:
1477 p.print(token.SWITCH)
1478 p.controlClause(false, s.Init, s.Tag, nil)
1479 p.block(s.Body, 0)
1480
1481 case *ast.TypeSwitchStmt:
1482 p.print(token.SWITCH)
1483 if s.Init != nil {
1484 p.print(blank)
1485 p.stmt(s.Init, false)
1486 p.print(token.SEMICOLON)
1487 }
1488 p.print(blank)
1489 p.stmt(s.Assign, false)
1490 p.print(blank)
1491 p.block(s.Body, 0)
1492
1493 case *ast.CommClause:
1494 if s.Comm != nil {
1495 p.print(token.CASE, blank)
1496 p.stmt(s.Comm, false)
1497 } else {
1498 p.print(token.DEFAULT)
1499 }
1500 p.setPos(s.Colon)
1501 p.print(token.COLON)
1502 p.stmtList(s.Body, 1, nextIsRBrace)
1503
1504 case *ast.SelectStmt:
1505 p.print(token.SELECT, blank)
1506 body := s.Body
1507 if len(body.List) == 0 && !p.commentBefore(p.posFor(body.Rbrace)) {
1508
1509 p.setPos(body.Lbrace)
1510 p.print(token.LBRACE)
1511 p.setPos(body.Rbrace)
1512 p.print(token.RBRACE)
1513 } else {
1514 p.block(body, 0)
1515 }
1516
1517 case *ast.ForStmt:
1518 p.print(token.FOR)
1519 p.controlClause(true, s.Init, s.Cond, s.Post)
1520 p.block(s.Body, 1)
1521
1522 case *ast.RangeStmt:
1523 p.print(token.FOR, blank)
1524 if s.Key != nil {
1525 p.expr(s.Key)
1526 if s.Value != nil {
1527
1528
1529 p.setPos(s.Value.Pos())
1530 p.print(token.COMMA, blank)
1531 p.expr(s.Value)
1532 }
1533 p.print(blank)
1534 p.setPos(s.TokPos)
1535 p.print(s.Tok, blank)
1536 }
1537 p.print(token.RANGE, blank)
1538 p.expr(stripParens(s.X))
1539 p.print(blank)
1540 p.block(s.Body, 1)
1541
1542 default:
1543 panic("unreachable")
1544 }
1545 }
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574 func keepTypeColumn(specs []ast.Spec) []bool {
1575 m := make([]bool, len(specs))
1576
1577 populate := func(i, j int, keepType bool) {
1578 if keepType {
1579 for ; i < j; i++ {
1580 m[i] = true
1581 }
1582 }
1583 }
1584
1585 i0 := -1
1586 var keepType bool
1587 for i, s := range specs {
1588 t := s.(*ast.ValueSpec)
1589 if t.Values != nil {
1590 if i0 < 0 {
1591
1592 i0 = i
1593 keepType = false
1594 }
1595 } else {
1596 if i0 >= 0 {
1597
1598 populate(i0, i, keepType)
1599 i0 = -1
1600 }
1601 }
1602 if t.Type != nil {
1603 keepType = true
1604 }
1605 }
1606 if i0 >= 0 {
1607
1608 populate(i0, len(specs), keepType)
1609 }
1610
1611 return m
1612 }
1613
1614 func (p *printer) valueSpec(s *ast.ValueSpec, keepType bool) {
1615 p.setComment(s.Doc)
1616 p.identList(s.Names, false)
1617 extraTabs := 3
1618 if s.Type != nil || keepType {
1619 p.print(vtab)
1620 extraTabs--
1621 }
1622 if s.Type != nil {
1623 p.expr(s.Type)
1624 }
1625 if s.Values != nil {
1626 p.print(vtab, token.ASSIGN, blank)
1627 p.exprList(token.NoPos, s.Values, 1, 0, token.NoPos, false)
1628 extraTabs--
1629 }
1630 if s.Comment != nil {
1631 for ; extraTabs > 0; extraTabs-- {
1632 p.print(vtab)
1633 }
1634 p.setComment(s.Comment)
1635 }
1636 }
1637
1638 func sanitizeImportPath(lit *ast.BasicLit) *ast.BasicLit {
1639
1640
1641
1642
1643
1644
1645
1646
1647 if lit.Kind != token.STRING {
1648 return lit
1649 }
1650 s, err := strconv.Unquote(lit.Value)
1651 if err != nil {
1652 return lit
1653 }
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663 if s == "" {
1664 return lit
1665 }
1666 const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
1667 for _, r := range s {
1668 if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
1669 return lit
1670 }
1671 }
1672
1673
1674 s = strconv.Quote(s)
1675 if s == lit.Value {
1676 return lit
1677 }
1678 return &ast.BasicLit{ValuePos: lit.ValuePos, Kind: token.STRING, Value: s}
1679 }
1680
1681
1682
1683
1684 func (p *printer) spec(spec ast.Spec, n int, doIndent bool) {
1685 switch s := spec.(type) {
1686 case *ast.ImportSpec:
1687 p.setComment(s.Doc)
1688 if s.Name != nil {
1689 p.expr(s.Name)
1690 p.print(blank)
1691 }
1692 p.expr(sanitizeImportPath(s.Path))
1693 p.setComment(s.Comment)
1694 p.setPos(s.EndPos)
1695
1696 case *ast.ValueSpec:
1697 if n != 1 {
1698 p.internalError("expected n = 1; got", n)
1699 }
1700 p.setComment(s.Doc)
1701 p.identList(s.Names, doIndent)
1702 if s.Type != nil {
1703 p.print(blank)
1704 p.expr(s.Type)
1705 }
1706 if s.Values != nil {
1707 p.print(blank, token.ASSIGN, blank)
1708 p.exprList(token.NoPos, s.Values, 1, 0, token.NoPos, false)
1709 }
1710 p.setComment(s.Comment)
1711
1712 case *ast.TypeSpec:
1713 p.setComment(s.Doc)
1714 p.expr(s.Name)
1715 if s.TypeParams != nil {
1716 p.parameters(s.TypeParams, typeTParam)
1717 }
1718 if n == 1 {
1719 p.print(blank)
1720 } else {
1721 p.print(vtab)
1722 }
1723 if s.Assign.IsValid() {
1724 p.print(token.ASSIGN, blank)
1725 }
1726 p.expr(s.Type)
1727 p.setComment(s.Comment)
1728
1729 default:
1730 panic("unreachable")
1731 }
1732 }
1733
1734 func (p *printer) genDecl(d *ast.GenDecl) {
1735 p.setComment(d.Doc)
1736 p.setPos(d.Pos())
1737 p.print(d.Tok, blank)
1738
1739 if d.Lparen.IsValid() || len(d.Specs) != 1 {
1740
1741 p.setPos(d.Lparen)
1742 p.print(token.LPAREN)
1743 if n := len(d.Specs); n > 0 {
1744 p.print(indent, formfeed)
1745 if n > 1 && (d.Tok == token.CONST || d.Tok == token.VAR) {
1746
1747
1748 keepType := keepTypeColumn(d.Specs)
1749 var line int
1750 for i, s := range d.Specs {
1751 if i > 0 {
1752 p.linebreak(p.lineFor(s.Pos()), 1, ignore, p.linesFrom(line) > 0)
1753 }
1754 p.recordLine(&line)
1755 p.valueSpec(s.(*ast.ValueSpec), keepType[i])
1756 }
1757 } else {
1758 var line int
1759 for i, s := range d.Specs {
1760 if i > 0 {
1761 p.linebreak(p.lineFor(s.Pos()), 1, ignore, p.linesFrom(line) > 0)
1762 }
1763 p.recordLine(&line)
1764 p.spec(s, n, false)
1765 }
1766 }
1767 p.print(unindent, formfeed)
1768 }
1769 p.setPos(d.Rparen)
1770 p.print(token.RPAREN)
1771
1772 } else if len(d.Specs) > 0 {
1773
1774 p.spec(d.Specs[0], 1, true)
1775 }
1776 }
1777
1778
1779
1780 type sizeCounter struct {
1781 hasNewline bool
1782 size int
1783 }
1784
1785 func (c *sizeCounter) Write(p []byte) (int, error) {
1786 if !c.hasNewline {
1787 for _, b := range p {
1788 if b == '\n' || b == '\f' {
1789 c.hasNewline = true
1790 break
1791 }
1792 }
1793 }
1794 c.size += len(p)
1795 return len(p), nil
1796 }
1797
1798
1799
1800
1801
1802 func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) {
1803
1804
1805
1806
1807 if size, found := p.nodeSizes[n]; found {
1808 return size
1809 }
1810
1811 size = maxSize + 1
1812 p.nodeSizes[n] = size
1813
1814
1815
1816
1817 cfg := Config{Mode: RawFormat}
1818 var counter sizeCounter
1819 if err := cfg.fprint(&counter, p.fset, n, p.nodeSizes); err != nil {
1820 return
1821 }
1822 if counter.size <= maxSize && !counter.hasNewline {
1823
1824 size = counter.size
1825 p.nodeSizes[n] = size
1826 }
1827 return
1828 }
1829
1830
1831 func (p *printer) numLines(n ast.Node) int {
1832 if from := n.Pos(); from.IsValid() {
1833 if to := n.End(); to.IsValid() {
1834 return p.lineFor(to) - p.lineFor(from) + 1
1835 }
1836 }
1837 return infinity
1838 }
1839
1840
1841 func (p *printer) bodySize(b *ast.BlockStmt, maxSize int) int {
1842 pos1 := b.Pos()
1843 pos2 := b.Rbrace
1844 if pos1.IsValid() && pos2.IsValid() && p.lineFor(pos1) != p.lineFor(pos2) {
1845
1846 return maxSize + 1
1847 }
1848 if len(b.List) > 5 {
1849
1850 return maxSize + 1
1851 }
1852
1853 bodySize := p.commentSizeBefore(p.posFor(pos2))
1854 for i, s := range b.List {
1855 if bodySize > maxSize {
1856 break
1857 }
1858 if i > 0 {
1859 bodySize += 2
1860 }
1861 bodySize += p.nodeSize(s, maxSize)
1862 }
1863 return bodySize
1864 }
1865
1866
1867
1868
1869
1870
1871 func (p *printer) funcBody(headerSize int, sep whiteSpace, b *ast.BlockStmt) {
1872 if b == nil {
1873 return
1874 }
1875
1876
1877 defer func(level int) {
1878 p.level = level
1879 }(p.level)
1880 p.level = 0
1881
1882 const maxSize = 100
1883 if headerSize+p.bodySize(b, maxSize) <= maxSize {
1884 p.print(sep)
1885 p.setPos(b.Lbrace)
1886 p.print(token.LBRACE)
1887 if len(b.List) > 0 {
1888 p.print(blank)
1889 for i, s := range b.List {
1890 if i > 0 {
1891 p.print(token.SEMICOLON, blank)
1892 }
1893 p.stmt(s, i == len(b.List)-1)
1894 }
1895 p.print(blank)
1896 }
1897 p.print(noExtraLinebreak)
1898 p.setPos(b.Rbrace)
1899 p.print(token.RBRACE, noExtraLinebreak)
1900 return
1901 }
1902
1903 if sep != ignore {
1904 p.print(blank)
1905 }
1906 p.block(b, 1)
1907 }
1908
1909
1910
1911
1912 func (p *printer) distanceFrom(startPos token.Pos, startOutCol int) int {
1913 if startPos.IsValid() && p.pos.IsValid() && p.posFor(startPos).Line == p.pos.Line {
1914 return p.out.Column - startOutCol
1915 }
1916 return infinity
1917 }
1918
1919 func (p *printer) funcDecl(d *ast.FuncDecl) {
1920 p.setComment(d.Doc)
1921 p.setPos(d.Pos())
1922 p.print(token.FUNC, blank)
1923
1924
1925
1926 startCol := p.out.Column - len("func ")
1927 if d.Recv != nil {
1928 p.parameters(d.Recv, funcParam)
1929 p.print(blank)
1930 }
1931 p.expr(d.Name)
1932 p.signature(d.Type)
1933 p.funcBody(p.distanceFrom(d.Pos(), startCol), vtab, d.Body)
1934 }
1935
1936 func (p *printer) decl(decl ast.Decl) {
1937 switch d := decl.(type) {
1938 case *ast.BadDecl:
1939 p.setPos(d.Pos())
1940 p.print("BadDecl")
1941 case *ast.GenDecl:
1942 p.genDecl(d)
1943 case *ast.FuncDecl:
1944 p.funcDecl(d)
1945 default:
1946 panic("unreachable")
1947 }
1948 }
1949
1950
1951
1952
1953 func declToken(decl ast.Decl) (tok token.Token) {
1954 tok = token.ILLEGAL
1955 switch d := decl.(type) {
1956 case *ast.GenDecl:
1957 tok = d.Tok
1958 case *ast.FuncDecl:
1959 tok = token.FUNC
1960 }
1961 return
1962 }
1963
1964 func (p *printer) declList(list []ast.Decl) {
1965 tok := token.ILLEGAL
1966 for _, d := range list {
1967 prev := tok
1968 tok = declToken(d)
1969
1970
1971
1972
1973
1974
1975
1976 if len(p.output) > 0 {
1977
1978
1979 min := 1
1980 if prev != tok || getDoc(d) != nil {
1981 min = 2
1982 }
1983
1984
1985 p.linebreak(p.lineFor(d.Pos()), min, ignore, tok == token.FUNC && p.numLines(d) > 1)
1986 }
1987 p.decl(d)
1988 }
1989 }
1990
1991 func (p *printer) file(src *ast.File) {
1992 p.setComment(src.Doc)
1993 p.setPos(src.Pos())
1994 p.print(token.PACKAGE, blank)
1995 p.expr(src.Name)
1996 p.declList(src.Decls)
1997 p.print(newline)
1998 }
1999
View as plain text