-
Notifications
You must be signed in to change notification settings - Fork 0
/
rules.go
151 lines (137 loc) · 4.82 KB
/
rules.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// Copyright 2019 Melvin Davis<hi@melvindavis.me>. All rights reserved.
// Use of this source code is governed by a Melvin Davis<hi@melvindavis.me>
// license that can be found in the LICENSE file.
//Package interpreter has the utilities and defnition of the interpreter implementation of octopus
package interpreter
/*
* This file contains the defnition of rule templates to be used for the interpreter
*/
//Rule represents a rule with template and resolver to resolve the parsed tokens
type Rule struct {
//Name of the rule for debugging purposes
Name string `json:"name,omitempty"`
//Description of the rule.
Description string `json:"description,omitempty"`
//Disabled indicates wether the riules is emnabled
Disabled bool `json:"disabled,omitempty"`
//Template is the template of the of the rule
Template []Type `json:"template,omitempty"`
//Resolve function will try to run the resolution for the rule.
//Query argument is the query to which the resolved tokens has to be attached
//The int argument gives the index of the fasttokoen we are referring to
//Resolve function should not mutate the state of the rule
Resolve func(Query, []FastToken, int) (Query, error) `json:"-"`
//Matches are the indices of the tokens in the list of tokens to which the rule template has found match
Matches []int `json:"-"`
//Pattern is the kmp buildup of the pattern
Pattern *KMP `json:"-"`
}
//RuleGroup stores the list of rules to be executed together with priority
type RuleGroup struct {
//Rules in the group
Rules []Rule `json:"rules,omitempty"`
//Tag identifier for the group
Tag string `json:"tag,omitempty"`
}
var rules = []*RuleGroup{}
//AddRule will add a given rule with the given priority and priority in the group
//It will also build the kmp pattern for the rule
func AddRule(rule Rule, priority, groupPriority int, tag string) {
/*
* If the group rules doesn't exist add a new one
* If a different group exist replace it
* If the group doesn't have space to add a new rule. Increase the size of the rules
* Initialize the rule pattern
* Add the rule
*/
//Adding new group if required
if len(rules) > priority && rules[priority] == nil {
rules[priority] = &RuleGroup{Rules: []Rule{}, Tag: tag}
} else if len(rules) <= priority {
rules = append(rules, make([]*RuleGroup, priority-len(rules)+1)...)
rules[priority] = &RuleGroup{Rules: []Rule{}, Tag: tag}
} else if len(rules) > priority && rules[priority] != nil && rules[priority].Tag != tag {
//replacing an existing group
rules[priority] = &RuleGroup{Rules: []Rule{}, Tag: tag}
}
groupRules := rules[priority].Rules
//add space for rules to group if necessary
if len(groupRules) <= groupPriority {
groupRules = append(groupRules, make([]Rule, groupPriority-len(groupRules)+1)...)
}
//initialize the rule pattern
rule.Pattern = NewKMP(rule.Template)
//adding thr rule
groupRules[groupPriority] = rule
rules[priority].Rules = groupRules
}
//MatchRules will try to match the tokens passed with rules existing in the interpreter
//If no match is found, will return nil
func MatchRules(tokens []FastToken) []Rule {
/*
* We will first build a pattern for the given tokens
* Then will match with the existing rule patterns using kmp
*/
result := []Rule{}
//building the pattern
tokPattern := BuildPattern(tokens)
//trying to find matches for the rules with the token pattern
for _, gr := range rules {
for _, r := range gr.Rules {
//if the disabled skip the rule
if r.Disabled {
continue
}
pos := r.Pattern.Matches(tokPattern)
if len(pos) > 0 {
newRule := Rule{Name: r.Name, Matches: pos, Resolve: r.Resolve}
copy(newRule.Template, r.Template)
result = append(result, newRule)
}
}
}
return result
}
//SetRuleDisableState will set the disable state of a rule
func SetRuleDisableState(pos, groupPos int, state bool) {
for i := 0; i < len(rules); i++ {
for j := 0; j < len(rules[i].Rules); j++ {
if i == pos && groupPos == j {
rules[i].Rules[j].Disabled = state
}
}
}
}
//GetRules return the rules used in the interpreter
func GetRules() []*RuleGroup {
return rules
}
//BuildPattern will build pattern for the given tokens
func BuildPattern(tokens []FastToken) []Type {
/*
* We will iterate through the tokens and retrive the types
*/
result := []Type{}
for _, v := range tokens {
//We will only take the first node in the token in the following order
// Operator
// Value
// Column
// Table
// Unknown
if len(v.Operators) > 0 {
result = append(result, Operator)
} else if len(v.Values) > 0 {
result = append(result, Value)
} else if len(v.Times) > 0 {
result = append(result, Time)
} else if len(v.Columns) > 0 {
result = append(result, Column)
} else if len(v.Tables) > 0 {
result = append(result, Table)
} else if len(v.Unknowns) > 0 {
result = append(result, Unknown)
}
}
return result
}