-
Notifications
You must be signed in to change notification settings - Fork 17
/
nodes.go
133 lines (118 loc) · 2.81 KB
/
nodes.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
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
package sigma
// NodeSimpleAnd is a list of matchers connected with logical conjunction
type NodeSimpleAnd []Branch
// Match implements Matcher
func (n NodeSimpleAnd) Match(e Event) (bool, bool) {
for _, b := range n {
match, applicable := b.Match(e)
if !match || !applicable {
return match, applicable
}
}
return true, true
}
// Reduce cleans up unneeded slices
// Static structures can be used if node only holds one or two elements
// Avoids pointless runtime loops
func (n NodeSimpleAnd) Reduce() Branch {
if len(n) == 1 {
return n[0]
}
if len(n) == 2 {
return &NodeAnd{L: n[0], R: n[1]}
}
return n
}
// NodeSimpleOr is a list of matchers connected with logical disjunction
type NodeSimpleOr []Branch
// Reduce cleans up unneeded slices
// Static structures can be used if node only holds one or two elements
// Avoids pointless runtime loops
func (n NodeSimpleOr) Reduce() Branch {
if len(n) == 1 {
return n[0]
}
if len(n) == 2 {
return &NodeOr{L: n[0], R: n[1]}
}
return n
}
// Match implements Matcher
func (n NodeSimpleOr) Match(e Event) (bool, bool) {
var oneApplicable bool
for _, b := range n {
match, applicable := b.Match(e)
if match {
return true, true
}
if applicable {
oneApplicable = true
}
}
return false, oneApplicable
}
// NodeNot negates a branch
type NodeNot struct {
B Branch
}
// Match implements Matcher
func (n NodeNot) Match(e Event) (bool, bool) {
match, applicable := n.B.Match(e)
if !applicable {
return match, applicable
}
return !match, applicable
}
// NodeAnd is a two element node of a binary tree with Left and Right branches
// connected via logical conjunction
type NodeAnd struct {
L, R Branch
}
// Match implements Matcher
func (n NodeAnd) Match(e Event) (bool, bool) {
lMatch, lApplicable := n.L.Match(e)
if !lMatch {
return false, lApplicable
}
rMatch, rApplicable := n.R.Match(e)
return lMatch && rMatch, lApplicable && rApplicable
}
// NodeOr is a two element node of a binary tree with Left and Right branches
// connected via logical disjunction
type NodeOr struct {
L, R Branch
}
// Match implements Matcher
func (n NodeOr) Match(e Event) (bool, bool) {
lMatch, lApplicable := n.L.Match(e)
if lMatch {
return true, lApplicable
}
rMatch, rApplicable := n.R.Match(e)
return lMatch || rMatch, lApplicable || rApplicable
}
func newNodeNotIfNegated(b Branch, negated bool) Branch {
if negated {
return &NodeNot{B: b}
}
return b
}
// TODO - use these functions to create binary trees instead of dunamic slices
func newConjunction(s NodeSimpleAnd) Branch {
if l := len(s); l == 1 || l == 2 {
return s.Reduce()
}
return &NodeAnd{
L: s[0],
R: newConjunction(s[1:]),
}
}
func newDisjunction(s NodeSimpleOr) Branch {
if l := len(s); l == 1 || l == 2 {
return s.Reduce()
}
return &NodeOr{
L: s[0],
R: newDisjunction(s[1:]),
}
}