- fraction type renamed as FractionType and moved from operator-fraction.go to fraction-type.go - ListType moved from operator-list.go to list-type.go - all test file were renamed adding the "t_" prefix - defined a test template in file t_temple_test.go - new test file t_relational_test.go where relational tests are collected - lists can now compared as set using operators <, <=, >, and >= (IMPORTANT: here = menas same content, not same list)
182 lines
4.2 KiB
Go
182 lines
4.2 KiB
Go
// 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, level, subPos int) (err error) {
|
|
if !(IsNumber(paramValue) || isFraction(paramValue)) /*|| isList(paramValue)*/ {
|
|
err = fmt.Errorf("%s(): param nr %d (%d in %d) has wrong type %T, number expected",
|
|
funcName, paramPos+1, subPos+1, level, paramValue)
|
|
}
|
|
return
|
|
}
|
|
|
|
func doAdd(ctx ExprContext, name string, it Iterator, count, level int) (result any, err error) {
|
|
var sumAsFloat, sumAsFract bool
|
|
var floatSum float64 = 0.0
|
|
var intSum int64 = 0
|
|
var fractSum *FractionType
|
|
var v any
|
|
|
|
level++
|
|
|
|
for v, err = it.Next(); err == nil; v, err = it.Next() {
|
|
if list, ok := v.(*ListType); ok {
|
|
v = NewListIterator(list, nil)
|
|
}
|
|
if subIter, ok := v.(Iterator); ok {
|
|
if v, err = doAdd(ctx, name, subIter, count, level); err != nil {
|
|
break
|
|
}
|
|
if extIter, ok := v.(ExtIterator); ok && extIter.HasOperation(cleanName) {
|
|
if _, err = extIter.CallOperation(cleanName, nil); err != nil {
|
|
return
|
|
}
|
|
}
|
|
} else if err = checkNumberParamExpected(name, v, count, level, it.Index()); err != nil {
|
|
break
|
|
}
|
|
count++
|
|
|
|
if !sumAsFloat {
|
|
if IsFloat(v) {
|
|
sumAsFloat = true
|
|
if sumAsFract {
|
|
floatSum = fractSum.toFloat()
|
|
} else {
|
|
floatSum = float64(intSum)
|
|
}
|
|
} else if !sumAsFract && isFraction(v) {
|
|
fractSum = newFraction(intSum, 1)
|
|
sumAsFract = true
|
|
}
|
|
}
|
|
|
|
if sumAsFloat {
|
|
floatSum += numAsFloat(v)
|
|
} else if sumAsFract {
|
|
var item *FractionType
|
|
var ok bool
|
|
if item, ok = v.(*FractionType); !ok {
|
|
iv, _ := v.(int64)
|
|
item = newFraction(iv, 1)
|
|
}
|
|
fractSum = sumFract(fractSum, item)
|
|
} else {
|
|
iv, _ := v.(int64)
|
|
intSum += iv
|
|
}
|
|
}
|
|
if err == nil || err == io.EOF {
|
|
err = nil
|
|
if sumAsFloat {
|
|
result = floatSum
|
|
} else if sumAsFract {
|
|
result = fractSum
|
|
} else {
|
|
result = intSum
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func addFunc(ctx ExprContext, name string, args []any) (result any, err error) {
|
|
result, err = doAdd(ctx, name, NewArrayIterator(args), 0, -1)
|
|
return
|
|
}
|
|
|
|
func doMul(ctx ExprContext, name string, it Iterator, count, level int) (result any, err error) {
|
|
var mulAsFloat, mulAsFract bool
|
|
var floatProd float64 = 1.0
|
|
var intProd int64 = 1
|
|
var fractProd *FractionType
|
|
var v any
|
|
|
|
level++
|
|
for v, err = it.Next(); err == nil; v, err = it.Next() {
|
|
if list, ok := v.(*ListType); ok {
|
|
v = NewListIterator(list, nil)
|
|
}
|
|
if subIter, ok := v.(Iterator); ok {
|
|
if v, err = doMul(ctx, name, subIter, count, level); err != nil {
|
|
break
|
|
}
|
|
if extIter, ok := v.(ExtIterator); ok && extIter.HasOperation(cleanName) {
|
|
if _, err = extIter.CallOperation(cleanName, nil); err != nil {
|
|
return
|
|
}
|
|
}
|
|
} else {
|
|
if err = checkNumberParamExpected(name, v, count, level, it.Index()); err != nil {
|
|
break
|
|
}
|
|
}
|
|
count++
|
|
|
|
if !mulAsFloat {
|
|
if IsFloat(v) {
|
|
mulAsFloat = true
|
|
if mulAsFract {
|
|
floatProd = fractProd.toFloat()
|
|
} else {
|
|
floatProd = float64(intProd)
|
|
}
|
|
} else if !mulAsFract && isFraction(v) {
|
|
fractProd = newFraction(intProd, 1)
|
|
mulAsFract = true
|
|
}
|
|
}
|
|
|
|
if mulAsFloat {
|
|
floatProd *= numAsFloat(v)
|
|
} else if mulAsFract {
|
|
var item *FractionType
|
|
var ok bool
|
|
if item, ok = v.(*FractionType); !ok {
|
|
iv, _ := v.(int64)
|
|
item = newFraction(iv, 1)
|
|
}
|
|
fractProd = mulFract(fractProd, item)
|
|
} else {
|
|
iv, _ := v.(int64)
|
|
intProd *= iv
|
|
}
|
|
}
|
|
if err == nil || err == io.EOF {
|
|
err = nil
|
|
if mulAsFloat {
|
|
result = floatProd
|
|
} else if mulAsFract {
|
|
result = fractProd
|
|
} else {
|
|
result = intProd
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func mulFunc(ctx ExprContext, name string, args []any) (result any, err error) {
|
|
result, err = doMul(ctx, name, NewArrayIterator(args), 0, -1)
|
|
return
|
|
}
|
|
|
|
func ImportMathFuncs(ctx ExprContext) {
|
|
ctx.RegisterFunc("add", &golangFunctor{f: addFunc}, typeNumber, []ExprFuncParam{
|
|
newFuncParamFlagDef(paramValue, pfOptional|pfRepeat, 0),
|
|
})
|
|
|
|
ctx.RegisterFunc("mul", &golangFunctor{f: mulFunc}, typeNumber, []ExprFuncParam{
|
|
newFuncParamFlagDef(paramValue, pfOptional|pfRepeat, 1),
|
|
})
|
|
}
|
|
|
|
func init() {
|
|
registerImport("math.arith", ImportMathFuncs, "Functions add() and mul()")
|
|
}
|