// Sum func SumFunc(ctx expr.EvalContext, vals ...value.Value) (value.NumberValue, bool) { //u.Debugf("Sum: %v", vals) sumval := float64(0) for _, val := range vals { if val == nil || val.Nil() || val.Err() { // we don't need to evaluate if nil or error } else { switch valValue := val.(type) { case value.StringsValue: //u.Debugf("Nice, we have strings: %v", valValue) for _, sv := range valValue.Value().([]string) { if fv, ok := value.ToFloat64(reflect.ValueOf(sv)); ok && !math.IsNaN(fv) { sumval += fv } } default: //u.Debugf("Sum: %T tofloat=%v %v", value.ToFloat64(val.Rv()), value.ToFloat64(val.Rv()), val.Rv()) if fv, ok := value.ToFloat64(val.Rv()); ok && !math.IsNaN(fv) { sumval += fv } } } } if sumval == float64(0) { return value.NumberNaNValue, false } //u.Debugf("Sum() about to return? %v Nan?%v", sumval, sumval == math.NaN()) return value.NewNumberValue(sumval), true }
// <= Less Than or Equal // Must be able to convert items to Floats or else not ok // func LeFunc(ctx expr.EvalContext, lv, rv value.Value) (value.BoolValue, bool) { left, _ := value.ToFloat64(lv.Rv()) right, _ := value.ToFloat64(rv.Rv()) if math.IsNaN(left) || math.IsNaN(right) { return value.BoolValueFalse, false } return value.NewBoolValue(left <= right), true }
// < Less Than // Must be able to convert items to Floats or else not ok // func LtFunc(ctx expr.EvalContext, lv, rv value.Value) (value.BoolValue, bool) { left := value.ToFloat64(lv.Rv()) right := value.ToFloat64(rv.Rv()) if left == math.NaN() || right == math.NaN() { return value.BoolValueFalse, false } return value.NewBoolValue(left < right), true }
// Convert to Number: Best attempt at converting to integer // // tonumber("5") => 5.0 // tonumber("5.75") => 5.75 // tonumber("5,555") => 5555 // tonumber("$5") => 5.00 // tonumber("5,555.00") => 5555 // func ToNumber(ctx expr.EvalContext, item value.Value) (value.NumberValue, bool) { fv, ok := value.ToFloat64(reflect.ValueOf(item.Value())) if !ok { return value.NewNumberValue(0), false } return value.NewNumberValue(fv), true }
// Pow func PowFunc(ctx EvalContext, val, toPower value.Value) (value.NumberValue, bool) { //Pow(x, y float64) float64 //u.Infof("powFunc: %T:%v %T:%v ", val, val.Value(), toPower, toPower.Value()) if val.Err() || val.Nil() { return value.NewNumberValue(0), false } if toPower.Err() || toPower.Nil() { return value.NewNumberValue(0), false } fv, pow := value.ToFloat64(val.Rv()), value.ToFloat64(toPower.Rv()) if fv == math.NaN() || pow == math.NaN() { return value.NewNumberValue(0), false } fv = math.Pow(fv, pow) //u.Infof("pow ??? vals=[%v]", fv, pow) return value.NewNumberValue(fv), true }
// creates a new Value with a nil group and given value. // TODO: convert this to an interface method on nodes called Value() func numberNodeToValue(t *expr.NumberNode) (v value.Value) { //u.Debugf("nodeToValue() isFloat?%v", t.IsFloat) if t.IsInt { v = value.NewIntValue(t.Int64) } else if t.IsFloat { v = value.NewNumberValue(value.ToFloat64(reflect.ValueOf(t.Text))) } else { u.Errorf("Could not find type? %v", t.Type()) } //u.Debugf("return nodeToValue() %v %T arg:%T", v, v, t) return v }
// creates a new Value with a nil group and given value. // TODO: convert this to an interface method on nodes called Value() func numberNodeToValue(t *expr.NumberNode) (value.Value, bool) { //u.Debugf("nodeToValue() isFloat?%v", t.IsFloat) var v value.Value if t.IsInt { v = value.NewIntValue(t.Int64) } else if t.IsFloat { fv, ok := value.ToFloat64(reflect.ValueOf(t.Text)) if !ok { u.Warnf("Could not perform numeric conversion for %q", t.Text) return value.NilValueVal, false } v = value.NewNumberValue(fv) } else { u.Warnf("Could not find numeric conversion for %v", t.Type()) return value.NilValueVal, false } //u.Debugf("return nodeToValue() %v %T arg:%T", v, v, t) return v, true }