summaryrefslogtreecommitdiff
path: root/calc.go
diff options
context:
space:
mode:
Diffstat (limited to 'calc.go')
-rw-r--r--calc.go336
1 files changed, 111 insertions, 225 deletions
diff --git a/calc.go b/calc.go
index badd30e..59131d8 100644
--- a/calc.go
+++ b/calc.go
@@ -2849,7 +2849,7 @@ func (fn *formulaFuncs) ARABIC(argsList *list.List) formulaArg {
return newErrorFormulaArg(formulaErrorVALUE, "ARABIC requires 1 numeric argument")
}
text := argsList.Front().Value.(formulaArg).Value()
- if len(text) > 255 {
+ if len(text) > MaxFieldLength {
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
}
text = strings.ToUpper(text)
@@ -7400,47 +7400,12 @@ func (fn *formulaFuncs) DAYS(argsList *list.List) formulaArg {
if argsList.Len() != 2 {
return newErrorFormulaArg(formulaErrorVALUE, "DAYS requires 2 arguments")
}
- var end, start float64
- endArg, startArg := argsList.Front().Value.(formulaArg), argsList.Back().Value.(formulaArg)
- switch endArg.Type {
- case ArgNumber:
- end = endArg.Number
- case ArgString:
- endNum := endArg.ToNumber()
- if endNum.Type == ArgNumber {
- end = endNum.Number
- } else {
- args := list.New()
- args.PushBack(endArg)
- endValue := fn.DATEVALUE(args)
- if endValue.Type == ArgError {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- end = endValue.Number
- }
- default:
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- switch startArg.Type {
- case ArgNumber:
- start = startArg.Number
- case ArgString:
- startNum := startArg.ToNumber()
- if startNum.Type == ArgNumber {
- start = startNum.Number
- } else {
- args := list.New()
- args.PushBack(startArg)
- startValue := fn.DATEVALUE(args)
- if startValue.Type == ArgError {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- start = startValue.Number
- }
- default:
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
+ args := fn.prepareDataValueArgs(2, argsList)
+ if args.Type != ArgList {
+ return args
}
- return newNumberFormulaArg(end - start)
+ end, start := args.List[0], args.List[1]
+ return newNumberFormulaArg(end.Number - start.Number)
}
// ISOWEEKNUM function returns the ISO week number of a supplied date. The
@@ -7695,28 +7660,18 @@ func (fn *formulaFuncs) YEARFRAC(argsList *list.List) formulaArg {
if argsList.Len() != 2 && argsList.Len() != 3 {
return newErrorFormulaArg(formulaErrorVALUE, "YEARFRAC requires 3 or 4 arguments")
}
- var basisArg formulaArg
- startArg, endArg := argsList.Front().Value.(formulaArg).ToNumber(), argsList.Front().Next().Value.(formulaArg).ToNumber()
- args := list.New().Init()
- if startArg.Type != ArgNumber {
- args.PushBack(argsList.Front().Value.(formulaArg))
- if startArg = fn.DATEVALUE(args); startArg.Type != ArgNumber {
- return startArg
- }
- }
- if endArg.Type != ArgNumber {
- args.Init()
- args.PushBack(argsList.Front().Next().Value.(formulaArg))
- if endArg = fn.DATEVALUE(args); endArg.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
+ args := fn.prepareDataValueArgs(2, argsList)
+ if args.Type != ArgList {
+ return args
}
+ start, end := args.List[0], args.List[1]
+ basis := newNumberFormulaArg(0)
if argsList.Len() == 3 {
- if basisArg = argsList.Back().Value.(formulaArg).ToNumber(); basisArg.Type != ArgNumber {
- return basisArg
+ if basis = argsList.Back().Value.(formulaArg).ToNumber(); basis.Type != ArgNumber {
+ return basis
}
}
- return yearFrac(startArg.Number, endArg.Number, int(basisArg.Number))
+ return yearFrac(start.Number, end.Number, int(basis.Number))
}
// NOW function returns the current date and time. The function receives no
@@ -7859,7 +7814,7 @@ func (fn *formulaFuncs) CHAR(argsList *list.List) formulaArg {
return arg
}
num := int(arg.Number)
- if num < 0 || num > 255 {
+ if num < 0 || num > MaxFieldLength {
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
}
return newStringFormulaArg(fmt.Sprintf("%c", num))
@@ -9413,24 +9368,11 @@ func (fn *formulaFuncs) ACCRINT(argsList *list.List) formulaArg {
if argsList.Len() > 8 {
return newErrorFormulaArg(formulaErrorVALUE, "ACCRINT allows at most 8 arguments")
}
- args := list.New().Init()
- args.PushBack(argsList.Front().Value.(formulaArg))
- issue := fn.DATEVALUE(args)
- if issue.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- args.Init()
- args.PushBack(argsList.Front().Next().Value.(formulaArg))
- fi := fn.DATEVALUE(args)
- if fi.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- args.Init()
- args.PushBack(argsList.Front().Next().Next().Value.(formulaArg))
- settlement := fn.DATEVALUE(args)
- if settlement.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
+ args := fn.prepareDataValueArgs(3, argsList)
+ if args.Type != ArgList {
+ return args
}
+ issue, settlement := args.List[0], args.List[2]
rate := argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber()
par := argsList.Front().Next().Next().Next().Next().Value.(formulaArg).ToNumber()
frequency := argsList.Front().Next().Next().Next().Next().Next().Value.(formulaArg).ToNumber()
@@ -9468,18 +9410,11 @@ func (fn *formulaFuncs) ACCRINTM(argsList *list.List) formulaArg {
if argsList.Len() != 4 && argsList.Len() != 5 {
return newErrorFormulaArg(formulaErrorVALUE, "ACCRINTM requires 4 or 5 arguments")
}
- args := list.New().Init()
- args.PushBack(argsList.Front().Value.(formulaArg))
- issue := fn.DATEVALUE(args)
- if issue.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- args.Init()
- args.PushBack(argsList.Front().Next().Value.(formulaArg))
- settlement := fn.DATEVALUE(args)
- if settlement.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
+ args := fn.prepareDataValueArgs(2, argsList)
+ if args.Type != ArgList {
+ return args
}
+ issue, settlement := args.List[0], args.List[1]
if settlement.Number < issue.Number {
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
}
@@ -9644,24 +9579,11 @@ func (fn *formulaFuncs) prepareCouponArgs(name string, argsList *list.List) form
if argsList.Len() != 3 && argsList.Len() != 4 {
return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 3 or 4 arguments", name))
}
- args := list.New().Init()
- settlement := argsList.Front().Value.(formulaArg).ToNumber()
- if settlement.Type != ArgNumber {
- args.PushBack(argsList.Front().Value.(formulaArg))
- settlement = fn.DATEVALUE(args)
- if settlement.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- }
- maturity := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if maturity.Type != ArgNumber {
- args.Init()
- args.PushBack(argsList.Front().Next().Value.(formulaArg))
- maturity = fn.DATEVALUE(args)
- if maturity.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
+ args := fn.prepareDataValueArgs(2, argsList)
+ if args.Type != ArgList {
+ return args
}
+ settlement, maturity := args.List[0], args.List[1]
if settlement.Number >= maturity.Number {
return newErrorFormulaArg(formulaErrorNUM, fmt.Sprintf("%s requires maturity > settlement", name))
}
@@ -10048,6 +9970,43 @@ func (fn *formulaFuncs) DDB(argsList *list.List) formulaArg {
return newNumberFormulaArg(depreciation)
}
+// prepareDataValueArgs convert first N arguments to data value for the
+// formula functions.
+func (fn *formulaFuncs) prepareDataValueArgs(n int, argsList *list.List) formulaArg {
+ l := list.New()
+ dataValues := []formulaArg{}
+ getDateValue := func(arg formulaArg, l *list.List) formulaArg {
+ switch arg.Type {
+ case ArgNumber:
+ break
+ case ArgString:
+ num := arg.ToNumber()
+ if num.Type == ArgNumber {
+ arg = num
+ break
+ }
+ l.Init()
+ l.PushBack(arg)
+ arg = fn.DATEVALUE(l)
+ if arg.Type == ArgError {
+ return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
+ }
+ default:
+ return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
+ }
+ return arg
+ }
+ for i, arg := 0, argsList.Front(); i < n; arg = arg.Next() {
+ dataValue := getDateValue(arg.Value.(formulaArg), l)
+ if dataValue.Type != ArgNumber {
+ return dataValue
+ }
+ dataValues = append(dataValues, dataValue)
+ i++
+ }
+ return newListFormulaArg(dataValues)
+}
+
// DISC function calculates the Discount Rate for a security. The syntax of
// the function is:
//
@@ -10057,18 +10016,11 @@ func (fn *formulaFuncs) DISC(argsList *list.List) formulaArg {
if argsList.Len() != 4 && argsList.Len() != 5 {
return newErrorFormulaArg(formulaErrorVALUE, "DISC requires 4 or 5 arguments")
}
- args := list.New().Init()
- args.PushBack(argsList.Front().Value.(formulaArg))
- settlement := fn.DATEVALUE(args)
- if settlement.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- args.Init()
- args.PushBack(argsList.Front().Next().Value.(formulaArg))
- maturity := fn.DATEVALUE(args)
- if maturity.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
+ args := fn.prepareDataValueArgs(2, argsList)
+ if args.Type != ArgList {
+ return args
}
+ settlement, maturity := args.List[0], args.List[1]
if maturity.Number <= settlement.Number {
return newErrorFormulaArg(formulaErrorNUM, "DISC requires maturity > settlement")
}
@@ -10253,18 +10205,11 @@ func (fn *formulaFuncs) INTRATE(argsList *list.List) formulaArg {
if argsList.Len() != 4 && argsList.Len() != 5 {
return newErrorFormulaArg(formulaErrorVALUE, "INTRATE requires 4 or 5 arguments")
}
- args := list.New().Init()
- args.PushBack(argsList.Front().Value.(formulaArg))
- settlement := fn.DATEVALUE(args)
- if settlement.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- args.Init()
- args.PushBack(argsList.Front().Next().Value.(formulaArg))
- maturity := fn.DATEVALUE(args)
- if maturity.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
+ args := fn.prepareDataValueArgs(2, argsList)
+ if args.Type != ArgList {
+ return args
}
+ settlement, maturity := args.List[0], args.List[1]
if maturity.Number <= settlement.Number {
return newErrorFormulaArg(formulaErrorNUM, "INTRATE requires maturity > settlement")
}
@@ -10707,18 +10652,11 @@ func (fn *formulaFuncs) PRICEDISC(argsList *list.List) formulaArg {
if argsList.Len() != 4 && argsList.Len() != 5 {
return newErrorFormulaArg(formulaErrorVALUE, "PRICEDISC requires 4 or 5 arguments")
}
- args := list.New().Init()
- args.PushBack(argsList.Front().Value.(formulaArg))
- settlement := fn.DATEVALUE(args)
- if settlement.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- args.Init()
- args.PushBack(argsList.Front().Next().Value.(formulaArg))
- maturity := fn.DATEVALUE(args)
- if maturity.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
+ args := fn.prepareDataValueArgs(2, argsList)
+ if args.Type != ArgList {
+ return args
}
+ settlement, maturity := args.List[0], args.List[1]
if maturity.Number <= settlement.Number {
return newErrorFormulaArg(formulaErrorNUM, "PRICEDISC requires maturity > settlement")
}
@@ -10758,27 +10696,14 @@ func (fn *formulaFuncs) PRICEMAT(argsList *list.List) formulaArg {
if argsList.Len() != 5 && argsList.Len() != 6 {
return newErrorFormulaArg(formulaErrorVALUE, "PRICEMAT requires 5 or 6 arguments")
}
- args := list.New().Init()
- args.PushBack(argsList.Front().Value.(formulaArg))
- settlement := fn.DATEVALUE(args)
- if settlement.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- args.Init()
- args.PushBack(argsList.Front().Next().Value.(formulaArg))
- maturity := fn.DATEVALUE(args)
- if maturity.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
+ args := fn.prepareDataValueArgs(3, argsList)
+ if args.Type != ArgList {
+ return args
}
+ settlement, maturity, issue := args.List[0], args.List[1], args.List[2]
if settlement.Number >= maturity.Number {
return newErrorFormulaArg(formulaErrorNUM, "PRICEMAT requires maturity > settlement")
}
- args.Init()
- args.PushBack(argsList.Front().Next().Next().Value.(formulaArg))
- issue := fn.DATEVALUE(args)
- if issue.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
if issue.Number >= settlement.Number {
return newErrorFormulaArg(formulaErrorNUM, "PRICEMAT requires settlement > issue")
}
@@ -10938,18 +10863,11 @@ func (fn *formulaFuncs) RECEIVED(argsList *list.List) formulaArg {
if argsList.Len() > 5 {
return newErrorFormulaArg(formulaErrorVALUE, "RECEIVED allows at most 5 arguments")
}
- args := list.New().Init()
- args.PushBack(argsList.Front().Value.(formulaArg))
- settlement := fn.DATEVALUE(args)
- if settlement.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- args.Init()
- args.PushBack(argsList.Front().Next().Value.(formulaArg))
- maturity := fn.DATEVALUE(args)
- if maturity.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
+ args := fn.prepareDataValueArgs(2, argsList)
+ if args.Type != ArgList {
+ return args
}
+ settlement, maturity := args.List[0], args.List[1]
investment := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
if investment.Type != ArgNumber {
return investment
@@ -11061,18 +10979,11 @@ func (fn *formulaFuncs) TBILLEQ(argsList *list.List) formulaArg {
if argsList.Len() != 3 {
return newErrorFormulaArg(formulaErrorVALUE, "TBILLEQ requires 3 arguments")
}
- args := list.New().Init()
- args.PushBack(argsList.Front().Value.(formulaArg))
- settlement := fn.DATEVALUE(args)
- if settlement.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- args.Init()
- args.PushBack(argsList.Front().Next().Value.(formulaArg))
- maturity := fn.DATEVALUE(args)
- if maturity.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
+ args := fn.prepareDataValueArgs(2, argsList)
+ if args.Type != ArgList {
+ return args
}
+ settlement, maturity := args.List[0], args.List[1]
dsm := maturity.Number - settlement.Number
if dsm > 365 || maturity.Number <= settlement.Number {
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
@@ -11096,18 +11007,11 @@ func (fn *formulaFuncs) TBILLPRICE(argsList *list.List) formulaArg {
if argsList.Len() != 3 {
return newErrorFormulaArg(formulaErrorVALUE, "TBILLPRICE requires 3 arguments")
}
- args := list.New().Init()
- args.PushBack(argsList.Front().Value.(formulaArg))
- settlement := fn.DATEVALUE(args)
- if settlement.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- args.Init()
- args.PushBack(argsList.Front().Next().Value.(formulaArg))
- maturity := fn.DATEVALUE(args)
- if maturity.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
+ args := fn.prepareDataValueArgs(2, argsList)
+ if args.Type != ArgList {
+ return args
}
+ settlement, maturity := args.List[0], args.List[1]
dsm := maturity.Number - settlement.Number
if dsm > 365 || maturity.Number <= settlement.Number {
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
@@ -11131,18 +11035,11 @@ func (fn *formulaFuncs) TBILLYIELD(argsList *list.List) formulaArg {
if argsList.Len() != 3 {
return newErrorFormulaArg(formulaErrorVALUE, "TBILLYIELD requires 3 arguments")
}
- args := list.New().Init()
- args.PushBack(argsList.Front().Value.(formulaArg))
- settlement := fn.DATEVALUE(args)
- if settlement.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- args.Init()
- args.PushBack(argsList.Front().Next().Value.(formulaArg))
- maturity := fn.DATEVALUE(args)
- if maturity.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
+ args := fn.prepareDataValueArgs(2, argsList)
+ if args.Type != ArgList {
+ return args
}
+ settlement, maturity := args.List[0], args.List[1]
dsm := maturity.Number - settlement.Number
if dsm > 365 || maturity.Number <= settlement.Number {
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
@@ -11231,18 +11128,11 @@ func (fn *formulaFuncs) YIELDDISC(argsList *list.List) formulaArg {
if argsList.Len() != 4 && argsList.Len() != 5 {
return newErrorFormulaArg(formulaErrorVALUE, "YIELDDISC requires 4 or 5 arguments")
}
- args := list.New().Init()
- args.PushBack(argsList.Front().Value.(formulaArg))
- settlement := fn.DATEVALUE(args)
- if settlement.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- args.Init()
- args.PushBack(argsList.Front().Next().Value.(formulaArg))
- maturity := fn.DATEVALUE(args)
- if maturity.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
+ args := fn.prepareDataValueArgs(2, argsList)
+ if args.Type != ArgList {
+ return args
}
+ settlement, maturity := args.List[0], args.List[1]
pr := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
if pr.Type != ArgNumber {
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
@@ -11279,23 +11169,19 @@ func (fn *formulaFuncs) YIELDMAT(argsList *list.List) formulaArg {
if argsList.Len() != 5 && argsList.Len() != 6 {
return newErrorFormulaArg(formulaErrorVALUE, "YIELDMAT requires 5 or 6 arguments")
}
- args := list.New().Init()
- args.PushBack(argsList.Front().Value.(formulaArg))
- settlement := fn.DATEVALUE(args)
- if settlement.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- args.Init()
- args.PushBack(argsList.Front().Next().Value.(formulaArg))
- maturity := fn.DATEVALUE(args)
- if maturity.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
+ args := fn.prepareDataValueArgs(2, argsList)
+ if args.Type != ArgList {
+ return args
}
- args.Init()
- args.PushBack(argsList.Front().Next().Next().Value.(formulaArg))
- issue := fn.DATEVALUE(args)
+ settlement, maturity := args.List[0], args.List[1]
+ arg := list.New().Init()
+ issue := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
if issue.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
+ arg.PushBack(argsList.Front().Next().Next().Value.(formulaArg))
+ issue = fn.DATEVALUE(arg)
+ if issue.Type != ArgNumber {
+ return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
+ }
}
if issue.Number >= settlement.Number {
return newErrorFormulaArg(formulaErrorNUM, "YIELDMAT requires settlement > issue")