]> Cypherpunks repositories - gostls13.git/commitdiff
position.go: more flexible AddFile method
authorRobert Griesemer <gri@golang.org>
Sun, 21 Nov 2010 05:30:36 +0000 (21:30 -0800)
committerRobert Griesemer <gri@golang.org>
Sun, 21 Nov 2010 05:30:36 +0000 (21:30 -0800)
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

src/pkg/go/token/position.go
src/pkg/go/token/position_test.go

index 716a71beae20948dbc88a95caf028936ab2986ea..657b77bb5f21aa9d5e7be5a11a09cd0dc4025173 100644 (file)
@@ -63,12 +63,15 @@ func (pos Position) String() string {
 // It can be converted into a Position for a more convenient, but much
 // 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)
-// and then call File.Pos(offset) of that file with the offset of
-// the source location. Given a Pos value p for a specific file set
-// fset, the corresponding Position value is obtained by calling
-// fset.Position(p).
+// and then call File.Pos(offset) for that file. Given a Pos value p
+// for a specific file set fset, the corresponding Position value is
+// obtained by calling fset.Position(p).
 //
 // 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
@@ -100,7 +103,11 @@ func searchFiles(a []*File, x int) int {
 
 func (s *FileSet) file(p Pos) *File {
        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
 }
@@ -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.
 func (f *File) Size() int {
        return f.size
@@ -224,7 +237,7 @@ func (f *File) Pos(offset int) Pos {
        if offset > f.size {
                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
-// file set s and returns the file. Multiple files may have the same name.
-// File.Pos may be used to create file-specific position values from a
-// file offset.
+// Base returns the minimum base offset that must be provided to
+// AddFile when adding the next file.
 //
-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()
        defer s.mutex.Unlock()
-       f := &File{s, filename, s.base, size, []int{0}, nil}
-       s.base += size + 1 // +1 because EOF also has a position
-       if s.base < 0 {
+       if base < s.base || size < 0 {
+               panic("illegal base or size")
+       }
+       // 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)")
        }
+       // add the file to the file set
+       s.base = base
        s.index[f] = len(s.files)
        s.files = append(s.files, f)
        return f
index 286819e267e6e084612e763ae4dc0429360508a4..bf4e67c1360784439287d98eaf4c336f0763e2eb 100644 (file)
@@ -78,10 +78,11 @@ func verifyPositions(t *testing.T, fset *FileSet, f *File, lines []int) {
 
 
 func TestPositions(t *testing.T) {
+       const delta = 7 // a non-zero base offset increment
        fset := NewFileSet()
        for _, test := range tests {
                // 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 {
                        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) {
        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}
        // add lines individually and provide alternative line information
        for _, offs := range lines {