mirror of
https://github.com/unidoc/unioffice.git
synced 2025-04-27 13:48:54 +08:00
229 lines
5.8 KiB
Go
229 lines
5.8 KiB
Go
// Copyright 2017 Baliance. All rights reserved.
|
|
//
|
|
// Use of this source code is governed by the terms of the Affero GNU General
|
|
// Public License version 3.0 as published by the Free Software Foundation and
|
|
// appearing in the file LICENSE included in the packaging of this file. A
|
|
// commercial license can be purchased by contacting sales@baliance.com.
|
|
|
|
package formula
|
|
|
|
func init() {
|
|
RegisterFunction("AND", And)
|
|
RegisterFunction("FALSE", False)
|
|
RegisterFunction("IF", If)
|
|
RegisterFunction("IFERROR", IfError)
|
|
RegisterFunction("_xlfn.IFNA", IfNA) // Only in Excel 2013+
|
|
// TODO: RegisterFunction("IFS", Ifs) // Only in Excel 2016+
|
|
RegisterFunction("NOT", Not)
|
|
RegisterFunction("OR", Or)
|
|
// TODO: RegisterFunction("SWITCH", Switch) // Only in Excel 2016+
|
|
RegisterFunction("TRUE", True) // yup, TRUE()/FALSE() are functions in Excel, news to me...
|
|
RegisterFunction("_xlfn.XOR", Xor)
|
|
|
|
}
|
|
|
|
// And is an implementation of the Excel AND() function.
|
|
func And(args []Result) Result {
|
|
if len(args) == 0 {
|
|
return MakeErrorResult("AND requires at least one argument")
|
|
}
|
|
result := true
|
|
for _, a := range args {
|
|
a = a.AsNumber()
|
|
switch a.Type {
|
|
case ResultTypeList, ResultTypeArray:
|
|
res := And(a.ListValues())
|
|
if res.Type == ResultTypeError {
|
|
return res
|
|
}
|
|
if res.ValueNumber == 0 {
|
|
result = false
|
|
}
|
|
case ResultTypeNumber:
|
|
if a.ValueNumber == 0 {
|
|
result = false
|
|
}
|
|
case ResultTypeString:
|
|
return MakeErrorResult("AND doesn't operate on strings")
|
|
case ResultTypeError:
|
|
return a
|
|
default:
|
|
return MakeErrorResult("unsupported argument type in AND")
|
|
}
|
|
}
|
|
return MakeBoolResult(result)
|
|
}
|
|
|
|
// False is an implementation of the Excel FALSE() function. It takes no
|
|
// arguments.
|
|
func False(args []Result) Result {
|
|
if len(args) != 0 {
|
|
return MakeErrorResult("FALSE takes no arguments")
|
|
}
|
|
return MakeBoolResult(false)
|
|
}
|
|
|
|
// If is an implementation of the Excel IF() function. It takes one, two or
|
|
// three arguments.
|
|
func If(args []Result) Result {
|
|
if len(args) == 0 {
|
|
return MakeErrorResult("IF requires at least one argument")
|
|
}
|
|
if len(args) > 3 {
|
|
return MakeErrorResult("IF accepts at most three arguments")
|
|
}
|
|
cond := args[0]
|
|
switch cond.Type {
|
|
case ResultTypeNumber:
|
|
case ResultTypeError:
|
|
return cond
|
|
default:
|
|
return MakeErrorResult("IF initial argument must be numeric")
|
|
}
|
|
|
|
// single argument just returns the condition value
|
|
if len(args) == 1 {
|
|
return MakeBoolResult(cond.ValueNumber != 0)
|
|
}
|
|
|
|
// true case
|
|
if cond.ValueNumber != 0 {
|
|
return args[1]
|
|
}
|
|
|
|
// false case
|
|
if len(args) == 3 {
|
|
return args[2]
|
|
}
|
|
return MakeBoolResult(false)
|
|
|
|
}
|
|
|
|
// IfError is an implementation of the Excel IFERROR() function. It takes two arguments.
|
|
func IfError(args []Result) Result {
|
|
if len(args) != 2 {
|
|
return MakeErrorResult("IFERROR requires two arguments")
|
|
}
|
|
|
|
if args[0].Type != ResultTypeError {
|
|
// empty cell returns a zero
|
|
if args[0].Type == ResultTypeEmpty {
|
|
return MakeNumberResult(0)
|
|
}
|
|
return args[0]
|
|
}
|
|
|
|
return args[1]
|
|
}
|
|
|
|
// IfNA is an implementation of the Excel IFNA() function. It takes two arguments.
|
|
func IfNA(args []Result) Result {
|
|
if len(args) != 2 {
|
|
return MakeErrorResult("IFNA requires two arguments")
|
|
}
|
|
|
|
if args[0].Type == ResultTypeError && args[0].ValueString == "#N/A" {
|
|
return args[1]
|
|
}
|
|
return args[0]
|
|
}
|
|
|
|
// Not is an implementation of the Excel NOT() function and takes a single
|
|
// argument.
|
|
func Not(args []Result) Result {
|
|
if len(args) != 1 {
|
|
return MakeErrorResult("NOT requires one argument")
|
|
}
|
|
switch args[0].Type {
|
|
case ResultTypeError:
|
|
return args[0]
|
|
case ResultTypeString, ResultTypeList:
|
|
return MakeErrorResult("NOT expects a numeric argument")
|
|
case ResultTypeNumber:
|
|
return MakeBoolResult(!(args[0].ValueNumber != 0))
|
|
default:
|
|
return MakeErrorResult("unhandled NOT argument type")
|
|
}
|
|
}
|
|
|
|
// Or is an implementation of the Excel OR() function and takes a variable
|
|
// number of arguments.
|
|
func Or(args []Result) Result {
|
|
if len(args) == 0 {
|
|
return MakeErrorResult("OR requires at least one argument")
|
|
}
|
|
result := false
|
|
for _, a := range args {
|
|
switch a.Type {
|
|
case ResultTypeList, ResultTypeArray:
|
|
res := Or(a.ListValues())
|
|
if res.Type == ResultTypeError {
|
|
return res
|
|
}
|
|
if res.ValueNumber != 0 {
|
|
result = true
|
|
}
|
|
case ResultTypeNumber:
|
|
if a.ValueNumber != 0 {
|
|
result = true
|
|
}
|
|
case ResultTypeString:
|
|
return MakeErrorResult("OR doesn't operate on strings")
|
|
case ResultTypeError:
|
|
return a
|
|
default:
|
|
return MakeErrorResult("unsupported argument type in OR")
|
|
}
|
|
}
|
|
return MakeBoolResult(result)
|
|
}
|
|
|
|
// True is an implementation of the Excel TRUE() function. It takes no
|
|
// arguments.
|
|
func True(args []Result) Result {
|
|
if len(args) != 0 {
|
|
return MakeErrorResult("TRUE takes no arguments")
|
|
}
|
|
return MakeBoolResult(true)
|
|
}
|
|
|
|
// Xor is an implementation of the Excel XOR() function and takes a variable
|
|
// number of arguments. It's odd to say the least. If any argument is numeric,
|
|
// it returns true if the number of non-zero numeric arguments is odd and false
|
|
// otherwise. If no argument is numeric, it returns an error.
|
|
func Xor(args []Result) Result {
|
|
if len(args) < 1 {
|
|
return MakeErrorResult("XOR requires at least one argument")
|
|
}
|
|
cnt := 0
|
|
hasNum := false
|
|
for _, arg := range args {
|
|
switch arg.Type {
|
|
case ResultTypeList, ResultTypeArray:
|
|
res := Xor(arg.ListValues())
|
|
if res.Type == ResultTypeError {
|
|
return res
|
|
}
|
|
if res.ValueNumber != 0 {
|
|
cnt++
|
|
}
|
|
hasNum = true
|
|
case ResultTypeNumber:
|
|
if arg.ValueNumber != 0 {
|
|
cnt++
|
|
}
|
|
hasNum = true
|
|
case ResultTypeString:
|
|
// XOR appers to treat strings as zero values.
|
|
case ResultTypeError:
|
|
return arg
|
|
default:
|
|
return MakeErrorResult("unsupported argument type in XOR")
|
|
}
|
|
}
|
|
if !hasNum {
|
|
return MakeErrorResult("XOR requires numeric input")
|
|
}
|
|
return MakeBoolResult(cnt%2 != 0)
|
|
}
|