diff --git a/pkg/nsrule/env.go b/pkg/nsrule/env.go index a8ab312..fdd6db3 100644 --- a/pkg/nsrule/env.go +++ b/pkg/nsrule/env.go @@ -2,14 +2,18 @@ package nsrule import ( "maps" + "reflect" + + "github.com/antonmedv/expr" ) // Env contains data used to evaluate rules. type Env map[string]any var ( - dummyEnv = Env{} - defaultEnv = Env{} + dummyEnv = Env{} + defaultEnv = Env{} + extraOptions []expr.Option ) // NewEnv shallow-copies the default values into a new Env. @@ -43,3 +47,11 @@ func Define[T any](name string) func(Env, T) { func DefineDefault[T any](name string, def T) func(Env, T) { return define[T](name, def, false) } + +// DefineOperator overloads an operator. +func DefineOperator[T any](op string, fn T) string { + name := op + " " + reflect.TypeOf(fn).String() + extraOptions = append(extraOptions, expr.Operator(op, name)) + define[T](name, fn, false) + return name +} diff --git a/pkg/nsrule/rule.go b/pkg/nsrule/rule.go index 4beac2a..baa6af0 100644 --- a/pkg/nsrule/rule.go +++ b/pkg/nsrule/rule.go @@ -171,7 +171,7 @@ func ParseRules(r io.Reader, name string) ([]Rule, error) { name: name, line: expN, } - if v, err := expr.Compile(expB.String(), expr.AsBool(), expr.Optimize(true), expr.Env(dummyEnv)); err != nil { // TODO: dummy env + if v, err := expr.Compile(expB.String(), append([]expr.Option{expr.AsBool(), expr.Optimize(true), expr.Env(dummyEnv)}, extraOptions...)...); err != nil { // TODO: dummy env return rs, fmt.Errorf("line %d: compile rule expression: %w", expN, err) } else { r.expr = v