// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). // All rights reserved. // funcs-math.go package expr import ( "fmt" "io" ) func checkNumberParamExpected(funcName string, paramValue any, paramPos int) (err error) { if !(isNumber(paramValue) || isList(paramValue) || isIterator(paramValue)) { err = fmt.Errorf("%s(): param nr %d has wrong type %T, number expected", funcName, paramPos+1, paramValue) } return } func doAdd(ctx ExprContext, name string, it Iterator) (result any, err error) { var sumAsFloat = false var floatSum float64 = 0.0 var intSum int64 = 0 var v any for v, err = it.Next(); err == nil; v, err = it.Next() { if subIter, ok := v.(Iterator); ok { if v, err = doAdd(ctx, name, subIter); err != nil { break } if subIter.HasOperation(cleanName) { if _, err = subIter.CallOperation(cleanName, nil); err != nil { return } } } else { if err = checkNumberParamExpected(name, v, it.Index()); err != nil { break } if array, ok := v.([]any); ok { if v, err = doAdd(ctx, name, NewFlatArrayIterator(array)); err != nil { break } } } if !sumAsFloat && isFloat(v) { sumAsFloat = true floatSum = float64(intSum) } if sumAsFloat { floatSum += numAsFloat(v) } else { iv, _ := v.(int64) intSum += iv } } if err == nil || err == io.EOF { err = nil if sumAsFloat { result = floatSum } else { result = intSum } } return } func addFunc(ctx ExprContext, name string, args []any) (result any, err error) { result, err = doAdd(ctx, name, NewFlatArrayIterator(args)) return } func doMul(ctx ExprContext, name string, it Iterator) (result any, err error) { var mulAsFloat = false var floatProd float64 = 1.0 var intProd int64 = 1 var v any for v, err = it.Next(); err == nil; v, err = it.Next() { if err = checkNumberParamExpected(name, v, it.Index()); err != nil { break } if array, ok := v.([]any); ok { if v, err = doMul(ctx, name, NewFlatArrayIterator(array)); err != nil { break } } if !mulAsFloat && isFloat(v) { mulAsFloat = true floatProd = float64(intProd) } if mulAsFloat { floatProd *= numAsFloat(v) } else { iv, _ := v.(int64) intProd *= iv } } if err == nil || err == io.EOF { err = nil if mulAsFloat { result = floatProd } else { result = intProd } } return } func mulFunc(ctx ExprContext, name string, args []any) (result any, err error) { result, err = doMul(ctx, name, NewFlatArrayIterator(args)) return } func ImportMathFuncs(ctx ExprContext) { ctx.RegisterFunc("add", &simpleFunctor{f: addFunc}, 0, -1) ctx.RegisterFunc("mul", &simpleFunctor{f: mulFunc}, 0, -1) } func init() { registerImport("math.arith", ImportMathFuncs, "Function add() and mul()") }