-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathruleEngine.go
58 lines (50 loc) · 1.66 KB
/
ruleEngine.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
package rule
import (
"github.com/antlr4-go/antlr/v4"
parser "github.com/sky93/go-rule/internal/antlr4"
)
// Evaluate applies the stored exprTree logic to a slice of Evaluation structs.
// Each Evaluation links a Parameter in g.Params to a real runtime value. The result is a bool.
func (g *Rule) Evaluate(values []Evaluation) (bool, error) {
valuesMap := make(map[int]any)
for _, value := range values {
valuesMap[value.Param.id] = value.Result
}
return g.exprTree.evaluate(valuesMap, g.debugMode)
}
// ParseQuery takes a SCIM-like query (e.g. `age gt 30 and (lang eq "en" or lang eq "fr")`) and
// compiles it into a Rule object. Optional config can enable DebugMode.
//
// If parsing fails due to syntax errors or other issues, an error is returned.
// Otherwise, the returned Rule can be used for Evaluate().
func ParseQuery(input string, config *Config) (Rule, error) {
debugMode := false
if config != nil && config.DebugMode {
debugMode = true
}
is := antlr.NewInputStream(input)
lexer := parser.NewSCIMQueryLexer(is)
stream := antlr.NewCommonTokenStream(lexer, antlr.TokenDefaultChannel)
p := parser.NewSCIMQueryParser(stream)
// Attach a custom error listener to catch syntax errors
errListener := &errorListener{}
p.RemoveErrorListeners()
p.AddErrorListener(errListener)
// Parse the input
tree := p.Root()
if errListener.hasErrors {
return Rule{}, errListener.errMsg
}
// Build internal expression tree
vis := &queryVisitor{}
exprAny, err := vis.visitRoot(tree.(*parser.RootContext))
if err != nil {
return Rule{}, err
}
expr, _ := exprAny.(*exprTree)
return Rule{
exprTree: *expr,
Params: vis.parameters,
debugMode: debugMode,
}, err
}