mirror of
https://github.com/hanzoai/expr.git
synced 2026-09-24 16:58:58 +00:00
Add predicates to list of builtins
This commit is contained in:
+41
-5
@@ -12,11 +12,12 @@ import (
|
||||
)
|
||||
|
||||
type Function struct {
|
||||
Name string
|
||||
Func func(args ...interface{}) (interface{}, error)
|
||||
Types []reflect.Type
|
||||
Builtin1 func(arg interface{}) interface{}
|
||||
Validate func(args []reflect.Type) (reflect.Type, error)
|
||||
Name string
|
||||
Func func(args ...interface{}) (interface{}, error)
|
||||
Types []reflect.Type
|
||||
Builtin1 func(arg interface{}) interface{}
|
||||
Validate func(args []reflect.Type) (reflect.Type, error)
|
||||
Predicate bool
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -34,6 +35,41 @@ func init() {
|
||||
}
|
||||
|
||||
var Builtins = []*Function{
|
||||
{
|
||||
Name: "all",
|
||||
Predicate: true,
|
||||
Types: types(new(func([]interface{}, func(interface{}) bool) bool)),
|
||||
},
|
||||
{
|
||||
Name: "none",
|
||||
Predicate: true,
|
||||
Types: types(new(func([]interface{}, func(interface{}) bool) bool)),
|
||||
},
|
||||
{
|
||||
Name: "any",
|
||||
Predicate: true,
|
||||
Types: types(new(func([]interface{}, func(interface{}) bool) bool)),
|
||||
},
|
||||
{
|
||||
Name: "one",
|
||||
Predicate: true,
|
||||
Types: types(new(func([]interface{}, func(interface{}) bool) bool)),
|
||||
},
|
||||
{
|
||||
Name: "filter",
|
||||
Predicate: true,
|
||||
Types: types(new(func([]interface{}, func(interface{}) bool) []interface{})),
|
||||
},
|
||||
{
|
||||
Name: "map",
|
||||
Predicate: true,
|
||||
Types: types(new(func([]interface{}, func(interface{}) interface{}) []interface{})),
|
||||
},
|
||||
{
|
||||
Name: "count",
|
||||
Predicate: true,
|
||||
Types: types(new(func([]interface{}, func(interface{}) bool) int)),
|
||||
},
|
||||
{
|
||||
Name: "len",
|
||||
Builtin1: Len,
|
||||
|
||||
+17
-8
@@ -113,6 +113,9 @@ func TestBuiltin_works_with_any(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, b := range builtin.Builtins {
|
||||
if b.Predicate {
|
||||
continue
|
||||
}
|
||||
t.Run(b.Name, func(t *testing.T) {
|
||||
arity := 1
|
||||
if c, ok := config[b.Name]; ok {
|
||||
@@ -249,12 +252,15 @@ func TestBuiltin_disallow_builtins_override(t *testing.T) {
|
||||
|
||||
func TestBuiltin_DisableBuiltin(t *testing.T) {
|
||||
t.Run("via env", func(t *testing.T) {
|
||||
for _, name := range builtin.Names {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
for _, b := range builtin.Builtins {
|
||||
if b.Predicate {
|
||||
continue // TODO: allow to disable predicates
|
||||
}
|
||||
t.Run(b.Name, func(t *testing.T) {
|
||||
env := map[string]interface{}{
|
||||
name: func() int { return 42 },
|
||||
b.Name: func() int { return 42 },
|
||||
}
|
||||
program, err := expr.Compile(name+"()", expr.Env(env), expr.DisableBuiltin(name))
|
||||
program, err := expr.Compile(b.Name+"()", expr.Env(env), expr.DisableBuiltin(b.Name))
|
||||
require.NoError(t, err)
|
||||
|
||||
out, err := expr.Run(program, env)
|
||||
@@ -264,15 +270,18 @@ func TestBuiltin_DisableBuiltin(t *testing.T) {
|
||||
}
|
||||
})
|
||||
t.Run("via expr.Function", func(t *testing.T) {
|
||||
for _, name := range builtin.Names {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
fn := expr.Function(name,
|
||||
for _, b := range builtin.Builtins {
|
||||
if b.Predicate {
|
||||
continue // TODO: allow to disable predicates
|
||||
}
|
||||
t.Run(b.Name, func(t *testing.T) {
|
||||
fn := expr.Function(b.Name,
|
||||
func(params ...interface{}) (interface{}, error) {
|
||||
return 42, nil
|
||||
},
|
||||
new(func() int),
|
||||
)
|
||||
program, err := expr.Compile(name+"()", fn, expr.DisableBuiltin(name))
|
||||
program, err := expr.Compile(b.Name+"()", fn, expr.DisableBuiltin(b.Name))
|
||||
require.NoError(t, err)
|
||||
|
||||
out, err := expr.Run(program, nil)
|
||||
|
||||
@@ -635,7 +635,7 @@ func TestCheck_AllowUndefinedVariables(t *testing.T) {
|
||||
A int
|
||||
}
|
||||
|
||||
tree, err := parser.Parse(`any + fn()`)
|
||||
tree, err := parser.Parse(`Any + fn()`)
|
||||
require.NoError(t, err)
|
||||
|
||||
config := conf.New(Env{})
|
||||
@@ -648,7 +648,7 @@ func TestCheck_AllowUndefinedVariables(t *testing.T) {
|
||||
func TestCheck_AllowUndefinedVariables_DefaultType(t *testing.T) {
|
||||
env := map[string]bool{}
|
||||
|
||||
tree, err := parser.Parse(`any`)
|
||||
tree, err := parser.Parse(`Any`)
|
||||
require.NoError(t, err)
|
||||
|
||||
config := conf.New(env)
|
||||
|
||||
@@ -12,12 +12,12 @@ func TestDeref_binary(t *testing.T) {
|
||||
i := 1
|
||||
env := map[string]interface{}{
|
||||
"i": &i,
|
||||
"map": map[string]interface{}{
|
||||
"obj": map[string]interface{}{
|
||||
"i": &i,
|
||||
},
|
||||
}
|
||||
t.Run("==", func(t *testing.T) {
|
||||
program, err := expr.Compile(`i == 1 && map.i == 1`, expr.Env(env))
|
||||
program, err := expr.Compile(`i == 1 && obj.i == 1`, expr.Env(env))
|
||||
require.NoError(t, err)
|
||||
|
||||
out, err := expr.Run(program, env)
|
||||
@@ -25,7 +25,7 @@ func TestDeref_binary(t *testing.T) {
|
||||
require.Equal(t, true, out)
|
||||
})
|
||||
t.Run("><", func(t *testing.T) {
|
||||
program, err := expr.Compile(`i > 0 && map.i < 99`, expr.Env(env))
|
||||
program, err := expr.Compile(`i > 0 && obj.i < 99`, expr.Env(env))
|
||||
require.NoError(t, err)
|
||||
|
||||
out, err := expr.Run(program, env)
|
||||
@@ -33,7 +33,7 @@ func TestDeref_binary(t *testing.T) {
|
||||
require.Equal(t, true, out)
|
||||
})
|
||||
t.Run("??+", func(t *testing.T) {
|
||||
program, err := expr.Compile(`(i ?? map.i) + 1`, expr.Env(env))
|
||||
program, err := expr.Compile(`(i ?? obj.i) + 1`, expr.Env(env))
|
||||
require.NoError(t, err)
|
||||
|
||||
out, err := expr.Run(program, env)
|
||||
@@ -47,12 +47,12 @@ func TestDeref_unary(t *testing.T) {
|
||||
ok := true
|
||||
env := map[string]interface{}{
|
||||
"i": &i,
|
||||
"map": map[string]interface{}{
|
||||
"obj": map[string]interface{}{
|
||||
"ok": &ok,
|
||||
},
|
||||
}
|
||||
|
||||
program, err := expr.Compile(`-i < 0 && !!map.ok`, expr.Env(env))
|
||||
program, err := expr.Compile(`-i < 0 && !!obj.ok`, expr.Env(env))
|
||||
require.NoError(t, err)
|
||||
|
||||
out, err := expr.Run(program, env)
|
||||
@@ -64,11 +64,11 @@ func TestDeref_eval(t *testing.T) {
|
||||
i := 1
|
||||
env := map[string]interface{}{
|
||||
"i": &i,
|
||||
"map": map[string]interface{}{
|
||||
"obj": map[string]interface{}{
|
||||
"i": &i,
|
||||
},
|
||||
}
|
||||
out, err := expr.Eval(`i == 1 && map.i == 1`, env)
|
||||
out, err := expr.Eval(`i == 1 && obj.i == 1`, env)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, out)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user