123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435 |
-
-
-
-
-
-
- package token
-
- import (
- "fmt"
- "sort"
- "sync"
- )
-
-
-
-
-
-
-
-
- type Position struct {
- Filename string
- Offset int
- Line int
- Column int
- }
-
-
- func (pos *Position) IsValid() bool { return pos.Line > 0 }
-
-
-
-
-
-
-
-
- func (pos Position) String() string {
- s := pos.Filename
- if pos.IsValid() {
- if s != "" {
- s += ":"
- }
- s += fmt.Sprintf("%d:%d", pos.Line, pos.Column)
- }
- if s == "" {
- s = "-"
- }
- return s
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- type Pos int
-
-
-
-
-
-
- const NoPos Pos = 0
-
-
- func (p Pos) IsValid() bool {
- return p != NoPos
- }
-
-
-
-
-
-
-
- type File struct {
- set *FileSet
- name string
- base int
- size int
-
-
- lines []int
- infos []lineInfo
- }
-
-
- func (f *File) Name() string {
- return f.name
- }
-
-
- func (f *File) Base() int {
- return f.base
- }
-
-
- func (f *File) Size() int {
- return f.size
- }
-
-
- func (f *File) LineCount() int {
- f.set.mutex.RLock()
- n := len(f.lines)
- f.set.mutex.RUnlock()
- return n
- }
-
-
-
-
-
- func (f *File) AddLine(offset int) {
- f.set.mutex.Lock()
- if i := len(f.lines); (i == 0 || f.lines[i-1] < offset) && offset < f.size {
- f.lines = append(f.lines, offset)
- }
- f.set.mutex.Unlock()
- }
-
-
-
-
-
-
-
-
-
- func (f *File) SetLines(lines []int) bool {
-
- size := f.size
- for i, offset := range lines {
- if i > 0 && offset <= lines[i-1] || size <= offset {
- return false
- }
- }
-
-
- f.set.mutex.Lock()
- f.lines = lines
- f.set.mutex.Unlock()
- return true
- }
-
-
- func (f *File) SetLinesForContent(content []byte) {
- var lines []int
- line := 0
- for offset, b := range content {
- if line >= 0 {
- lines = append(lines, line)
- }
- line = -1
- if b == '\n' {
- line = offset + 1
- }
- }
-
-
- f.set.mutex.Lock()
- f.lines = lines
- f.set.mutex.Unlock()
- }
-
-
-
-
- type lineInfo struct {
-
- Offset int
- Filename string
- Line int
- }
-
-
-
-
-
-
-
-
-
- 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()
- }
-
-
-
-
-
- func (f *File) Pos(offset int) Pos {
- if offset > f.size {
- panic("illegal file offset")
- }
- return Pos(f.base + offset)
- }
-
-
-
-
-
- func (f *File) Offset(p Pos) int {
- if int(p) < f.base || int(p) > f.base+f.size {
- panic("illegal Pos value")
- }
- return int(p) - f.base
- }
-
-
-
-
- func (f *File) Line(p Pos) int {
-
- return f.Position(p).Line
- }
-
- func searchLineInfos(a []lineInfo, x int) int {
- return sort.Search(len(a), func(i int) bool { return a[i].Offset > x }) - 1
- }
-
-
- func (f *File) info(offset int) (filename string, line, column int) {
- filename = f.name
- if i := searchInts(f.lines, offset); i >= 0 {
- line, column = i+1, offset-f.lines[i]+1
- }
- if len(f.infos) > 0 {
-
- 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
- }
- }
- }
- 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
- }
-
-
-
-
- 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
- }
-
-
-
-
-
-
-
-
- type FileSet struct {
- mutex sync.RWMutex
- base int
- files []*File
- last *File
- }
-
-
- func NewFileSet() *FileSet {
- s := new(FileSet)
- s.base = 1
- return s
- }
-
-
-
-
- func (s *FileSet) Base() int {
- s.mutex.RLock()
- b := s.base
- s.mutex.RUnlock()
- return b
-
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- func (s *FileSet) AddFile(filename string, base, size int) *File {
- s.mutex.Lock()
- defer s.mutex.Unlock()
- if base < s.base || size < 0 {
- panic("illegal base or size")
- }
-
- f := &File{s, filename, base, size, []int{0}, nil}
- base += size + 1
- if base < 0 {
- panic("token.Pos offset overflow (> 2G of source code in file set)")
- }
-
- s.base = base
- s.files = append(s.files, f)
- s.last = f
- return f
- }
-
-
-
-
- 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]
- }
- 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 {
-
- 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]
-
- if int(p) <= f.base+f.size {
- s.last = f
- return f
- }
- }
- return nil
- }
-
-
-
-
-
- func (s *FileSet) File(p Pos) (f *File) {
- if p != NoPos {
- s.mutex.RLock()
- f = s.file(p)
- s.mutex.RUnlock()
- }
- return
- }
-
-
- 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
- }
-
-
-
-
- func searchInts(a []int, x int) int {
-
-
-
-
-
-
-
-
-
- i, j := 0, len(a)
- for i < j {
- h := i + (j-i)/2
-
- if a[h] <= x {
- i = h + 1
- } else {
- j = h
- }
- }
- return i - 1
- }
|