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.
14 type importReader
struct {
23 func isIdent(c
byte) bool {
24 return 'A' <= c
&& c
<= 'Z' ||
'a' <= c
&& c
<= 'z' ||
'0' <= c
&& c
<= '9' || c
== '_' || c
>= utf8
.RuneSelf
28 errSyntax
= errors
.New("syntax error")
29 errNUL
= errors
.New("unexpected NUL in input")
32 // syntaxError records a syntax error, but only if an I/O error has not already been recorded.
33 func (r
*importReader
) syntaxError() {
39 // readByte reads the next byte from the input, saves it in buf, and returns it.
40 // If an error occurs, readByte records the error in r.err and returns 0.
41 func (r
*importReader
) readByte() byte {
42 c
, err
:= r
.b
.ReadByte()
44 r
.buf
= append(r
.buf
, c
)
52 } else if r
.err
== nil {
60 // peekByte returns the next byte from the input reader but does not advance beyond it.
61 // If skipSpace is set, peekByte skips leading spaces and comments.
62 func (r
*importReader
) peekByte(skipSpace
bool) byte {
64 if r
.nerr
++; r
.nerr
> 10000 {
65 panic("go/build: import reader looping")
70 // Use r.peek as first input byte.
71 // Don't just return r.peek here: it might have been left by peekByte(false)
72 // and this might be peekByte(true).
77 for r
.err
== nil && !r
.eof
{
79 // For the purposes of this reader, semicolons are never necessary to
80 // understand the input and are treated as spaces.
82 case ' ', '\f', '\t', '\r', '\n', ';':
89 for c
!= '\n' && r
.err
== nil && !r
.eof
{
94 for (c
!= '*' || c1
!= '/') && r
.err
== nil {
98 c
, c1
= c1
, r
.readByte()
113 // nextByte is like peekByte but advances beyond the returned byte.
114 func (r
*importReader
) nextByte(skipSpace
bool) byte {
115 c
:= r
.peekByte(skipSpace
)
120 // readKeyword reads the given keyword from the input.
121 // If the keyword is not present, readKeyword records a syntax error.
122 func (r
*importReader
) readKeyword(kw
string) {
124 for i
:= 0; i
< len(kw
); i
++ {
125 if r
.nextByte(false) != kw
[i
] {
130 if isIdent(r
.peekByte(false)) {
135 // readIdent reads an identifier from the input.
136 // If an identifier is not present, readIdent records a syntax error.
137 func (r
*importReader
) readIdent() {
138 c
:= r
.peekByte(true)
143 for isIdent(r
.peekByte(false)) {
148 // readString reads a quoted string literal from the input.
149 // If an identifier is not present, readString records a syntax error.
150 func (r
*importReader
) readString(save
*[]string) {
151 switch r
.nextByte(true) {
153 start
:= len(r
.buf
) - 1
155 if r
.nextByte(false) == '`' {
157 *save
= append(*save
, string(r
.buf
[start
:]))
166 start
:= len(r
.buf
) - 1
168 c
:= r
.nextByte(false)
171 *save
= append(*save
, string(r
.buf
[start
:]))
175 if r
.eof || c
== '\n' {
187 // readImport reads an import clause - optional identifier followed by quoted string -
189 func (r
*importReader
) readImport(imports
*[]string) {
190 c
:= r
.peekByte(true)
193 } else if isIdent(c
) {
196 r
.readString(imports
)
199 // readComments is like ioutil.ReadAll, except that it only reads the leading
200 // block of comments in the file.
201 func readComments(f io
.Reader
) ([]byte, error
) {
202 r
:= &importReader
{b
: bufio
.NewReader(f
)}
204 if r
.err
== nil && !r
.eof
{
205 // Didn't reach EOF, so must have found a non-space byte. Remove it.
206 r
.buf
= r
.buf
[:len(r
.buf
)-1]
211 // readImports is like ioutil.ReadAll, except that it expects a Go file as input
212 // and stops reading the input once the imports have completed.
213 func readImports(f io
.Reader
, reportSyntaxError
bool, imports
*[]string) ([]byte, error
) {
214 r
:= &importReader
{b
: bufio
.NewReader(f
)}
216 r
.readKeyword("package")
218 for r
.peekByte(true) == 'i' {
219 r
.readKeyword("import")
220 if r
.peekByte(true) == '(' {
222 for r
.peekByte(true) != ')' && r
.err
== nil {
223 r
.readImport(imports
)
227 r
.readImport(imports
)
231 // If we stopped successfully before EOF, we read a byte that told us we were done.
232 // Return all but that last byte, which would cause a syntax error if we let it through.
233 if r
.err
== nil && !r
.eof
{
234 return r
.buf
[:len(r
.buf
)-1], nil
237 // If we stopped for a syntax error, consume the whole file so that
238 // we are sure we don't change the errors that go/parser returns.
239 if r
.err
== errSyntax
&& !reportSyntaxError
{
241 for r
.err
== nil && !r
.eof
{