summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--calc.go1728
-rw-r--r--calc_test.go227
-rw-r--r--go.mod8
-rw-r--r--go.sum24
4 files changed, 943 insertions, 1044 deletions
diff --git a/calc.go b/calc.go
index 5b975f5..0a65328 100644
--- a/calc.go
+++ b/calc.go
@@ -88,15 +88,36 @@ type ArgType byte
// Formula argument types enumeration.
const (
ArgUnknown ArgType = iota
+ ArgNumber
ArgString
+ ArgList
ArgMatrix
+ ArgError
+ ArgEmpty
)
// formulaArg is the argument of a formula or function.
type formulaArg struct {
- String string
- Matrix [][]formulaArg
- Type ArgType
+ Number float64
+ String string
+ List []formulaArg
+ Matrix [][]formulaArg
+ Boolean bool
+ Error string
+ Type ArgType
+}
+
+// Value returns a string data type of the formula argument.
+func (fa formulaArg) Value() (value string) {
+ switch fa.Type {
+ case ArgNumber:
+ return fmt.Sprintf("%g", fa.Number)
+ case ArgString:
+ return fa.String
+ case ArgError:
+ return fa.Error
+ }
+ return
}
// formulaFuncs is the type of the formula functions.
@@ -124,15 +145,94 @@ var tokenPriority = map[string]int{
//
// Supported formulas:
//
-// ABS, ACOS, ACOSH, ACOT, ACOTH, AND, ARABIC, ASIN, ASINH, ATAN2, ATANH,
-// BASE, CEILING, CEILING.MATH, CEILING.PRECISE, CLEAN, COMBIN, COMBINA,
-// COS, COSH, COT, COTH, COUNTA, CSC, CSCH, DATE, DECIMAL, DEGREES, EVEN,
-// EXP, FACT, FACTDOUBLE, FLOOR, FLOOR.MATH, FLOOR.PRECISE, GCD, INT,
-// ISBLANK, ISERR, ISERROR, ISEVEN, ISNA, ISNONTEXT, ISNUMBER, ISO.CEILING,
-// ISODD, LCM, LN, LOG, LOG10, LOWER, MDETERM, MEDIAN, MOD, MROUND,
-// MULTINOMIAL, MUNIT, NA, ODD, OR, PI, POWER, PRODUCT, PROPER, QUOTIENT,
-// RADIANS, RAND, RANDBETWEEN, ROUND, ROUNDDOWN, ROUNDUP, SEC, SECH, SIGN,
-// SIN, SINH, SQRT, SQRTPI, SUM, SUMIF, SUMSQ, TAN, TANH, TRIM, TRUNC,
+// ABS
+// ACOS
+// ACOSH
+// ACOT
+// ACOTH
+// AND
+// ARABIC
+// ASIN
+// ASINH
+// ATAN2
+// ATANH
+// BASE
+// CEILING
+// CEILING.MATH
+// CEILING.PRECISE
+// CHOOSE
+// CLEAN
+// COMBIN
+// COMBINA
+// COS
+// COSH
+// COT
+// COTH
+// COUNTA
+// CSC
+// CSCH
+// DATE
+// DECIMAL
+// DEGREES
+// EVEN
+// EXP
+// FACT
+// FACTDOUBLE
+// FLOOR
+// FLOOR.MATH
+// FLOOR.PRECISE
+// GCD
+// IF
+// INT
+// ISBLANK
+// ISERR
+// ISERROR
+// ISEVEN
+// ISNA
+// ISNONTEXT
+// ISNUMBER
+// ISODD
+// ISO.CEILING
+// LCM
+// LEN
+// LN
+// LOG
+// LOG10
+// LOWER
+// MDETERM
+// MEDIAN
+// MOD
+// MROUND
+// MULTINOMIAL
+// MUNIT
+// NA
+// ODD
+// OR
+// PI
+// POWER
+// PRODUCT
+// PROPER
+// QUOTIENT
+// RADIANS
+// RAND
+// RANDBETWEEN
+// ROUND
+// ROUNDDOWN
+// ROUNDUP
+// SEC
+// SECH
+// SIGN
+// SIN
+// SINH
+// SQRT
+// SQRTPI
+// SUM
+// SUMIF
+// SUMSQ
+// TAN
+// TANH
+// TRIM
+// TRUNC
// UPPER
//
func (f *File) CalcCellValue(sheet, cell string) (result string, err error) {
@@ -172,6 +272,21 @@ func getPriority(token efp.Token) (pri int) {
return
}
+// newNumberFormulaArg constructs a number formula argument.
+func newNumberFormulaArg(n float64) formulaArg {
+ return formulaArg{Type: ArgNumber, Number: n}
+}
+
+// newStringFormulaArg constructs a string formula argument.
+func newStringFormulaArg(s string) formulaArg {
+ return formulaArg{Type: ArgString, String: s}
+}
+
+// newErrorFormulaArg create an error formula argument of a given type with a specified error message.
+func newErrorFormulaArg(formulaError, msg string) formulaArg {
+ return formulaArg{Type: ArgError, String: formulaError, Error: msg}
+}
+
// evalInfixExp evaluate syntax analysis by given infix expression after
// lexical analysis. Evaluate an infix expression containing formulas by
// stacks:
@@ -302,18 +417,18 @@ func (f *File) evalInfixExp(sheet string, tokens []efp.Token) (efp.Token, error)
})
}
// call formula function to evaluate
- result, err := callFuncByName(&formulaFuncs{}, strings.NewReplacer(
+ arg := callFuncByName(&formulaFuncs{}, strings.NewReplacer(
"_xlfn", "", ".", "").Replace(opfStack.Peek().(efp.Token).TValue),
[]reflect.Value{reflect.ValueOf(argsList)})
- if err != nil {
- return efp.Token{}, err
+ if arg.Type == ArgError {
+ return efp.Token{}, errors.New(arg.Value())
}
argsList.Init()
opfStack.Pop()
if opfStack.Len() > 0 { // still in function stack
- opfdStack.Push(efp.Token{TValue: result, TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeNumber})
+ opfdStack.Push(efp.Token{TValue: arg.Value(), TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeNumber})
} else {
- opdStack.Push(efp.Token{TValue: result, TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeNumber})
+ opdStack.Push(efp.Token{TValue: arg.Value(), TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeNumber})
}
}
}
@@ -573,6 +688,7 @@ func isOperatorPrefixToken(token efp.Token) bool {
return false
}
+// getDefinedNameRefTo convert defined name to reference range.
func (f *File) getDefinedNameRefTo(definedNameName string, currentSheet string) (refTo string) {
for _, definedName := range f.GetDefinedName() {
if definedName.Name == definedNameName {
@@ -775,22 +891,17 @@ func (f *File) rangeResolver(cellRefs, cellRanges *list.List) (arg formulaArg, e
// callFuncByName calls the no error or only error return function with
// reflect by given receiver, name and parameters.
-func callFuncByName(receiver interface{}, name string, params []reflect.Value) (result string, err error) {
+func callFuncByName(receiver interface{}, name string, params []reflect.Value) (arg formulaArg) {
function := reflect.ValueOf(receiver).MethodByName(name)
if function.IsValid() {
rt := function.Call(params)
if len(rt) == 0 {
return
}
- if !rt[1].IsNil() {
- err = rt[1].Interface().(error)
- return
- }
- result = rt[0].Interface().(string)
+ arg = rt[0].Interface().(formulaArg)
return
}
- err = fmt.Errorf("not support %s function", name)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("not support %s function", name))
}
// formulaCriteriaParser parse formula criteria.
@@ -879,18 +990,15 @@ func formulaCriteriaEval(val string, criteria *formulaCriteria) (result bool, er
//
// ABS(number)
//
-func (fn *formulaFuncs) ABS(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) ABS(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("ABS requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ABS requires 1 numeric argument")
}
- var val float64
- if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = fmt.Sprintf("%g", math.Abs(val))
- return
+ return newNumberFormulaArg(math.Abs(val))
}
// ACOS function calculates the arccosine (i.e. the inverse cosine) of a given
@@ -899,18 +1007,15 @@ func (fn *formulaFuncs) ABS(argsList *list.List) (result string, err error) {
//
// ACOS(number)
//
-func (fn *formulaFuncs) ACOS(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) ACOS(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("ACOS requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ACOS requires 1 numeric argument")
}
- var val float64
- if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = fmt.Sprintf("%g", math.Acos(val))
- return
+ return newNumberFormulaArg(math.Acos(val))
}
// ACOSH function calculates the inverse hyperbolic cosine of a supplied number.
@@ -918,18 +1023,15 @@ func (fn *formulaFuncs) ACOS(argsList *list.List) (result string, err error) {
//
// ACOSH(number)
//
-func (fn *formulaFuncs) ACOSH(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) ACOSH(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("ACOSH requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ACOSH requires 1 numeric argument")
}
- var val float64
- if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = fmt.Sprintf("%g", math.Acosh(val))
- return
+ return newNumberFormulaArg(math.Acosh(val))
}
// ACOT function calculates the arccotangent (i.e. the inverse cotangent) of a
@@ -938,18 +1040,15 @@ func (fn *formulaFuncs) ACOSH(argsList *list.List) (result string, err error) {
//
// ACOT(number)
//
-func (fn *formulaFuncs) ACOT(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) ACOT(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("ACOT requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ACOT requires 1 numeric argument")
}
- var val float64
- if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = fmt.Sprintf("%g", math.Pi/2-math.Atan(val))
- return
+ return newNumberFormulaArg(math.Pi/2 - math.Atan(val))
}
// ACOTH function calculates the hyperbolic arccotangent (coth) of a supplied
@@ -957,18 +1056,15 @@ func (fn *formulaFuncs) ACOT(argsList *list.List) (result string, err error) {
//
// ACOTH(number)
//
-func (fn *formulaFuncs) ACOTH(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) ACOTH(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("ACOTH requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ACOTH requires 1 numeric argument")
}
- var val float64
- if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = fmt.Sprintf("%g", math.Atanh(1/val))
- return
+ return newNumberFormulaArg(math.Atanh(1 / val))
}
// ARABIC function converts a Roman numeral into an Arabic numeral. The syntax
@@ -976,10 +1072,9 @@ func (fn *formulaFuncs) ACOTH(argsList *list.List) (result string, err error) {
//
// ARABIC(text)
//
-func (fn *formulaFuncs) ARABIC(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) ARABIC(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("ARABIC requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ARABIC requires 1 numeric argument")
}
charMap := map[rune]float64{'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000}
val, last, prefix := 0.0, 0.0, 1.0
@@ -993,19 +1088,16 @@ func (fn *formulaFuncs) ARABIC(argsList *list.List) (result string, err error) {
val += digit
switch {
case last == digit && (last == 5 || last == 50 || last == 500):
- result = formulaErrorVALUE
- return
+ return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
case 2*last == digit:
- result = formulaErrorVALUE
- return
+ return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
}
if last < digit {
val -= 2 * last
}
last = digit
}
- result = fmt.Sprintf("%g", prefix*val)
- return
+ return newNumberFormulaArg(prefix * val)
}
// ASIN function calculates the arcsine (i.e. the inverse sine) of a given
@@ -1014,18 +1106,15 @@ func (fn *formulaFuncs) ARABIC(argsList *list.List) (result string, err error) {
//
// ASIN(number)
//
-func (fn *formulaFuncs) ASIN(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) ASIN(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("ASIN requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ASIN requires 1 numeric argument")
}
- var val float64
- if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = fmt.Sprintf("%g", math.Asin(val))
- return
+ return newNumberFormulaArg(math.Asin(val))
}
// ASINH function calculates the inverse hyperbolic sine of a supplied number.
@@ -1033,18 +1122,15 @@ func (fn *formulaFuncs) ASIN(argsList *list.List) (result string, err error) {
//
// ASINH(number)
//
-func (fn *formulaFuncs) ASINH(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) ASINH(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("ASINH requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ASINH requires 1 numeric argument")
}
- var val float64
- if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = fmt.Sprintf("%g", math.Asinh(val))
- return
+ return newNumberFormulaArg(math.Asinh(val))
}
// ATAN function calculates the arctangent (i.e. the inverse tangent) of a
@@ -1053,18 +1139,15 @@ func (fn *formulaFuncs) ASINH(argsList *list.List) (result string, err error) {
//
// ATAN(number)
//
-func (fn *formulaFuncs) ATAN(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) ATAN(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("ATAN requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ATAN requires 1 numeric argument")
}
- var val float64
- if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = fmt.Sprintf("%g", math.Atan(val))
- return
+ return newNumberFormulaArg(math.Atan(val))
}
// ATANH function calculates the inverse hyperbolic tangent of a supplied
@@ -1072,18 +1155,15 @@ func (fn *formulaFuncs) ATAN(argsList *list.List) (result string, err error) {
//
// ATANH(number)
//
-func (fn *formulaFuncs) ATANH(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) ATANH(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("ATANH requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ATANH requires 1 numeric argument")
}
- var val float64
- if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = fmt.Sprintf("%g", math.Atanh(val))
- return
+ return newNumberFormulaArg(math.Atanh(val))
}
// ATAN2 function calculates the arctangent (i.e. the inverse tangent) of a
@@ -1092,22 +1172,19 @@ func (fn *formulaFuncs) ATANH(argsList *list.List) (result string, err error) {
//
// ATAN2(x_num,y_num)
//
-func (fn *formulaFuncs) ATAN2(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) ATAN2(argsList *list.List) formulaArg {
if argsList.Len() != 2 {
- err = errors.New("ATAN2 requires 2 numeric arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ATAN2 requires 2 numeric arguments")
}
- var x, y float64
- if x, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ x, err := strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- if y, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ y, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = fmt.Sprintf("%g", math.Atan2(x, y))
- return
+ return newNumberFormulaArg(math.Atan2(x, y))
}
// BASE function converts a number into a supplied base (radix), and returns a
@@ -1115,41 +1192,35 @@ func (fn *formulaFuncs) ATAN2(argsList *list.List) (result string, err error) {
//
// BASE(number,radix,[min_length])
//
-func (fn *formulaFuncs) BASE(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) BASE(argsList *list.List) formulaArg {
if argsList.Len() < 2 {
- err = errors.New("BASE requires at least 2 arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "BASE requires at least 2 arguments")
}
if argsList.Len() > 3 {
- err = errors.New("BASE allows at most 3 arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "BASE allows at most 3 arguments")
}
var number float64
var radix, minLength int
+ var err error
if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if radix, err = strconv.Atoi(argsList.Front().Next().Value.(formulaArg).String); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if radix < 2 || radix > 36 {
- err = errors.New("radix must be an integer >= 2 and <= 36")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "radix must be an integer >= 2 and <= 36")
}
if argsList.Len() > 2 {
if minLength, err = strconv.Atoi(argsList.Back().Value.(formulaArg).String); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
}
- result = strconv.FormatInt(int64(number), radix)
+ result := strconv.FormatInt(int64(number), radix)
if len(result) < minLength {
result = strings.Repeat("0", minLength-len(result)) + result
}
- result = strings.ToUpper(result)
- return
+ return newStringFormulaArg(strings.ToUpper(result))
}
// CEILING function rounds a supplied number away from zero, to the nearest
@@ -1157,43 +1228,38 @@ func (fn *formulaFuncs) BASE(argsList *list.List) (result string, err error) {
//
// CEILING(number,significance)
//
-func (fn *formulaFuncs) CEILING(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) CEILING(argsList *list.List) formulaArg {
if argsList.Len() == 0 {
- err = errors.New("CEILING requires at least 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "CEILING requires at least 1 argument")
}
if argsList.Len() > 2 {
- err = errors.New("CEILING allows at most 2 arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "CEILING allows at most 2 arguments")
}
number, significance, res := 0.0, 1.0, 0.0
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ var err error
+ number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if number < 0 {
significance = -1
}
if argsList.Len() > 1 {
if significance, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
}
if significance < 0 && number > 0 {
- err = errors.New("negative sig to CEILING invalid")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "negative sig to CEILING invalid")
}
if argsList.Len() == 1 {
- result = fmt.Sprintf("%g", math.Ceil(number))
- return
+ return newNumberFormulaArg(math.Ceil(number))
}
number, res = math.Modf(number / significance)
if res > 0 {
number++
}
- result = fmt.Sprintf("%g", number*significance)
- return
+ return newNumberFormulaArg(number * significance)
}
// CEILINGMATH function rounds a supplied number up to a supplied multiple of
@@ -1201,37 +1267,32 @@ func (fn *formulaFuncs) CEILING(argsList *list.List) (result string, err error)
//
// CEILING.MATH(number,[significance],[mode])
//
-func (fn *formulaFuncs) CEILINGMATH(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) CEILINGMATH(argsList *list.List) formulaArg {
if argsList.Len() == 0 {
- err = errors.New("CEILING.MATH requires at least 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "CEILING.MATH requires at least 1 argument")
}
if argsList.Len() > 3 {
- err = errors.New("CEILING.MATH allows at most 3 arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "CEILING.MATH allows at most 3 arguments")
}
number, significance, mode := 0.0, 1.0, 1.0
+ var err error
if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if number < 0 {
significance = -1
}
if argsList.Len() > 1 {
if significance, err = strconv.ParseFloat(argsList.Front().Next().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
}
if argsList.Len() == 1 {
- result = fmt.Sprintf("%g", math.Ceil(number))
- return
+ return newNumberFormulaArg(math.Ceil(number))
}
if argsList.Len() > 2 {
if mode, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
}
val, res := math.Modf(number / significance)
@@ -1242,8 +1303,7 @@ func (fn *formulaFuncs) CEILINGMATH(argsList *list.List) (result string, err err
val--
}
}
- result = fmt.Sprintf("%g", val*significance)
- return
+ return newNumberFormulaArg(val * significance)
}
// CEILINGPRECISE function rounds a supplied number up (regardless of the
@@ -1252,36 +1312,33 @@ func (fn *formulaFuncs) CEILINGMATH(argsList *list.List) (result string, err err
//
// CEILING.PRECISE(number,[significance])
//
-func (fn *formulaFuncs) CEILINGPRECISE(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) CEILINGPRECISE(argsList *list.List) formulaArg {
if argsList.Len() == 0 {
- err = errors.New("CEILING.PRECISE requires at least 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "CEILING.PRECISE requires at least 1 argument")
}
if argsList.Len() > 2 {
- err = errors.New("CEILING.PRECISE allows at most 2 arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "CEILING.PRECISE allows at most 2 arguments")
}
number, significance := 0.0, 1.0
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ var err error
+ number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if number < 0 {
significance = -1
}
if argsList.Len() == 1 {
- result = fmt.Sprintf("%g", math.Ceil(number))
- return
+ return newNumberFormulaArg(math.Ceil(number))
}
if argsList.Len() > 1 {
if significance, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil {
err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
significance = math.Abs(significance)
if significance == 0 {
- result = "0"
- return
+ return newStringFormulaArg("0")
}
}
val, res := math.Modf(number / significance)
@@ -1290,8 +1347,7 @@ func (fn *formulaFuncs) CEILINGPRECISE(argsList *list.List) (result string, err
val++
}
}
- result = fmt.Sprintf("%g", val*significance)
- return
+ return newNumberFormulaArg(val * significance)
}
// COMBIN function calculates the number of combinations (in any order) of a
@@ -1299,34 +1355,29 @@ func (fn *formulaFuncs) CEILINGPRECISE(argsList *list.List) (result string, err
//
// COMBIN(number,number_chosen)
//
-func (fn *formulaFuncs) COMBIN(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) COMBIN(argsList *list.List) formulaArg {
if argsList.Len() != 2 {
- err = errors.New("COMBIN requires 2 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "COMBIN requires 2 argument")
}
number, chosen, val := 0.0, 0.0, 1.0
+ var err error
if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if chosen, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
number, chosen = math.Trunc(number), math.Trunc(chosen)
if chosen > number {
- err = errors.New("COMBIN requires number >= number_chosen")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "COMBIN requires number >= number_chosen")
}
if chosen == number || chosen == 0 {
- result = "1"
- return
+ return newStringFormulaArg("1")
}
for c := float64(1); c <= chosen; c++ {
val *= (number + 1 - c) / c
}
- result = fmt.Sprintf("%g", math.Ceil(val))
- return
+ return newNumberFormulaArg(math.Ceil(val))
}
// COMBINA function calculates the number of combinations, with repetitions,
@@ -1334,28 +1385,26 @@ func (fn *formulaFuncs) COMBIN(argsList *list.List) (result string, err error) {
//
// COMBINA(number,number_chosen)
//
-func (fn *formulaFuncs) COMBINA(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) COMBINA(argsList *list.List) formulaArg {
if argsList.Len() != 2 {
- err = errors.New("COMBINA requires 2 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "COMBINA requires 2 argument")
}
var number, chosen float64
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ var err error
+ number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- if chosen, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ chosen, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
number, chosen = math.Trunc(number), math.Trunc(chosen)
if number < chosen {
- err = errors.New("COMBINA requires number > number_chosen")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "COMBINA requires number > number_chosen")
}
if number == 0 {
- result = "0"
- return
+ return newStringFormulaArg("0")
}
args := list.New()
args.PushBack(formulaArg{
@@ -1374,18 +1423,15 @@ func (fn *formulaFuncs) COMBINA(argsList *list.List) (result string, err error)
//
// COS(number)
//
-func (fn *formulaFuncs) COS(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) COS(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("COS requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "COS requires 1 numeric argument")
}
- var val float64
- if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = fmt.Sprintf("%g", math.Cos(val))
- return
+ return newNumberFormulaArg(math.Cos(val))
}
// COSH function calculates the hyperbolic cosine (cosh) of a supplied number.
@@ -1393,18 +1439,15 @@ func (fn *formulaFuncs) COS(argsList *list.List) (result string, err error) {
//
// COSH(number)
//
-func (fn *formulaFuncs) COSH(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) COSH(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("COSH requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "COSH requires 1 numeric argument")
}
- var val float64
- if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = fmt.Sprintf("%g", math.Cosh(val))
- return
+ return newNumberFormulaArg(math.Cosh(val))
}
// COT function calculates the cotangent of a given angle. The syntax of the
@@ -1412,22 +1455,18 @@ func (fn *formulaFuncs) COSH(argsList *list.List) (result string, err error) {
//
// COT(number)
//
-func (fn *formulaFuncs) COT(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) COT(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("COT requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "COT requires 1 numeric argument")
}
- var val float64
- if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if val == 0 {
- err = errors.New(formulaErrorDIV)
- return
+ return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
}
- result = fmt.Sprintf("%g", math.Tan(val))
- return
+ return newNumberFormulaArg(math.Tan(val))
}
// COTH function calculates the hyperbolic cotangent (coth) of a supplied
@@ -1435,22 +1474,18 @@ func (fn *formulaFuncs) COT(argsList *list.List) (result string, err error) {
//
// COTH(number)
//
-func (fn *formulaFuncs) COTH(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) COTH(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("COTH requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "COTH requires 1 numeric argument")
}
- var val float64
- if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if val == 0 {
- err = errors.New(formulaErrorDIV)
- return
+ return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
}
- result = fmt.Sprintf("%g", math.Tanh(val))
- return
+ return newNumberFormulaArg(math.Tanh(val))
}
// CSC function calculates the cosecant of a given angle. The syntax of the
@@ -1458,22 +1493,18 @@ func (fn *formulaFuncs) COTH(argsList *list.List) (result string, err error) {
//
// CSC(number)
//
-func (fn *formulaFuncs) CSC(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) CSC(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("CSC requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "CSC requires 1 numeric argument")
}
- var val float64
- if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if val == 0 {
- err = errors.New(formulaErrorDIV)
- return
+ return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
}
- result = fmt.Sprintf("%g", 1/math.Sin(val))
- return
+ return newNumberFormulaArg(1 / math.Sin(val))
}
// CSCH function calculates the hyperbolic cosecant (csch) of a supplied
@@ -1481,22 +1512,18 @@ func (fn *formulaFuncs) CSC(argsList *list.List) (result string, err error) {
//
// CSCH(number)
//
-func (fn *formulaFuncs) CSCH(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) CSCH(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("CSCH requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "CSCH requires 1 numeric argument")
}
- var val float64
- if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if val == 0 {
- err = errors.New(formulaErrorDIV)
- return
+ return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
}
- result = fmt.Sprintf("%g", 1/math.Sinh(val))
- return
+ return newNumberFormulaArg(1 / math.Sinh(val))
}
// DECIMAL function converts a text representation of a number in a specified
@@ -1504,27 +1531,25 @@ func (fn *formulaFuncs) CSCH(argsList *list.List) (result string, err error) {
//
// DECIMAL(text,radix)
//
-func (fn *formulaFuncs) DECIMAL(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) DECIMAL(argsList *list.List) formulaArg {
if argsList.Len() != 2 {
- err = errors.New("DECIMAL requires 2 numeric arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "DECIMAL requires 2 numeric arguments")
}
var text = argsList.Front().Value.(formulaArg).String
var radix int
- if radix, err = strconv.Atoi(argsList.Back().Value.(formulaArg).String); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ var err error
+ radix, err = strconv.Atoi(argsList.Back().Value.(formulaArg).String)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if len(text) > 2 && (strings.HasPrefix(text, "0x") || strings.HasPrefix(text, "0X")) {
text = text[2:]
}
val, err := strconv.ParseInt(text, radix, 64)
if err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = fmt.Sprintf("%g", float64(val))
- return
+ return newNumberFormulaArg(float64(val))
}
// DEGREES function converts radians into degrees. The syntax of the function
@@ -1532,22 +1557,18 @@ func (fn *formulaFuncs) DECIMAL(argsList *list.List) (result string, err error)
//
// DEGREES(angle)
//
-func (fn *formulaFuncs) DEGREES(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) DEGREES(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("DEGREES requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "DEGREES requires 1 numeric argument")
}
- var val float64
- if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if val == 0 {
- err = errors.New(formulaErrorDIV)
- return
+ return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
}
- result = fmt.Sprintf("%g", 180.0/math.Pi*val)
- return
+ return newNumberFormulaArg(180.0 / math.Pi * val)
}
// EVEN function rounds a supplied number away from zero (i.e. rounds a
@@ -1556,15 +1577,13 @@ func (fn *formulaFuncs) DEGREES(argsList *list.List) (result string, err error)
//
// EVEN(number)
//
-func (fn *formulaFuncs) EVEN(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) EVEN(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("EVEN requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "EVEN requires 1 numeric argument")
}
- var number float64
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
sign := math.Signbit(number)
m, frac := math.Modf(number / 2)
@@ -1576,8 +1595,7 @@ func (fn *formulaFuncs) EVEN(argsList *list.List) (result string, err error) {
val -= 2
}
}
- result = fmt.Sprintf("%g", val)
- return
+ return newNumberFormulaArg(val)
}
// EXP function calculates the value of the mathematical constant e, raised to
@@ -1585,18 +1603,15 @@ func (fn *formulaFuncs) EVEN(argsList *list.List) (result string, err error) {
//
// EXP(number)
//
-func (fn *formulaFuncs) EXP(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) EXP(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("EXP requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "EXP requires 1 numeric argument")
}
- var number float64
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = strings.ToUpper(fmt.Sprintf("%g", math.Exp(number)))
- return
+ return newStringFormulaArg(strings.ToUpper(fmt.Sprintf("%g", math.Exp(number))))
}
// fact returns the factorial of a supplied number.
@@ -1613,21 +1628,18 @@ func fact(number float64) float64 {
//
// FACT(number)
//
-func (fn *formulaFuncs) FACT(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) FACT(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("FACT requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "FACT requires 1 numeric argument")
}
- var number float64
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if number < 0 {
- err = errors.New(formulaErrorNUM)
+ return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
}
- result = strings.ToUpper(fmt.Sprintf("%g", fact(number)))
- return
+ return newStringFormulaArg(strings.ToUpper(fmt.Sprintf("%g", fact(number))))
}
// FACTDOUBLE function returns the double factorial of a supplied number. The
@@ -1635,25 +1647,22 @@ func (fn *formulaFuncs) FACT(argsList *list.List) (result string, err error) {
//
// FACTDOUBLE(number)
//
-func (fn *formulaFuncs) FACTDOUBLE(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) FACTDOUBLE(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("FACTDOUBLE requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "FACTDOUBLE requires 1 numeric argument")
}
- number, val := 0.0, 1.0
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ val := 1.0
+ number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if number < 0 {
- err = errors.New(formulaErrorNUM)
- return
+ return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
}
for i := math.Trunc(number); i > 1; i -= 2 {
val *= i
}
- result = strings.ToUpper(fmt.Sprintf("%g", val))
- return
+ return newStringFormulaArg(strings.ToUpper(fmt.Sprintf("%g", val)))
}
// FLOOR function rounds a supplied number towards zero to the nearest
@@ -1661,23 +1670,22 @@ func (fn *formulaFuncs) FACTDOUBLE(argsList *list.List) (result string, err erro
//
// FLOOR(number,significance)
//
-func (fn *formulaFuncs) FLOOR(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) FLOOR(argsList *list.List) formulaArg {
if argsList.Len() != 2 {
- err = errors.New("FLOOR requires 2 numeric arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "FLOOR requires 2 numeric arguments")
}
var number, significance float64
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ var err error
+ number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- if significance, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ significance, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if significance < 0 && number >= 0 {
- err = errors.New(formulaErrorNUM)
- return
+ return newErrorFormulaArg(formulaErrorNUM, "invalid arguments to FLOOR")
}
val := number
val, res := math.Modf(val / significance)
@@ -1686,8 +1694,7 @@ func (fn *formulaFuncs) FLOOR(argsList *list.List) (result string, err error) {
val--
}
}
- result = strings.ToUpper(fmt.Sprintf("%g", val*significance))
- return
+ return newStringFormulaArg(strings.ToUpper(fmt.Sprintf("%g", val*significance)))
}
// FLOORMATH function rounds a supplied number down to a supplied multiple of
@@ -1695,45 +1702,40 @@ func (fn *formulaFuncs) FLOOR(argsList *list.List) (result string, err error) {
//
// FLOOR.MATH(number,[significance],[mode])
//
-func (fn *formulaFuncs) FLOORMATH(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) FLOORMATH(argsList *list.List) formulaArg {
if argsList.Len() == 0 {
- err = errors.New("FLOOR.MATH requires at least 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "FLOOR.MATH requires at least 1 argument")
}
if argsList.Len() > 3 {
- err = errors.New("FLOOR.MATH allows at most 3 arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "FLOOR.MATH allows at most 3 arguments")
}
number, significance, mode := 0.0, 1.0, 1.0
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ var err error
+ number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if number < 0 {
significance = -1
}
if argsList.Len() > 1 {
if significance, err = strconv.ParseFloat(argsList.Front().Next().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
}
if argsList.Len() == 1 {
- result = fmt.Sprintf("%g", math.Floor(number))
- return
+ return newNumberFormulaArg(math.Floor(number))
}
if argsList.Len() > 2 {
if mode, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
}
val, res := math.Modf(number / significance)
if res != 0 && number < 0 && mode > 0 {
val--
}
- result = fmt.Sprintf("%g", val*significance)
- return
+ return newNumberFormulaArg(val * significance)
}
// FLOORPRECISE function rounds a supplied number down to a supplied multiple
@@ -1741,36 +1743,32 @@ func (fn *formulaFuncs) FLOORMATH(argsList *list.List) (result string, err error
//
// FLOOR.PRECISE(number,[significance])
//
-func (fn *formulaFuncs) FLOORPRECISE(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) FLOORPRECISE(argsList *list.List) formulaArg {
if argsList.Len() == 0 {
- err = errors.New("FLOOR.PRECISE requires at least 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "FLOOR.PRECISE requires at least 1 argument")
}
if argsList.Len() > 2 {
- err = errors.New("FLOOR.PRECISE allows at most 2 arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "FLOOR.PRECISE allows at most 2 arguments")
}
var number, significance float64
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ var err error
+ number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if number < 0 {
significance = -1
}
if argsList.Len() == 1 {
- result = fmt.Sprintf("%g", math.Floor(number))
- return
+ return newNumberFormulaArg(math.Floor(number))
}
if argsList.Len() > 1 {
if significance, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
significance = math.Abs(significance)
if significance == 0 {
- result = "0"
- return
+ return newStringFormulaArg("0")
}
}
val, res := math.Modf(number / significance)
@@ -1779,8 +1777,7 @@ func (fn *formulaFuncs) FLOORPRECISE(argsList *list.List) (result string, err er
val--
}
}
- result = fmt.Sprintf("%g", val*significance)
- return
+ return newNumberFormulaArg(val * significance)
}
// gcd returns the greatest common divisor of two supplied integers.
@@ -1807,14 +1804,14 @@ func gcd(x, y float64) float64 {
//
// GCD(number1,[number2],...)
//
-func (fn *formulaFuncs) GCD(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) GCD(argsList *list.List) formulaArg {
if argsList.Len() == 0 {
- err = errors.New("GCD requires at least 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "GCD requires at least 1 argument")
}
var (
val float64
nums = []float64{}
+ err error
)
for arg := argsList.Front(); arg != nil; arg = arg.Next() {
token := arg.Value.(formulaArg).String
@@ -1822,29 +1819,24 @@ func (fn *formulaFuncs) GCD(argsList *list.List) (result string, err error) {
continue
}
if val, err = strconv.ParseFloat(token, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
nums = append(nums, val)
}
if nums[0] < 0 {
- err = errors.New("GCD only accepts positive arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "GCD only accepts positive arguments")
}
if len(nums) == 1 {
- result = fmt.Sprintf("%g", nums[0])
- return
+ return newNumberFormulaArg(nums[0])
}
cd := nums[0]
for i := 1; i < len(nums); i++ {
if nums[i] < 0 {
- err = errors.New("GCD only accepts positive arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "GCD only accepts positive arguments")
}
cd = gcd(cd, nums[i])
}
- result = fmt.Sprintf("%g", cd)
- return
+ return newNumberFormulaArg(cd)
}
// INT function truncates a supplied number down to the closest integer. The
@@ -1852,22 +1844,19 @@ func (fn *formulaFuncs) GCD(argsList *list.List) (result string, err error) {
//
// INT(number)
//
-func (fn *formulaFuncs) INT(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) INT(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("INT requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "INT requires 1 numeric argument")
}
- var number float64
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
val, frac := math.Modf(number)
if frac < 0 {
val--
}
- result = fmt.Sprintf("%g", val)
- return
+ return newNumberFormulaArg(val)
}
// ISOCEILING function rounds a supplied number up (regardless of the number's
@@ -1876,36 +1865,31 @@ func (fn *formulaFuncs) INT(argsList *list.List) (result string, err error) {
//
// ISO.CEILING(number,[significance])
//
-func (fn *formulaFuncs) ISOCEILING(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) ISOCEILING(argsList *list.List) formulaArg {
if argsList.Len() == 0 {
- err = errors.New("ISO.CEILING requires at least 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ISO.CEILING requires at least 1 argument")
}
if argsList.Len() > 2 {
- err = errors.New("ISO.CEILING allows at most 2 arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ISO.CEILING allows at most 2 arguments")
}
var number, significance float64
+ var err error
if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if number < 0 {
significance = -1
}
if argsList.Len() == 1 {
- result = fmt.Sprintf("%g", math.Ceil(number))
- return
+ return newNumberFormulaArg(math.Ceil(number))
}
if argsList.Len() > 1 {
if significance, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
significance = math.Abs(significance)
if significance == 0 {
- result = "0"
- return
+ return newStringFormulaArg("0")
}
}
val, res := math.Modf(number / significance)
@@ -1914,8 +1898,7 @@ func (fn *formulaFuncs) ISOCEILING(argsList *list.List) (result string, err erro
val++
}
}
- result = fmt.Sprintf("%g", val*significance)
- return
+ return newNumberFormulaArg(val * significance)
}
// lcm returns the least common multiple of two supplied integers.
@@ -1933,14 +1916,14 @@ func lcm(a, b float64) float64 {
//
// LCM(number1,[number2],...)
//
-func (fn *formulaFuncs) LCM(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) LCM(argsList *list.List) formulaArg {
if argsList.Len() == 0 {
- err = errors.New("LCM requires at least 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "LCM requires at least 1 argument")
}
var (
val float64
nums = []float64{}
+ err error
)
for arg := argsList.Front(); arg != nil; arg = arg.Next() {
token := arg.Value.(formulaArg).String
@@ -1948,29 +1931,24 @@ func (fn *formulaFuncs) LCM(argsList *list.List) (result string, err error) {
continue
}
if val, err = strconv.ParseFloat(token, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
nums = append(nums, val)
}
if nums[0] < 0 {
- err = errors.New("LCM only accepts positive arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "LCM only accepts positive arguments")
}
if len(nums) == 1 {
- result = fmt.Sprintf("%g", nums[0])
- return
+ return newNumberFormulaArg(nums[0])
}
cm := nums[0]
for i := 1; i < len(nums); i++ {
if nums[i] < 0 {
- err = errors.New("LCM only accepts positive arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "LCM only accepts positive arguments")
}
cm = lcm(cm, nums[i])
}
- result = fmt.Sprintf("%g", cm)
- return
+ return newNumberFormulaArg(cm)
}
// LN function calculates the natural logarithm of a given number. The syntax
@@ -1978,18 +1956,15 @@ func (fn *formulaFuncs) LCM(argsList *list.List) (result string, err error) {
//
// LN(number)
//
-func (fn *formulaFuncs) LN(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) LN(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("LN requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "LN requires 1 numeric argument")
}
- var number float64
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = fmt.Sprintf("%g", math.Log(number))
- return
+ return newNumberFormulaArg(math.Log(number))
}
// LOG function calculates the logarithm of a given number, to a supplied
@@ -1997,40 +1972,34 @@ func (fn *formulaFuncs) LN(argsList *list.List) (result string, err error) {
//
// LOG(number,[base])
//
-func (fn *formulaFuncs) LOG(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) LOG(argsList *list.List) formulaArg {
if argsList.Len() == 0 {
- err = errors.New("LOG requires at least 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "LOG requires at least 1 argument")
}
if argsList.Len() > 2 {
- err = errors.New("LOG allows at most 2 arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "LOG allows at most 2 arguments")
}
number, base := 0.0, 10.0
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ var err error
+ number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if argsList.Len() > 1 {
if base, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
}
if number == 0 {
- err = errors.New(formulaErrorNUM)
- return
+ return newErrorFormulaArg(formulaErrorNUM, formulaErrorDIV)
}
if base == 0 {
- err = errors.New(formulaErrorNUM)
- return
+ return newErrorFormulaArg(formulaErrorNUM, formulaErrorDIV)
}
if base == 1 {
- err = errors.New(formulaErrorDIV)
- return
+ return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
}
- result = fmt.Sprintf("%g", math.Log(number)/math.Log(base))
- return
+ return newNumberFormulaArg(math.Log(number) / math.Log(base))
}
// LOG10 function calculates the base 10 logarithm of a given number. The
@@ -2038,20 +2007,19 @@ func (fn *formulaFuncs) LOG(argsList *list.List) (result string, err error) {
//
// LOG10(number)
//
-func (fn *formulaFuncs) LOG10(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) LOG10(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("LOG10 requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "LOG10 requires 1 numeric argument")
}
- var number float64
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = fmt.Sprintf("%g", math.Log10(number))
- return
+ return newNumberFormulaArg(math.Log10(number))
}
+// minor function implement a minor of a matrix A is the determinant of some
+// smaller square matrix.
func minor(sqMtx [][]float64, idx int) [][]float64 {
ret := [][]float64{}
for i := range sqMtx {
@@ -2092,30 +2060,31 @@ func det(sqMtx [][]float64) float64 {
//
// MDETERM(array)
//
-func (fn *formulaFuncs) MDETERM(argsList *list.List) (result string, err error) {
- var num float64
- var numMtx = [][]float64{}
- var strMtx = argsList.Front().Value.(formulaArg).Matrix
+func (fn *formulaFuncs) MDETERM(argsList *list.List) (result formulaArg) {
+ var (
+ num float64
+ numMtx = [][]float64{}
+ err error
+ strMtx = argsList.Front().Value.(formulaArg).Matrix
+ )
if argsList.Len() < 1 {
return
}
var rows = len(strMtx)
for _, row := range argsList.Front().Value.(formulaArg).Matrix {
if len(row) != rows {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
}
numRow := []float64{}
for _, ele := range row {
if num, err = strconv.ParseFloat(ele.String, 64); err != nil {
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
numRow = append(numRow, num)
}
numMtx = append(numMtx, numRow)
}
- result = fmt.Sprintf("%g", det(numMtx))
- return
+ return newNumberFormulaArg(det(numMtx))
}
// MOD function returns the remainder of a division between two supplied
@@ -2123,30 +2092,28 @@ func (fn *formulaFuncs) MDETERM(argsList *list.List) (result string, err error)
//
// MOD(number,divisor)
//
-func (fn *formulaFuncs) MOD(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) MOD(argsList *list.List) formulaArg {
if argsList.Len() != 2 {
- err = errors.New("MOD requires 2 numeric arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "MOD requires 2 numeric arguments")
}
var number, divisor float64
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ var err error
+ number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- if divisor, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ divisor, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if divisor == 0 {
- err = errors.New(formulaErrorDIV)
- return
+ return newErrorFormulaArg(formulaErrorDIV, "MOD divide by zero")
}
trunc, rem := math.Modf(number / divisor)
if rem < 0 {
trunc--
}
- result = fmt.Sprintf("%g", number-divisor*trunc)
- return
+ return newNumberFormulaArg(number - divisor*trunc)
}
// MROUND function rounds a supplied number up or down to the nearest multiple
@@ -2154,35 +2121,32 @@ func (fn *formulaFuncs) MOD(argsList *list.List) (result string, err error) {
//
// MROUND(number,multiple)
//
-func (fn *formulaFuncs) MROUND(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) MROUND(argsList *list.List) formulaArg {
if argsList.Len() != 2 {
- err = errors.New("MROUND requires 2 numeric arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "MROUND requires 2 numeric arguments")
}
var number, multiple float64
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ var err error
+ number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- if multiple, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ multiple, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if multiple == 0 {
- err = errors.New(formulaErrorNUM)
- return
+ return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
}
if multiple < 0 && number > 0 ||
multiple > 0 && number < 0 {
- err = errors.New(formulaErrorNUM)
- return
+ return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
}
number, res := math.Modf(number / multiple)
if math.Trunc(res+0.5) > 0 {
number++
}
- result = fmt.Sprintf("%g", number*multiple)
- return
+ return newNumberFormulaArg(number * multiple)
}
// MULTINOMIAL function calculates the ratio of the factorial of a sum of
@@ -2191,22 +2155,21 @@ func (fn *formulaFuncs) MROUND(argsList *list.List) (result string, err error) {
//
// MULTINOMIAL(number1,[number2],...)
//
-func (fn *formulaFuncs) MULTINOMIAL(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) MULTINOMIAL(argsList *list.List) formulaArg {
val, num, denom := 0.0, 0.0, 1.0
+ var err error
for arg := argsList.Front(); arg != nil; arg = arg.Next() {
token := arg.Value.(formulaArg)
if token.String == "" {
continue
}
if val, err = strconv.ParseFloat(token.String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
num += val
denom *= fact(val)
}
- result = fmt.Sprintf("%g", fact(num)/denom)
- return
+ return newNumberFormulaArg(fact(num) / denom)
}
// MUNIT function returns the unit matrix for a specified dimension. The
@@ -2214,15 +2177,13 @@ func (fn *formulaFuncs) MULTINOMIAL(argsList *list.List) (result string, err err
//
// MUNIT(dimension)
//
-func (fn *formulaFuncs) MUNIT(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) MUNIT(argsList *list.List) (result formulaArg) {
if argsList.Len() != 1 {
- err = errors.New("MUNIT requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "MUNIT requires 1 numeric argument")
}
- var dimension int
- if dimension, err = strconv.Atoi(argsList.Front().Value.(formulaArg).String); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ dimension, err := strconv.Atoi(argsList.Front().Value.(formulaArg).String)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
matrix := make([][]float64, 0, dimension)
for i := 0; i < dimension; i++ {
@@ -2245,19 +2206,16 @@ func (fn *formulaFuncs) MUNIT(argsList *list.List) (result string, err error) {
//
// ODD(number)
//
-func (fn *formulaFuncs) ODD(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) ODD(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("ODD requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ODD requires 1 numeric argument")
}
- var number float64
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if number == 0 {
- result = "1"
- return
+ return newStringFormulaArg("1")
}
sign := math.Signbit(number)
m, frac := math.Modf((number - 1) / 2)
@@ -2269,8 +2227,7 @@ func (fn *formulaFuncs) ODD(argsList *list.List) (result string, err error) {
val -= 2
}
}
- result = fmt.Sprintf("%g", val)
- return
+ return newNumberFormulaArg(val)
}
// PI function returns the value of the mathematical constant π (pi), accurate
@@ -2278,13 +2235,11 @@ func (fn *formulaFuncs) ODD(argsList *list.List) (result string, err error) {
//
// PI()
//
-func (fn *formulaFuncs) PI(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) PI(argsList *list.List) formulaArg {
if argsList.Len() != 0 {
- err = errors.New("PI accepts no arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "PI accepts no arguments")
}
- result = fmt.Sprintf("%g", math.Pi)
- return
+ return newNumberFormulaArg(math.Pi)
}
// POWER function calculates a given number, raised to a supplied power.
@@ -2292,30 +2247,27 @@ func (fn *formulaFuncs) PI(argsList *list.List) (result string, err error) {
//
// POWER(number,power)
//
-func (fn *formulaFuncs) POWER(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) POWER(argsList *list.List) formulaArg {
if argsList.Len() != 2 {
- err = errors.New("POWER requires 2 numeric arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "POWER requires 2 numeric arguments")
}
var x, y float64
- if x, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ var err error
+ x, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- if y, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ y, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if x == 0 && y == 0 {
- err = errors.New(formulaErrorNUM)
- return
+ return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
}
if x == 0 && y < 0 {
- err = errors.New(formulaErrorDIV)
- return
+ return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
}
- result = fmt.Sprintf("%g", math.Pow(x, y))
- return
+ return newNumberFormulaArg(math.Pow(x, y))
}
// PRODUCT function returns the product (multiplication) of a supplied set of
@@ -2323,8 +2275,9 @@ func (fn *formulaFuncs) POWER(argsList *list.List) (result string, err error) {
//
// PRODUCT(number1,[number2],...)
//
-func (fn *formulaFuncs) PRODUCT(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) PRODUCT(argsList *list.List) formulaArg {
val, product := 0.0, 1.0
+ var err error
for arg := argsList.Front(); arg != nil; arg = arg.Next() {
token := arg.Value.(formulaArg)
switch token.Type {
@@ -2335,8 +2288,7 @@ func (fn *formulaFuncs) PRODUCT(argsList *list.List) (result string, err error)
continue
}
if val, err = strconv.ParseFloat(token.String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
product = product * val
case ArgMatrix:
@@ -2346,16 +2298,14 @@ func (fn *formulaFuncs) PRODUCT(argsList *list.List) (result string, err error)
continue
}
if val, err = strconv.ParseFloat(value.String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
product = product * val
}
}
}
}
- result = fmt.Sprintf("%g", product)
- return
+ return newNumberFormulaArg(product)
}
// QUOTIENT function returns the integer portion of a division between two
@@ -2363,44 +2313,39 @@ func (fn *formulaFuncs) PRODUCT(argsList *list.List) (result string, err error)
//
// QUOTIENT(numerator,denominator)
//
-func (fn *formulaFuncs) QUOTIENT(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) QUOTIENT(argsList *list.List) formulaArg {
if argsList.Len() != 2 {
- err = errors.New("QUOTIENT requires 2 numeric arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "QUOTIENT requires 2 numeric arguments")
}
var x, y float64
- if x, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ var err error
+ x, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- if y, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ y, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if y == 0 {
- err = errors.New(formulaErrorDIV)
- return
+ return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
}
- result = fmt.Sprintf("%g", math.Trunc(x/y))
- return
+ return newNumberFormulaArg(math.Trunc(x / y))
}
// RADIANS function converts radians into degrees. The syntax of the function is:
//
// RADIANS(angle)
//
-func (fn *formulaFuncs) RADIANS(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) RADIANS(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("RADIANS requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "RADIANS requires 1 numeric argument")
}
- var angle float64
- if angle, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ angle, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = fmt.Sprintf("%g", math.Pi/180.0*angle)
- return
+ return newNumberFormulaArg(math.Pi / 180.0 * angle)
}
// RAND function generates a random real number between 0 and 1. The syntax of
@@ -2408,13 +2353,11 @@ func (fn *formulaFuncs) RADIANS(argsList *list.List) (result string, err error)
//
// RAND()
//
-func (fn *formulaFuncs) RAND(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) RAND(argsList *list.List) formulaArg {
if argsList.Len() != 0 {
- err = errors.New("RAND accepts no arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "RAND accepts no arguments")
}
- result = fmt.Sprintf("%g", rand.New(rand.NewSource(time.Now().UnixNano())).Float64())
- return
+ return newNumberFormulaArg(rand.New(rand.NewSource(time.Now().UnixNano())).Float64())
}
// RANDBETWEEN function generates a random integer between two supplied
@@ -2422,26 +2365,24 @@ func (fn *formulaFuncs) RAND(argsList *list.List) (result string, err error) {
//
// RANDBETWEEN(bottom,top)
//
-func (fn *formulaFuncs) RANDBETWEEN(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) RANDBETWEEN(argsList *list.List) formulaArg {
if argsList.Len() != 2 {
- err = errors.New("RANDBETWEEN requires 2 numeric arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "RANDBETWEEN requires 2 numeric arguments")
}
var bottom, top int64
- if bottom, err = strconv.ParseInt(argsList.Front().Value.(formulaArg).String, 10, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ var err error
+ bottom, err = strconv.ParseInt(argsList.Front().Value.(formulaArg).String, 10, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- if top, err = strconv.ParseInt(argsList.Back().Value.(formulaArg).String, 10, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ top, err = strconv.ParseInt(argsList.Back().Value.(formulaArg).String, 10, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if top < bottom {
- err = errors.New(formulaErrorNUM)
- return
+ return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
}
- result = fmt.Sprintf("%g", float64(rand.New(rand.NewSource(time.Now().UnixNano())).Int63n(top-bottom+1)+bottom))
- return
+ return newNumberFormulaArg(float64(rand.New(rand.NewSource(time.Now().UnixNano())).Int63n(top-bottom+1) + bottom))
}
// romanNumerals defined a numeral system that originated in ancient Rome and
@@ -2464,25 +2405,23 @@ var romanTable = [][]romanNumerals{{{1000, "M"}, {900, "CM"}, {500, "D"}, {400,
//
// ROMAN(number,[form])
//
-func (fn *formulaFuncs) ROMAN(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) ROMAN(argsList *list.List) formulaArg {
if argsList.Len() == 0 {
- err = errors.New("ROMAN requires at least 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ROMAN requires at least 1 argument")
}
if argsList.Len() > 2 {
- err = errors.New("ROMAN allows at most 2 arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ROMAN allows at most 2 arguments")
}
var number float64
var form int
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ var err error
+ number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if argsList.Len() > 1 {
if form, err = strconv.Atoi(argsList.Back().Value.(formulaArg).String); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if form < 0 {
form = 0
@@ -2509,8 +2448,7 @@ func (fn *formulaFuncs) ROMAN(argsList *list.List) (result string, err error) {
val -= r.n
}
}
- result = buf.String()
- return
+ return newStringFormulaArg(buf.String())
}
type roundMode byte
@@ -2554,22 +2492,21 @@ func (fn *formulaFuncs) round(number, digits float64, mode roundMode) float64 {
//
// ROUND(number,num_digits)
//
-func (fn *formulaFuncs) ROUND(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) ROUND(argsList *list.List) formulaArg {
if argsList.Len() != 2 {
- err = errors.New("ROUND requires 2 numeric arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ROUND requires 2 numeric arguments")
}
var number, digits float64
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ var err error
+ number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- if digits, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ digits, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = fmt.Sprintf("%g", fn.round(number, digits, closest))
- return
+ return newNumberFormulaArg(fn.round(number, digits, closest))
}
// ROUNDDOWN function rounds a supplied number down towards zero, to a
@@ -2577,22 +2514,21 @@ func (fn *formulaFuncs) ROUND(argsList *list.List) (result string, err error) {
//
// ROUNDDOWN(number,num_digits)
//
-func (fn *formulaFuncs) ROUNDDOWN(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) ROUNDDOWN(argsList *list.List) formulaArg {
if argsList.Len() != 2 {
- err = errors.New("ROUNDDOWN requires 2 numeric arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ROUNDDOWN requires 2 numeric arguments")
}
var number, digits float64
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ var err error
+ number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- if digits, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ digits, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = fmt.Sprintf("%g", fn.round(number, digits, down))
- return
+ return newNumberFormulaArg(fn.round(number, digits, down))
}
// ROUNDUP function rounds a supplied number up, away from zero, to a
@@ -2600,22 +2536,21 @@ func (fn *formulaFuncs) ROUNDDOWN(argsList *list.List) (result string, err error
//
// ROUNDUP(number,num_digits)
//
-func (fn *formulaFuncs) ROUNDUP(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) ROUNDUP(argsList *list.List) formulaArg {
if argsList.Len() != 2 {
- err = errors.New("ROUNDUP requires 2 numeric arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ROUNDUP requires 2 numeric arguments")
}
var number, digits float64
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ var err error
+ number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- if digits, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ digits, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = fmt.Sprintf("%g", fn.round(number, digits, up))
- return
+ return newNumberFormulaArg(fn.round(number, digits, up))
}
// SEC function calculates the secant of a given angle. The syntax of the
@@ -2623,18 +2558,15 @@ func (fn *formulaFuncs) ROUNDUP(argsList *list.List) (result string, err error)
//
// SEC(number)
//
-func (fn *formulaFuncs) SEC(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) SEC(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("SEC requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "SEC requires 1 numeric argument")
}
- var number float64
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = fmt.Sprintf("%g", math.Cos(number))
- return
+ return newNumberFormulaArg(math.Cos(number))
}
// SECH function calculates the hyperbolic secant (sech) of a supplied angle.
@@ -2642,18 +2574,15 @@ func (fn *formulaFuncs) SEC(argsList *list.List) (result string, err error) {
//
// SECH(number)
//
-func (fn *formulaFuncs) SECH(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) SECH(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("SECH requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "SECH requires 1 numeric argument")
}
- var number float64
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = fmt.Sprintf("%g", 1/math.Cosh(number))
- return
+ return newNumberFormulaArg(1 / math.Cosh(number))
}
// SIGN function returns the arithmetic sign (+1, -1 or 0) of a supplied
@@ -2663,26 +2592,21 @@ func (fn *formulaFuncs) SECH(argsList *list.List) (result string, err error) {
//
// SIGN(number)
//
-func (fn *formulaFuncs) SIGN(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) SIGN(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("SIGN requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "SIGN requires 1 numeric argument")
}
- var val float64
- if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if val < 0 {
- result = "-1"
- return
+ return newStringFormulaArg("-1")
}
if val > 0 {
- result = "1"
- return
+ return newStringFormulaArg("1")
}
- result = "0"
- return
+ return newStringFormulaArg("0")
}
// SIN function calculates the sine of a given angle. The syntax of the
@@ -2690,18 +2614,15 @@ func (fn *formulaFuncs) SIGN(argsList *list.List) (result string, err error) {
//
// SIN(number)
//
-func (fn *formulaFuncs) SIN(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) SIN(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("SIN requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "SIN requires 1 numeric argument")
}
- var number float64
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = fmt.Sprintf("%g", math.Sin(number))
- return
+ return newNumberFormulaArg(math.Sin(number))
}
// SINH function calculates the hyperbolic sine (sinh) of a supplied number.
@@ -2709,18 +2630,15 @@ func (fn *formulaFuncs) SIN(argsList *list.List) (result string, err error) {
//
// SINH(number)
//
-func (fn *formulaFuncs) SINH(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) SINH(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("SINH requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "SINH requires 1 numeric argument")
}
- var number float64
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = fmt.Sprintf("%g", math.Sinh(number))
- return
+ return newNumberFormulaArg(math.Sinh(number))
}
// SQRT function calculates the positive square root of a supplied number. The
@@ -2728,27 +2646,23 @@ func (fn *formulaFuncs) SINH(argsList *list.List) (result string, err error) {
//
// SQRT(number)
//
-func (fn *formulaFuncs) SQRT(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) SQRT(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("SQRT requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "SQRT requires 1 numeric argument")
}
var res float64
var value = argsList.Front().Value.(formulaArg).String
if value == "" {
- result = "0"
- return
+ return newStringFormulaArg("0")
}
- if res, err = strconv.ParseFloat(value, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ res, err := strconv.ParseFloat(value, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if res < 0 {
- err = errors.New(formulaErrorNUM)
- return
+ return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
}
- result = fmt.Sprintf("%g", math.Sqrt(res))
- return
+ return newNumberFormulaArg(math.Sqrt(res))
}
// SQRTPI function returns the square root of a supplied number multiplied by
@@ -2756,18 +2670,15 @@ func (fn *formulaFuncs) SQRT(argsList *list.List) (result string, err error) {
//
// SQRTPI(number)
//
-func (fn *formulaFuncs) SQRTPI(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) SQRTPI(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("SQRTPI requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "SQRTPI requires 1 numeric argument")
}
- var number float64
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = fmt.Sprintf("%g", math.Sqrt(number*math.Pi))
- return
+ return newNumberFormulaArg(math.Sqrt(number * math.Pi))
}
// SUM function adds together a supplied set of numbers and returns the sum of
@@ -2775,8 +2686,11 @@ func (fn *formulaFuncs) SQRTPI(argsList *list.List) (result string, err error) {
//
// SUM(number1,[number2],...)
//
-func (fn *formulaFuncs) SUM(argsList *list.List) (result string, err error) {
- var val, sum float64
+func (fn *formulaFuncs) SUM(argsList *list.List) formulaArg {
+ var (
+ val, sum float64
+ err error
+ )
for arg := argsList.Front(); arg != nil; arg = arg.Next() {
token := arg.Value.(formulaArg)
switch token.Type {
@@ -2787,8 +2701,7 @@ func (fn *formulaFuncs) SUM(argsList *list.List) (result string, err error) {
continue
}
if val, err = strconv.ParseFloat(token.String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
sum += val
case ArgMatrix:
@@ -2798,16 +2711,14 @@ func (fn *formulaFuncs) SUM(argsList *list.List) (result string, err error) {
continue
}
if val, err = strconv.ParseFloat(value.String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
sum += val
}
}
}
}
- result = fmt.Sprintf("%g", sum)
- return
+ return newNumberFormulaArg(sum)
}
// SUMIF function finds the values in a supplied array, that satisfy a given
@@ -2816,10 +2727,9 @@ func (fn *formulaFuncs) SUM(argsList *list.List) (result string, err error) {
//
// SUMIF(range,criteria,[sum_range])
//
-func (fn *formulaFuncs) SUMIF(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) SUMIF(argsList *list.List) formulaArg {
if argsList.Len() < 2 {
- err = errors.New("SUMIF requires at least 2 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "SUMIF requires at least 2 argument")
}
var criteria = formulaCriteriaParser(argsList.Front().Next().Value.(formulaArg).String)
var rangeMtx = argsList.Front().Value.(formulaArg).Matrix
@@ -2828,6 +2738,7 @@ func (fn *formulaFuncs) SUMIF(argsList *list.List) (result string, err error) {
sumRange = argsList.Back().Value.(formulaArg).Matrix
}
var sum, val float64
+ var err error
for rowIdx, row := range rangeMtx {
for colIdx, col := range row {
var ok bool
@@ -2836,7 +2747,7 @@ func (fn *formulaFuncs) SUMIF(argsList *list.List) (result string, err error) {
continue
}
if ok, err = formulaCriteriaEval(fromVal, criteria); err != nil {
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if ok {
if argsList.Len() == 3 {
@@ -2846,15 +2757,13 @@ func (fn *formulaFuncs) SUMIF(argsList *list.List) (result string, err error) {
fromVal = sumRange[rowIdx][colIdx].String
}
if val, err = strconv.ParseFloat(fromVal, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
sum += val
}
}
}
- result = fmt.Sprintf("%g", sum)
- return
+ return newNumberFormulaArg(sum)
}
// SUMSQ function returns the sum of squares of a supplied set of values. The
@@ -2862,8 +2771,9 @@ func (fn *formulaFuncs) SUMIF(argsList *list.List) (result string, err error) {
//
// SUMSQ(number1,[number2],...)
//
-func (fn *formulaFuncs) SUMSQ(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) SUMSQ(argsList *list.List) formulaArg {
var val, sq float64
+ var err error
for arg := argsList.Front(); arg != nil; arg = arg.Next() {
token := arg.Value.(formulaArg)
switch token.Type {
@@ -2872,8 +2782,7 @@ func (fn *formulaFuncs) SUMSQ(argsList *list.List) (result string, err error) {
continue
}
if val, err = strconv.ParseFloat(token.String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
sq += val * val
case ArgMatrix:
@@ -2883,16 +2792,14 @@ func (fn *formulaFuncs) SUMSQ(argsList *list.List) (result string, err error) {
continue
}
if val, err = strconv.ParseFloat(value.String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
sq += val * val
}
}
}
}
- result = fmt.Sprintf("%g", sq)
- return
+ return newNumberFormulaArg(sq)
}
// TAN function calculates the tangent of a given angle. The syntax of the
@@ -2900,18 +2807,15 @@ func (fn *formulaFuncs) SUMSQ(argsList *list.List) (result string, err error) {
//
// TAN(number)
//
-func (fn *formulaFuncs) TAN(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) TAN(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("TAN requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "TAN requires 1 numeric argument")
}
- var number float64
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = fmt.Sprintf("%g", math.Tan(number))
- return
+ return newNumberFormulaArg(math.Tan(number))
}
// TANH function calculates the hyperbolic tangent (tanh) of a supplied
@@ -2919,18 +2823,15 @@ func (fn *formulaFuncs) TAN(argsList *list.List) (result string, err error) {
//
// TANH(number)
//
-func (fn *formulaFuncs) TANH(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) TANH(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("TANH requires 1 numeric argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "TANH requires 1 numeric argument")
}
- var number float64
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- result = fmt.Sprintf("%g", math.Tanh(number))
- return
+ return newNumberFormulaArg(math.Tanh(number))
}
// TRUNC function truncates a supplied number to a specified number of decimal
@@ -2938,20 +2839,19 @@ func (fn *formulaFuncs) TANH(argsList *list.List) (result string, err error) {
//
// TRUNC(number,[number_digits])
//
-func (fn *formulaFuncs) TRUNC(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) TRUNC(argsList *list.List) formulaArg {
if argsList.Len() == 0 {
- err = errors.New("TRUNC requires at least 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "TRUNC requires at least 1 argument")
}
var number, digits, adjust, rtrim float64
- if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ var err error
+ number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if argsList.Len() > 1 {
if digits, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
digits = math.Floor(digits)
}
@@ -2959,15 +2859,13 @@ func (fn *formulaFuncs) TRUNC(argsList *list.List) (result string, err error) {
x := int((math.Abs(number) - math.Abs(float64(int(number)))) * adjust)
if x != 0 {
if rtrim, err = strconv.ParseFloat(strings.TrimRight(strconv.Itoa(x), "0"), 64); err != nil {
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
}
if (digits > 0) && (rtrim < adjust/10) {
- result = fmt.Sprintf("%g", number)
- return
+ return newNumberFormulaArg(number)
}
- result = fmt.Sprintf("%g", float64(int(number*adjust))/adjust)
- return
+ return newNumberFormulaArg(float64(int(number*adjust)) / adjust)
}
// Statistical functions
@@ -2977,7 +2875,7 @@ func (fn *formulaFuncs) TRUNC(argsList *list.List) (result string, err error) {
//
// COUNTA(value1,[value2],...)
//
-func (fn *formulaFuncs) COUNTA(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) COUNTA(argsList *list.List) formulaArg {
var count int
for token := argsList.Front(); token != nil; token = token.Next() {
arg := token.Value.(formulaArg)
@@ -2996,8 +2894,7 @@ func (fn *formulaFuncs) COUNTA(argsList *list.List) (result string, err error) {
}
}
}
- result = fmt.Sprintf("%d", count)
- return
+ return newStringFormulaArg(fmt.Sprintf("%d", count))
}
// MEDIAN function returns the statistical median (the middle value) of a list
@@ -3005,20 +2902,19 @@ func (fn *formulaFuncs) COUNTA(argsList *list.List) (result string, err error) {
//
// MEDIAN(number1,[number2],...)
//
-func (fn *formulaFuncs) MEDIAN(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) MEDIAN(argsList *list.List) formulaArg {
if argsList.Len() == 0 {
- err = errors.New("MEDIAN requires at least 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "MEDIAN requires at least 1 argument")
}
- values := []float64{}
+ var values = []float64{}
var median, digits float64
+ var err error
for token := argsList.Front(); token != nil; token = token.Next() {
arg := token.Value.(formulaArg)
switch arg.Type {
case ArgString:
if digits, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
values = append(values, digits)
case ArgMatrix:
@@ -3028,8 +2924,7 @@ func (fn *formulaFuncs) MEDIAN(argsList *list.List) (result string, err error) {
continue
}
if digits, err = strconv.ParseFloat(value.String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
values = append(values, digits)
}
@@ -3042,8 +2937,7 @@ func (fn *formulaFuncs) MEDIAN(argsList *list.List) (result string, err error) {
} else {
median = values[len(values)/2]
}
- result = fmt.Sprintf("%g", median)
- return
+ return newNumberFormulaArg(median)
}
// Information functions
@@ -3054,13 +2948,12 @@ func (fn *formulaFuncs) MEDIAN(argsList *list.List) (result string, err error) {
//
// ISBLANK(value)
//
-func (fn *formulaFuncs) ISBLANK(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) ISBLANK(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("ISBLANK requires 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ISBLANK requires 1 argument")
}
token := argsList.Front().Value.(formulaArg)
- result = "FALSE"
+ result := "FALSE"
switch token.Type {
case ArgUnknown:
result = "TRUE"
@@ -3069,7 +2962,7 @@ func (fn *formulaFuncs) ISBLANK(argsList *list.List) (result string, err error)
result = "TRUE"
}
}
- return
+ return newStringFormulaArg(result)
}
// ISERR function tests if an initial supplied expression (or value) returns
@@ -3079,13 +2972,12 @@ func (fn *formulaFuncs) ISBLANK(argsList *list.List) (result string, err error)
//
// ISERR(value)
//
-func (fn *formulaFuncs) ISERR(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) ISERR(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("ISERR requires 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ISERR requires 1 argument")
}
token := argsList.Front().Value.(formulaArg)
- result = "FALSE"
+ result := "FALSE"
if token.Type == ArgString {
for _, errType := range []string{formulaErrorDIV, formulaErrorNAME, formulaErrorNUM, formulaErrorVALUE, formulaErrorREF, formulaErrorNULL, formulaErrorSPILL, formulaErrorCALC, formulaErrorGETTINGDATA} {
if errType == token.String {
@@ -3093,7 +2985,7 @@ func (fn *formulaFuncs) ISERR(argsList *list.List) (result string, err error) {
}
}
}
- return
+ return newStringFormulaArg(result)
}
// ISERROR function tests if an initial supplied expression (or value) returns
@@ -3102,13 +2994,12 @@ func (fn *formulaFuncs) ISERR(argsList *list.List) (result string, err error) {
//
// ISERROR(value)
//
-func (fn *formulaFuncs) ISERROR(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) ISERROR(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("ISERROR requires 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ISERROR requires 1 argument")
}
token := argsList.Front().Value.(formulaArg)
- result = "FALSE"
+ result := "FALSE"
if token.Type == ArgString {
for _, errType := range []string{formulaErrorDIV, formulaErrorNAME, formulaErrorNA, formulaErrorNUM, formulaErrorVALUE, formulaErrorREF, formulaErrorNULL, formulaErrorSPILL, formulaErrorCALC, formulaErrorGETTINGDATA} {
if errType == token.String {
@@ -3116,7 +3007,7 @@ func (fn *formulaFuncs) ISERROR(argsList *list.List) (result string, err error)
}
}
}
- return
+ return newStringFormulaArg(result)
}
// ISEVEN function tests if a supplied number (or numeric expression)
@@ -3125,25 +3016,25 @@ func (fn *formulaFuncs) ISERROR(argsList *list.List) (result string, err error)
//
// ISEVEN(value)
//
-func (fn *formulaFuncs) ISEVEN(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) ISEVEN(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("ISEVEN requires 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ISEVEN requires 1 argument")
}
- token := argsList.Front().Value.(formulaArg)
- result = "FALSE"
- var numeric int
+ var (
+ token = argsList.Front().Value.(formulaArg)
+ result = "FALSE"
+ numeric int
+ err error
+ )
if token.Type == ArgString {
if numeric, err = strconv.Atoi(token.String); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if numeric == numeric/2*2 {
- result = "TRUE"
- return
+ return newStringFormulaArg("TRUE")
}
}
- return
+ return newStringFormulaArg(result)
}
// ISNA function tests if an initial supplied expression (or value) returns
@@ -3152,17 +3043,16 @@ func (fn *formulaFuncs) ISEVEN(argsList *list.List) (result string, err error) {
//
// ISNA(value)
//
-func (fn *formulaFuncs) ISNA(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) ISNA(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("ISNA requires 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ISNA requires 1 argument")
}
token := argsList.Front().Value.(formulaArg)
- result = "FALSE"
+ result := "FALSE"
if token.Type == ArgString && token.String == formulaErrorNA {
result = "TRUE"
}
- return
+ return newStringFormulaArg(result)
}
// ISNONTEXT function function tests if a supplied value is text. If not, the
@@ -3171,17 +3061,16 @@ func (fn *formulaFuncs) ISNA(argsList *list.List) (result string, err error) {
//
// ISNONTEXT(value)
//
-func (fn *formulaFuncs) ISNONTEXT(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) ISNONTEXT(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("ISNONTEXT requires 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ISNONTEXT requires 1 argument")
}
token := argsList.Front().Value.(formulaArg)
- result = "TRUE"
+ result := "TRUE"
if token.Type == ArgString && token.String != "" {
result = "FALSE"
}
- return
+ return newStringFormulaArg(result)
}
// ISNUMBER function function tests if a supplied value is a number. If so,
@@ -3190,20 +3079,18 @@ func (fn *formulaFuncs) ISNONTEXT(argsList *list.List) (result string, err error
//
// ISNUMBER(value)
//
-func (fn *formulaFuncs) ISNUMBER(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) ISNUMBER(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("ISNUMBER requires 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ISNUMBER requires 1 argument")
}
token := argsList.Front().Value.(formulaArg)
- result = "FALSE"
+ result := "FALSE"
if token.Type == ArgString && token.String != "" {
- if _, err = strconv.Atoi(token.String); err == nil {
+ if _, err := strconv.Atoi(token.String); err == nil {
result = "TRUE"
}
- err = nil
}
- return
+ return newStringFormulaArg(result)
}
// ISODD function tests if a supplied number (or numeric expression) evaluates
@@ -3212,25 +3099,25 @@ func (fn *formulaFuncs) ISNUMBER(argsList *list.List) (result string, err error)
//
// ISODD(value)
//
-func (fn *formulaFuncs) ISODD(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) ISODD(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("ISODD requires 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "ISODD requires 1 argument")
}
- token := argsList.Front().Value.(formulaArg)
- result = "FALSE"
- var numeric int
+ var (
+ token = argsList.Front().Value.(formulaArg)
+ result = "FALSE"
+ numeric int
+ err error
+ )
if token.Type == ArgString {
if numeric, err = strconv.Atoi(token.String); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if numeric != numeric/2*2 {
- result = "TRUE"
- return
+ return newStringFormulaArg("TRUE")
}
}
- return
+ return newStringFormulaArg(result)
}
// NA function returns the Excel #N/A error. This error message has the
@@ -3239,13 +3126,11 @@ func (fn *formulaFuncs) ISODD(argsList *list.List) (result string, err error) {
//
// NA()
//
-func (fn *formulaFuncs) NA(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) NA(argsList *list.List) formulaArg {
if argsList.Len() != 0 {
- err = errors.New("NA accepts no arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "NA accepts no arguments")
}
- result = formulaErrorNA
- return
+ return newStringFormulaArg(formulaErrorNA)
}
// Logical Functions
@@ -3255,17 +3140,18 @@ func (fn *formulaFuncs) NA(argsList *list.List) (result string, err error) {
//
// AND(logical_test1,[logical_test2],...)
//
-func (fn *formulaFuncs) AND(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) AND(argsList *list.List) formulaArg {
if argsList.Len() == 0 {
- err = errors.New("AND requires at least 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "AND requires at least 1 argument")
}
if argsList.Len() > 30 {
- err = errors.New("AND accepts at most 30 arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "AND accepts at most 30 arguments")
}
- var and = true
- var val float64
+ var (
+ and = true
+ val float64
+ err error
+ )
for arg := argsList.Front(); arg != nil; arg = arg.Next() {
token := arg.Value.(formulaArg)
switch token.Type {
@@ -3276,22 +3162,18 @@ func (fn *formulaFuncs) AND(argsList *list.List) (result string, err error) {
continue
}
if token.String == "FALSE" {
- result = token.String
- return
+ return newStringFormulaArg(token.String)
}
if val, err = strconv.ParseFloat(token.String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
and = and && (val != 0)
case ArgMatrix:
// TODO
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
}
}
- result = strings.ToUpper(strconv.FormatBool(and))
- return
+ return newStringFormulaArg(strings.ToUpper(strconv.FormatBool(and)))
}
// OR function tests a number of supplied conditions and returns either TRUE
@@ -3299,17 +3181,18 @@ func (fn *formulaFuncs) AND(argsList *list.List) (result string, err error) {
//
// OR(logical_test1,[logical_test2],...)
//
-func (fn *formulaFuncs) OR(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) OR(argsList *list.List) formulaArg {
if argsList.Len() == 0 {
- err = errors.New("OR requires at least 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "OR requires at least 1 argument")
}
if argsList.Len() > 30 {
- err = errors.New("OR accepts at most 30 arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "OR accepts at most 30 arguments")
}
- var or bool
- var val float64
+ var (
+ or bool
+ val float64
+ err error
+ )
for arg := argsList.Front(); arg != nil; arg = arg.Next() {
token := arg.Value.(formulaArg)
switch token.Type {
@@ -3324,18 +3207,15 @@ func (fn *formulaFuncs) OR(argsList *list.List) (result string, err error) {
continue
}
if val, err = strconv.ParseFloat(token.String, 64); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
or = val != 0
case ArgMatrix:
// TODO
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
}
}
- result = strings.ToUpper(strconv.FormatBool(or))
- return
+ return newStringFormulaArg(strings.ToUpper(strconv.FormatBool(or)))
}
// Date and Time Functions
@@ -3345,27 +3225,23 @@ func (fn *formulaFuncs) OR(argsList *list.List) (result string, err error) {
//
// DATE(year,month,day)
//
-func (fn *formulaFuncs) DATE(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) DATE(argsList *list.List) formulaArg {
if argsList.Len() != 3 {
- err = errors.New("DATE requires 3 number arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "DATE requires 3 number arguments")
}
var year, month, day int
+ var err error
if year, err = strconv.Atoi(argsList.Front().Value.(formulaArg).String); err != nil {
- err = errors.New("DATE requires 3 number arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "DATE requires 3 number arguments")
}
if month, err = strconv.Atoi(argsList.Front().Next().Value.(formulaArg).String); err != nil {
- err = errors.New("DATE requires 3 number arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "DATE requires 3 number arguments")
}
if day, err = strconv.Atoi(argsList.Back().Value.(formulaArg).String); err != nil {
- err = errors.New("DATE requires 3 number arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "DATE requires 3 number arguments")
}
d := makeDate(year, time.Month(month), day)
- result = timeFromExcelTime(daysBetween(excelMinTime1900.Unix(), d)+1, false).String()
- return
+ return newStringFormulaArg(timeFromExcelTime(daysBetween(excelMinTime1900.Unix(), d)+1, false).String())
}
// makeDate return date as a Unix time, the number of seconds elapsed since
@@ -3391,10 +3267,9 @@ func daysBetween(startDate, endDate int64) float64 {
//
// CLEAN(text)
//
-func (fn *formulaFuncs) CLEAN(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) CLEAN(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("CLEAN requires 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "CLEAN requires 1 argument")
}
b := bytes.Buffer{}
for _, c := range argsList.Front().Value.(formulaArg).String {
@@ -3402,8 +3277,7 @@ func (fn *formulaFuncs) CLEAN(argsList *list.List) (result string, err error) {
b.WriteRune(c)
}
}
- result = b.String()
- return
+ return newStringFormulaArg(b.String())
}
// LEN returns the length of a supplied text string. The syntax of the
@@ -3411,13 +3285,11 @@ func (fn *formulaFuncs) CLEAN(argsList *list.List) (result string, err error) {
//
// LEN(text)
//
-func (fn *formulaFuncs) LEN(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) LEN(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("LEN requires 1 string argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "LEN requires 1 string argument")
}
- result = strconv.Itoa(len(argsList.Front().Value.(formulaArg).String))
- return
+ return newStringFormulaArg(strconv.Itoa(len(argsList.Front().Value.(formulaArg).String)))
}
// TRIM removes extra spaces (i.e. all spaces except for single spaces between
@@ -3426,13 +3298,11 @@ func (fn *formulaFuncs) LEN(argsList *list.List) (result string, err error) {
//
// TRIM(text)
//
-func (fn *formulaFuncs) TRIM(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) TRIM(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("TRIM requires 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "TRIM requires 1 argument")
}
- result = strings.TrimSpace(argsList.Front().Value.(formulaArg).String)
- return
+ return newStringFormulaArg(strings.TrimSpace(argsList.Front().Value.(formulaArg).String))
}
// LOWER converts all characters in a supplied text string to lower case. The
@@ -3440,13 +3310,11 @@ func (fn *formulaFuncs) TRIM(argsList *list.List) (result string, err error) {
//
// LOWER(text)
//
-func (fn *formulaFuncs) LOWER(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) LOWER(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("LOWER requires 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "LOWER requires 1 argument")
}
- result = strings.ToLower(argsList.Front().Value.(formulaArg).String)
- return
+ return newStringFormulaArg(strings.ToLower(argsList.Front().Value.(formulaArg).String))
}
// PROPER converts all characters in a supplied text string to proper case
@@ -3456,10 +3324,9 @@ func (fn *formulaFuncs) LOWER(argsList *list.List) (result string, err error) {
//
// PROPER(text)
//
-func (fn *formulaFuncs) PROPER(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) PROPER(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("PROPER requires 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "PROPER requires 1 argument")
}
buf := bytes.Buffer{}
isLetter := false
@@ -3471,9 +3338,7 @@ func (fn *formulaFuncs) PROPER(argsList *list.List) (result string, err error) {
}
isLetter = unicode.IsLetter(char)
}
-
- result = buf.String()
- return
+ return newStringFormulaArg(buf.String())
}
// UPPER converts all characters in a supplied text string to upper case. The
@@ -3481,13 +3346,11 @@ func (fn *formulaFuncs) PROPER(argsList *list.List) (result string, err error) {
//
// UPPER(text)
//
-func (fn *formulaFuncs) UPPER(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) UPPER(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
- err = errors.New("UPPER requires 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "UPPER requires 1 argument")
}
- result = strings.ToUpper(argsList.Front().Value.(formulaArg).String)
- return
+ return newStringFormulaArg(strings.ToUpper(argsList.Front().Value.(formulaArg).String))
}
// Conditional Functions
@@ -3496,36 +3359,61 @@ func (fn *formulaFuncs) UPPER(argsList *list.List) (result string, err error) {
// condition evaluates to TRUE, and another result if the condition evaluates
// to FALSE. The syntax of the function is:
//
-// IF( logical_test, value_if_true, value_if_false )
+// IF(logical_test,value_if_true,value_if_false)
//
-func (fn *formulaFuncs) IF(argsList *list.List) (result string, err error) {
+func (fn *formulaFuncs) IF(argsList *list.List) formulaArg {
if argsList.Len() == 0 {
- err = errors.New("IF requires at least 1 argument")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "IF requires at least 1 argument")
}
if argsList.Len() > 3 {
- err = errors.New("IF accepts at most 3 arguments")
- return
+ return newErrorFormulaArg(formulaErrorVALUE, "IF accepts at most 3 arguments")
}
token := argsList.Front().Value.(formulaArg)
- var cond bool
+ var (
+ cond bool
+ err error
+ result string
+ )
switch token.Type {
case ArgString:
if cond, err = strconv.ParseBool(token.String); err != nil {
- err = errors.New(formulaErrorVALUE)
- return
+ return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if argsList.Len() == 1 {
- result = strings.ToUpper(strconv.FormatBool(cond))
- return
+ return newStringFormulaArg(strings.ToUpper(strconv.FormatBool(cond)))
}
if cond {
- result = argsList.Front().Next().Value.(formulaArg).String
- return
+ return newStringFormulaArg(argsList.Front().Next().Value.(formulaArg).String)
}
if argsList.Len() == 3 {
result = argsList.Back().Value.(formulaArg).String
}
}
- return
+ return newStringFormulaArg(result)
+}
+
+// Excel Lookup and Reference Functions
+
+// CHOOSE function returns a value from an array, that corresponds to a
+// supplied index number (position). The syntax of the function is:
+//
+// CHOOSE(index_num,value1,[value2],...)
+//
+// TODO: resolve range choose.
+func (fn *formulaFuncs) CHOOSE(argsList *list.List) formulaArg {
+ if argsList.Len() < 2 {
+ return newErrorFormulaArg(formulaErrorVALUE, "CHOOSE requires 2 arguments")
+ }
+ idx, err := strconv.Atoi(argsList.Front().Value.(formulaArg).String)
+ if err != nil {
+ return newErrorFormulaArg(formulaErrorVALUE, "CHOOSE requires first argument of type number")
+ }
+ if argsList.Len() <= idx {
+ return newErrorFormulaArg(formulaErrorVALUE, "index_num should be <= to the number of values")
+ }
+ arg := argsList.Front()
+ for i := 0; i < idx; i++ {
+ arg = arg.Next()
+ }
+ return newStringFormulaArg(arg.Value.(formulaArg).String)
}
diff --git a/calc_test.go b/calc_test.go
index c999540..d890043 100644
--- a/calc_test.go
+++ b/calc_test.go
@@ -494,6 +494,10 @@ func TestCalcCellValue(t *testing.T) {
"=IF(1<>1)": "FALSE",
"=IF(5<0, \"negative\", \"positive\")": "positive",
"=IF(-2<0, \"negative\", \"positive\")": "negative",
+ // Excel Lookup and Reference Functions
+ // CHOOSE
+ "=CHOOSE(4,\"red\",\"blue\",\"green\",\"brown\")": "brown",
+ "=CHOOSE(1,\"red\",\"blue\",\"green\",\"brown\")": "red",
}
for formula, expected := range mathCalc {
f := prepareData()
@@ -505,248 +509,248 @@ func TestCalcCellValue(t *testing.T) {
mathCalcError := map[string]string{
// ABS
"=ABS()": "ABS requires 1 numeric argument",
- `=ABS("X")`: "#VALUE!",
+ `=ABS("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
"=ABS(~)": `cannot convert cell "~" to coordinates: invalid cell name "~"`,
// ACOS
"=ACOS()": "ACOS requires 1 numeric argument",
- `=ACOS("X")`: "#VALUE!",
+ `=ACOS("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// ACOSH
"=ACOSH()": "ACOSH requires 1 numeric argument",
- `=ACOSH("X")`: "#VALUE!",
+ `=ACOSH("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// _xlfn.ACOT
"=_xlfn.ACOT()": "ACOT requires 1 numeric argument",
- `=_xlfn.ACOT("X")`: "#VALUE!",
+ `=_xlfn.ACOT("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// _xlfn.ACOTH
"=_xlfn.ACOTH()": "ACOTH requires 1 numeric argument",
- `=_xlfn.ACOTH("X")`: "#VALUE!",
+ `=_xlfn.ACOTH("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// _xlfn.ARABIC
"=_xlfn.ARABIC()": "ARABIC requires 1 numeric argument",
// ASIN
"=ASIN()": "ASIN requires 1 numeric argument",
- `=ASIN("X")`: "#VALUE!",
+ `=ASIN("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// ASINH
"=ASINH()": "ASINH requires 1 numeric argument",
- `=ASINH("X")`: "#VALUE!",
+ `=ASINH("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// ATAN
"=ATAN()": "ATAN requires 1 numeric argument",
- `=ATAN("X")`: "#VALUE!",
+ `=ATAN("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// ATANH
"=ATANH()": "ATANH requires 1 numeric argument",
- `=ATANH("X")`: "#VALUE!",
+ `=ATANH("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// ATAN2
"=ATAN2()": "ATAN2 requires 2 numeric arguments",
- `=ATAN2("X",0)`: "#VALUE!",
- `=ATAN2(0,"X")`: "#VALUE!",
+ `=ATAN2("X",0)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ `=ATAN2(0,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// BASE
"=BASE()": "BASE requires at least 2 arguments",
"=BASE(1,2,3,4)": "BASE allows at most 3 arguments",
"=BASE(1,1)": "radix must be an integer >= 2 and <= 36",
- `=BASE("X",2)`: "#VALUE!",
- `=BASE(1,"X")`: "#VALUE!",
- `=BASE(1,2,"X")`: "#VALUE!",
+ `=BASE("X",2)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ `=BASE(1,"X")`: "strconv.Atoi: parsing \"X\": invalid syntax",
+ `=BASE(1,2,"X")`: "strconv.Atoi: parsing \"X\": invalid syntax",
// CEILING
"=CEILING()": "CEILING requires at least 1 argument",
"=CEILING(1,2,3)": "CEILING allows at most 2 arguments",
"=CEILING(1,-1)": "negative sig to CEILING invalid",
- `=CEILING("X",0)`: "#VALUE!",
- `=CEILING(0,"X")`: "#VALUE!",
+ `=CEILING("X",0)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ `=CEILING(0,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// _xlfn.CEILING.MATH
"=_xlfn.CEILING.MATH()": "CEILING.MATH requires at least 1 argument",
"=_xlfn.CEILING.MATH(1,2,3,4)": "CEILING.MATH allows at most 3 arguments",
- `=_xlfn.CEILING.MATH("X")`: "#VALUE!",
- `=_xlfn.CEILING.MATH(1,"X")`: "#VALUE!",
- `=_xlfn.CEILING.MATH(1,2,"X")`: "#VALUE!",
+ `=_xlfn.CEILING.MATH("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ `=_xlfn.CEILING.MATH(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ `=_xlfn.CEILING.MATH(1,2,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// _xlfn.CEILING.PRECISE
"=_xlfn.CEILING.PRECISE()": "CEILING.PRECISE requires at least 1 argument",
"=_xlfn.CEILING.PRECISE(1,2,3)": "CEILING.PRECISE allows at most 2 arguments",
- `=_xlfn.CEILING.PRECISE("X",2)`: "#VALUE!",
+ `=_xlfn.CEILING.PRECISE("X",2)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
`=_xlfn.CEILING.PRECISE(1,"X")`: "#VALUE!",
// COMBIN
"=COMBIN()": "COMBIN requires 2 argument",
"=COMBIN(-1,1)": "COMBIN requires number >= number_chosen",
- `=COMBIN("X",1)`: "#VALUE!",
- `=COMBIN(-1,"X")`: "#VALUE!",
+ `=COMBIN("X",1)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ `=COMBIN(-1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// _xlfn.COMBINA
"=_xlfn.COMBINA()": "COMBINA requires 2 argument",
"=_xlfn.COMBINA(-1,1)": "COMBINA requires number > number_chosen",
"=_xlfn.COMBINA(-1,-1)": "COMBIN requires number >= number_chosen",
- `=_xlfn.COMBINA("X",1)`: "#VALUE!",
- `=_xlfn.COMBINA(-1,"X")`: "#VALUE!",
+ `=_xlfn.COMBINA("X",1)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ `=_xlfn.COMBINA(-1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// COS
"=COS()": "COS requires 1 numeric argument",
- `=COS("X")`: "#VALUE!",
+ `=COS("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// COSH
"=COSH()": "COSH requires 1 numeric argument",
- `=COSH("X")`: "#VALUE!",
+ `=COSH("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// _xlfn.COT
"=COT()": "COT requires 1 numeric argument",
- `=COT("X")`: "#VALUE!",
+ `=COT("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
"=COT(0)": "#DIV/0!",
// _xlfn.COTH
"=COTH()": "COTH requires 1 numeric argument",
- `=COTH("X")`: "#VALUE!",
+ `=COTH("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
"=COTH(0)": "#DIV/0!",
// _xlfn.CSC
"=_xlfn.CSC()": "CSC requires 1 numeric argument",
- `=_xlfn.CSC("X")`: "#VALUE!",
+ `=_xlfn.CSC("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
"=_xlfn.CSC(0)": "#DIV/0!",
// _xlfn.CSCH
"=_xlfn.CSCH()": "CSCH requires 1 numeric argument",
- `=_xlfn.CSCH("X")`: "#VALUE!",
+ `=_xlfn.CSCH("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
"=_xlfn.CSCH(0)": "#DIV/0!",
// _xlfn.DECIMAL
"=_xlfn.DECIMAL()": "DECIMAL requires 2 numeric arguments",
- `=_xlfn.DECIMAL("X", 2)`: "#VALUE!",
- `=_xlfn.DECIMAL(2000, "X")`: "#VALUE!",
+ `=_xlfn.DECIMAL("X", 2)`: "strconv.ParseInt: parsing \"X\": invalid syntax",
+ `=_xlfn.DECIMAL(2000, "X")`: "strconv.Atoi: parsing \"X\": invalid syntax",
// DEGREES
"=DEGREES()": "DEGREES requires 1 numeric argument",
- `=DEGREES("X")`: "#VALUE!",
+ `=DEGREES("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
"=DEGREES(0)": "#DIV/0!",
// EVEN
"=EVEN()": "EVEN requires 1 numeric argument",
- `=EVEN("X")`: "#VALUE!",
+ `=EVEN("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// EXP
"=EXP()": "EXP requires 1 numeric argument",
- `=EXP("X")`: "#VALUE!",
+ `=EXP("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// FACT
"=FACT()": "FACT requires 1 numeric argument",
- `=FACT("X")`: "#VALUE!",
+ `=FACT("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
"=FACT(-1)": "#NUM!",
// FACTDOUBLE
"=FACTDOUBLE()": "FACTDOUBLE requires 1 numeric argument",
- `=FACTDOUBLE("X")`: "#VALUE!",
+ `=FACTDOUBLE("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
"=FACTDOUBLE(-1)": "#NUM!",
// FLOOR
"=FLOOR()": "FLOOR requires 2 numeric arguments",
- `=FLOOR("X",-1)`: "#VALUE!",
- `=FLOOR(1,"X")`: "#VALUE!",
- "=FLOOR(1,-1)": "#NUM!",
+ `=FLOOR("X",-1)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ `=FLOOR(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ "=FLOOR(1,-1)": "invalid arguments to FLOOR",
// _xlfn.FLOOR.MATH
"=_xlfn.FLOOR.MATH()": "FLOOR.MATH requires at least 1 argument",
"=_xlfn.FLOOR.MATH(1,2,3,4)": "FLOOR.MATH allows at most 3 arguments",
- `=_xlfn.FLOOR.MATH("X",2,3)`: "#VALUE!",
- `=_xlfn.FLOOR.MATH(1,"X",3)`: "#VALUE!",
- `=_xlfn.FLOOR.MATH(1,2,"X")`: "#VALUE!",
+ `=_xlfn.FLOOR.MATH("X",2,3)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ `=_xlfn.FLOOR.MATH(1,"X",3)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ `=_xlfn.FLOOR.MATH(1,2,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// _xlfn.FLOOR.PRECISE
"=_xlfn.FLOOR.PRECISE()": "FLOOR.PRECISE requires at least 1 argument",
"=_xlfn.FLOOR.PRECISE(1,2,3)": "FLOOR.PRECISE allows at most 2 arguments",
- `=_xlfn.FLOOR.PRECISE("X",2)`: "#VALUE!",
- `=_xlfn.FLOOR.PRECISE(1,"X")`: "#VALUE!",
+ `=_xlfn.FLOOR.PRECISE("X",2)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ `=_xlfn.FLOOR.PRECISE(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// GCD
"=GCD()": "GCD requires at least 1 argument",
"=GCD(-1)": "GCD only accepts positive arguments",
"=GCD(1,-1)": "GCD only accepts positive arguments",
- `=GCD("X")`: "#VALUE!",
+ `=GCD("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// INT
"=INT()": "INT requires 1 numeric argument",
- `=INT("X")`: "#VALUE!",
+ `=INT("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// ISO.CEILING
"=ISO.CEILING()": "ISO.CEILING requires at least 1 argument",
"=ISO.CEILING(1,2,3)": "ISO.CEILING allows at most 2 arguments",
- `=ISO.CEILING("X",2)`: "#VALUE!",
- `=ISO.CEILING(1,"X")`: "#VALUE!",
+ `=ISO.CEILING("X",2)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ `=ISO.CEILING(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// LCM
"=LCM()": "LCM requires at least 1 argument",
"=LCM(-1)": "LCM only accepts positive arguments",
"=LCM(1,-1)": "LCM only accepts positive arguments",
- `=LCM("X")`: "#VALUE!",
+ `=LCM("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// LN
"=LN()": "LN requires 1 numeric argument",
- `=LN("X")`: "#VALUE!",
+ `=LN("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// LOG
"=LOG()": "LOG requires at least 1 argument",
"=LOG(1,2,3)": "LOG allows at most 2 arguments",
- `=LOG("X",1)`: "#VALUE!",
- `=LOG(1,"X")`: "#VALUE!",
- "=LOG(0,0)": "#NUM!",
- "=LOG(1,0)": "#NUM!",
+ `=LOG("X",1)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ `=LOG(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ "=LOG(0,0)": "#DIV/0!",
+ "=LOG(1,0)": "#DIV/0!",
"=LOG(1,1)": "#DIV/0!",
// LOG10
"=LOG10()": "LOG10 requires 1 numeric argument",
- `=LOG10("X")`: "#VALUE!",
+ `=LOG10("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// MOD
"=MOD()": "MOD requires 2 numeric arguments",
- "=MOD(6,0)": "#DIV/0!",
- `=MOD("X",0)`: "#VALUE!",
- `=MOD(6,"X")`: "#VALUE!",
+ "=MOD(6,0)": "MOD divide by zero",
+ `=MOD("X",0)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ `=MOD(6,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// MROUND
"=MROUND()": "MROUND requires 2 numeric arguments",
"=MROUND(1,0)": "#NUM!",
"=MROUND(1,-1)": "#NUM!",
- `=MROUND("X",0)`: "#VALUE!",
- `=MROUND(1,"X")`: "#VALUE!",
+ `=MROUND("X",0)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ `=MROUND(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// MULTINOMIAL
- `=MULTINOMIAL("X")`: "#VALUE!",
+ `=MULTINOMIAL("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// _xlfn.MUNIT
- "=_xlfn.MUNIT()": "MUNIT requires 1 numeric argument", // not support currently
- `=_xlfn.MUNIT("X")`: "#VALUE!", // not support currently
+ "=_xlfn.MUNIT()": "MUNIT requires 1 numeric argument", // not support currently
+ `=_xlfn.MUNIT("X")`: "strconv.Atoi: parsing \"X\": invalid syntax", // not support currently
// ODD
"=ODD()": "ODD requires 1 numeric argument",
- `=ODD("X")`: "#VALUE!",
+ `=ODD("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// PI
"=PI(1)": "PI accepts no arguments",
// POWER
- `=POWER("X",1)`: "#VALUE!",
- `=POWER(1,"X")`: "#VALUE!",
+ `=POWER("X",1)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ `=POWER(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
"=POWER(0,0)": "#NUM!",
"=POWER(0,-1)": "#DIV/0!",
"=POWER(1)": "POWER requires 2 numeric arguments",
// PRODUCT
- `=PRODUCT("X")`: "#VALUE!",
+ `=PRODUCT("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// QUOTIENT
- `=QUOTIENT("X",1)`: "#VALUE!",
- `=QUOTIENT(1,"X")`: "#VALUE!",
+ `=QUOTIENT("X",1)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ `=QUOTIENT(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
"=QUOTIENT(1,0)": "#DIV/0!",
"=QUOTIENT(1)": "QUOTIENT requires 2 numeric arguments",
// RADIANS
- `=RADIANS("X")`: "#VALUE!",
+ `=RADIANS("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
"=RADIANS()": "RADIANS requires 1 numeric argument",
// RAND
"=RAND(1)": "RAND accepts no arguments",
// RANDBETWEEN
- `=RANDBETWEEN("X",1)`: "#VALUE!",
- `=RANDBETWEEN(1,"X")`: "#VALUE!",
+ `=RANDBETWEEN("X",1)`: "strconv.ParseInt: parsing \"X\": invalid syntax",
+ `=RANDBETWEEN(1,"X")`: "strconv.ParseInt: parsing \"X\": invalid syntax",
"=RANDBETWEEN()": "RANDBETWEEN requires 2 numeric arguments",
"=RANDBETWEEN(2,1)": "#NUM!",
// ROMAN
"=ROMAN()": "ROMAN requires at least 1 argument",
"=ROMAN(1,2,3)": "ROMAN allows at most 2 arguments",
- `=ROMAN("X")`: "#VALUE!",
- `=ROMAN("X",1)`: "#VALUE!",
+ `=ROMAN("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ `=ROMAN("X",1)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// ROUND
"=ROUND()": "ROUND requires 2 numeric arguments",
- `=ROUND("X",1)`: "#VALUE!",
- `=ROUND(1,"X")`: "#VALUE!",
+ `=ROUND("X",1)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ `=ROUND(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// ROUNDDOWN
"=ROUNDDOWN()": "ROUNDDOWN requires 2 numeric arguments",
- `=ROUNDDOWN("X",1)`: "#VALUE!",
- `=ROUNDDOWN(1,"X")`: "#VALUE!",
+ `=ROUNDDOWN("X",1)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ `=ROUNDDOWN(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// ROUNDUP
"=ROUNDUP()": "ROUNDUP requires 2 numeric arguments",
- `=ROUNDUP("X",1)`: "#VALUE!",
- `=ROUNDUP(1,"X")`: "#VALUE!",
+ `=ROUNDUP("X",1)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ `=ROUNDUP(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// SEC
"=_xlfn.SEC()": "SEC requires 1 numeric argument",
- `=_xlfn.SEC("X")`: "#VALUE!",
+ `=_xlfn.SEC("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// _xlfn.SECH
"=_xlfn.SECH()": "SECH requires 1 numeric argument",
- `=_xlfn.SECH("X")`: "#VALUE!",
+ `=_xlfn.SECH("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// SIGN
"=SIGN()": "SIGN requires 1 numeric argument",
- `=SIGN("X")`: "#VALUE!",
+ `=SIGN("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// SIN
"=SIN()": "SIN requires 1 numeric argument",
- `=SIN("X")`: "#VALUE!",
+ `=SIN("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// SINH
"=SINH()": "SINH requires 1 numeric argument",
- `=SINH("X")`: "#VALUE!",
+ `=SINH("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// SQRT
"=SQRT()": "SQRT requires 1 numeric argument",
- `=SQRT("X")`: "#VALUE!",
+ `=SQRT("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
"=SQRT(-1)": "#NUM!",
// SQRTPI
"=SQRTPI()": "SQRTPI requires 1 numeric argument",
- `=SQRTPI("X")`: "#VALUE!",
+ `=SQRTPI("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// SUM
"=SUM((": "formula not valid",
"=SUM(-)": "formula not valid",
@@ -754,21 +758,21 @@ func TestCalcCellValue(t *testing.T) {
"=SUM(1-)": "formula not valid",
"=SUM(1*)": "formula not valid",
"=SUM(1/)": "formula not valid",
- `=SUM("X")`: "#VALUE!",
+ `=SUM("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// SUMIF
"=SUMIF()": "SUMIF requires at least 2 argument",
// SUMSQ
- `=SUMSQ("X")`: "#VALUE!",
+ `=SUMSQ("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// TAN
"=TAN()": "TAN requires 1 numeric argument",
- `=TAN("X")`: "#VALUE!",
+ `=TAN("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// TANH
"=TANH()": "TANH requires 1 numeric argument",
- `=TANH("X")`: "#VALUE!",
+ `=TANH("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// TRUNC
"=TRUNC()": "TRUNC requires at least 1 argument",
- `=TRUNC("X")`: "#VALUE!",
- `=TRUNC(1,"X")`: "#VALUE!",
+ `=TRUNC("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
+ `=TRUNC(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// Statistical Functions
// MEDIAN
"=MEDIAN()": "MEDIAN requires at least 1 argument",
@@ -781,7 +785,7 @@ func TestCalcCellValue(t *testing.T) {
"=ISERROR()": "ISERROR requires 1 argument",
// ISEVEN
"=ISEVEN()": "ISEVEN requires 1 argument",
- `=ISEVEN("text")`: "#VALUE!",
+ `=ISEVEN("text")`: "strconv.Atoi: parsing \"text\": invalid syntax",
// ISNA
"=ISNA()": "ISNA requires 1 argument",
// ISNONTEXT
@@ -790,17 +794,17 @@ func TestCalcCellValue(t *testing.T) {
"=ISNUMBER()": "ISNUMBER requires 1 argument",
// ISODD
"=ISODD()": "ISODD requires 1 argument",
- `=ISODD("text")`: "#VALUE!",
+ `=ISODD("text")`: "strconv.Atoi: parsing \"text\": invalid syntax",
// NA
"=NA(1)": "NA accepts no arguments",
// Logical Functions
// AND
- `=AND("text")`: "#VALUE!",
+ `=AND("text")`: "strconv.ParseFloat: parsing \"text\": invalid syntax",
`=AND(A1:B1)`: "#VALUE!",
"=AND()": "AND requires at least 1 argument",
"=AND(1" + strings.Repeat(",1", 30) + ")": "AND accepts at most 30 arguments",
// OR
- `=OR("text")`: "#VALUE!",
+ `=OR("text")`: "strconv.ParseFloat: parsing \"text\": invalid syntax",
`=OR(A1:B1)`: "#VALUE!",
"=OR()": "OR requires at least 1 argument",
"=OR(1" + strings.Repeat(",1", 30) + ")": "OR accepts at most 30 arguments",
@@ -832,13 +836,18 @@ func TestCalcCellValue(t *testing.T) {
// IF
"=IF()": "IF requires at least 1 argument",
"=IF(0,1,2,3)": "IF accepts at most 3 arguments",
- "=IF(D1,1,2)": "#VALUE!",
+ "=IF(D1,1,2)": "strconv.ParseBool: parsing \"Month\": invalid syntax",
+ // Excel Lookup and Reference Functions
+ // CHOOSE
+ "=CHOOSE()": "CHOOSE requires 2 arguments",
+ "=CHOOSE(\"index_num\",0)": "CHOOSE requires first argument of type number",
+ "=CHOOSE(2,0)": "index_num should be <= to the number of values",
}
for formula, expected := range mathCalcError {
f := prepareData()
assert.NoError(t, f.SetCellFormula("Sheet1", "C1", formula))
result, err := f.CalcCellValue("Sheet1", "C1")
- assert.EqualError(t, err, expected)
+ assert.EqualError(t, err, expected, formula)
assert.Equal(t, "", result, formula)
}
@@ -976,9 +985,9 @@ func TestISBLANK(t *testing.T) {
Type: ArgUnknown,
})
fn := formulaFuncs{}
- result, err := fn.ISBLANK(argsList)
- assert.Equal(t, result, "TRUE")
- assert.NoError(t, err)
+ result := fn.ISBLANK(argsList)
+ assert.Equal(t, result.String, "TRUE")
+ assert.Empty(t, result.Error)
}
func TestAND(t *testing.T) {
@@ -987,9 +996,9 @@ func TestAND(t *testing.T) {
Type: ArgUnknown,
})
fn := formulaFuncs{}
- result, err := fn.AND(argsList)
- assert.Equal(t, result, "TRUE")
- assert.NoError(t, err)
+ result := fn.AND(argsList)
+ assert.Equal(t, result.String, "TRUE")
+ assert.Empty(t, result.Error)
}
func TestOR(t *testing.T) {
@@ -998,9 +1007,9 @@ func TestOR(t *testing.T) {
Type: ArgUnknown,
})
fn := formulaFuncs{}
- result, err := fn.OR(argsList)
- assert.Equal(t, result, "FALSE")
- assert.NoError(t, err)
+ result := fn.OR(argsList)
+ assert.Equal(t, result.String, "FALSE")
+ assert.Empty(t, result.Error)
}
func TestDet(t *testing.T) {
diff --git a/go.mod b/go.mod
index 9637ba0..41babe1 100644
--- a/go.mod
+++ b/go.mod
@@ -6,9 +6,9 @@ require (
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
github.com/richardlehane/mscfb v1.0.3
github.com/stretchr/testify v1.6.1
- github.com/xuri/efp v0.0.0-20201016154823-031c29024257
- golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee
+ github.com/xuri/efp v0.0.0-20210128032744-13be4fd5dcb5
+ golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
golang.org/x/image v0.0.0-20201208152932-35266b937fa6
- golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0
- golang.org/x/text v0.3.3
+ golang.org/x/net v0.0.0-20210119194325-5f4716e94777
+ golang.org/x/text v0.3.5
)
diff --git a/go.sum b/go.sum
index 24aa225..75323d6 100644
--- a/go.sum
+++ b/go.sum
@@ -8,28 +8,30 @@ github.com/richardlehane/mscfb v1.0.3 h1:rD8TBkYWkObWO0oLDFCbwMeZ4KoalxQy+QgniCj
github.com/richardlehane/mscfb v1.0.3/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
github.com/richardlehane/msoleps v1.0.1 h1:RfrALnSNXzmXLbGct/P2b4xkFz4e8Gmj/0Vj9M9xC1o=
github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
-github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/xuri/efp v0.0.0-20201016154823-031c29024257 h1:6ldmGEJXtsRMwdR2KuS3esk9wjVJNvgk05/YY2XmOj0=
-github.com/xuri/efp v0.0.0-20201016154823-031c29024257/go.mod h1:uBiSUepVYMhGTfDeBKKasV4GpgBlzJ46gXUBAqV8qLk=
+github.com/xuri/efp v0.0.0-20210128032744-13be4fd5dcb5 h1:hO7we8DcWAkmZX/Voqa04Tuo84SbeXIJbdgMj92hIpA=
+github.com/xuri/efp v0.0.0-20210128032744-13be4fd5dcb5/go.mod h1:uBiSUepVYMhGTfDeBKKasV4GpgBlzJ46gXUBAqV8qLk=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee h1:4yd7jl+vXjalO5ztz6Vc1VADv+S/80LGJmyl1ROJ2AI=
-golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
+golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/image v0.0.0-20201208152932-35266b937fa6 h1:nfeHNc1nAqecKCy2FCy4HY+soOOe5sDLJ/gZLbx6GYI=
golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0 h1:5kGOVHlq0euqwzgTC9Vu15p6fV1Wi0ArVi8da2urnVg=
-golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
+golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
+golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=