1// Copyright 2010 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package token 6 7import ( 8 "go/token" 9 "sync" 10) 11 12// ----------------------------------------------------------------------------- 13// File 14 15// A File is a handle for a file belonging to a FileSet. 16// A File has a name, size, line offset table and optionally source code. 17// 18type File struct { 19 *token.File 20 mutex sync.Mutex // protects source 21 source []string // optional, used by debugger to show source code. each line does NOT contain the final '\n' 22 line int // starting line of this file 23} 24 25// PositionFor returns the Position value for the given file position p. 26// If adjusted is set, the position may be adjusted by position-altering 27// //line comments; otherwise those comments are ignored. 28// p must be a Pos value in f or NoPos. 29// 30func (f *File) PositionFor(p token.Pos, adjusted bool) (pos token.Position) { 31 pos = f.File.PositionFor(p, adjusted) 32 if pos.IsValid() { 33 pos.Line += f.line 34 } 35 return pos 36} 37 38// Position returns the Position value for the given file position p. 39// Calling f.Position(p) is equivalent to calling f.PositionFor(p, true). 40// 41func (f *File) Position(p token.Pos) (pos token.Position) { 42 return f.PositionFor(p, true) 43} 44 45// Source returns the source code for the given file position p, if available. 46// 47func (f *File) Source(p token.Pos) (line string, pos token.Position) { 48 if p != token.NoPos { 49 pos = f.Position(p) 50 if pos.IsValid() { 51 f.mutex.Lock() 52 source := f.source 53 f.mutex.Unlock() 54 line := pos.Line - f.line 55 if line > 0 && line <= len(source) { 56 return source[line-1], pos 57 } 58 } 59 } 60 return "", pos 61} 62 63// SetSource sets the source code for the given file. 64// 65func (f *File) SetSource(source []string) { 66 f.mutex.Lock() 67 f.source = source 68 f.mutex.Unlock() 69} 70 71// SetSourceForContent computes and sets the source code for the given file. 72// 73func (f *File) SetSourceForContent(content []byte) { 74 str := string(content) 75 start, n := 0, len(str) 76 var source []string 77 for i := 0; i < n; i++ { 78 if str[i] == '\n' { 79 source = append(source, str[start:i]) 80 // skip '\n' 81 start = i + 1 82 } 83 } 84 if start < n { 85 source = append(source, str[start:]) 86 } 87 f.SetSource(source) 88} 89 90// ----------------------------------------------------------------------------- 91// FileSet 92 93// A FileSet represents a set of source files. 94// This is a wrapper for go/token.FileSet that adds a starting line offset to each file in the set 95// 96type FileSet struct { 97 token.FileSet 98 filemap map[*token.File]*File 99} 100 101// NewFileSet creates a new file set. 102func NewFileSet() *FileSet { 103 return &FileSet{ 104 FileSet: *token.NewFileSet(), 105 filemap: make(map[*token.File]*File), 106 } 107} 108 109// AddFile adds a new file with a given filename, base offset, and file size 110func (s *FileSet) AddFile(filename string, base, size, line int) *File { 111 innerf := s.FileSet.AddFile(filename, base, size) 112 f := &File{File: innerf, line: line} 113 s.filemap[innerf] = f 114 return f 115} 116 117// File returns the file that contains the position p. 118// If no such file is found (for instance for p == NoPos), 119// the result is nil. 120// 121func (s *FileSet) File(p token.Pos) (f *File) { 122 if p != token.NoPos { 123 innerf := s.FileSet.File(p) 124 f = s.filemap[innerf] 125 } 126 return 127} 128 129// PositionFor converts a Pos p in the fileset into a Position value. 130// If adjusted is set, the position may be adjusted by position-altering 131// //line comments; otherwise those comments are ignored. 132// p must be a Pos value in s or NoPos. 133// 134func (s *FileSet) PositionFor(p token.Pos, adjusted bool) (pos token.Position) { 135 if f := s.File(p); f != nil { 136 pos = f.PositionFor(p, adjusted) 137 } 138 return 139} 140 141// Position converts a Pos p in the fileset into a Position value. 142// Calling s.Position(p) is equivalent to calling s.PositionFor(p, true). 143// 144func (s *FileSet) Position(p token.Pos) (pos token.Position) { 145 return s.PositionFor(p, true) 146} 147 148// Source converts a Pos p in the fileset into a line of source code (if available) and a Position value. 149// 150func (s *FileSet) Source(p token.Pos) (line string, pos token.Position) { 151 if f := s.File(p); f != nil { 152 line, pos = f.Source(p) 153 } 154 return 155} 156