mirror of
https://github.com/adnanh/webhook.git
synced 2025-07-05 02:38:31 +00:00
wip
This commit is contained in:
parent
e329b6d9ff
commit
568c711625
138 changed files with 22876 additions and 90497 deletions
77
vendor/github.com/antonmedv/expr/optimizer/const_expr.go
generated
vendored
Normal file
77
vendor/github.com/antonmedv/expr/optimizer/const_expr.go
generated
vendored
Normal file
|
@ -0,0 +1,77 @@
|
|||
package optimizer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
. "github.com/antonmedv/expr/ast"
|
||||
"github.com/antonmedv/expr/file"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type constExpr struct {
|
||||
applied bool
|
||||
err error
|
||||
fns map[string]reflect.Value
|
||||
}
|
||||
|
||||
func (*constExpr) Enter(*Node) {}
|
||||
func (c *constExpr) Exit(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,
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
patch := func(newNode Node) {
|
||||
c.applied = true
|
||||
Patch(node, newNode)
|
||||
}
|
||||
|
||||
switch n := (*node).(type) {
|
||||
case *FunctionNode:
|
||||
fn, ok := c.fns[n.Name]
|
||||
if ok {
|
||||
in := make([]reflect.Value, len(n.Arguments))
|
||||
for i := 0; i < len(n.Arguments); i++ {
|
||||
arg := n.Arguments[i]
|
||||
var param interface{}
|
||||
|
||||
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)
|
||||
constNode := &ConstantNode{Value: out[0].Interface()}
|
||||
patch(constNode)
|
||||
}
|
||||
}
|
||||
}
|
33
vendor/github.com/antonmedv/expr/optimizer/const_range.go
generated
vendored
Normal file
33
vendor/github.com/antonmedv/expr/optimizer/const_range.go
generated
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
package optimizer
|
||||
|
||||
import (
|
||||
. "github.com/antonmedv/expr/ast"
|
||||
)
|
||||
|
||||
type constRange struct{}
|
||||
|
||||
func (*constRange) Enter(*Node) {}
|
||||
func (*constRange) Exit(node *Node) {
|
||||
switch n := (*node).(type) {
|
||||
case *BinaryNode:
|
||||
if n.Operator == ".." {
|
||||
if min, ok := n.Left.(*IntegerNode); ok {
|
||||
if max, ok := n.Right.(*IntegerNode); ok {
|
||||
size := max.Value - min.Value + 1
|
||||
// In this case array is too big. Skip generation,
|
||||
// and wait for memory budget detection on runtime.
|
||||
if size > 1e6 {
|
||||
return
|
||||
}
|
||||
value := make([]int, size)
|
||||
for i := range value {
|
||||
value[i] = min.Value + i
|
||||
}
|
||||
Patch(node, &ConstantNode{
|
||||
Value: value,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
133
vendor/github.com/antonmedv/expr/optimizer/fold.go
generated
vendored
Normal file
133
vendor/github.com/antonmedv/expr/optimizer/fold.go
generated
vendored
Normal file
|
@ -0,0 +1,133 @@
|
|||
package optimizer
|
||||
|
||||
import (
|
||||
"math"
|
||||
"reflect"
|
||||
|
||||
. "github.com/antonmedv/expr/ast"
|
||||
"github.com/antonmedv/expr/file"
|
||||
)
|
||||
|
||||
type fold struct {
|
||||
applied bool
|
||||
err *file.Error
|
||||
}
|
||||
|
||||
func (*fold) Enter(*Node) {}
|
||||
func (fold *fold) Exit(node *Node) {
|
||||
patch := func(newNode Node) {
|
||||
fold.applied = true
|
||||
Patch(node, newNode)
|
||||
}
|
||||
// for IntegerNode the type may have been changed from int->float
|
||||
// preserve this information by setting the type after the Patch
|
||||
patchWithType := func(newNode Node, leafType reflect.Type) {
|
||||
patch(newNode)
|
||||
newNode.SetType(leafType)
|
||||
}
|
||||
|
||||
switch n := (*node).(type) {
|
||||
case *UnaryNode:
|
||||
switch n.Operator {
|
||||
case "-":
|
||||
if i, ok := n.Node.(*IntegerNode); ok {
|
||||
patchWithType(&IntegerNode{Value: -i.Value}, n.Node.Type())
|
||||
}
|
||||
case "+":
|
||||
if i, ok := n.Node.(*IntegerNode); ok {
|
||||
patchWithType(&IntegerNode{Value: i.Value}, n.Node.Type())
|
||||
}
|
||||
}
|
||||
|
||||
case *BinaryNode:
|
||||
switch n.Operator {
|
||||
case "+":
|
||||
if a, ok := n.Left.(*IntegerNode); ok {
|
||||
if b, ok := n.Right.(*IntegerNode); ok {
|
||||
patchWithType(&IntegerNode{Value: a.Value + b.Value}, a.Type())
|
||||
}
|
||||
}
|
||||
if a, ok := n.Left.(*StringNode); ok {
|
||||
if b, ok := n.Right.(*StringNode); ok {
|
||||
patch(&StringNode{Value: a.Value + b.Value})
|
||||
}
|
||||
}
|
||||
case "-":
|
||||
if a, ok := n.Left.(*IntegerNode); ok {
|
||||
if b, ok := n.Right.(*IntegerNode); ok {
|
||||
patchWithType(&IntegerNode{Value: a.Value - b.Value}, a.Type())
|
||||
}
|
||||
}
|
||||
case "*":
|
||||
if a, ok := n.Left.(*IntegerNode); ok {
|
||||
if b, ok := n.Right.(*IntegerNode); ok {
|
||||
patchWithType(&IntegerNode{Value: a.Value * b.Value}, a.Type())
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
patchWithType(&IntegerNode{Value: a.Value / b.Value}, a.Type())
|
||||
}
|
||||
}
|
||||
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 "**":
|
||||
if a, ok := n.Left.(*IntegerNode); ok {
|
||||
if b, ok := n.Right.(*IntegerNode); ok {
|
||||
patch(&FloatNode{Value: math.Pow(float64(a.Value), float64(b.Value))})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case *ArrayNode:
|
||||
if len(n.Nodes) > 0 {
|
||||
|
||||
for _, a := range n.Nodes {
|
||||
if _, ok := a.(*IntegerNode); !ok {
|
||||
goto string
|
||||
}
|
||||
}
|
||||
{
|
||||
value := make([]int, len(n.Nodes))
|
||||
for i, a := range n.Nodes {
|
||||
value[i] = a.(*IntegerNode).Value
|
||||
}
|
||||
patch(&ConstantNode{Value: value})
|
||||
}
|
||||
|
||||
string:
|
||||
for _, a := range n.Nodes {
|
||||
if _, ok := a.(*StringNode); !ok {
|
||||
return
|
||||
}
|
||||
}
|
||||
{
|
||||
value := make([]string, len(n.Nodes))
|
||||
for i, a := range n.Nodes {
|
||||
value[i] = a.(*StringNode).Value
|
||||
}
|
||||
patch(&ConstantNode{Value: value})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
65
vendor/github.com/antonmedv/expr/optimizer/in_array.go
generated
vendored
Normal file
65
vendor/github.com/antonmedv/expr/optimizer/in_array.go
generated
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
package optimizer
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
. "github.com/antonmedv/expr/ast"
|
||||
)
|
||||
|
||||
type inArray struct{}
|
||||
|
||||
func (*inArray) Enter(*Node) {}
|
||||
func (*inArray) Exit(node *Node) {
|
||||
switch n := (*node).(type) {
|
||||
case *BinaryNode:
|
||||
if n.Operator == "in" || n.Operator == "not 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{}{}
|
||||
}
|
||||
Patch(node, &BinaryNode{
|
||||
Operator: n.Operator,
|
||||
Left: n.Left,
|
||||
Right: &ConstantNode{Value: value},
|
||||
})
|
||||
}
|
||||
|
||||
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{}{}
|
||||
}
|
||||
Patch(node, &BinaryNode{
|
||||
Operator: n.Operator,
|
||||
Left: n.Left,
|
||||
Right: &ConstantNode{Value: value},
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
41
vendor/github.com/antonmedv/expr/optimizer/in_range.go
generated
vendored
Normal file
41
vendor/github.com/antonmedv/expr/optimizer/in_range.go
generated
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
package optimizer
|
||||
|
||||
import (
|
||||
. "github.com/antonmedv/expr/ast"
|
||||
)
|
||||
|
||||
type inRange struct{}
|
||||
|
||||
func (*inRange) Enter(*Node) {}
|
||||
func (*inRange) Exit(node *Node) {
|
||||
switch n := (*node).(type) {
|
||||
case *BinaryNode:
|
||||
if n.Operator == "in" || n.Operator == "not in" {
|
||||
if rng, ok := n.Right.(*BinaryNode); ok && rng.Operator == ".." {
|
||||
if from, ok := rng.Left.(*IntegerNode); ok {
|
||||
if to, ok := rng.Right.(*IntegerNode); ok {
|
||||
Patch(node, &BinaryNode{
|
||||
Operator: "and",
|
||||
Left: &BinaryNode{
|
||||
Operator: ">=",
|
||||
Left: n.Left,
|
||||
Right: from,
|
||||
},
|
||||
Right: &BinaryNode{
|
||||
Operator: "<=",
|
||||
Left: n.Left,
|
||||
Right: to,
|
||||
},
|
||||
})
|
||||
if n.Operator == "not in" {
|
||||
Patch(node, &UnaryNode{
|
||||
Operator: "not",
|
||||
Node: *node,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
37
vendor/github.com/antonmedv/expr/optimizer/optimizer.go
generated
vendored
Normal file
37
vendor/github.com/antonmedv/expr/optimizer/optimizer.go
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
package optimizer
|
||||
|
||||
import (
|
||||
. "github.com/antonmedv/expr/ast"
|
||||
"github.com/antonmedv/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.ConstExprFns) > 0 {
|
||||
for limit := 100; limit >= 0; limit-- {
|
||||
constExpr := &constExpr{
|
||||
fns: config.ConstExprFns,
|
||||
}
|
||||
Walk(node, constExpr)
|
||||
if constExpr.err != nil {
|
||||
return constExpr.err
|
||||
}
|
||||
if !constExpr.applied {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
Walk(node, &inRange{})
|
||||
Walk(node, &constRange{})
|
||||
return nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue