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.
13
type importReader struct {
22
func isIdent(c byte) bool {
23
return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '_' || c >= 0x80
27
errSyntax = errors.New("syntax error")
28
errNUL = errors.New("unexpected NUL in input")
31
// syntaxError records a syntax error, but only if an I/O error has not already been recorded.
32
func (r *importReader) syntaxError() {
38
// readByte reads the next byte from the input, saves it in buf, and returns it.
39
// If an error occurs, readByte records the error in r.err and returns 0.
40
func (r *importReader) readByte() byte {
41
c, err := r.b.ReadByte()
43
r.buf = append(r.buf, c)
51
} else if r.err == nil {
59
// peekByte returns the next byte from the input reader but does not advance beyond it.
60
// If skipSpace is set, peekByte skips leading spaces and comments.
61
func (r *importReader) peekByte(skipSpace bool) byte {
63
if r.nerr++; r.nerr > 10000 {
64
panic("go/build: import reader looping")
69
// Use r.peek as first input byte.
70
// Don't just return r.peek here: it might have been left by peekByte(false)
71
// and this might be peekByte(true).
76
for r.err == nil && !r.eof {
78
// For the purposes of this reader, semicolons are never necessary to
79
// understand the input and are treated as spaces.
81
case ' ', '\f', '\t', '\r', '\n', ';':
88
for c != '\n' && r.err == nil && !r.eof {
93
for (c != '*' || c1 != '/') && r.err == nil {
97
c, c1 = c1, r.readByte()
112
// nextByte is like peekByte but advances beyond the returned byte.
113
func (r *importReader) nextByte(skipSpace bool) byte {
114
c := r.peekByte(skipSpace)
119
// readKeyword reads the given keyword from the input.
120
// If the keyword is not present, readKeyword records a syntax error.
121
func (r *importReader) readKeyword(kw string) {
123
for i := 0; i < len(kw); i++ {
124
if r.nextByte(false) != kw[i] {
129
if isIdent(r.peekByte(false)) {
134
// readIdent reads an identifier from the input.
135
// If an identifier is not present, readIdent records a syntax error.
136
func (r *importReader) readIdent() {
137
c := r.peekByte(true)
142
for isIdent(r.peekByte(false)) {
147
// readString reads a quoted string literal from the input.
148
// If an identifier is not present, readString records a syntax error.
149
func (r *importReader) readString() {
150
switch r.nextByte(true) {
153
if r.nextByte(false) == '`' {
162
c := r.nextByte(false)
166
if r.eof || c == '\n' {
178
// readImport reads an import clause - optional identifier followed by quoted string -
180
func (r *importReader) readImport() {
181
c := r.peekByte(true)
184
} else if isIdent(c) {
190
// readComments is like ioutil.ReadAll, except that it only reads the leading
191
// block of comments in the file.
192
func readComments(f io.Reader) ([]byte, error) {
193
r := &importReader{b: bufio.NewReader(f)}
195
if r.err == nil && !r.eof {
196
// Didn't reach EOF, so must have found a non-space byte. Remove it.
197
r.buf = r.buf[:len(r.buf)-1]
202
// readImports is like ioutil.ReadAll, except that it expects a Go file as input
203
// and stops reading the input once the imports have completed.
204
func readImports(f io.Reader, reportSyntaxError bool) ([]byte, error) {
205
r := &importReader{b: bufio.NewReader(f)}
207
r.readKeyword("package")
209
for r.peekByte(true) == 'i' {
210
r.readKeyword("import")
211
if r.peekByte(true) == '(' {
213
for r.peekByte(true) != ')' && r.err == nil {
222
// If we stopped successfully before EOF, we read a byte that told us we were done.
223
// Return all but that last byte, which would cause a syntax error if we let it through.
224
if r.err == nil && !r.eof {
225
return r.buf[:len(r.buf)-1], nil
228
// If we stopped for a syntax error, consume the whole file so that
229
// we are sure we don't change the errors that go/parser returns.
230
if r.err == errSyntax && !reportSyntaxError {
232
for r.err == nil && !r.eof {