package jmespath

import (
	
	
	
	
	
	
	
	
	
)

type jpFunction func(arguments []interface{}) (interface{}, error)

type jpType string

const (
	jpUnknown     jpType = "unknown"
	jpNumber      jpType = "number"
	jpString      jpType = "string"
	jpArray       jpType = "array"
	jpObject      jpType = "object"
	jpArrayNumber jpType = "array[number]"
	jpArrayString jpType = "array[string]"
	jpExpref      jpType = "expref"
	jpAny         jpType = "any"
)

type functionEntry struct {
	name      string
	arguments []argSpec
	handler   jpFunction
	hasExpRef bool
}

type argSpec struct {
	types    []jpType
	variadic bool
}

type byExprString struct {
	intr     *treeInterpreter
	node     ASTNode
	items    []interface{}
	hasError bool
}

func ( *byExprString) () int {
	return len(.items)
}
func ( *byExprString) (,  int) {
	.items[], .items[] = .items[], .items[]
}
func ( *byExprString) (,  int) bool {
	,  := .intr.Execute(.node, .items[])
	if  != nil {
Return a dummy value.
		return true
	}
	,  := .(string)
	if ! {
		.hasError = true
		return true
	}
	,  := .intr.Execute(.node, .items[])
	if  != nil {
Return a dummy value.
		return true
	}
	,  := .(string)
	if ! {
		.hasError = true
		return true
	}
	return  < 
}

type byExprFloat struct {
	intr     *treeInterpreter
	node     ASTNode
	items    []interface{}
	hasError bool
}

func ( *byExprFloat) () int {
	return len(.items)
}
func ( *byExprFloat) (,  int) {
	.items[], .items[] = .items[], .items[]
}
func ( *byExprFloat) (,  int) bool {
	,  := .intr.Execute(.node, .items[])
	if  != nil {
Return a dummy value.
		return true
	}
	,  := .(float64)
	if ! {
		.hasError = true
		return true
	}
	,  := .intr.Execute(.node, .items[])
	if  != nil {
Return a dummy value.
		return true
	}
	,  := .(float64)
	if ! {
		.hasError = true
		return true
	}
	return  < 
}

type functionCaller struct {
	functionTable map[string]functionEntry
}

func () *functionCaller {
	 := &functionCaller{}
	.functionTable = map[string]functionEntry{
		"length": {
			name: "length",
			arguments: []argSpec{
				{types: []jpType{jpString, jpArray, jpObject}},
			},
			handler: jpfLength,
		},
		"starts_with": {
			name: "starts_with",
			arguments: []argSpec{
				{types: []jpType{jpString}},
				{types: []jpType{jpString}},
			},
			handler: jpfStartsWith,
		},
		"abs": {
			name: "abs",
			arguments: []argSpec{
				{types: []jpType{jpNumber}},
			},
			handler: jpfAbs,
		},
		"avg": {
			name: "avg",
			arguments: []argSpec{
				{types: []jpType{jpArrayNumber}},
			},
			handler: jpfAvg,
		},
		"ceil": {
			name: "ceil",
			arguments: []argSpec{
				{types: []jpType{jpNumber}},
			},
			handler: jpfCeil,
		},
		"contains": {
			name: "contains",
			arguments: []argSpec{
				{types: []jpType{jpArray, jpString}},
				{types: []jpType{jpAny}},
			},
			handler: jpfContains,
		},
		"ends_with": {
			name: "ends_with",
			arguments: []argSpec{
				{types: []jpType{jpString}},
				{types: []jpType{jpString}},
			},
			handler: jpfEndsWith,
		},
		"floor": {
			name: "floor",
			arguments: []argSpec{
				{types: []jpType{jpNumber}},
			},
			handler: jpfFloor,
		},
		"map": {
			name: "amp",
			arguments: []argSpec{
				{types: []jpType{jpExpref}},
				{types: []jpType{jpArray}},
			},
			handler:   jpfMap,
			hasExpRef: true,
		},
		"max": {
			name: "max",
			arguments: []argSpec{
				{types: []jpType{jpArrayNumber, jpArrayString}},
			},
			handler: jpfMax,
		},
		"merge": {
			name: "merge",
			arguments: []argSpec{
				{types: []jpType{jpObject}, variadic: true},
			},
			handler: jpfMerge,
		},
		"max_by": {
			name: "max_by",
			arguments: []argSpec{
				{types: []jpType{jpArray}},
				{types: []jpType{jpExpref}},
			},
			handler:   jpfMaxBy,
			hasExpRef: true,
		},
		"sum": {
			name: "sum",
			arguments: []argSpec{
				{types: []jpType{jpArrayNumber}},
			},
			handler: jpfSum,
		},
		"min": {
			name: "min",
			arguments: []argSpec{
				{types: []jpType{jpArrayNumber, jpArrayString}},
			},
			handler: jpfMin,
		},
		"min_by": {
			name: "min_by",
			arguments: []argSpec{
				{types: []jpType{jpArray}},
				{types: []jpType{jpExpref}},
			},
			handler:   jpfMinBy,
			hasExpRef: true,
		},
		"type": {
			name: "type",
			arguments: []argSpec{
				{types: []jpType{jpAny}},
			},
			handler: jpfType,
		},
		"keys": {
			name: "keys",
			arguments: []argSpec{
				{types: []jpType{jpObject}},
			},
			handler: jpfKeys,
		},
		"values": {
			name: "values",
			arguments: []argSpec{
				{types: []jpType{jpObject}},
			},
			handler: jpfValues,
		},
		"sort": {
			name: "sort",
			arguments: []argSpec{
				{types: []jpType{jpArrayString, jpArrayNumber}},
			},
			handler: jpfSort,
		},
		"sort_by": {
			name: "sort_by",
			arguments: []argSpec{
				{types: []jpType{jpArray}},
				{types: []jpType{jpExpref}},
			},
			handler:   jpfSortBy,
			hasExpRef: true,
		},
		"join": {
			name: "join",
			arguments: []argSpec{
				{types: []jpType{jpString}},
				{types: []jpType{jpArrayString}},
			},
			handler: jpfJoin,
		},
		"reverse": {
			name: "reverse",
			arguments: []argSpec{
				{types: []jpType{jpArray, jpString}},
			},
			handler: jpfReverse,
		},
		"to_array": {
			name: "to_array",
			arguments: []argSpec{
				{types: []jpType{jpAny}},
			},
			handler: jpfToArray,
		},
		"to_string": {
			name: "to_string",
			arguments: []argSpec{
				{types: []jpType{jpAny}},
			},
			handler: jpfToString,
		},
		"to_number": {
			name: "to_number",
			arguments: []argSpec{
				{types: []jpType{jpAny}},
			},
			handler: jpfToNumber,
		},
		"not_null": {
			name: "not_null",
			arguments: []argSpec{
				{types: []jpType{jpAny}, variadic: true},
			},
			handler: jpfNotNull,
		},
	}
	return 
}

func ( *functionEntry) ( []interface{}) ([]interface{}, error) {
	if len(.arguments) == 0 {
		return , nil
	}
	if !.arguments[len(.arguments)-1].variadic {
		if len(.arguments) != len() {
			return nil, errors.New("incorrect number of args")
		}
		for ,  := range .arguments {
			 := []
			 := .typeCheck()
			if  != nil {
				return nil, 
			}
		}
		return , nil
	}
	if len() < len(.arguments) {
		return nil, errors.New("Invalid arity.")
	}
	return , nil
}

func ( *argSpec) ( interface{}) error {
	for ,  := range .types {
		switch  {
		case jpNumber:
			if ,  := .(float64);  {
				return nil
			}
		case jpString:
			if ,  := .(string);  {
				return nil
			}
		case jpArray:
			if isSliceType() {
				return nil
			}
		case jpObject:
			if ,  := .(map[string]interface{});  {
				return nil
			}
		case jpArrayNumber:
			if ,  := toArrayNum();  {
				return nil
			}
		case jpArrayString:
			if ,  := toArrayStr();  {
				return nil
			}
		case jpAny:
			return nil
		case jpExpref:
			if ,  := .(expRef);  {
				return nil
			}
		}
	}
	return fmt.Errorf("Invalid type for: %v, expected: %#v", , .types)
}

func ( *functionCaller) ( string,  []interface{},  *treeInterpreter) (interface{}, error) {
	,  := .functionTable[]
	if ! {
		return nil, errors.New("unknown function: " + )
	}
	,  := .resolveArgs()
	if  != nil {
		return nil, 
	}
	if .hasExpRef {
		var  []interface{}
		 = append(, )
		 = append(, ...)
	}
	return .handler()
}

func ( []interface{}) (interface{}, error) {
	 := [0].(float64)
	return math.Abs(), nil
}

func ( []interface{}) (interface{}, error) {
	 := [0]
	if ,  := .(string);  {
		return float64(utf8.RuneCountInString()), nil
	} else if isSliceType() {
		 := reflect.ValueOf()
		return float64(.Len()), nil
	} else if ,  := .(map[string]interface{});  {
		return float64(len()), nil
	}
	return nil, errors.New("could not compute length()")
}

func ( []interface{}) (interface{}, error) {
	 := [0].(string)
	 := [1].(string)
	return strings.HasPrefix(, ), nil
}

We've already type checked the value so we can safely use type assertions.
	 := [0].([]interface{})
	 := float64(len())
	 := 0.0
	for ,  := range  {
		 += .(float64)
	}
	return  / , nil
}
func ( []interface{}) (interface{}, error) {
	 := [0].(float64)
	return math.Ceil(), nil
}
func ( []interface{}) (interface{}, error) {
	 := [0]
	 := [1]
	if ,  := .(string);  {
		if ,  := .(string);  {
			return strings.Index(, ) != -1, nil
		}
		return false, nil
Otherwise this is a generic contains for []interface{}
	 := .([]interface{})
	for ,  := range  {
		if  ==  {
			return true, nil
		}
	}
	return false, nil
}
func ( []interface{}) (interface{}, error) {
	 := [0].(string)
	 := [1].(string)
	return strings.HasSuffix(, ), nil
}
func ( []interface{}) (interface{}, error) {
	 := [0].(float64)
	return math.Floor(), nil
}
func ( []interface{}) (interface{}, error) {
	 := [0].(*treeInterpreter)
	 := [1].(expRef)
	 := .ref
	 := [2].([]interface{})
	 := make([]interface{}, 0, len())
	for ,  := range  {
		,  := .Execute(, )
		if  != nil {
			return nil, 
		}
		 = append(, )
	}
	return , nil
}
func ( []interface{}) (interface{}, error) {
	if ,  := toArrayNum([0]);  {
		if len() == 0 {
			return nil, nil
		}
		if len() == 1 {
			return [0], nil
		}
		 := [0]
		for ,  := range [1:] {
			if  >  {
				 = 
			}
		}
		return , nil
Otherwise we're dealing with a max() of strings.
	,  := toArrayStr([0])
	if len() == 0 {
		return nil, nil
	}
	if len() == 1 {
		return [0], nil
	}
	 := [0]
	for ,  := range [1:] {
		if  >  {
			 = 
		}
	}
	return , nil
}
func ( []interface{}) (interface{}, error) {
	 := make(map[string]interface{})
	for ,  := range  {
		 := .(map[string]interface{})
		for ,  := range  {
			[] = 
		}
	}
	return , nil
}
func ( []interface{}) (interface{}, error) {
	 := [0].(*treeInterpreter)
	 := [1].([]interface{})
	 := [2].(expRef)
	 := .ref
	if len() == 0 {
		return nil, nil
	} else if len() == 1 {
		return [0], nil
	}
	,  := .Execute(, [0])
	if  != nil {
		return nil, 
	}
	switch t := .(type) {
	case float64:
		 := 
		 := [0]
		for ,  := range [1:] {
			,  := .Execute(, )
			if  != nil {
				return nil, 
			}
			,  := .(float64)
			if ! {
				return nil, errors.New("invalid type, must be number")
			}
			if  >  {
				 = 
				 = 
			}
		}
		return , nil
	case string:
		 := 
		 := [0]
		for ,  := range [1:] {
			,  := .Execute(, )
			if  != nil {
				return nil, 
			}
			,  := .(string)
			if ! {
				return nil, errors.New("invalid type, must be string")
			}
			if  >  {
				 = 
				 = 
			}
		}
		return , nil
	default:
		return nil, errors.New("invalid type, must be number of string")
	}
}
func ( []interface{}) (interface{}, error) {
	,  := toArrayNum([0])
	 := 0.0
	for ,  := range  {
		 += 
	}
	return , nil
}

func ( []interface{}) (interface{}, error) {
	if ,  := toArrayNum([0]);  {
		if len() == 0 {
			return nil, nil
		}
		if len() == 1 {
			return [0], nil
		}
		 := [0]
		for ,  := range [1:] {
			if  <  {
				 = 
			}
		}
		return , nil
	}
	,  := toArrayStr([0])
	if len() == 0 {
		return nil, nil
	}
	if len() == 1 {
		return [0], nil
	}
	 := [0]
	for ,  := range [1:] {
		if  <  {
			 = 
		}
	}
	return , nil
}

func ( []interface{}) (interface{}, error) {
	 := [0].(*treeInterpreter)
	 := [1].([]interface{})
	 := [2].(expRef)
	 := .ref
	if len() == 0 {
		return nil, nil
	} else if len() == 1 {
		return [0], nil
	}
	,  := .Execute(, [0])
	if  != nil {
		return nil, 
	}
	if ,  := .(float64);  {
		 := 
		 := [0]
		for ,  := range [1:] {
			,  := .Execute(, )
			if  != nil {
				return nil, 
			}
			,  := .(float64)
			if ! {
				return nil, errors.New("invalid type, must be number")
			}
			if  <  {
				 = 
				 = 
			}
		}
		return , nil
	} else if ,  := .(string);  {
		 := 
		 := [0]
		for ,  := range [1:] {
			,  := .Execute(, )
			if  != nil {
				return nil, 
			}
			,  := .(string)
			if ! {
				return nil, errors.New("invalid type, must be string")
			}
			if  <  {
				 = 
				 = 
			}
		}
		return , nil
	} else {
		return nil, errors.New("invalid type, must be number of string")
	}
}
func ( []interface{}) (interface{}, error) {
	 := [0]
	if ,  := .(float64);  {
		return "number", nil
	}
	if ,  := .(string);  {
		return "string", nil
	}
	if ,  := .([]interface{});  {
		return "array", nil
	}
	if ,  := .(map[string]interface{});  {
		return "object", nil
	}
	if  == nil {
		return "null", nil
	}
	if  == true ||  == false {
		return "boolean", nil
	}
	return nil, errors.New("unknown type")
}
func ( []interface{}) (interface{}, error) {
	 := [0].(map[string]interface{})
	 := make([]interface{}, 0, len())
	for  := range  {
		 = append(, )
	}
	return , nil
}
func ( []interface{}) (interface{}, error) {
	 := [0].(map[string]interface{})
	 := make([]interface{}, 0, len())
	for ,  := range  {
		 = append(, )
	}
	return , nil
}
func ( []interface{}) (interface{}, error) {
	if ,  := toArrayNum([0]);  {
		 := sort.Float64Slice()
		sort.Stable()
		 := make([]interface{}, len())
		for ,  := range  {
			[] = 
		}
		return , nil
Otherwise we're dealing with sort()'ing strings.
	,  := toArrayStr([0])
	 := sort.StringSlice()
	sort.Stable()
	 := make([]interface{}, len())
	for ,  := range  {
		[] = 
	}
	return , nil
}
func ( []interface{}) (interface{}, error) {
	 := [0].(*treeInterpreter)
	 := [1].([]interface{})
	 := [2].(expRef)
	 := .ref
	if len() == 0 {
		return , nil
	} else if len() == 1 {
		return , nil
	}
	,  := .Execute(, [0])
	if  != nil {
		return nil, 
	}
	if ,  := .(float64);  {
		 := &byExprFloat{, , , false}
		sort.Stable()
		if .hasError {
			return nil, errors.New("error in sort_by comparison")
		}
		return , nil
	} else if ,  := .(string);  {
		 := &byExprString{, , , false}
		sort.Stable()
		if .hasError {
			return nil, errors.New("error in sort_by comparison")
		}
		return , nil
	} else {
		return nil, errors.New("invalid type, must be number of string")
	}
}
func ( []interface{}) (interface{}, error) {
We can't just do arguments[1].([]string), we have to manually convert each item to a string.
	 := []string{}
	for ,  := range [1].([]interface{}) {
		 = append(, .(string))
	}
	return strings.Join(, ), nil
}
func ( []interface{}) (interface{}, error) {
	if ,  := [0].(string);  {
		 := []rune()
		for ,  := 0, len()-1;  < len()/2; ,  = +1, -1 {
			[], [] = [], []
		}
		return string(), nil
	}
	 := [0].([]interface{})
	 := len()
	 := make([]interface{}, )
	for ,  := range  {
		[-(+1)] = 
	}
	return , nil
}
func ( []interface{}) (interface{}, error) {
	if ,  := [0].([]interface{});  {
		return [0], nil
	}
	return [:1:1], nil
}
func ( []interface{}) (interface{}, error) {
	if ,  := [0].(string);  {
		return , nil
	}
	,  := json.Marshal([0])
	if  != nil {
		return nil, 
	}
	return string(), nil
}
func ( []interface{}) (interface{}, error) {
	 := [0]
	if ,  := .(float64);  {
		return , nil
	}
	if ,  := .(string);  {
		,  := strconv.ParseFloat(, 64)
		if  != nil {
			return nil, nil
		}
		return , nil
	}
	if ,  := .([]interface{});  {
		return nil, nil
	}
	if ,  := .(map[string]interface{});  {
		return nil, nil
	}
	if  == nil {
		return nil, nil
	}
	if  == true ||  == false {
		return nil, nil
	}
	return nil, errors.New("unknown type")
}
func ( []interface{}) (interface{}, error) {
	for ,  := range  {
		if  != nil {
			return , nil
		}
	}
	return nil, nil