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