~ubuntu-branches/ubuntu/vivid/golang/vivid

« back to all changes in this revision

Viewing changes to src/pkg/go/build/read.go

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2013-08-20 14:06:23 UTC
  • mfrom: (14.1.23 saucy-proposed)
  • Revision ID: package-import@ubuntu.com-20130820140623-b414jfxi3m0qkmrq
Tags: 2:1.1.2-2ubuntu1
* Merge from Debian unstable (LP: #1211749, #1202027). Remaining changes:
  - 016-armhf-elf-header.patch: Use correct ELF header for armhf binaries.
  - d/control,control.cross: Update Breaks/Replaces for Ubuntu
    versions to ensure smooth upgrades, regenerate control file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
package build
 
6
 
 
7
import (
 
8
        "bufio"
 
9
        "errors"
 
10
        "io"
 
11
)
 
12
 
 
13
type importReader struct {
 
14
        b    *bufio.Reader
 
15
        buf  []byte
 
16
        peek byte
 
17
        err  error
 
18
        eof  bool
 
19
        nerr int
 
20
}
 
21
 
 
22
func isIdent(c byte) bool {
 
23
        return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '_' || c >= 0x80
 
24
}
 
25
 
 
26
var (
 
27
        errSyntax = errors.New("syntax error")
 
28
        errNUL    = errors.New("unexpected NUL in input")
 
29
)
 
30
 
 
31
// syntaxError records a syntax error, but only if an I/O error has not already been recorded.
 
32
func (r *importReader) syntaxError() {
 
33
        if r.err == nil {
 
34
                r.err = errSyntax
 
35
        }
 
36
}
 
37
 
 
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()
 
42
        if err == nil {
 
43
                r.buf = append(r.buf, c)
 
44
                if c == 0 {
 
45
                        err = errNUL
 
46
                }
 
47
        }
 
48
        if err != nil {
 
49
                if err == io.EOF {
 
50
                        r.eof = true
 
51
                } else if r.err == nil {
 
52
                        r.err = err
 
53
                }
 
54
                c = 0
 
55
        }
 
56
        return c
 
57
}
 
58
 
 
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 {
 
62
        if r.err != nil {
 
63
                if r.nerr++; r.nerr > 10000 {
 
64
                        panic("go/build: import reader looping")
 
65
                }
 
66
                return 0
 
67
        }
 
68
 
 
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).
 
72
        c := r.peek
 
73
        if c == 0 {
 
74
                c = r.readByte()
 
75
        }
 
76
        for r.err == nil && !r.eof {
 
77
                if skipSpace {
 
78
                        // For the purposes of this reader, semicolons are never necessary to
 
79
                        // understand the input and are treated as spaces.
 
80
                        switch c {
 
81
                        case ' ', '\f', '\t', '\r', '\n', ';':
 
82
                                c = r.readByte()
 
83
                                continue
 
84
 
 
85
                        case '/':
 
86
                                c = r.readByte()
 
87
                                if c == '/' {
 
88
                                        for c != '\n' && r.err == nil && !r.eof {
 
89
                                                c = r.readByte()
 
90
                                        }
 
91
                                } else if c == '*' {
 
92
                                        var c1 byte
 
93
                                        for (c != '*' || c1 != '/') && r.err == nil {
 
94
                                                if r.eof {
 
95
                                                        r.syntaxError()
 
96
                                                }
 
97
                                                c, c1 = c1, r.readByte()
 
98
                                        }
 
99
                                } else {
 
100
                                        r.syntaxError()
 
101
                                }
 
102
                                c = r.readByte()
 
103
                                continue
 
104
                        }
 
105
                }
 
106
                break
 
107
        }
 
108
        r.peek = c
 
109
        return r.peek
 
110
}
 
111
 
 
112
// nextByte is like peekByte but advances beyond the returned byte.
 
113
func (r *importReader) nextByte(skipSpace bool) byte {
 
114
        c := r.peekByte(skipSpace)
 
115
        r.peek = 0
 
116
        return c
 
117
}
 
118
 
 
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) {
 
122
        r.peekByte(true)
 
123
        for i := 0; i < len(kw); i++ {
 
124
                if r.nextByte(false) != kw[i] {
 
125
                        r.syntaxError()
 
126
                        return
 
127
                }
 
128
        }
 
129
        if isIdent(r.peekByte(false)) {
 
130
                r.syntaxError()
 
131
        }
 
132
}
 
133
 
 
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)
 
138
        if !isIdent(c) {
 
139
                r.syntaxError()
 
140
                return
 
141
        }
 
142
        for isIdent(r.peekByte(false)) {
 
143
                r.peek = 0
 
144
        }
 
145
}
 
146
 
 
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) {
 
151
        case '`':
 
152
                for r.err == nil {
 
153
                        if r.nextByte(false) == '`' {
 
154
                                break
 
155
                        }
 
156
                        if r.eof {
 
157
                                r.syntaxError()
 
158
                        }
 
159
                }
 
160
        case '"':
 
161
                for r.err == nil {
 
162
                        c := r.nextByte(false)
 
163
                        if c == '"' {
 
164
                                break
 
165
                        }
 
166
                        if r.eof || c == '\n' {
 
167
                                r.syntaxError()
 
168
                        }
 
169
                        if c == '\\' {
 
170
                                r.nextByte(false)
 
171
                        }
 
172
                }
 
173
        default:
 
174
                r.syntaxError()
 
175
        }
 
176
}
 
177
 
 
178
// readImport reads an import clause - optional identifier followed by quoted string -
 
179
// from the input.
 
180
func (r *importReader) readImport() {
 
181
        c := r.peekByte(true)
 
182
        if c == '.' {
 
183
                r.peek = 0
 
184
        } else if isIdent(c) {
 
185
                r.readIdent()
 
186
        }
 
187
        r.readString()
 
188
}
 
189
 
 
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)}
 
194
        r.peekByte(true)
 
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]
 
198
        }
 
199
        return r.buf, r.err
 
200
}
 
201
 
 
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)}
 
206
 
 
207
        r.readKeyword("package")
 
208
        r.readIdent()
 
209
        for r.peekByte(true) == 'i' {
 
210
                r.readKeyword("import")
 
211
                if r.peekByte(true) == '(' {
 
212
                        r.nextByte(false)
 
213
                        for r.peekByte(true) != ')' && r.err == nil {
 
214
                                r.readImport()
 
215
                        }
 
216
                        r.nextByte(false)
 
217
                } else {
 
218
                        r.readImport()
 
219
                }
 
220
        }
 
221
 
 
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
 
226
        }
 
227
 
 
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 {
 
231
                r.err = nil
 
232
                for r.err == nil && !r.eof {
 
233
                        r.readByte()
 
234
                }
 
235
        }
 
236
 
 
237
        return r.buf, r.err
 
238
}