diff options
Diffstat (limited to 'src/cmd/compile/internal/noder/posmap.go')
-rw-r--r-- | src/cmd/compile/internal/noder/posmap.go | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/noder/posmap.go b/src/cmd/compile/internal/noder/posmap.go new file mode 100644 index 0000000..439daf4 --- /dev/null +++ b/src/cmd/compile/internal/noder/posmap.go @@ -0,0 +1,74 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package noder + +import ( + "cmd/compile/internal/base" + "cmd/compile/internal/syntax" + "cmd/internal/src" +) + +// A posMap handles mapping from syntax.Pos to src.XPos. +type posMap struct { + bases map[*syntax.PosBase]*src.PosBase + cache struct { + last *syntax.PosBase + base *src.PosBase + } +} + +type poser interface{ Pos() syntax.Pos } +type ender interface{ End() syntax.Pos } + +func (m *posMap) pos(p poser) src.XPos { return m.makeXPos(p.Pos()) } +func (m *posMap) end(p ender) src.XPos { return m.makeXPos(p.End()) } + +func (m *posMap) makeXPos(pos syntax.Pos) src.XPos { + // Predeclared objects (e.g., the result parameter for error.Error) + // do not have a position. + if !pos.IsKnown() { + return src.NoXPos + } + + posBase := m.makeSrcPosBase(pos.Base()) + return base.Ctxt.PosTable.XPos(src.MakePos(posBase, pos.Line(), pos.Col())) +} + +// makeSrcPosBase translates from a *syntax.PosBase to a *src.PosBase. +func (m *posMap) makeSrcPosBase(b0 *syntax.PosBase) *src.PosBase { + // fast path: most likely PosBase hasn't changed + if m.cache.last == b0 { + return m.cache.base + } + + b1, ok := m.bases[b0] + if !ok { + fn := b0.Filename() + absfn := trimFilename(b0) + + if b0.IsFileBase() { + b1 = src.NewFileBase(fn, absfn) + } else { + // line directive base + p0 := b0.Pos() + p0b := p0.Base() + if p0b == b0 { + panic("infinite recursion in makeSrcPosBase") + } + p1 := src.MakePos(m.makeSrcPosBase(p0b), p0.Line(), p0.Col()) + b1 = src.NewLinePragmaBase(p1, fn, absfn, b0.Line(), b0.Col()) + } + if m.bases == nil { + m.bases = make(map[*syntax.PosBase]*src.PosBase) + } + m.bases[b0] = b1 + } + + // update cache + m.cache.last = b0 + m.cache.base = b1 + + return b1 +} |