// }
//
//
-// Pos encodes a file:line pair, incorporating a simple delta encoding
-// scheme within a data object. See exportWriter.pos for details.
+// Pos encodes a file:line:column triple, incorporating a simple delta
+// encoding scheme within a data object. See exportWriter.pos for
+// details.
//
//
// Compiler-specific details.
)
// Current indexed export format version. Increase with each format change.
+// 1: added column details to Pos
// 0: Go1.11 encoding
-const iexportVersion = 0
+const iexportVersion = 1
// predeclReserved is the number of type offsets reserved for types
// implicitly declared in the universe block.
type exportWriter struct {
p *iexporter
- data intWriter
- currPkg *types.Pkg
- prevFile string
- prevLine int64
+ data intWriter
+ currPkg *types.Pkg
+ prevFile string
+ prevLine int64
+ prevColumn int64
}
func (p *iexporter) doDecl(n *Node) {
p := Ctxt.PosTable.Pos(pos)
file := p.Base().AbsFilename()
line := int64(p.RelLine())
+ column := int64(p.RelCol())
- // When file is the same as the last position (common case),
- // we can save a few bytes by delta encoding just the line
- // number.
+ // Encode position relative to the last position: column
+ // delta, then line delta, then file name. We reserve the
+ // bottom bit of the column and line deltas to encode whether
+ // the remaining fields are present.
//
// Note: Because data objects may be read out of order (or not
// at all), we can only apply delta encoding within a single
- // object. This is handled implicitly by tracking prevFile and
- // prevLine as fields of exportWriter.
-
- if file == w.prevFile {
- delta := line - w.prevLine
- w.int64(delta)
- if delta == deltaNewFile {
- w.int64(-1)
+ // object. This is handled implicitly by tracking prevFile,
+ // prevLine, and prevColumn as fields of exportWriter.
+
+ deltaColumn := (column - w.prevColumn) << 1
+ deltaLine := (line - w.prevLine) << 1
+
+ if file != w.prevFile {
+ deltaLine |= 1
+ }
+ if deltaLine != 0 {
+ deltaColumn |= 1
+ }
+
+ w.int64(deltaColumn)
+ if deltaColumn&1 != 0 {
+ w.int64(deltaLine)
+ if deltaLine&1 != 0 {
+ w.string(file)
}
- } else {
- w.int64(deltaNewFile)
- w.int64(line) // line >= 0
- w.string(file)
- w.prevFile = file
}
+
+ w.prevFile = file
w.prevLine = line
+ w.prevColumn = column
}
func (w *exportWriter) pkg(pkg *types.Pkg) {
strings.Reader
p *iimporter
- currPkg *types.Pkg
- prevBase *src.PosBase
- prevLine int64
+ currPkg *types.Pkg
+ prevBase *src.PosBase
+ prevLine int64
+ prevColumn int64
}
func (p *iimporter) newReader(off uint64, pkg *types.Pkg) *importReader {
func (r *importReader) pos() src.XPos {
delta := r.int64()
- if delta != deltaNewFile {
- r.prevLine += delta
- } else if l := r.int64(); l == -1 {
- r.prevLine += deltaNewFile
- } else {
- r.prevBase = r.posBase()
- r.prevLine = l
+ r.prevColumn += delta >> 1
+ if delta&1 != 0 {
+ delta = r.int64()
+ r.prevLine += delta >> 1
+ if delta&1 != 0 {
+ r.prevBase = r.posBase()
+ }
}
- if (r.prevBase == nil || r.prevBase.AbsFilename() == "") && r.prevLine == 0 {
+ if (r.prevBase == nil || r.prevBase.AbsFilename() == "") && r.prevLine == 0 && r.prevColumn == 0 {
// TODO(mdempsky): Remove once we reliably write
// position information for all nodes.
return src.NoXPos
if r.prevBase == nil {
Fatalf("missing posbase")
}
- pos := src.MakePos(r.prevBase, uint(r.prevLine), 0)
+ pos := src.MakePos(r.prevBase, uint(r.prevLine), uint(r.prevColumn))
return Ctxt.PosTable.XPos(pos)
}
p.prevFile = file
p.prevLine = line
- return p.fake.pos(file, line)
+ return p.fake.pos(file, line, 0)
}
// Synthesize a token.Pos
files map[string]*token.File
}
-func (s *fakeFileSet) pos(file string, line int) token.Pos {
+func (s *fakeFileSet) pos(file string, line, column int) token.Pos {
+ // TODO(mdempsky): Make use of column.
+
// Since we don't know the set of needed file positions, we
// reserve maxlines positions per file.
const maxlines = 64 * 1024
// If the export data version is not recognized or the format is otherwise
// compromised, an error is returned.
func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) {
- const currentVersion = 0
- version := -1
+ const currentVersion = 1
+ version := int64(-1)
defer func() {
if e := recover(); e != nil {
if version > currentVersion {
r := &intReader{bytes.NewReader(data), path}
- version = int(r.uint64())
+ version = int64(r.uint64())
switch version {
- case currentVersion:
+ case currentVersion, 0:
default:
errorf("unknown iexport format version %d", version)
}
r.Seek(sLen+dLen, io.SeekCurrent)
p := iimporter{
- ipath: path,
+ ipath: path,
+ version: int(version),
stringData: stringData,
stringCache: make(map[uint64]string),
}
type iimporter struct {
- ipath string
+ ipath string
+ version int
stringData []byte
stringCache map[uint64]string
currPkg *types.Package
prevFile string
prevLine int64
+ prevColumn int64
}
func (r *importReader) obj(name string) {
}
func (r *importReader) pos() token.Pos {
+ if r.p.version >= 1 {
+ r.posv1()
+ } else {
+ r.posv0()
+ }
+
+ if r.prevFile == "" && r.prevLine == 0 && r.prevColumn == 0 {
+ return token.NoPos
+ }
+ return r.p.fake.pos(r.prevFile, int(r.prevLine), int(r.prevColumn))
+}
+
+func (r *importReader) posv0() {
delta := r.int64()
if delta != deltaNewFile {
r.prevLine += delta
r.prevFile = r.string()
r.prevLine = l
}
+}
- if r.prevFile == "" && r.prevLine == 0 {
- return token.NoPos
+func (r *importReader) posv1() {
+ delta := r.int64()
+ r.prevColumn += delta >> 1
+ if delta&1 != 0 {
+ delta = r.int64()
+ r.prevLine += delta >> 1
+ if delta&1 != 0 {
+ r.prevFile = r.string()
+ }
}
-
- return r.p.fake.pos(r.prevFile, int(r.prevLine))
}
func (r *importReader) typ() types.Type {