Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / github.com / rogpeppe / go-internal / modfile / print.go
1 // Copyright 2018 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // Package modfile implements parsing and formatting for
6 // go.mod files.
7 package modfile
8
9 import (
10         "bytes"
11         "fmt"
12         "strings"
13 )
14
15 func Format(f *FileSyntax) []byte {
16         pr := &printer{}
17         pr.file(f)
18         return pr.Bytes()
19 }
20
21 // A printer collects the state during printing of a file or expression.
22 type printer struct {
23         bytes.Buffer           // output buffer
24         comment      []Comment // pending end-of-line comments
25         margin       int       // left margin (indent), a number of tabs
26 }
27
28 // printf prints to the buffer.
29 func (p *printer) printf(format string, args ...interface{}) {
30         fmt.Fprintf(p, format, args...)
31 }
32
33 // indent returns the position on the current line, in bytes, 0-indexed.
34 func (p *printer) indent() int {
35         b := p.Bytes()
36         n := 0
37         for n < len(b) && b[len(b)-1-n] != '\n' {
38                 n++
39         }
40         return n
41 }
42
43 // newline ends the current line, flushing end-of-line comments.
44 func (p *printer) newline() {
45         if len(p.comment) > 0 {
46                 p.printf(" ")
47                 for i, com := range p.comment {
48                         if i > 0 {
49                                 p.trim()
50                                 p.printf("\n")
51                                 for i := 0; i < p.margin; i++ {
52                                         p.printf("\t")
53                                 }
54                         }
55                         p.printf("%s", strings.TrimSpace(com.Token))
56                 }
57                 p.comment = p.comment[:0]
58         }
59
60         p.trim()
61         p.printf("\n")
62         for i := 0; i < p.margin; i++ {
63                 p.printf("\t")
64         }
65 }
66
67 // trim removes trailing spaces and tabs from the current line.
68 func (p *printer) trim() {
69         // Remove trailing spaces and tabs from line we're about to end.
70         b := p.Bytes()
71         n := len(b)
72         for n > 0 && (b[n-1] == '\t' || b[n-1] == ' ') {
73                 n--
74         }
75         p.Truncate(n)
76 }
77
78 // file formats the given file into the print buffer.
79 func (p *printer) file(f *FileSyntax) {
80         for _, com := range f.Before {
81                 p.printf("%s", strings.TrimSpace(com.Token))
82                 p.newline()
83         }
84
85         for i, stmt := range f.Stmt {
86                 switch x := stmt.(type) {
87                 case *CommentBlock:
88                         // comments already handled
89                         p.expr(x)
90
91                 default:
92                         p.expr(x)
93                         p.newline()
94                 }
95
96                 for _, com := range stmt.Comment().After {
97                         p.printf("%s", strings.TrimSpace(com.Token))
98                         p.newline()
99                 }
100
101                 if i+1 < len(f.Stmt) {
102                         p.newline()
103                 }
104         }
105 }
106
107 func (p *printer) expr(x Expr) {
108         // Emit line-comments preceding this expression.
109         if before := x.Comment().Before; len(before) > 0 {
110                 // Want to print a line comment.
111                 // Line comments must be at the current margin.
112                 p.trim()
113                 if p.indent() > 0 {
114                         // There's other text on the line. Start a new line.
115                         p.printf("\n")
116                 }
117                 // Re-indent to margin.
118                 for i := 0; i < p.margin; i++ {
119                         p.printf("\t")
120                 }
121                 for _, com := range before {
122                         p.printf("%s", strings.TrimSpace(com.Token))
123                         p.newline()
124                 }
125         }
126
127         switch x := x.(type) {
128         default:
129                 panic(fmt.Errorf("printer: unexpected type %T", x))
130
131         case *CommentBlock:
132                 // done
133
134         case *LParen:
135                 p.printf("(")
136         case *RParen:
137                 p.printf(")")
138
139         case *Line:
140                 sep := ""
141                 for _, tok := range x.Token {
142                         p.printf("%s%s", sep, tok)
143                         sep = " "
144                 }
145
146         case *LineBlock:
147                 for _, tok := range x.Token {
148                         p.printf("%s ", tok)
149                 }
150                 p.expr(&x.LParen)
151                 p.margin++
152                 for _, l := range x.Line {
153                         p.newline()
154                         p.expr(l)
155                 }
156                 p.margin--
157                 p.newline()
158                 p.expr(&x.RParen)
159         }
160
161         // Queue end-of-line comments for printing when we
162         // reach the end of the line.
163         p.comment = append(p.comment, x.Comment().Suffix...)
164 }