diff options
| author | Ondřej Surý <ondrej@sury.org> | 2012-04-06 15:14:11 +0200 | 
|---|---|---|
| committer | Ondřej Surý <ondrej@sury.org> | 2012-04-06 15:14:11 +0200 | 
| commit | 505c19580e0f43fe5224431459cacb7c21edd93d (patch) | |
| tree | 79e2634c253d60afc0cc0b2f510dc7dcbb48497b /src/pkg/go/token/position.go | |
| parent | 1336a7c91e596c423a49d1194ea42d98bca0d958 (diff) | |
| download | golang-505c19580e0f43fe5224431459cacb7c21edd93d.tar.gz | |
Imported Upstream version 1upstream/1
Diffstat (limited to 'src/pkg/go/token/position.go')
| -rw-r--r-- | src/pkg/go/token/position.go | 277 | 
1 files changed, 144 insertions, 133 deletions
| diff --git a/src/pkg/go/token/position.go b/src/pkg/go/token/position.go index c559e19f8..647d1b770 100644 --- a/src/pkg/go/token/position.go +++ b/src/pkg/go/token/position.go @@ -12,6 +12,9 @@ import (  	"sync"  ) +// ----------------------------------------------------------------------------- +// Positions +  // Position describes an arbitrary source position  // including the file, line, and column location.  // A Position is valid if the line number is > 0. @@ -81,82 +84,8 @@ func (p Pos) IsValid() bool {  	return p != NoPos  } -func searchFiles(a []*File, x int) int { -	return sort.Search(len(a), func(i int) bool { return a[i].base > x }) - 1 -} - -func (s *FileSet) file(p Pos) *File { -	if f := s.last; f != nil && f.base <= int(p) && int(p) <= f.base+f.size { -		return f -	} -	if i := searchFiles(s.files, int(p)); i >= 0 { -		f := s.files[i] -		// f.base <= int(p) by definition of searchFiles -		if int(p) <= f.base+f.size { -			s.last = f -			return f -		} -	} -	return nil -} - -// File returns the file which contains the position p. -// If no such file is found (for instance for p == NoPos), -// the result is nil. -// -func (s *FileSet) File(p Pos) (f *File) { -	if p != NoPos { -		s.mutex.RLock() -		f = s.file(p) -		s.mutex.RUnlock() -	} -	return -} - -func (f *File) position(p Pos) (pos Position) { -	offset := int(p) - f.base -	pos.Offset = offset -	pos.Filename, pos.Line, pos.Column = f.info(offset) -	return -} - -// Position converts a Pos in the fileset into a general Position. -func (s *FileSet) Position(p Pos) (pos Position) { -	if p != NoPos { -		// TODO(gri) consider optimizing the case where p -		//           is in the last file added, or perhaps -		//           looked at - will eliminate one level -		//           of search -		s.mutex.RLock() -		if f := s.file(p); f != nil { -			pos = f.position(p) -		} -		s.mutex.RUnlock() -	} -	return -} - -type lineInfo struct { -	offset   int -	filename string -	line     int -} - -// AddLineInfo adds alternative file and line number information for -// a given file offset. The offset must be larger than the offset for -// the previously added alternative line info and smaller than the -// file size; otherwise the information is ignored. -// -// AddLineInfo is typically used to register alternative position -// information for //line filename:line comments in source files. -// -func (f *File) AddLineInfo(offset int, filename string, line int) { -	f.set.mutex.Lock() -	if i := len(f.infos); i == 0 || f.infos[i-1].offset < offset && offset < f.size { -		f.infos = append(f.infos, lineInfo{offset, filename, line}) -	} -	f.set.mutex.Unlock() -} +// ----------------------------------------------------------------------------- +// File  // A File is a handle for a file belonging to a FileSet.  // A File has a name, size, and line offset table. @@ -251,6 +180,32 @@ func (f *File) SetLinesForContent(content []byte) {  	f.set.mutex.Unlock()  } +// A lineInfo object describes alternative file and line number +// information (such as provided via a //line comment in a .go +// file) for a given file offset. +type lineInfo struct { +	// fields are exported to make them accessible to gob +	Offset   int +	Filename string +	Line     int +} + +// AddLineInfo adds alternative file and line number information for +// a given file offset. The offset must be larger than the offset for +// the previously added alternative line info and smaller than the +// file size; otherwise the information is ignored. +// +// AddLineInfo is typically used to register alternative position +// information for //line filename:line comments in source files. +// +func (f *File) AddLineInfo(offset int, filename string, line int) { +	f.set.mutex.Lock() +	if i := len(f.infos); i == 0 || f.infos[i-1].Offset < offset && offset < f.size { +		f.infos = append(f.infos, lineInfo{offset, filename, line}) +	} +	f.set.mutex.Unlock() +} +  // Pos returns the Pos value for the given file offset;  // the offset must be <= f.Size().  // f.Pos(f.Offset(p)) == p. @@ -281,43 +236,8 @@ func (f *File) Line(p Pos) int {  	return f.Position(p).Line  } -// Position returns the Position value for the given file position p; -// p must be a Pos value in that file or NoPos. -// -func (f *File) Position(p Pos) (pos Position) { -	if p != NoPos { -		if int(p) < f.base || int(p) > f.base+f.size { -			panic("illegal Pos value") -		} -		pos = f.position(p) -	} -	return -} - -func searchInts(a []int, x int) int { -	// This function body is a manually inlined version of: -	// -	//   return sort.Search(len(a), func(i int) bool { return a[i] > x }) - 1 -	// -	// With better compiler optimizations, this may not be needed in the -	// future, but at the moment this change improves the go/printer -	// benchmark performance by ~30%. This has a direct impact on the -	// speed of gofmt and thus seems worthwhile (2011-04-29). -	i, j := 0, len(a) -	for i < j { -		h := i + (j-i)/2 // avoid overflow when computing h -		// i ≤ h < j -		if a[h] <= x { -			i = h + 1 -		} else { -			j = h -		} -	} -	return i - 1 -} -  func searchLineInfos(a []lineInfo, x int) int { -	return sort.Search(len(a), func(i int) bool { return a[i].offset > x }) - 1 +	return sort.Search(len(a), func(i int) bool { return a[i].Offset > x }) - 1  }  // info returns the file name, line, and column number for a file offset. @@ -330,15 +250,38 @@ func (f *File) info(offset int) (filename string, line, column int) {  		// almost no files have extra line infos  		if i := searchLineInfos(f.infos, offset); i >= 0 {  			alt := &f.infos[i] -			filename = alt.filename -			if i := searchInts(f.lines, alt.offset); i >= 0 { -				line += alt.line - i - 1 +			filename = alt.Filename +			if i := searchInts(f.lines, alt.Offset); i >= 0 { +				line += alt.Line - i - 1  			}  		}  	}  	return  } +func (f *File) position(p Pos) (pos Position) { +	offset := int(p) - f.base +	pos.Offset = offset +	pos.Filename, pos.Line, pos.Column = f.info(offset) +	return +} + +// Position returns the Position value for the given file position p; +// p must be a Pos value in that file or NoPos. +// +func (f *File) Position(p Pos) (pos Position) { +	if p != NoPos { +		if int(p) < f.base || int(p) > f.base+f.size { +			panic("illegal Pos value") +		} +		pos = f.position(p) +	} +	return +} + +// ----------------------------------------------------------------------------- +// FileSet +  // A FileSet represents a set of source files.  // Methods of file sets are synchronized; multiple goroutines  // may invoke them concurrently. @@ -402,23 +345,91 @@ func (s *FileSet) AddFile(filename string, base, size int) *File {  	return f  } -// Files returns the files added to the file set. -func (s *FileSet) Files() <-chan *File { -	ch := make(chan *File) -	go func() { -		for i := 0; ; i++ { -			var f *File -			s.mutex.RLock() -			if i < len(s.files) { -				f = s.files[i] -			} -			s.mutex.RUnlock() -			if f == nil { -				break -			} -			ch <- f +// Iterate calls f for the files in the file set in the order they were added +// until f returns false. +//  +func (s *FileSet) Iterate(f func(*File) bool) { +	for i := 0; ; i++ { +		var file *File +		s.mutex.RLock() +		if i < len(s.files) { +			file = s.files[i]  		} -		close(ch) -	}() -	return ch +		s.mutex.RUnlock() +		if file == nil || !f(file) { +			break +		} +	} +} + +func searchFiles(a []*File, x int) int { +	return sort.Search(len(a), func(i int) bool { return a[i].base > x }) - 1 +} + +func (s *FileSet) file(p Pos) *File { +	// common case: p is in last file +	if f := s.last; f != nil && f.base <= int(p) && int(p) <= f.base+f.size { +		return f +	} +	// p is not in last file - search all files +	if i := searchFiles(s.files, int(p)); i >= 0 { +		f := s.files[i] +		// f.base <= int(p) by definition of searchFiles +		if int(p) <= f.base+f.size { +			s.last = f +			return f +		} +	} +	return nil +} + +// File returns the file that contains the position p. +// If no such file is found (for instance for p == NoPos), +// the result is nil. +// +func (s *FileSet) File(p Pos) (f *File) { +	if p != NoPos { +		s.mutex.RLock() +		f = s.file(p) +		s.mutex.RUnlock() +	} +	return +} + +// Position converts a Pos in the fileset into a general Position. +func (s *FileSet) Position(p Pos) (pos Position) { +	if p != NoPos { +		s.mutex.RLock() +		if f := s.file(p); f != nil { +			pos = f.position(p) +		} +		s.mutex.RUnlock() +	} +	return +} + +// ----------------------------------------------------------------------------- +// Helper functions + +func searchInts(a []int, x int) int { +	// This function body is a manually inlined version of: +	// +	//   return sort.Search(len(a), func(i int) bool { return a[i] > x }) - 1 +	// +	// With better compiler optimizations, this may not be needed in the +	// future, but at the moment this change improves the go/printer +	// benchmark performance by ~30%. This has a direct impact on the +	// speed of gofmt and thus seems worthwhile (2011-04-29). +	// TODO(gri): Remove this when compilers have caught up. +	i, j := 0, len(a) +	for i < j { +		h := i + (j-i)/2 // avoid overflow when computing h +		// i ≤ h < j +		if a[h] <= x { +			i = h + 1 +		} else { +			j = h +		} +	} +	return i - 1  } | 
