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