Files
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
6c89137ee1 Bump github.com/expr-lang/expr from 1.16.9 to 1.17.0 (#4868)
Bumps [github.com/expr-lang/expr](https://github.com/expr-lang/expr) from 1.16.9 to 1.17.0.
- [Release notes](https://github.com/expr-lang/expr/releases)
- [Commits](https://github.com/expr-lang/expr/compare/v1.16.9...v1.17.0)

---
updated-dependencies:
- dependency-name: github.com/expr-lang/expr
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-18 09:50:29 +01:00

62 lines
1.7 KiB
Go

package optimizer
import (
. "github.com/expr-lang/expr/ast"
"github.com/expr-lang/expr/parser/operator"
)
/*
predicateCombination is a visitor that combines multiple predicate calls into a single call.
For example, the following expression:
all(x, x > 1) && all(x, x < 10) -> all(x, x > 1 && x < 10)
any(x, x > 1) || any(x, x < 10) -> any(x, x > 1 || x < 10)
none(x, x > 1) && none(x, x < 10) -> none(x, x > 1 || x < 10)
*/
type predicateCombination struct{}
func (v *predicateCombination) Visit(node *Node) {
if op, ok := (*node).(*BinaryNode); ok && operator.IsBoolean(op.Operator) {
if left, ok := op.Left.(*BuiltinNode); ok {
if combinedOp, ok := combinedOperator(left.Name, op.Operator); ok {
if right, ok := op.Right.(*BuiltinNode); ok && right.Name == left.Name {
if left.Arguments[0].Type() == right.Arguments[0].Type() && left.Arguments[0].String() == right.Arguments[0].String() {
predicate := &PredicateNode{
Node: &BinaryNode{
Operator: combinedOp,
Left: left.Arguments[1].(*PredicateNode).Node,
Right: right.Arguments[1].(*PredicateNode).Node,
},
}
v.Visit(&predicate.Node)
patchCopyType(node, &BuiltinNode{
Name: left.Name,
Arguments: []Node{
left.Arguments[0],
predicate,
},
})
}
}
}
}
}
}
func combinedOperator(fn, op string) (string, bool) {
switch {
case fn == "all" && (op == "and" || op == "&&"):
return op, true
case fn == "any" && (op == "or" || op == "||"):
return op, true
case fn == "none" && (op == "and" || op == "&&"):
switch op {
case "and":
return "or", true
case "&&":
return "||", true
}
}
return "", false
}