github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/go/not-internal/imports/read.go (about) 1 // Copyright 2012 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 // Copied from Go distribution src/go/build/read.go. 6 7 package imports 8 9 import ( 10 "bufio" 11 "errors" 12 "io" 13 "unicode/utf8" 14 ) 15 16 type importReader struct { 17 b *bufio.Reader 18 buf []byte 19 peek byte 20 err error 21 eof bool 22 nerr int 23 } 24 25 func isIdent(c byte) bool { 26 return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '_' || c >= utf8.RuneSelf 27 } 28 29 var ( 30 errSyntax = errors.New("syntax error") 31 errNUL = errors.New("unexpected NUL in input") 32 ) 33 34 // syntaxError records a syntax error, but only if an I/O error has not already been recorded. 35 func (r *importReader) syntaxError() { 36 if r.err == nil { 37 r.err = errSyntax 38 } 39 } 40 41 // readByte reads the next byte from the input, saves it in buf, and returns it. 42 // If an error occurs, readByte records the error in r.err and returns 0. 43 func (r *importReader) readByte() byte { 44 c, err := r.b.ReadByte() 45 if err == nil { 46 r.buf = append(r.buf, c) 47 if c == 0 { 48 err = errNUL 49 } 50 } 51 if err != nil { 52 if err == io.EOF { 53 r.eof = true 54 } else if r.err == nil { 55 r.err = err 56 } 57 c = 0 58 } 59 return c 60 } 61 62 // peekByte returns the next byte from the input reader but does not advance beyond it. 63 // If skipSpace is set, peekByte skips leading spaces and comments. 64 func (r *importReader) peekByte(skipSpace bool) byte { 65 if r.err != nil { 66 if r.nerr++; r.nerr > 10000 { 67 panic("go/build: import reader looping") 68 } 69 return 0 70 } 71 72 // Use r.peek as first input byte. 73 // Don't just return r.peek here: it might have been left by peekByte(false) 74 // and this might be peekByte(true). 75 c := r.peek 76 if c == 0 { 77 c = r.readByte() 78 } 79 for r.err == nil && !r.eof { 80 if skipSpace { 81 // For the purposes of this reader, semicolons are never necessary to 82 // understand the input and are treated as spaces. 83 switch c { 84 case ' ', '\f', '\t', '\r', '\n', ';': 85 c = r.readByte() 86 continue 87 88 case '/': 89 c = r.readByte() 90 if c == '/' { 91 for c != '\n' && r.err == nil && !r.eof { 92 c = r.readByte() 93 } 94 } else if c == '*' { 95 var c1 byte 96 for (c != '*' || c1 != '/') && r.err == nil { 97 if r.eof { 98 r.syntaxError() 99 } 100 c, c1 = c1, r.readByte() 101 } 102 } else { 103 r.syntaxError() 104 } 105 c = r.readByte() 106 continue 107 } 108 } 109 break 110 } 111 r.peek = c 112 return r.peek 113 } 114 115 // nextByte is like peekByte but advances beyond the returned byte. 116 func (r *importReader) nextByte(skipSpace bool) byte { 117 c := r.peekByte(skipSpace) 118 r.peek = 0 119 return c 120 } 121 122 // readKeyword reads the given keyword from the input. 123 // If the keyword is not present, readKeyword records a syntax error. 124 func (r *importReader) readKeyword(kw string) { 125 r.peekByte(true) 126 for i := 0; i < len(kw); i++ { 127 if r.nextByte(false) != kw[i] { 128 r.syntaxError() 129 return 130 } 131 } 132 if isIdent(r.peekByte(false)) { 133 r.syntaxError() 134 } 135 } 136 137 // readIdent reads an identifier from the input. 138 // If an identifier is not present, readIdent records a syntax error. 139 func (r *importReader) readIdent() { 140 c := r.peekByte(true) 141 if !isIdent(c) { 142 r.syntaxError() 143 return 144 } 145 for isIdent(r.peekByte(false)) { 146 r.peek = 0 147 } 148 } 149 150 // readString reads a quoted string literal from the input. 151 // If an identifier is not present, readString records a syntax error. 152 func (r *importReader) readString(save *[]string) { 153 switch r.nextByte(true) { 154 case '`': 155 start := len(r.buf) - 1 156 for r.err == nil { 157 if r.nextByte(false) == '`' { 158 if save != nil { 159 *save = append(*save, string(r.buf[start:])) 160 } 161 break 162 } 163 if r.eof { 164 r.syntaxError() 165 } 166 } 167 case '"': 168 start := len(r.buf) - 1 169 for r.err == nil { 170 c := r.nextByte(false) 171 if c == '"' { 172 if save != nil { 173 *save = append(*save, string(r.buf[start:])) 174 } 175 break 176 } 177 if r.eof || c == '\n' { 178 r.syntaxError() 179 } 180 if c == '\\' { 181 r.nextByte(false) 182 } 183 } 184 default: 185 r.syntaxError() 186 } 187 } 188 189 // readImport reads an import clause - optional identifier followed by quoted string - 190 // from the input. 191 func (r *importReader) readImport(imports *[]string) { 192 c := r.peekByte(true) 193 if c == '.' { 194 r.peek = 0 195 } else if isIdent(c) { 196 r.readIdent() 197 } 198 r.readString(imports) 199 } 200 201 // ReadComments is like ioutil.ReadAll, except that it only reads the leading 202 // block of comments in the file. 203 func ReadComments(f io.Reader) ([]byte, error) { 204 r := &importReader{b: bufio.NewReader(f)} 205 r.peekByte(true) 206 if r.err == nil && !r.eof { 207 // Didn't reach EOF, so must have found a non-space byte. Remove it. 208 r.buf = r.buf[:len(r.buf)-1] 209 } 210 return r.buf, r.err 211 } 212 213 // ReadImports is like ioutil.ReadAll, except that it expects a Go file as input 214 // and stops reading the input once the imports have completed. 215 func ReadImports(f io.Reader, reportSyntaxError bool, imports *[]string) ([]byte, error) { 216 r := &importReader{b: bufio.NewReader(f)} 217 218 r.readKeyword("package") 219 r.readIdent() 220 for r.peekByte(true) == 'i' { 221 r.readKeyword("import") 222 if r.peekByte(true) == '(' { 223 r.nextByte(false) 224 for r.peekByte(true) != ')' && r.err == nil { 225 r.readImport(imports) 226 } 227 r.nextByte(false) 228 } else { 229 r.readImport(imports) 230 } 231 } 232 233 // If we stopped successfully before EOF, we read a byte that told us we were done. 234 // Return all but that last byte, which would cause a syntax error if we let it through. 235 if r.err == nil && !r.eof { 236 return r.buf[:len(r.buf)-1], nil 237 } 238 239 // If we stopped for a syntax error, consume the whole file so that 240 // we are sure we don't change the errors that go/parser returns. 241 if r.err == errSyntax && !reportSyntaxError { 242 r.err = nil 243 for r.err == nil && !r.eof { 244 r.readByte() 245 } 246 } 247 248 return r.buf, r.err 249 }