mirror of
https://github.com/golang/go
synced 2024-11-25 14:07:56 -07:00
position.go: more flexible AddFile method
This will make it easier to use Pos values together with suffix arrays by slightly de- coupling the mapping of Pos values to global offsets. R=rsc CC=golang-dev https://golang.org/cl/3231041
This commit is contained in:
parent
8cb8ba14a5
commit
e21aac29ba
@ -63,12 +63,15 @@ func (pos Position) String() string {
|
|||||||
// It can be converted into a Position for a more convenient, but much
|
// It can be converted into a Position for a more convenient, but much
|
||||||
// larger, representation.
|
// larger, representation.
|
||||||
//
|
//
|
||||||
// To create the Pos value for a specific source location, first add
|
// The Pos value for a given file is a number in the range [base, base+size],
|
||||||
|
// where base and size are specified when adding the file to the file set via
|
||||||
|
// AddFile.
|
||||||
|
//
|
||||||
|
// To create the Pos value for a specific source offset, first add
|
||||||
// the respective file to the current file set (via FileSet.AddFile)
|
// the respective file to the current file set (via FileSet.AddFile)
|
||||||
// and then call File.Pos(offset) of that file with the offset of
|
// and then call File.Pos(offset) for that file. Given a Pos value p
|
||||||
// the source location. Given a Pos value p for a specific file set
|
// for a specific file set fset, the corresponding Position value is
|
||||||
// fset, the corresponding Position value is obtained by calling
|
// obtained by calling fset.Position(p).
|
||||||
// fset.Position(p).
|
|
||||||
//
|
//
|
||||||
// Pos values can be compared directly with the usual comparison operators:
|
// Pos values can be compared directly with the usual comparison operators:
|
||||||
// If two Pos values p and q are in the same file, comparing p and q is
|
// If two Pos values p and q are in the same file, comparing p and q is
|
||||||
@ -100,7 +103,11 @@ func searchFiles(a []*File, x int) int {
|
|||||||
|
|
||||||
func (s *FileSet) file(p Pos) *File {
|
func (s *FileSet) file(p Pos) *File {
|
||||||
if i := searchFiles(s.files, int(p)); i >= 0 {
|
if i := searchFiles(s.files, int(p)); i >= 0 {
|
||||||
return s.files[i]
|
f := s.files[i]
|
||||||
|
// f.base <= int(p) by definition of searchFiles
|
||||||
|
if int(p) <= f.base+f.size {
|
||||||
|
return f
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -166,6 +173,12 @@ func (f *File) Name() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Base returns the base offset of file f as registered with AddFile.
|
||||||
|
func (f *File) Base() int {
|
||||||
|
return f.base
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Size returns the size of file f as registered with AddFile.
|
// Size returns the size of file f as registered with AddFile.
|
||||||
func (f *File) Size() int {
|
func (f *File) Size() int {
|
||||||
return f.size
|
return f.size
|
||||||
@ -224,7 +237,7 @@ func (f *File) Pos(offset int) Pos {
|
|||||||
if offset > f.size {
|
if offset > f.size {
|
||||||
panic("illegal file offset")
|
panic("illegal file offset")
|
||||||
}
|
}
|
||||||
return Pos(offset + f.base)
|
return Pos(f.base + offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -296,19 +309,43 @@ func NewFileSet() *FileSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// AddFile adds a new file with a given filename and file size to a the
|
// Base returns the minimum base offset that must be provided to
|
||||||
// file set s and returns the file. Multiple files may have the same name.
|
// AddFile when adding the next file.
|
||||||
// File.Pos may be used to create file-specific position values from a
|
|
||||||
// file offset.
|
|
||||||
//
|
//
|
||||||
func (s *FileSet) AddFile(filename string, size int) *File {
|
func (s *FileSet) Base() int {
|
||||||
|
return s.base
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// AddFile adds a new file with a given filename, base offset, and file size
|
||||||
|
// to the file set s and returns the file. Multiple files may have the same
|
||||||
|
// name. The base offset must not be smaller than the FileSet's Base(), and
|
||||||
|
// size must not be negative.
|
||||||
|
//
|
||||||
|
// Adding the file will set the file set's Base() value to base + size + 1
|
||||||
|
// as the minimum base value for the next file. The following relationship
|
||||||
|
// exists between a Pos value p for a given file offset offs:
|
||||||
|
//
|
||||||
|
// int(p) = base + offs
|
||||||
|
//
|
||||||
|
// with offs in the range [0, size] and thus p in the range [base, base+size].
|
||||||
|
// For convenience, File.Pos may be used to create file-specific position
|
||||||
|
// values from a file offset.
|
||||||
|
//
|
||||||
|
func (s *FileSet) AddFile(filename string, base, size int) *File {
|
||||||
s.mutex.Lock()
|
s.mutex.Lock()
|
||||||
defer s.mutex.Unlock()
|
defer s.mutex.Unlock()
|
||||||
f := &File{s, filename, s.base, size, []int{0}, nil}
|
if base < s.base || size < 0 {
|
||||||
s.base += size + 1 // +1 because EOF also has a position
|
panic("illegal base or size")
|
||||||
if s.base < 0 {
|
}
|
||||||
|
// base >= s.base && size >= 0
|
||||||
|
f := &File{s, filename, base, size, []int{0}, nil}
|
||||||
|
base += size + 1 // +1 because EOF also has a position
|
||||||
|
if base < 0 {
|
||||||
panic("token.Pos offset overflow (> 2G of source code in file set)")
|
panic("token.Pos offset overflow (> 2G of source code in file set)")
|
||||||
}
|
}
|
||||||
|
// add the file to the file set
|
||||||
|
s.base = base
|
||||||
s.index[f] = len(s.files)
|
s.index[f] = len(s.files)
|
||||||
s.files = append(s.files, f)
|
s.files = append(s.files, f)
|
||||||
return f
|
return f
|
||||||
|
@ -78,10 +78,11 @@ func verifyPositions(t *testing.T, fset *FileSet, f *File, lines []int) {
|
|||||||
|
|
||||||
|
|
||||||
func TestPositions(t *testing.T) {
|
func TestPositions(t *testing.T) {
|
||||||
|
const delta = 7 // a non-zero base offset increment
|
||||||
fset := NewFileSet()
|
fset := NewFileSet()
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
// add file and verify name and size
|
// add file and verify name and size
|
||||||
f := fset.AddFile(test.filename, test.size)
|
f := fset.AddFile(test.filename, fset.Base()+delta, test.size)
|
||||||
if f.Name() != test.filename {
|
if f.Name() != test.filename {
|
||||||
t.Errorf("expected filename %q; got %q", test.filename, f.Name())
|
t.Errorf("expected filename %q; got %q", test.filename, f.Name())
|
||||||
}
|
}
|
||||||
@ -118,7 +119,7 @@ func TestPositions(t *testing.T) {
|
|||||||
|
|
||||||
func TestLineInfo(t *testing.T) {
|
func TestLineInfo(t *testing.T) {
|
||||||
fset := NewFileSet()
|
fset := NewFileSet()
|
||||||
f := fset.AddFile("foo", 500)
|
f := fset.AddFile("foo", fset.Base(), 500)
|
||||||
lines := []int{0, 42, 77, 100, 210, 220, 277, 300, 333, 401}
|
lines := []int{0, 42, 77, 100, 210, 220, 277, 300, 333, 401}
|
||||||
// add lines individually and provide alternative line information
|
// add lines individually and provide alternative line information
|
||||||
for _, offs := range lines {
|
for _, offs := range lines {
|
||||||
|
Loading…
Reference in New Issue
Block a user