github.com/expr-lang/expr@v1.16.9/optimizer/predicate_combination.go (about) 1 package optimizer 2 3 import ( 4 . "github.com/expr-lang/expr/ast" 5 "github.com/expr-lang/expr/parser/operator" 6 ) 7 8 /* 9 predicateCombination is a visitor that combines multiple predicate calls into a single call. 10 For example, the following expression: 11 12 all(x, x > 1) && all(x, x < 10) -> all(x, x > 1 && x < 10) 13 any(x, x > 1) || any(x, x < 10) -> any(x, x > 1 || x < 10) 14 none(x, x > 1) && none(x, x < 10) -> none(x, x > 1 || x < 10) 15 */ 16 type predicateCombination struct{} 17 18 func (v *predicateCombination) Visit(node *Node) { 19 if op, ok := (*node).(*BinaryNode); ok && operator.IsBoolean(op.Operator) { 20 if left, ok := op.Left.(*BuiltinNode); ok { 21 if combinedOp, ok := combinedOperator(left.Name, op.Operator); ok { 22 if right, ok := op.Right.(*BuiltinNode); ok && right.Name == left.Name { 23 if left.Arguments[0].Type() == right.Arguments[0].Type() && left.Arguments[0].String() == right.Arguments[0].String() { 24 closure := &ClosureNode{ 25 Node: &BinaryNode{ 26 Operator: combinedOp, 27 Left: left.Arguments[1].(*ClosureNode).Node, 28 Right: right.Arguments[1].(*ClosureNode).Node, 29 }, 30 } 31 v.Visit(&closure.Node) 32 Patch(node, &BuiltinNode{ 33 Name: left.Name, 34 Arguments: []Node{ 35 left.Arguments[0], 36 closure, 37 }, 38 }) 39 } 40 } 41 } 42 } 43 } 44 } 45 46 func combinedOperator(fn, op string) (string, bool) { 47 switch { 48 case fn == "all" && (op == "and" || op == "&&"): 49 return op, true 50 case fn == "any" && (op == "or" || op == "||"): 51 return op, true 52 case fn == "none" && (op == "and" || op == "&&"): 53 switch op { 54 case "and": 55 return "or", true 56 case "&&": 57 return "||", true 58 } 59 } 60 return "", false 61 }