1 package compiler
2
3
4
5
6 import (
7 "fmt"
8 "reflect"
9
10 "github.com/gobwas/glob/match"
11 "github.com/gobwas/glob/syntax/ast"
12 "github.com/gobwas/glob/util/runes"
13 )
14
15 func optimizeMatcher(matcher match.Matcher) match.Matcher {
16 switch m := matcher.(type) {
17
18 case match.Any:
19 if len(m.Separators) == 0 {
20 return match.NewSuper()
21 }
22
23 case match.AnyOf:
24 if len(m.Matchers) == 1 {
25 return m.Matchers[0]
26 }
27
28 return m
29
30 case match.List:
31 if m.Not == false && len(m.List) == 1 {
32 return match.NewText(string(m.List))
33 }
34
35 return m
36
37 case match.BTree:
38 m.Left = optimizeMatcher(m.Left)
39 m.Right = optimizeMatcher(m.Right)
40
41 r, ok := m.Value.(match.Text)
42 if !ok {
43 return m
44 }
45
46 var (
47 leftNil = m.Left == nil
48 rightNil = m.Right == nil
49 )
50 if leftNil && rightNil {
51 return match.NewText(r.Str)
52 }
53
54 _, leftSuper := m.Left.(match.Super)
55 lp, leftPrefix := m.Left.(match.Prefix)
56 la, leftAny := m.Left.(match.Any)
57
58 _, rightSuper := m.Right.(match.Super)
59 rs, rightSuffix := m.Right.(match.Suffix)
60 ra, rightAny := m.Right.(match.Any)
61
62 switch {
63 case leftSuper && rightSuper:
64 return match.NewContains(r.Str, false)
65
66 case leftSuper && rightNil:
67 return match.NewSuffix(r.Str)
68
69 case rightSuper && leftNil:
70 return match.NewPrefix(r.Str)
71
72 case leftNil && rightSuffix:
73 return match.NewPrefixSuffix(r.Str, rs.Suffix)
74
75 case rightNil && leftPrefix:
76 return match.NewPrefixSuffix(lp.Prefix, r.Str)
77
78 case rightNil && leftAny:
79 return match.NewSuffixAny(r.Str, la.Separators)
80
81 case leftNil && rightAny:
82 return match.NewPrefixAny(r.Str, ra.Separators)
83 }
84
85 return m
86 }
87
88 return matcher
89 }
90
91 func compileMatchers(matchers []match.Matcher) (match.Matcher, error) {
92 if len(matchers) == 0 {
93 return nil, fmt.Errorf("compile error: need at least one matcher")
94 }
95 if len(matchers) == 1 {
96 return matchers[0], nil
97 }
98 if m := glueMatchers(matchers); m != nil {
99 return m, nil
100 }
101
102 idx := -1
103 maxLen := -1
104 var val match.Matcher
105 for i, matcher := range matchers {
106 if l := matcher.Len(); l != -1 && l >= maxLen {
107 maxLen = l
108 idx = i
109 val = matcher
110 }
111 }
112
113 if val == nil {
114 r, err := compileMatchers(matchers[1:])
115 if err != nil {
116 return nil, err
117 }
118 return match.NewBTree(matchers[0], nil, r), nil
119 }
120
121 left := matchers[:idx]
122 var right []match.Matcher
123 if len(matchers) > idx+1 {
124 right = matchers[idx+1:]
125 }
126
127 var l, r match.Matcher
128 var err error
129 if len(left) > 0 {
130 l, err = compileMatchers(left)
131 if err != nil {
132 return nil, err
133 }
134 }
135
136 if len(right) > 0 {
137 r, err = compileMatchers(right)
138 if err != nil {
139 return nil, err
140 }
141 }
142
143 return match.NewBTree(val, l, r), nil
144 }
145
146 func glueMatchers(matchers []match.Matcher) match.Matcher {
147 if m := glueMatchersAsEvery(matchers); m != nil {
148 return m
149 }
150 if m := glueMatchersAsRow(matchers); m != nil {
151 return m
152 }
153 return nil
154 }
155
156 func glueMatchersAsRow(matchers []match.Matcher) match.Matcher {
157 if len(matchers) <= 1 {
158 return nil
159 }
160
161 var (
162 c []match.Matcher
163 l int
164 )
165 for _, matcher := range matchers {
166 if ml := matcher.Len(); ml == -1 {
167 return nil
168 } else {
169 c = append(c, matcher)
170 l += ml
171 }
172 }
173 return match.NewRow(l, c...)
174 }
175
176 func glueMatchersAsEvery(matchers []match.Matcher) match.Matcher {
177 if len(matchers) <= 1 {
178 return nil
179 }
180
181 var (
182 hasAny bool
183 hasSuper bool
184 hasSingle bool
185 min int
186 separator []rune
187 )
188
189 for i, matcher := range matchers {
190 var sep []rune
191
192 switch m := matcher.(type) {
193 case match.Super:
194 sep = []rune{}
195 hasSuper = true
196
197 case match.Any:
198 sep = m.Separators
199 hasAny = true
200
201 case match.Single:
202 sep = m.Separators
203 hasSingle = true
204 min++
205
206 case match.List:
207 if !m.Not {
208 return nil
209 }
210 sep = m.List
211 hasSingle = true
212 min++
213
214 default:
215 return nil
216 }
217
218
219 if i == 0 {
220 separator = sep
221 }
222
223 if runes.Equal(sep, separator) {
224 continue
225 }
226
227 return nil
228 }
229
230 if hasSuper && !hasAny && !hasSingle {
231 return match.NewSuper()
232 }
233
234 if hasAny && !hasSuper && !hasSingle {
235 return match.NewAny(separator)
236 }
237
238 if (hasAny || hasSuper) && min > 0 && len(separator) == 0 {
239 return match.NewMin(min)
240 }
241
242 every := match.NewEveryOf()
243
244 if min > 0 {
245 every.Add(match.NewMin(min))
246
247 if !hasAny && !hasSuper {
248 every.Add(match.NewMax(min))
249 }
250 }
251
252 if len(separator) > 0 {
253 every.Add(match.NewContains(string(separator), true))
254 }
255
256 return every
257 }
258
259 func minimizeMatchers(matchers []match.Matcher) []match.Matcher {
260 var done match.Matcher
261 var left, right, count int
262
263 for l := 0; l < len(matchers); l++ {
264 for r := len(matchers); r > l; r-- {
265 if glued := glueMatchers(matchers[l:r]); glued != nil {
266 var swap bool
267
268 if done == nil {
269 swap = true
270 } else {
271 cl, gl := done.Len(), glued.Len()
272 swap = cl > -1 && gl > -1 && gl > cl
273 swap = swap || count < r-l
274 }
275
276 if swap {
277 done = glued
278 left = l
279 right = r
280 count = r - l
281 }
282 }
283 }
284 }
285
286 if done == nil {
287 return matchers
288 }
289
290 next := append(append([]match.Matcher{}, matchers[:left]...), done)
291 if right < len(matchers) {
292 next = append(next, matchers[right:]...)
293 }
294
295 if len(next) == len(matchers) {
296 return next
297 }
298
299 return minimizeMatchers(next)
300 }
301
302
303 func minimizeTree(tree *ast.Node) *ast.Node {
304 switch tree.Kind {
305 case ast.KindAnyOf:
306 return minimizeTreeAnyOf(tree)
307 default:
308 return nil
309 }
310 }
311
312
313
314
315
316 func minimizeTreeAnyOf(tree *ast.Node) *ast.Node {
317 if !areOfSameKind(tree.Children, ast.KindPattern) {
318 return nil
319 }
320
321 commonLeft, commonRight := commonChildren(tree.Children)
322 commonLeftCount, commonRightCount := len(commonLeft), len(commonRight)
323 if commonLeftCount == 0 && commonRightCount == 0 {
324 return nil
325 }
326
327 var result []*ast.Node
328 if commonLeftCount > 0 {
329 result = append(result, ast.NewNode(ast.KindPattern, nil, commonLeft...))
330 }
331
332 var anyOf []*ast.Node
333 for _, child := range tree.Children {
334 reuse := child.Children[commonLeftCount : len(child.Children)-commonRightCount]
335 var node *ast.Node
336 if len(reuse) == 0 {
337
338
339 node = ast.NewNode(ast.KindNothing, nil)
340 } else {
341 node = ast.NewNode(ast.KindPattern, nil, reuse...)
342 }
343 anyOf = appendIfUnique(anyOf, node)
344 }
345 switch {
346 case len(anyOf) == 1 && anyOf[0].Kind != ast.KindNothing:
347 result = append(result, anyOf[0])
348 case len(anyOf) > 1:
349 result = append(result, ast.NewNode(ast.KindAnyOf, nil, anyOf...))
350 }
351
352 if commonRightCount > 0 {
353 result = append(result, ast.NewNode(ast.KindPattern, nil, commonRight...))
354 }
355
356 return ast.NewNode(ast.KindPattern, nil, result...)
357 }
358
359 func commonChildren(nodes []*ast.Node) (commonLeft, commonRight []*ast.Node) {
360 if len(nodes) <= 1 {
361 return
362 }
363
364
365 idx := leastChildren(nodes)
366 if idx == -1 {
367 return
368 }
369 tree := nodes[idx]
370 treeLength := len(tree.Children)
371
372
373
374
375 commonRight = make([]*ast.Node, treeLength)
376 lastRight := treeLength
377
378 var (
379 breakLeft bool
380 breakRight bool
381 commonTotal int
382 )
383 for i, j := 0, treeLength-1; commonTotal < treeLength && j >= 0 && !(breakLeft && breakRight); i, j = i+1, j-1 {
384 treeLeft := tree.Children[i]
385 treeRight := tree.Children[j]
386
387 for k := 0; k < len(nodes) && !(breakLeft && breakRight); k++ {
388
389 if k == idx {
390 continue
391 }
392
393 restLeft := nodes[k].Children[i]
394 restRight := nodes[k].Children[j+len(nodes[k].Children)-treeLength]
395
396 breakLeft = breakLeft || !treeLeft.Equal(restLeft)
397
398
399 breakRight = breakRight || (!breakLeft && j <= i)
400 breakRight = breakRight || !treeRight.Equal(restRight)
401 }
402
403 if !breakLeft {
404 commonTotal++
405 commonLeft = append(commonLeft, treeLeft)
406 }
407 if !breakRight {
408 commonTotal++
409 lastRight = j
410 commonRight[j] = treeRight
411 }
412 }
413
414 commonRight = commonRight[lastRight:]
415
416 return
417 }
418
419 func appendIfUnique(target []*ast.Node, val *ast.Node) []*ast.Node {
420 for _, n := range target {
421 if reflect.DeepEqual(n, val) {
422 return target
423 }
424 }
425 return append(target, val)
426 }
427
428 func areOfSameKind(nodes []*ast.Node, kind ast.Kind) bool {
429 for _, n := range nodes {
430 if n.Kind != kind {
431 return false
432 }
433 }
434 return true
435 }
436
437 func leastChildren(nodes []*ast.Node) int {
438 min := -1
439 idx := -1
440 for i, n := range nodes {
441 if idx == -1 || (len(n.Children) < min) {
442 min = len(n.Children)
443 idx = i
444 }
445 }
446 return idx
447 }
448
449 func compileTreeChildren(tree *ast.Node, sep []rune) ([]match.Matcher, error) {
450 var matchers []match.Matcher
451 for _, desc := range tree.Children {
452 m, err := compile(desc, sep)
453 if err != nil {
454 return nil, err
455 }
456 matchers = append(matchers, optimizeMatcher(m))
457 }
458 return matchers, nil
459 }
460
461 func compile(tree *ast.Node, sep []rune) (m match.Matcher, err error) {
462 switch tree.Kind {
463 case ast.KindAnyOf:
464
465 if n := minimizeTree(tree); n != nil {
466 return compile(n, sep)
467 }
468 matchers, err := compileTreeChildren(tree, sep)
469 if err != nil {
470 return nil, err
471 }
472 return match.NewAnyOf(matchers...), nil
473
474 case ast.KindPattern:
475 if len(tree.Children) == 0 {
476 return match.NewNothing(), nil
477 }
478 matchers, err := compileTreeChildren(tree, sep)
479 if err != nil {
480 return nil, err
481 }
482 m, err = compileMatchers(minimizeMatchers(matchers))
483 if err != nil {
484 return nil, err
485 }
486
487 case ast.KindAny:
488 m = match.NewAny(sep)
489
490 case ast.KindSuper:
491 m = match.NewSuper()
492
493 case ast.KindSingle:
494 m = match.NewSingle(sep)
495
496 case ast.KindNothing:
497 m = match.NewNothing()
498
499 case ast.KindList:
500 l := tree.Value.(ast.List)
501 m = match.NewList([]rune(l.Chars), l.Not)
502
503 case ast.KindRange:
504 r := tree.Value.(ast.Range)
505 m = match.NewRange(r.Lo, r.Hi, r.Not)
506
507 case ast.KindText:
508 t := tree.Value.(ast.Text)
509 m = match.NewText(t.Text)
510
511 default:
512 return nil, fmt.Errorf("could not compile tree: unknown node type")
513 }
514
515 return optimizeMatcher(m), nil
516 }
517
518 func Compile(tree *ast.Node, sep []rune) (match.Matcher, error) {
519 m, err := compile(tree, sep)
520 if err != nil {
521 return nil, err
522 }
523
524 return m, nil
525 }
526
View as plain text