mirror of
https://github.com/kubenetworks/kubevpn.git
synced 2025-10-12 18:51:02 +08:00
chore: upgrade coredns version (#550)
This commit is contained in:
81
vendor/github.com/expr-lang/expr/optimizer/const_expr.go
generated
vendored
Normal file
81
vendor/github.com/expr-lang/expr/optimizer/const_expr.go
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
package optimizer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
. "github.com/expr-lang/expr/ast"
|
||||
"github.com/expr-lang/expr/file"
|
||||
)
|
||||
|
||||
var errorType = reflect.TypeOf((*error)(nil)).Elem()
|
||||
|
||||
type constExpr struct {
|
||||
applied bool
|
||||
err error
|
||||
fns map[string]reflect.Value
|
||||
}
|
||||
|
||||
func (c *constExpr) Visit(node *Node) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
msg := fmt.Sprintf("%v", r)
|
||||
// Make message more actual, it's a runtime error, but at compile step.
|
||||
msg = strings.Replace(msg, "runtime error:", "compile error:", 1)
|
||||
c.err = &file.Error{
|
||||
Location: (*node).Location(),
|
||||
Message: msg,
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if call, ok := (*node).(*CallNode); ok {
|
||||
if name, ok := call.Callee.(*IdentifierNode); ok {
|
||||
fn, ok := c.fns[name.Value]
|
||||
if ok {
|
||||
in := make([]reflect.Value, len(call.Arguments))
|
||||
for i := 0; i < len(call.Arguments); i++ {
|
||||
arg := call.Arguments[i]
|
||||
var param any
|
||||
|
||||
switch a := arg.(type) {
|
||||
case *NilNode:
|
||||
param = nil
|
||||
case *IntegerNode:
|
||||
param = a.Value
|
||||
case *FloatNode:
|
||||
param = a.Value
|
||||
case *BoolNode:
|
||||
param = a.Value
|
||||
case *StringNode:
|
||||
param = a.Value
|
||||
case *ConstantNode:
|
||||
param = a.Value
|
||||
|
||||
default:
|
||||
return // Const expr optimization not applicable.
|
||||
}
|
||||
|
||||
if param == nil && reflect.TypeOf(param) == nil {
|
||||
// In case of nil value and nil type use this hack,
|
||||
// otherwise reflect.Call will panic on zero value.
|
||||
in[i] = reflect.ValueOf(¶m).Elem()
|
||||
} else {
|
||||
in[i] = reflect.ValueOf(param)
|
||||
}
|
||||
}
|
||||
|
||||
out := fn.Call(in)
|
||||
value := out[0].Interface()
|
||||
if len(out) == 2 && out[1].Type() == errorType && !out[1].IsNil() {
|
||||
c.err = out[1].Interface().(error)
|
||||
return
|
||||
}
|
||||
constNode := &ConstantNode{Value: value}
|
||||
patchWithType(node, constNode)
|
||||
c.applied = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
38
vendor/github.com/expr-lang/expr/optimizer/filter_first.go
generated
vendored
Normal file
38
vendor/github.com/expr-lang/expr/optimizer/filter_first.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
package optimizer
|
||||
|
||||
import (
|
||||
. "github.com/expr-lang/expr/ast"
|
||||
)
|
||||
|
||||
type filterFirst struct{}
|
||||
|
||||
func (*filterFirst) Visit(node *Node) {
|
||||
if member, ok := (*node).(*MemberNode); ok && member.Property != nil && !member.Optional {
|
||||
if prop, ok := member.Property.(*IntegerNode); ok && prop.Value == 0 {
|
||||
if filter, ok := member.Node.(*BuiltinNode); ok &&
|
||||
filter.Name == "filter" &&
|
||||
len(filter.Arguments) == 2 {
|
||||
patchCopyType(node, &BuiltinNode{
|
||||
Name: "find",
|
||||
Arguments: filter.Arguments,
|
||||
Throws: true, // to match the behavior of filter()[0]
|
||||
Map: filter.Map,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
if first, ok := (*node).(*BuiltinNode); ok &&
|
||||
first.Name == "first" &&
|
||||
len(first.Arguments) == 1 {
|
||||
if filter, ok := first.Arguments[0].(*BuiltinNode); ok &&
|
||||
filter.Name == "filter" &&
|
||||
len(filter.Arguments) == 2 {
|
||||
patchCopyType(node, &BuiltinNode{
|
||||
Name: "find",
|
||||
Arguments: filter.Arguments,
|
||||
Throws: false, // as first() will return nil if not found
|
||||
Map: filter.Map,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
38
vendor/github.com/expr-lang/expr/optimizer/filter_last.go
generated
vendored
Normal file
38
vendor/github.com/expr-lang/expr/optimizer/filter_last.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
package optimizer
|
||||
|
||||
import (
|
||||
. "github.com/expr-lang/expr/ast"
|
||||
)
|
||||
|
||||
type filterLast struct{}
|
||||
|
||||
func (*filterLast) Visit(node *Node) {
|
||||
if member, ok := (*node).(*MemberNode); ok && member.Property != nil && !member.Optional {
|
||||
if prop, ok := member.Property.(*IntegerNode); ok && prop.Value == -1 {
|
||||
if filter, ok := member.Node.(*BuiltinNode); ok &&
|
||||
filter.Name == "filter" &&
|
||||
len(filter.Arguments) == 2 {
|
||||
patchCopyType(node, &BuiltinNode{
|
||||
Name: "findLast",
|
||||
Arguments: filter.Arguments,
|
||||
Throws: true, // to match the behavior of filter()[-1]
|
||||
Map: filter.Map,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
if first, ok := (*node).(*BuiltinNode); ok &&
|
||||
first.Name == "last" &&
|
||||
len(first.Arguments) == 1 {
|
||||
if filter, ok := first.Arguments[0].(*BuiltinNode); ok &&
|
||||
filter.Name == "filter" &&
|
||||
len(filter.Arguments) == 2 {
|
||||
patchCopyType(node, &BuiltinNode{
|
||||
Name: "findLast",
|
||||
Arguments: filter.Arguments,
|
||||
Throws: false, // as last() will return nil if not found
|
||||
Map: filter.Map,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
22
vendor/github.com/expr-lang/expr/optimizer/filter_len.go
generated
vendored
Normal file
22
vendor/github.com/expr-lang/expr/optimizer/filter_len.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
package optimizer
|
||||
|
||||
import (
|
||||
. "github.com/expr-lang/expr/ast"
|
||||
)
|
||||
|
||||
type filterLen struct{}
|
||||
|
||||
func (*filterLen) Visit(node *Node) {
|
||||
if ln, ok := (*node).(*BuiltinNode); ok &&
|
||||
ln.Name == "len" &&
|
||||
len(ln.Arguments) == 1 {
|
||||
if filter, ok := ln.Arguments[0].(*BuiltinNode); ok &&
|
||||
filter.Name == "filter" &&
|
||||
len(filter.Arguments) == 2 {
|
||||
patchCopyType(node, &BuiltinNode{
|
||||
Name: "count",
|
||||
Arguments: filter.Arguments,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
33
vendor/github.com/expr-lang/expr/optimizer/filter_map.go
generated
vendored
Normal file
33
vendor/github.com/expr-lang/expr/optimizer/filter_map.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
package optimizer
|
||||
|
||||
import (
|
||||
. "github.com/expr-lang/expr/ast"
|
||||
)
|
||||
|
||||
type filterMap struct{}
|
||||
|
||||
func (*filterMap) Visit(node *Node) {
|
||||
if mapBuiltin, ok := (*node).(*BuiltinNode); ok &&
|
||||
mapBuiltin.Name == "map" &&
|
||||
len(mapBuiltin.Arguments) == 2 &&
|
||||
Find(mapBuiltin.Arguments[1], isIndexPointer) == nil {
|
||||
if predicate, ok := mapBuiltin.Arguments[1].(*PredicateNode); ok {
|
||||
if filter, ok := mapBuiltin.Arguments[0].(*BuiltinNode); ok &&
|
||||
filter.Name == "filter" &&
|
||||
filter.Map == nil /* not already optimized */ {
|
||||
patchCopyType(node, &BuiltinNode{
|
||||
Name: "filter",
|
||||
Arguments: filter.Arguments,
|
||||
Map: predicate.Node,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func isIndexPointer(node Node) bool {
|
||||
if pointer, ok := node.(*PointerNode); ok && pointer.Name == "index" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
341
vendor/github.com/expr-lang/expr/optimizer/fold.go
generated
vendored
Normal file
341
vendor/github.com/expr-lang/expr/optimizer/fold.go
generated
vendored
Normal file
@@ -0,0 +1,341 @@
|
||||
package optimizer
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
. "github.com/expr-lang/expr/ast"
|
||||
"github.com/expr-lang/expr/file"
|
||||
)
|
||||
|
||||
type fold struct {
|
||||
applied bool
|
||||
err *file.Error
|
||||
}
|
||||
|
||||
func (fold *fold) Visit(node *Node) {
|
||||
patch := func(newNode Node) {
|
||||
fold.applied = true
|
||||
patchWithType(node, newNode)
|
||||
}
|
||||
patchCopy := func(newNode Node) {
|
||||
fold.applied = true
|
||||
patchCopyType(node, newNode)
|
||||
}
|
||||
|
||||
switch n := (*node).(type) {
|
||||
case *UnaryNode:
|
||||
switch n.Operator {
|
||||
case "-":
|
||||
if i, ok := n.Node.(*IntegerNode); ok {
|
||||
patch(&IntegerNode{Value: -i.Value})
|
||||
}
|
||||
if i, ok := n.Node.(*FloatNode); ok {
|
||||
patch(&FloatNode{Value: -i.Value})
|
||||
}
|
||||
case "+":
|
||||
if i, ok := n.Node.(*IntegerNode); ok {
|
||||
patch(&IntegerNode{Value: i.Value})
|
||||
}
|
||||
if i, ok := n.Node.(*FloatNode); ok {
|
||||
patch(&FloatNode{Value: i.Value})
|
||||
}
|
||||
case "!", "not":
|
||||
if a := toBool(n.Node); a != nil {
|
||||
patch(&BoolNode{Value: !a.Value})
|
||||
}
|
||||
}
|
||||
|
||||
case *BinaryNode:
|
||||
switch n.Operator {
|
||||
case "+":
|
||||
{
|
||||
a := toInteger(n.Left)
|
||||
b := toInteger(n.Right)
|
||||
if a != nil && b != nil {
|
||||
patch(&IntegerNode{Value: a.Value + b.Value})
|
||||
}
|
||||
}
|
||||
{
|
||||
a := toInteger(n.Left)
|
||||
b := toFloat(n.Right)
|
||||
if a != nil && b != nil {
|
||||
patch(&FloatNode{Value: float64(a.Value) + b.Value})
|
||||
}
|
||||
}
|
||||
{
|
||||
a := toFloat(n.Left)
|
||||
b := toInteger(n.Right)
|
||||
if a != nil && b != nil {
|
||||
patch(&FloatNode{Value: a.Value + float64(b.Value)})
|
||||
}
|
||||
}
|
||||
{
|
||||
a := toFloat(n.Left)
|
||||
b := toFloat(n.Right)
|
||||
if a != nil && b != nil {
|
||||
patch(&FloatNode{Value: a.Value + b.Value})
|
||||
}
|
||||
}
|
||||
{
|
||||
a := toString(n.Left)
|
||||
b := toString(n.Right)
|
||||
if a != nil && b != nil {
|
||||
patch(&StringNode{Value: a.Value + b.Value})
|
||||
}
|
||||
}
|
||||
case "-":
|
||||
{
|
||||
a := toInteger(n.Left)
|
||||
b := toInteger(n.Right)
|
||||
if a != nil && b != nil {
|
||||
patch(&IntegerNode{Value: a.Value - b.Value})
|
||||
}
|
||||
}
|
||||
{
|
||||
a := toInteger(n.Left)
|
||||
b := toFloat(n.Right)
|
||||
if a != nil && b != nil {
|
||||
patch(&FloatNode{Value: float64(a.Value) - b.Value})
|
||||
}
|
||||
}
|
||||
{
|
||||
a := toFloat(n.Left)
|
||||
b := toInteger(n.Right)
|
||||
if a != nil && b != nil {
|
||||
patch(&FloatNode{Value: a.Value - float64(b.Value)})
|
||||
}
|
||||
}
|
||||
{
|
||||
a := toFloat(n.Left)
|
||||
b := toFloat(n.Right)
|
||||
if a != nil && b != nil {
|
||||
patch(&FloatNode{Value: a.Value - b.Value})
|
||||
}
|
||||
}
|
||||
case "*":
|
||||
{
|
||||
a := toInteger(n.Left)
|
||||
b := toInteger(n.Right)
|
||||
if a != nil && b != nil {
|
||||
patch(&IntegerNode{Value: a.Value * b.Value})
|
||||
}
|
||||
}
|
||||
{
|
||||
a := toInteger(n.Left)
|
||||
b := toFloat(n.Right)
|
||||
if a != nil && b != nil {
|
||||
patch(&FloatNode{Value: float64(a.Value) * b.Value})
|
||||
}
|
||||
}
|
||||
{
|
||||
a := toFloat(n.Left)
|
||||
b := toInteger(n.Right)
|
||||
if a != nil && b != nil {
|
||||
patch(&FloatNode{Value: a.Value * float64(b.Value)})
|
||||
}
|
||||
}
|
||||
{
|
||||
a := toFloat(n.Left)
|
||||
b := toFloat(n.Right)
|
||||
if a != nil && b != nil {
|
||||
patch(&FloatNode{Value: a.Value * b.Value})
|
||||
}
|
||||
}
|
||||
case "/":
|
||||
{
|
||||
a := toInteger(n.Left)
|
||||
b := toInteger(n.Right)
|
||||
if a != nil && b != nil {
|
||||
patch(&FloatNode{Value: float64(a.Value) / float64(b.Value)})
|
||||
}
|
||||
}
|
||||
{
|
||||
a := toInteger(n.Left)
|
||||
b := toFloat(n.Right)
|
||||
if a != nil && b != nil {
|
||||
patch(&FloatNode{Value: float64(a.Value) / b.Value})
|
||||
}
|
||||
}
|
||||
{
|
||||
a := toFloat(n.Left)
|
||||
b := toInteger(n.Right)
|
||||
if a != nil && b != nil {
|
||||
patch(&FloatNode{Value: a.Value / float64(b.Value)})
|
||||
}
|
||||
}
|
||||
{
|
||||
a := toFloat(n.Left)
|
||||
b := toFloat(n.Right)
|
||||
if a != nil && b != nil {
|
||||
patch(&FloatNode{Value: a.Value / b.Value})
|
||||
}
|
||||
}
|
||||
case "%":
|
||||
if a, ok := n.Left.(*IntegerNode); ok {
|
||||
if b, ok := n.Right.(*IntegerNode); ok {
|
||||
if b.Value == 0 {
|
||||
fold.err = &file.Error{
|
||||
Location: (*node).Location(),
|
||||
Message: "integer divide by zero",
|
||||
}
|
||||
return
|
||||
}
|
||||
patch(&IntegerNode{Value: a.Value % b.Value})
|
||||
}
|
||||
}
|
||||
case "**", "^":
|
||||
{
|
||||
a := toInteger(n.Left)
|
||||
b := toInteger(n.Right)
|
||||
if a != nil && b != nil {
|
||||
patch(&FloatNode{Value: math.Pow(float64(a.Value), float64(b.Value))})
|
||||
}
|
||||
}
|
||||
{
|
||||
a := toInteger(n.Left)
|
||||
b := toFloat(n.Right)
|
||||
if a != nil && b != nil {
|
||||
patch(&FloatNode{Value: math.Pow(float64(a.Value), b.Value)})
|
||||
}
|
||||
}
|
||||
{
|
||||
a := toFloat(n.Left)
|
||||
b := toInteger(n.Right)
|
||||
if a != nil && b != nil {
|
||||
patch(&FloatNode{Value: math.Pow(a.Value, float64(b.Value))})
|
||||
}
|
||||
}
|
||||
{
|
||||
a := toFloat(n.Left)
|
||||
b := toFloat(n.Right)
|
||||
if a != nil && b != nil {
|
||||
patch(&FloatNode{Value: math.Pow(a.Value, b.Value)})
|
||||
}
|
||||
}
|
||||
case "and", "&&":
|
||||
a := toBool(n.Left)
|
||||
b := toBool(n.Right)
|
||||
|
||||
if a != nil && a.Value { // true and x
|
||||
patchCopy(n.Right)
|
||||
} else if b != nil && b.Value { // x and true
|
||||
patchCopy(n.Left)
|
||||
} else if (a != nil && !a.Value) || (b != nil && !b.Value) { // "x and false" or "false and x"
|
||||
patch(&BoolNode{Value: false})
|
||||
}
|
||||
case "or", "||":
|
||||
a := toBool(n.Left)
|
||||
b := toBool(n.Right)
|
||||
|
||||
if a != nil && !a.Value { // false or x
|
||||
patchCopy(n.Right)
|
||||
} else if b != nil && !b.Value { // x or false
|
||||
patchCopy(n.Left)
|
||||
} else if (a != nil && a.Value) || (b != nil && b.Value) { // "x or true" or "true or x"
|
||||
patch(&BoolNode{Value: true})
|
||||
}
|
||||
case "==":
|
||||
{
|
||||
a := toInteger(n.Left)
|
||||
b := toInteger(n.Right)
|
||||
if a != nil && b != nil {
|
||||
patch(&BoolNode{Value: a.Value == b.Value})
|
||||
}
|
||||
}
|
||||
{
|
||||
a := toString(n.Left)
|
||||
b := toString(n.Right)
|
||||
if a != nil && b != nil {
|
||||
patch(&BoolNode{Value: a.Value == b.Value})
|
||||
}
|
||||
}
|
||||
{
|
||||
a := toBool(n.Left)
|
||||
b := toBool(n.Right)
|
||||
if a != nil && b != nil {
|
||||
patch(&BoolNode{Value: a.Value == b.Value})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case *ArrayNode:
|
||||
if len(n.Nodes) > 0 {
|
||||
for _, a := range n.Nodes {
|
||||
switch a.(type) {
|
||||
case *IntegerNode, *FloatNode, *StringNode, *BoolNode:
|
||||
continue
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
value := make([]any, len(n.Nodes))
|
||||
for i, a := range n.Nodes {
|
||||
switch b := a.(type) {
|
||||
case *IntegerNode:
|
||||
value[i] = b.Value
|
||||
case *FloatNode:
|
||||
value[i] = b.Value
|
||||
case *StringNode:
|
||||
value[i] = b.Value
|
||||
case *BoolNode:
|
||||
value[i] = b.Value
|
||||
}
|
||||
}
|
||||
patch(&ConstantNode{Value: value})
|
||||
}
|
||||
|
||||
case *BuiltinNode:
|
||||
// TODO: Move this to a separate visitor filter_filter.go
|
||||
switch n.Name {
|
||||
case "filter":
|
||||
if len(n.Arguments) != 2 {
|
||||
return
|
||||
}
|
||||
if base, ok := n.Arguments[0].(*BuiltinNode); ok && base.Name == "filter" {
|
||||
patchCopy(&BuiltinNode{
|
||||
Name: "filter",
|
||||
Arguments: []Node{
|
||||
base.Arguments[0],
|
||||
&BinaryNode{
|
||||
Operator: "&&",
|
||||
Left: base.Arguments[1].(*PredicateNode).Node,
|
||||
Right: n.Arguments[1].(*PredicateNode).Node,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func toString(n Node) *StringNode {
|
||||
switch a := n.(type) {
|
||||
case *StringNode:
|
||||
return a
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func toInteger(n Node) *IntegerNode {
|
||||
switch a := n.(type) {
|
||||
case *IntegerNode:
|
||||
return a
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func toFloat(n Node) *FloatNode {
|
||||
switch a := n.(type) {
|
||||
case *FloatNode:
|
||||
return a
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func toBool(n Node) *BoolNode {
|
||||
switch a := n.(type) {
|
||||
case *BoolNode:
|
||||
return a
|
||||
}
|
||||
return nil
|
||||
}
|
68
vendor/github.com/expr-lang/expr/optimizer/in_array.go
generated
vendored
Normal file
68
vendor/github.com/expr-lang/expr/optimizer/in_array.go
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
package optimizer
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
. "github.com/expr-lang/expr/ast"
|
||||
)
|
||||
|
||||
type inArray struct{}
|
||||
|
||||
func (*inArray) Visit(node *Node) {
|
||||
switch n := (*node).(type) {
|
||||
case *BinaryNode:
|
||||
if n.Operator == "in" {
|
||||
if array, ok := n.Right.(*ArrayNode); ok {
|
||||
if len(array.Nodes) > 0 {
|
||||
t := n.Left.Type()
|
||||
if t == nil || t.Kind() != reflect.Int {
|
||||
// This optimization can be only performed if left side is int type,
|
||||
// as runtime.in func uses reflect.Map.MapIndex and keys of map must,
|
||||
// be same as checked value type.
|
||||
goto string
|
||||
}
|
||||
|
||||
for _, a := range array.Nodes {
|
||||
if _, ok := a.(*IntegerNode); !ok {
|
||||
goto string
|
||||
}
|
||||
}
|
||||
{
|
||||
value := make(map[int]struct{})
|
||||
for _, a := range array.Nodes {
|
||||
value[a.(*IntegerNode).Value] = struct{}{}
|
||||
}
|
||||
m := &ConstantNode{Value: value}
|
||||
m.SetType(reflect.TypeOf(value))
|
||||
patchCopyType(node, &BinaryNode{
|
||||
Operator: n.Operator,
|
||||
Left: n.Left,
|
||||
Right: m,
|
||||
})
|
||||
}
|
||||
|
||||
string:
|
||||
for _, a := range array.Nodes {
|
||||
if _, ok := a.(*StringNode); !ok {
|
||||
return
|
||||
}
|
||||
}
|
||||
{
|
||||
value := make(map[string]struct{})
|
||||
for _, a := range array.Nodes {
|
||||
value[a.(*StringNode).Value] = struct{}{}
|
||||
}
|
||||
m := &ConstantNode{Value: value}
|
||||
m.SetType(reflect.TypeOf(value))
|
||||
patchCopyType(node, &BinaryNode{
|
||||
Operator: n.Operator,
|
||||
Left: n.Left,
|
||||
Right: m,
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
43
vendor/github.com/expr-lang/expr/optimizer/in_range.go
generated
vendored
Normal file
43
vendor/github.com/expr-lang/expr/optimizer/in_range.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
package optimizer
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
. "github.com/expr-lang/expr/ast"
|
||||
)
|
||||
|
||||
type inRange struct{}
|
||||
|
||||
func (*inRange) Visit(node *Node) {
|
||||
switch n := (*node).(type) {
|
||||
case *BinaryNode:
|
||||
if n.Operator == "in" {
|
||||
t := n.Left.Type()
|
||||
if t == nil {
|
||||
return
|
||||
}
|
||||
if t.Kind() != reflect.Int {
|
||||
return
|
||||
}
|
||||
if rangeOp, ok := n.Right.(*BinaryNode); ok && rangeOp.Operator == ".." {
|
||||
if from, ok := rangeOp.Left.(*IntegerNode); ok {
|
||||
if to, ok := rangeOp.Right.(*IntegerNode); ok {
|
||||
patchCopyType(node, &BinaryNode{
|
||||
Operator: "and",
|
||||
Left: &BinaryNode{
|
||||
Operator: ">=",
|
||||
Left: n.Left,
|
||||
Right: from,
|
||||
},
|
||||
Right: &BinaryNode{
|
||||
Operator: "<=",
|
||||
Left: n.Left,
|
||||
Right: to,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
79
vendor/github.com/expr-lang/expr/optimizer/optimizer.go
generated
vendored
Normal file
79
vendor/github.com/expr-lang/expr/optimizer/optimizer.go
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
package optimizer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
. "github.com/expr-lang/expr/ast"
|
||||
"github.com/expr-lang/expr/conf"
|
||||
)
|
||||
|
||||
func Optimize(node *Node, config *conf.Config) error {
|
||||
Walk(node, &inArray{})
|
||||
for limit := 1000; limit >= 0; limit-- {
|
||||
fold := &fold{}
|
||||
Walk(node, fold)
|
||||
if fold.err != nil {
|
||||
return fold.err
|
||||
}
|
||||
if !fold.applied {
|
||||
break
|
||||
}
|
||||
}
|
||||
if config != nil && len(config.ConstFns) > 0 {
|
||||
for limit := 100; limit >= 0; limit-- {
|
||||
constExpr := &constExpr{
|
||||
fns: config.ConstFns,
|
||||
}
|
||||
Walk(node, constExpr)
|
||||
if constExpr.err != nil {
|
||||
return constExpr.err
|
||||
}
|
||||
if !constExpr.applied {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
Walk(node, &inRange{})
|
||||
Walk(node, &filterMap{})
|
||||
Walk(node, &filterLen{})
|
||||
Walk(node, &filterLast{})
|
||||
Walk(node, &filterFirst{})
|
||||
Walk(node, &predicateCombination{})
|
||||
Walk(node, &sumArray{})
|
||||
Walk(node, &sumMap{})
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
boolType = reflect.TypeOf(true)
|
||||
integerType = reflect.TypeOf(0)
|
||||
floatType = reflect.TypeOf(float64(0))
|
||||
stringType = reflect.TypeOf("")
|
||||
)
|
||||
|
||||
func patchWithType(node *Node, newNode Node) {
|
||||
switch n := newNode.(type) {
|
||||
case *BoolNode:
|
||||
newNode.SetType(boolType)
|
||||
case *IntegerNode:
|
||||
newNode.SetType(integerType)
|
||||
case *FloatNode:
|
||||
newNode.SetType(floatType)
|
||||
case *StringNode:
|
||||
newNode.SetType(stringType)
|
||||
case *ConstantNode:
|
||||
newNode.SetType(reflect.TypeOf(n.Value))
|
||||
case *BinaryNode:
|
||||
newNode.SetType(n.Type())
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown type %T", newNode))
|
||||
}
|
||||
Patch(node, newNode)
|
||||
}
|
||||
|
||||
func patchCopyType(node *Node, newNode Node) {
|
||||
t := (*node).Type()
|
||||
newNode.SetType(t)
|
||||
Patch(node, newNode)
|
||||
}
|
61
vendor/github.com/expr-lang/expr/optimizer/predicate_combination.go
generated
vendored
Normal file
61
vendor/github.com/expr-lang/expr/optimizer/predicate_combination.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
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
|
||||
}
|
37
vendor/github.com/expr-lang/expr/optimizer/sum_array.go
generated
vendored
Normal file
37
vendor/github.com/expr-lang/expr/optimizer/sum_array.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
package optimizer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
. "github.com/expr-lang/expr/ast"
|
||||
)
|
||||
|
||||
type sumArray struct{}
|
||||
|
||||
func (*sumArray) Visit(node *Node) {
|
||||
if sumBuiltin, ok := (*node).(*BuiltinNode); ok &&
|
||||
sumBuiltin.Name == "sum" &&
|
||||
len(sumBuiltin.Arguments) == 1 {
|
||||
if array, ok := sumBuiltin.Arguments[0].(*ArrayNode); ok &&
|
||||
len(array.Nodes) >= 2 {
|
||||
patchCopyType(node, sumArrayFold(array))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func sumArrayFold(array *ArrayNode) *BinaryNode {
|
||||
if len(array.Nodes) > 2 {
|
||||
return &BinaryNode{
|
||||
Operator: "+",
|
||||
Left: array.Nodes[0],
|
||||
Right: sumArrayFold(&ArrayNode{Nodes: array.Nodes[1:]}),
|
||||
}
|
||||
} else if len(array.Nodes) == 2 {
|
||||
return &BinaryNode{
|
||||
Operator: "+",
|
||||
Left: array.Nodes[0],
|
||||
Right: array.Nodes[1],
|
||||
}
|
||||
}
|
||||
panic(fmt.Errorf("sumArrayFold: invalid array length %d", len(array.Nodes)))
|
||||
}
|
25
vendor/github.com/expr-lang/expr/optimizer/sum_map.go
generated
vendored
Normal file
25
vendor/github.com/expr-lang/expr/optimizer/sum_map.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
package optimizer
|
||||
|
||||
import (
|
||||
. "github.com/expr-lang/expr/ast"
|
||||
)
|
||||
|
||||
type sumMap struct{}
|
||||
|
||||
func (*sumMap) Visit(node *Node) {
|
||||
if sumBuiltin, ok := (*node).(*BuiltinNode); ok &&
|
||||
sumBuiltin.Name == "sum" &&
|
||||
len(sumBuiltin.Arguments) == 1 {
|
||||
if mapBuiltin, ok := sumBuiltin.Arguments[0].(*BuiltinNode); ok &&
|
||||
mapBuiltin.Name == "map" &&
|
||||
len(mapBuiltin.Arguments) == 2 {
|
||||
patchCopyType(node, &BuiltinNode{
|
||||
Name: "sum",
|
||||
Arguments: []Node{
|
||||
mapBuiltin.Arguments[0],
|
||||
mapBuiltin.Arguments[1],
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user