github.com/bir3/gocompiler@v0.3.205/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 return pr.Bytes() 20 } 21 22 // A printer collects the state during printing of a file or expression. 23 type printer struct { 24 bytes.Buffer // output buffer 25 comment []Comment // pending end-of-line comments 26 margin int // left margin (indent), a number of tabs 27 } 28 29 // printf prints to the buffer. 30 func (p *printer) printf(format string, args ...interface{}) { 31 fmt.Fprintf(p, format, args...) 32 } 33 34 // indent returns the position on the current line, in bytes, 0-indexed. 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 // newline ends the current line, flushing end-of-line comments. 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 // trim removes trailing spaces and tabs from the current line. 69 func (p *printer) trim() { 70 // Remove trailing spaces and tabs from line we're about to end. 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 // file formats the given file into the print buffer. 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 // comments already handled 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 // Emit line-comments preceding this expression. 110 if before := x.Comment().Before; len(before) > 0 { 111 // Want to print a line comment. 112 // Line comments must be at the current margin. 113 p.trim() 114 if p.indent() > 0 { 115 // There's other text on the line. Start a new line. 116 p.printf("\n") 117 } 118 // Re-indent to margin. 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 // done 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 // Queue end-of-line comments for printing when we 158 // reach the end of the line. 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 }