1
2
3
4
5
6
7 package modfile
8
9 import (
10 "bytes"
11 "fmt"
12 "strings"
13 )
14
15
16 func Format(f *FileSyntax) []byte {
17 pr := &printer{}
18 pr.file(f)
19 return pr.Bytes()
20 }
21
22
23 type printer struct {
24 bytes.Buffer
25 comment []Comment
26 margin int
27 }
28
29
30 func (p *printer) printf(format string, args ...interface{}) {
31 fmt.Fprintf(p, format, args...)
32 }
33
34
35 func (p *printer) indent() int {
36 b := p.Bytes()
37 n := 0
38 for n < len(b) && b[len(b)-1-n] != '\n' {
39 n++
40 }
41 return n
42 }
43
44
45 func (p *printer) newline() {
46 if len(p.comment) > 0 {
47 p.printf(" ")
48 for i, com := range p.comment {
49 if i > 0 {
50 p.trim()
51 p.printf("\n")
52 for i := 0; i < p.margin; i++ {
53 p.printf("\t")
54 }
55 }
56 p.printf("%s", strings.TrimSpace(com.Token))
57 }
58 p.comment = p.comment[:0]
59 }
60
61 p.trim()
62 p.printf("\n")
63 for i := 0; i < p.margin; i++ {
64 p.printf("\t")
65 }
66 }
67
68
69 func (p *printer) trim() {
70
71 b := p.Bytes()
72 n := len(b)
73 for n > 0 && (b[n-1] == '\t' || b[n-1] == ' ') {
74 n--
75 }
76 p.Truncate(n)
77 }
78
79
80 func (p *printer) file(f *FileSyntax) {
81 for _, com := range f.Before {
82 p.printf("%s", strings.TrimSpace(com.Token))
83 p.newline()
84 }
85
86 for i, stmt := range f.Stmt {
87 switch x := stmt.(type) {
88 case *CommentBlock:
89
90 p.expr(x)
91
92 default:
93 p.expr(x)
94 p.newline()
95 }
96
97 for _, com := range stmt.Comment().After {
98 p.printf("%s", strings.TrimSpace(com.Token))
99 p.newline()
100 }
101
102 if i+1 < len(f.Stmt) {
103 p.newline()
104 }
105 }
106 }
107
108 func (p *printer) expr(x Expr) {
109
110 if before := x.Comment().Before; len(before) > 0 {
111
112
113 p.trim()
114 if p.indent() > 0 {
115
116 p.printf("\n")
117 }
118
119 for i := 0; i < p.margin; i++ {
120 p.printf("\t")
121 }
122 for _, com := range before {
123 p.printf("%s", strings.TrimSpace(com.Token))
124 p.newline()
125 }
126 }
127
128 switch x := x.(type) {
129 default:
130 panic(fmt.Errorf("printer: unexpected type %T", x))
131
132 case *CommentBlock:
133
134
135 case *LParen:
136 p.printf("(")
137 case *RParen:
138 p.printf(")")
139
140 case *Line:
141 p.tokens(x.Token)
142
143 case *LineBlock:
144 p.tokens(x.Token)
145 p.printf(" ")
146 p.expr(&x.LParen)
147 p.margin++
148 for _, l := range x.Line {
149 p.newline()
150 p.expr(l)
151 }
152 p.margin--
153 p.newline()
154 p.expr(&x.RParen)
155 }
156
157
158
159 p.comment = append(p.comment, x.Comment().Suffix...)
160 }
161
162 func (p *printer) tokens(tokens []string) {
163 sep := ""
164 for _, t := range tokens {
165 if t == "," || t == ")" || t == "]" || t == "}" {
166 sep = ""
167 }
168 p.printf("%s%s", sep, t)
169 sep = " "
170 if t == "(" || t == "[" || t == "{" {
171 sep = ""
172 }
173 }
174 }
175
View as plain text