1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
|
// Package parseutil contains various utilities for parsing GoAWK source code.
package parseutil
import (
"bytes"
"io"
)
// FileReader serves two purposes:
// 1. read input sources and join them into a single source (slice of bytes)
// 2. track the lines counts of each input source
type FileReader struct {
files []file
source bytes.Buffer
}
type file struct {
path string
lines int
}
// AddFile adds a single source file.
func (fr *FileReader) AddFile(path string, source io.Reader) error {
curLen := fr.source.Len()
_, err := fr.source.ReadFrom(source)
if err != nil {
return err
}
if !bytes.HasSuffix(fr.source.Bytes(), []byte("\n")) {
// Append newline to file in case it doesn't end with one
fr.source.WriteByte('\n')
}
content := fr.source.Bytes()[curLen:]
lines := bytes.Count(content, []byte("\n"))
fr.files = append(fr.files, file{path, lines})
return nil
}
// FileLine resolves an overall line number from the concatenated source code
// to the local line number in that source file (identified by path).
func (fr *FileReader) FileLine(line int) (path string, fileLine int) {
startLine := 1
for _, f := range fr.files {
if line >= startLine && line < startLine+f.lines {
return f.path, line - startLine + 1
}
startLine += f.lines
}
return "", 0
}
// Source returns the concatenated source code from all files added.
func (fr *FileReader) Source() []byte {
return fr.source.Bytes()
}
|