* tree-ssa-reassoc.c (reassociate_bb): Clarify code slighly.
[official-gcc.git] / libgo / go / go / build / read.go
blob29b8cdc786711ba08716bb1a42454eadf3ba5b44
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.
5 package build
7 import (
8 "bufio"
9 "errors"
10 "io"
11 "unicode/utf8"
14 type importReader struct {
15 b *bufio.Reader
16 buf []byte
17 peek byte
18 err error
19 eof bool
20 nerr int
23 func isIdent(c byte) bool {
24 return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '_' || c >= utf8.RuneSelf
27 var (
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() {
34 if r.err == nil {
35 r.err = errSyntax
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()
43 if err == nil {
44 r.buf = append(r.buf, c)
45 if c == 0 {
46 err = errNUL
49 if err != nil {
50 if err == io.EOF {
51 r.eof = true
52 } else if r.err == nil {
53 r.err = err
55 c = 0
57 return c
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 {
63 if r.err != nil {
64 if r.nerr++; r.nerr > 10000 {
65 panic("go/build: import reader looping")
67 return 0
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).
73 c := r.peek
74 if c == 0 {
75 c = r.readByte()
77 for r.err == nil && !r.eof {
78 if skipSpace {
79 // For the purposes of this reader, semicolons are never necessary to
80 // understand the input and are treated as spaces.
81 switch c {
82 case ' ', '\f', '\t', '\r', '\n', ';':
83 c = r.readByte()
84 continue
86 case '/':
87 c = r.readByte()
88 if c == '/' {
89 for c != '\n' && r.err == nil && !r.eof {
90 c = r.readByte()
92 } else if c == '*' {
93 var c1 byte
94 for (c != '*' || c1 != '/') && r.err == nil {
95 if r.eof {
96 r.syntaxError()
98 c, c1 = c1, r.readByte()
100 } else {
101 r.syntaxError()
103 c = r.readByte()
104 continue
107 break
109 r.peek = c
110 return r.peek
113 // nextByte is like peekByte but advances beyond the returned byte.
114 func (r *importReader) nextByte(skipSpace bool) byte {
115 c := r.peekByte(skipSpace)
116 r.peek = 0
117 return c
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) {
123 r.peekByte(true)
124 for i := 0; i < len(kw); i++ {
125 if r.nextByte(false) != kw[i] {
126 r.syntaxError()
127 return
130 if isIdent(r.peekByte(false)) {
131 r.syntaxError()
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)
139 if !isIdent(c) {
140 r.syntaxError()
141 return
143 for isIdent(r.peekByte(false)) {
144 r.peek = 0
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) {
152 case '`':
153 start := len(r.buf) - 1
154 for r.err == nil {
155 if r.nextByte(false) == '`' {
156 if save != nil {
157 *save = append(*save, string(r.buf[start:]))
159 break
161 if r.eof {
162 r.syntaxError()
165 case '"':
166 start := len(r.buf) - 1
167 for r.err == nil {
168 c := r.nextByte(false)
169 if c == '"' {
170 if save != nil {
171 *save = append(*save, string(r.buf[start:]))
173 break
175 if r.eof || c == '\n' {
176 r.syntaxError()
178 if c == '\\' {
179 r.nextByte(false)
182 default:
183 r.syntaxError()
187 // readImport reads an import clause - optional identifier followed by quoted string -
188 // from the input.
189 func (r *importReader) readImport(imports *[]string) {
190 c := r.peekByte(true)
191 if c == '.' {
192 r.peek = 0
193 } else if isIdent(c) {
194 r.readIdent()
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)}
203 r.peekByte(true)
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]
208 return r.buf, r.err
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")
217 r.readIdent()
218 for r.peekByte(true) == 'i' {
219 r.readKeyword("import")
220 if r.peekByte(true) == '(' {
221 r.nextByte(false)
222 for r.peekByte(true) != ')' && r.err == nil {
223 r.readImport(imports)
225 r.nextByte(false)
226 } else {
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 {
240 r.err = nil
241 for r.err == nil && !r.eof {
242 r.readByte()
246 return r.buf, r.err