-
Notifications
You must be signed in to change notification settings - Fork 232
/
posmap.go
77 lines (62 loc) · 1.65 KB
/
posmap.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package posmap
import (
"go/ast"
"sort"
"encr.dev/pkg/option"
)
func Build[NodeLike ast.Node](nodes ...NodeLike) Map[NodeLike] {
return (&Builder[NodeLike]{}).Add(nodes...).Build()
}
type Builder[NodeLike ast.Node] struct {
nodes []NodeLike
}
func (b *Builder[NodeLike]) Add(nodes ...NodeLike) *Builder[NodeLike] {
b.nodes = append(b.nodes, nodes...)
return b
}
func (b *Builder[NodeLike]) Build() Map[NodeLike] {
sort.Slice(b.nodes, func(i, j int) bool {
return b.nodes[i].Pos() < b.nodes[j].Pos()
})
return Map[NodeLike]{
nodes: b.nodes,
}
}
type Map[NodeLike ast.Node] struct {
nodes []NodeLike
}
func (m Map[NodeLike]) All() []NodeLike {
return m.nodes
}
func (m Map[NodeLike]) Within(node ast.Node) []NodeLike {
startIdx := sort.Search(len(m.nodes), func(i int) bool {
return m.nodes[i].Pos() >= node.Pos()
})
endIdx := startIdx
for endIdx < len(m.nodes) && m.nodes[endIdx].End() <= node.End() {
endIdx++
}
nodes := make([]NodeLike, endIdx-startIdx)
copy(nodes, m.nodes[startIdx:endIdx])
return nodes
}
func (m Map[NodeLike]) Containing(node ast.Node) option.Option[NodeLike] {
idx := sort.Search(len(m.nodes), func(i int) bool {
return m.nodes[i].Pos() >= node.Pos()
})
// The containing resource, if any, has a starting position before this node
// and an ending position after this node.
if idx > 0 {
candidate := m.nodes[idx-1]
if candidate.Pos() <= node.Pos() && candidate.End() >= node.End() {
return option.Some(candidate)
}
}
if len(m.nodes) > 0 {
candidate := m.nodes[0]
if candidate.Pos() <= node.Pos() && candidate.End() >= node.End() {
return option.Some(candidate)
}
}
return option.None[NodeLike]()
}