56 lines
1.4 KiB
Go
56 lines
1.4 KiB
Go
// 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()
|
|
}
|