1// Copyright 2016 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
5// This file implements the compressed encoding of source
6// positions using a lookup table.
7
8package src
9
10// XPos is a more compact representation of Pos.
11type XPos struct {
12	index int32
13	lico
14}
15
16// NoXPos is a valid unknown position.
17var NoXPos XPos
18
19// IsKnown reports whether the position p is known.
20// XPos.IsKnown() matches Pos.IsKnown() for corresponding
21// positions.
22func (p XPos) IsKnown() bool {
23	return p.index != 0 || p.Line() != 0
24}
25
26// Before reports whether the position p comes before q in the source.
27// For positions with different bases, ordering is by base index.
28func (p XPos) Before(q XPos) bool {
29	n, m := p.index, q.index
30	return n < m || n == m && p.lico < q.lico
31}
32
33// After reports whether the position p comes after q in the source.
34// For positions with different bases, ordering is by base index.
35func (p XPos) After(q XPos) bool {
36	n, m := p.index, q.index
37	return n > m || n == m && p.lico > q.lico
38}
39
40// A PosTable tracks Pos -> XPos conversions and vice versa.
41// Its zero value is a ready-to-use PosTable.
42type PosTable struct {
43	baseList []*PosBase
44	indexMap map[*PosBase]int
45}
46
47// XPos returns the corresponding XPos for the given pos,
48// adding pos to t if necessary.
49func (t *PosTable) XPos(pos Pos) XPos {
50	m := t.indexMap
51	if m == nil {
52		// Create new list and map and populate with nil
53		// base so that NoPos always gets index 0.
54		t.baseList = append(t.baseList, nil)
55		m = map[*PosBase]int{nil: 0}
56		t.indexMap = m
57	}
58	i, ok := m[pos.base]
59	if !ok {
60		i = len(t.baseList)
61		t.baseList = append(t.baseList, pos.base)
62		t.indexMap[pos.base] = i
63	}
64	return XPos{int32(i), pos.lico}
65}
66
67// Pos returns the corresponding Pos for the given p.
68// If p cannot be translated via t, the function panics.
69func (t *PosTable) Pos(p XPos) Pos {
70	var base *PosBase
71	if p.index != 0 {
72		base = t.baseList[p.index]
73	}
74	return Pos{base, p.lico}
75}
76