| // 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 { |
| if !pos.IsKnown() { |
| // TODO(mdempsky): Investigate restoring base.Fatalf. |
| 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 |
| } |
| |
| func (m *posMap) join(other *posMap) { |
| if m.bases == nil { |
| m.bases = make(map[*syntax.PosBase]*src.PosBase) |
| } |
| for k, v := range other.bases { |
| if m.bases[k] != nil { |
| base.Fatalf("duplicate posmap bases") |
| } |
| m.bases[k] = v |
| } |
| } |