github.com/bir3/gocompiler@v0.9.2202/src/xvendor/golang.org/x/mod/modfile/print.go (about) 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 // Module file printer. 6 7 package modfile 8 9 import ( 10 "bytes" 11 "fmt" 12 "strings" 13 ) 14 15 // Format returns a go.mod file as a byte slice, formatted in standard style. 16 func Format(f *FileSyntax) []byte { 17 pr := &printer{} 18 pr.file(f) 19 20 // remove trailing blank lines 21 b := pr.Bytes() 22 for len(b) > 0 && b[len(b)-1] == '\n' && (len(b) == 1 || b[len(b)-2] == '\n') { 23 b = b[:len(b)-1] 24 } 25 return b 26 } 27 28 // A printer collects the state during printing of a file or expression. 29 type printer struct { 30 bytes.Buffer // output buffer 31 comment []Comment // pending end-of-line comments 32 margin int // left margin (indent), a number of tabs 33 } 34 35 // printf prints to the buffer. 36 func (p *printer) printf(format string, args ...interface{}) { 37 fmt.Fprintf(p, format, args...) 38 } 39 40 // indent returns the position on the current line, in bytes, 0-indexed. 41 func (p *printer) indent() int { 42 b := p.Bytes() 43 n := 0 44 for n < len(b) && b[len(b)-1-n] != '\n' { 45 n++ 46 } 47 return n 48 } 49 50 // newline ends the current line, flushing end-of-line comments. 51 func (p *printer) newline() { 52 if len(p.comment) > 0 { 53 p.printf(" ") 54 for i, com := range p.comment { 55 if i > 0 { 56 p.trim() 57 p.printf("\n") 58 for i := 0; i < p.margin; i++ { 59 p.printf("\t") 60 } 61 } 62 p.printf("%s", strings.TrimSpace(com.Token)) 63 } 64 p.comment = p.comment[:0] 65 } 66 67 p.trim() 68 if b := p.Bytes(); len(b) == 0 || (len(b) >= 2 && b[len(b)-1] == '\n' && b[len(b)-2] == '\n') { 69 // skip the blank line at top of file or after a blank line 70 } else { 71 p.printf("\n") 72 } 73 for i := 0; i < p.margin; i++ { 74 p.printf("\t") 75 } 76 } 77 78 // trim removes trailing spaces and tabs from the current line. 79 func (p *printer) trim() { 80 // Remove trailing spaces and tabs from line we're about to end. 81 b := p.Bytes() 82 n := len(b) 83 for n > 0 && (b[n-1] == '\t' || b[n-1] == ' ') { 84 n-- 85 } 86 p.Truncate(n) 87 } 88 89 // file formats the given file into the print buffer. 90 func (p *printer) file(f *FileSyntax) { 91 for _, com := range f.Before { 92 p.printf("%s", strings.TrimSpace(com.Token)) 93 p.newline() 94 } 95 96 for i, stmt := range f.Stmt { 97 switch x := stmt.(type) { 98 case *CommentBlock: 99 // comments already handled 100 p.expr(x) 101 102 default: 103 p.expr(x) 104 p.newline() 105 } 106 107 for _, com := range stmt.Comment().After { 108 p.printf("%s", strings.TrimSpace(com.Token)) 109 p.newline() 110 } 111 112 if i+1 < len(f.Stmt) { 113 p.newline() 114 } 115 } 116 } 117 118 func (p *printer) expr(x Expr) { 119 // Emit line-comments preceding this expression. 120 if before := x.Comment().Before; len(before) > 0 { 121 // Want to print a line comment. 122 // Line comments must be at the current margin. 123 p.trim() 124 if p.indent() > 0 { 125 // There's other text on the line. Start a new line. 126 p.printf("\n") 127 } 128 // Re-indent to margin. 129 for i := 0; i < p.margin; i++ { 130 p.printf("\t") 131 } 132 for _, com := range before { 133 p.printf("%s", strings.TrimSpace(com.Token)) 134 p.newline() 135 } 136 } 137 138 switch x := x.(type) { 139 default: 140 panic(fmt.Errorf("printer: unexpected type %T", x)) 141 142 case *CommentBlock: 143 // done 144 145 case *LParen: 146 p.printf("(") 147 case *RParen: 148 p.printf(")") 149 150 case *Line: 151 p.tokens(x.Token) 152 153 case *LineBlock: 154 p.tokens(x.Token) 155 p.printf(" ") 156 p.expr(&x.LParen) 157 p.margin++ 158 for _, l := range x.Line { 159 p.newline() 160 p.expr(l) 161 } 162 p.margin-- 163 p.newline() 164 p.expr(&x.RParen) 165 } 166 167 // Queue end-of-line comments for printing when we 168 // reach the end of the line. 169 p.comment = append(p.comment, x.Comment().Suffix...) 170 } 171 172 func (p *printer) tokens(tokens []string) { 173 sep := "" 174 for _, t := range tokens { 175 if t == "," || t == ")" || t == "]" || t == "}" { 176 sep = "" 177 } 178 p.printf("%s%s", sep, t) 179 sep = " " 180 if t == "(" || t == "[" || t == "{" { 181 sep = "" 182 } 183 } 184 }