-
Notifications
You must be signed in to change notification settings - Fork 3
/
search.peg
103 lines (86 loc) · 2.16 KB
/
search.peg
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
{
package search
import (
"github.com/gobwas/glob"
"github.com/sirupsen/logrus"
"strings"
)
type Node interface {
Evaluate(input map[string]string) (bool, error)
}
type Term struct {
node Node
}
func (t *Term) Evaluate(input map[string]string) (bool, error) {
return t.node.Evaluate(input)
}
type AndNode struct {
Left, Right Node
}
func (n *AndNode) Evaluate(input map[string]string) (bool, error) {
for _, node := range []Node{n.Left, n.Right} {
matched, err := node.Evaluate(input)
if err != nil {
return false, err
}
if !matched {
return false, nil
}
}
return true, nil
}
type Variable struct {
Field string
Value glob.Glob
}
func (v *Variable) Evaluate(input map[string]string) (bool, error) {
logrus.Debug(v)
if v.Value == nil {
return false, nil
}
return v.Value.Match(strings.ToLower(input[v.Field])), nil
}
func toString(v interface{}) string {
var sb strings.Builder
value := v.([]interface{})
for _, i := range(value) {
switch b := i.(type) {
case []byte:
sb.WriteByte(b[0])
case []interface{}:
sb.WriteString(toString(i))
}
}
return sb.String()
}
}
Input = t:Expression !. {
return t, nil
}
WS = ' '
Expression = (
AndExpr /
Parenthetical /
Term
)
AndExpr = l:(Parenthetical / Term) WS+ `AND` WS+ r:Expression {
return &AndNode{l.(Node),r.(Node)}, nil
}
Parenthetical = '(' WS* e:Expression WS* ')' {
return e, nil
}
Term = left:BareValue ':' right:BareValue {
return &Variable{
Field: left.(string),
Value: glob.MustCompile(strings.ToLower(right.(string))),
}, nil
}
BareValue = bv:BareValueCharacter+ {
return toString(bv), nil
}
BareValueCharacter = (
[^ :()] /
`\:` { return []byte{':'}, nil } /
`\(` { return []byte{'('}, nil } /
`\)` { return []byte{')'}, nil }
)