/
engine_glob.go
104 lines (90 loc) · 2.57 KB
/
engine_glob.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
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
package rule
import (
"bytes"
"hash/crc64"
"github.com/gobwas/glob"
)
type globMatchingEngine struct {
compiled glob.Glob
checksum uint64
table *crc64.Table
}
// Checksum of a saved pattern.
func (ge *globMatchingEngine) Checksum() uint64 {
return ge.checksum
}
// IsMatching determines whether the input matches the pattern.
func (ge *globMatchingEngine) IsMatching(pattern, matchAgainst string) (bool, error) {
if err := ge.compile(pattern); err != nil {
return false, err
}
return ge.compiled.Match(matchAgainst), nil
}
// ReplaceAllString is noop for now and always returns an error.
func (ge *globMatchingEngine) ReplaceAllString(_, _, _ string) (string, error) {
return "", ErrMethodNotImplemented
}
// FindStringSubmatch is noop for now and always returns an empty array
func (ge *globMatchingEngine) FindStringSubmatch(pattern, matchAgainst string) ([]string, error) {
return []string{}, nil
}
func (ge *globMatchingEngine) compile(pattern string) error {
if ge.table == nil {
ge.table = crc64.MakeTable(polynomial)
}
if checksum := crc64.Checksum([]byte(pattern), ge.table); checksum != ge.checksum {
compiled, err := compileGlob(pattern, '<', '>')
if err != nil {
return err
}
ge.checksum = checksum
ge.compiled = compiled
}
return nil
}
// delimiterIndices returns the first level delimiter indices from a string.
// It returns an error in case of unbalanced delimiters.
func delimiterIndices(s string, delimiterStart, delimiterEnd rune) ([]int, error) {
var level, idx int
idxs := make([]int, 0)
for ind := 0; ind < len(s); ind++ {
switch s[ind] {
case byte(delimiterStart):
if level++; level == 1 {
idx = ind
}
case byte(delimiterEnd):
if level--; level == 0 {
idxs = append(idxs, idx, ind+1)
} else if level < 0 {
return nil, ErrUnbalancedPattern
}
}
}
if level != 0 {
return nil, ErrUnbalancedPattern
}
return idxs, nil
}
func compileGlob(pattern string, delimiterStart, delimiterEnd rune) (glob.Glob, error) {
// Check if it is well-formed.
idxs, errBraces := delimiterIndices(pattern, delimiterStart, delimiterEnd)
if errBraces != nil {
return nil, errBraces
}
buffer := bytes.NewBufferString("")
var end int
for ind := 0; ind < len(idxs); ind += 2 {
// Set all values we are interested in.
raw := pattern[end:idxs[ind]]
end = idxs[ind+1]
patt := pattern[idxs[ind]+1 : end-1]
buffer.WriteString(glob.QuoteMeta(raw))
buffer.WriteString(patt)
}
// Add the remaining.
raw := pattern[end:]
buffer.WriteString(glob.QuoteMeta(raw))
// Compile full regexp.
return glob.Compile(buffer.String())
}