chore: upgrade coredns version (#550)

This commit is contained in:
naison
2025-04-19 10:06:56 +08:00
committed by GitHub
parent c42e3475f9
commit c9f1ce6522
1701 changed files with 235209 additions and 29271 deletions

View 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(&param).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
}
}
}
}

View 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,
})
}
}
}

View 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,
})
}
}
}

View 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,
})
}
}
}

View 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
View 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
View 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
View 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,
},
})
}
}
}
}
}
}

View 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)
}

View 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
}

View 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
View 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],
},
})
}
}
}