-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathframes_deps.go
More file actions
237 lines (206 loc) · 5.29 KB
/
frames_deps.go
File metadata and controls
237 lines (206 loc) · 5.29 KB
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
package entitydebs
import (
"iter"
"math"
"slices"
"github.com/ndabAP/entitydebs/dependency"
"github.com/ndabAP/entitydebs/tokenize"
)
type (
deps struct {
// forest contains all dependency forest of all frames.
forest []dependency.Tree
// entities contains all entity tokens of all frames.
entities []*tokenize.Token
}
)
// Forest returns a forest of dependency trees that contain entity tokens.
// The first call to Forest constructs the forest, subsequent calls return the
// cached forest.
func (f *Frames) Forest() deps {
if f.deps.forest != nil {
return f.deps
}
deps := deps{
forest: make([]dependency.Tree, 0),
entities: make([]*tokenize.Token, 0),
}
// Accumulate all entities of all frames.
for _, frame := range f.frames {
for _, tokens := range frame.entities {
deps.entities = append(deps.entities, tokens...)
}
}
// Accumulate all dependency trees of all frames.
var offset int32
for index, tokens := range f.All() {
if index == 0 {
// Next frame, reset offset.
offset = 0
}
// We are looking for trees that contain entity tokens.
if !slices.ContainsFunc(tokens, func(token *tokenize.Token) bool {
return slices.Contains(deps.entities, token)
}) {
// Don't corrupt offset.
n := len(tokens)
if n > math.MaxInt32 {
panic("entitydebs: too many tokens")
}
offset += int32(n)
continue
}
offset += index
tree := dependency.Parse(offset, tokens)
deps.forest = append(deps.forest, tree)
}
f.deps = deps
return f.deps
}
// Trees returns all dependency trees of all frames.
func (f Frames) Trees() iter.Seq[dependency.Tree] {
return func(yield func(dependency.Tree) bool) {
for _, tree := range f.Forest().forest {
if !yield(tree) {
return
}
}
}
}
// Roots returns all root tokens for every tree.
func (deps deps) Roots() iter.Seq[*tokenize.Token] {
return func(yield func(*tokenize.Token) bool) {
for _, tree := range deps.forest {
if !yield(tree.Root()) {
return
}
}
}
}
// Entities returns all entities of all trees.
func (deps deps) Entities() iter.Seq[*tokenize.Token] {
return func(yield func(*tokenize.Token) bool) {
for _, entity := range deps.entities {
if !yield(entity) {
return
}
}
}
}
// Heads returns all head tokens from entity tokens. Every token is called
// with fn. If fn returns false, Heads is cancelled.
func (deps deps) Heads(fn func(t *tokenize.Token) bool) []*tokenize.Token {
var (
heads = make([]*tokenize.Token, 0)
seen = make(map[*tokenize.Token]struct{})
)
deps.walker(func(token *tokenize.Token, tree dependency.Tree) bool {
if !slices.Contains(deps.entities, token) {
return true
}
// Skip connected entity tokens.
var (
dependent = token
head *tokenize.Token
)
for {
head = tree.Head(dependent)
if head == nil {
// No head found.
return true
}
if _, ok := seen[head]; ok {
// Head already seen, next token.
return true
}
if !slices.Contains(deps.entities, head) {
// Final head found.
break
}
// Retry with head of head.
dependent = head
}
// Head found.
heads = append(heads, head)
if fn != nil && !fn(head) {
return false
}
seen[head] = struct{}{}
return true
})
return heads
}
// Dependents returns all dependent tokens from entity tokens.
func (deps deps) Dependents(fn func(t *tokenize.Token) bool) []*tokenize.Token {
dependents := make([]*tokenize.Token, 0)
deps.walker(func(token *tokenize.Token, tree dependency.Tree) bool {
if !slices.Contains(deps.entities, token) {
return true
}
head := token
for !tree.Dependents(head, func(dependent *tokenize.Token) bool {
// Follow multi-token entities.
if slices.Contains(deps.entities, dependent) {
// Retry with dependent of dependent.
head = dependent
return false
}
// Dependent found.
dependents = append(dependents, dependent)
if fn != nil && !fn(dependent) {
return false
}
return true
}) {
// No more dependents.
if head == token {
break
}
}
return true
})
return dependents
}
// Relationships returns all heads and dependents tokens from entity tokens.
func (deps deps) Relationships() iter.Seq[*tokenize.Token] {
return func(yield func(*tokenize.Token) bool) {
for _, head := range deps.Heads(nil) {
if !yield(head) {
return
}
}
for _, dependent := range deps.Dependents(nil) {
if !yield(dependent) {
return
}
}
}
}
// Dependencies iterates over all dependencies, with fn receiving the head,
// dependent, dependency edge label, and tree.
func (deps deps) Dependencies(
fn func(
head,
dependent *tokenize.Token,
dep tokenize.DependencyEdgeLabel,
tree dependency.Tree,
) bool,
) {
for _, tree := range deps.forest {
tree.Dependencies(func(head, dependent *tokenize.Token) bool {
dep := dependent.DependencyEdge.Label
return fn(head, dependent, dep, tree)
})
}
}
// Walk walks every token of every tree in a forest in pre-order and executes
// fn.
func (deps deps) Walk(fn func(token *tokenize.Token, tree dependency.Tree) bool) {
deps.walker(fn)
}
// walker walks every token of every tree in a forest and executes fn.
func (deps deps) walker(fn func(token *tokenize.Token, tree dependency.Tree) bool) {
for _, tree := range deps.forest {
tree.Walk(func(token *tokenize.Token) bool { return fn(token, tree) })
}
}