cat / 012
clone

a spreadsheet for the terminal: lotus 1-2-3 looks, google sheets keys and formulas, one go binary

Add logical and IS functions

Dami committed c3dcac1
IFS, SWITCH, XOR, IFNA, ISBLANK, ISNUMBER, ISTEXT, ISLOGICAL, ISERROR,
ISERR and ISNA.
commit
c3dcac1729e400af42ec4cc30af0a3c01b3240cf
parent
1b1b376f3aca34d44babdcae3cc2d8800977ad7b
author
Dami <dami.etoile@gmail.com>
2 files changed, +127 -0
Ainternal/sheet/functions_logic.go87++++++++++++++++++++++++++++++
Ainternal/sheet/functions_logic_test.go40++++++++++++++
A internal/sheet/functions_logic.go +87 -0
@@ -0,0 +1,87 @@
1+package sheet2+3+func init() {4+ define(5+ &FuncDef{Name: "IFS", Args: "condition1, value1, [condition2, value2, ...]", Desc: "The value of the first true condition", Min: 2, Max: -1, step: 2,6+ eval: func(args []Node, get lookup) Value {7+ for i := 0; i+1 < len(args); i += 2 {8+ c, err := numArg(args[i], get)9+ if err != nil {10+ return *err11+ }12+ if c != 0 {13+ return eval(args[i+1], get)14+ }15+ }16+ return ErrNA17+ }, format: func(args []Node, infer func(Node) Format) Format {18+ var vals []Node19+ for i := 1; i < len(args); i += 2 {20+ vals = append(vals, args[i])21+ }22+ return inherit(vals, infer)23+ }},24+ &FuncDef{Name: "SWITCH", Args: "expression, case1, value1, [case2, value2, ...], [default]", Desc: "The value for the first case equal to an expression", Min: 3, Max: -1,25+ eval: func(args []Node, get lookup) Value {26+ x := eval(args[0], get)27+ if x.Kind == Error {28+ return x29+ }30+ i := 131+ for ; i+1 < len(args); i += 2 {32+ c := eval(args[i], get)33+ if c.Kind == Error {34+ return c35+ }36+ if sameKind(x, c) && compare(x, c) == 0 {37+ return eval(args[i+1], get)38+ }39+ }40+ if i < len(args) {41+ return eval(args[i], get)42+ }43+ return ErrNA44+ }},45+ &FuncDef{Name: "XOR", Args: "logical1, [logical2, ...]", Desc: "TRUE if an odd number of arguments are true", Min: 1, Max: -1,46+ eval: logical(func(t, _ int) bool { return t%2 == 1 })},47+ &FuncDef{Name: "IFNA", Args: "value, value_if_na", Desc: "A fallback when a value is #N/A", Min: 2, Max: 2,48+ eval: func(args []Node, get lookup) Value {49+ v := eval(args[0], get)50+ if v == ErrNA {51+ return eval(args[1], get)52+ }53+ return v54+ }, format: inherit},55+ &FuncDef{Name: "ISBLANK", Args: "value", Desc: "TRUE if a cell is empty", Min: 1, Max: 1,56+ eval: is(func(v Value) bool { return v.Kind == Empty })},57+ &FuncDef{Name: "ISNUMBER", Args: "value", Desc: "TRUE if a value is a number", Min: 1, Max: 1,58+ eval: is(func(v Value) bool { return v.Kind == Number })},59+ &FuncDef{Name: "ISTEXT", Args: "value", Desc: "TRUE if a value is text", Min: 1, Max: 1,60+ eval: is(func(v Value) bool { return v.Kind == Text })},61+ &FuncDef{Name: "ISLOGICAL", Args: "value", Desc: "TRUE if a value is TRUE or FALSE", Min: 1, Max: 1,62+ eval: is(func(v Value) bool { return v.Kind == Bool })},63+ &FuncDef{Name: "ISERROR", Args: "value", Desc: "TRUE if a value is any error", Min: 1, Max: 1,64+ eval: is(func(v Value) bool { return v.Kind == Error })},65+ &FuncDef{Name: "ISERR", Args: "value", Desc: "TRUE if a value is an error other than #N/A", Min: 1, Max: 1,66+ eval: is(func(v Value) bool { return v.Kind == Error && v != ErrNA })},67+ &FuncDef{Name: "ISNA", Args: "value", Desc: "TRUE if a value is #N/A", Min: 1, Max: 1,68+ eval: is(func(v Value) bool { return v == ErrNA })},69+ )70+}71+72+// is builds the IS functions, which never return an error themselves.73+func is(test func(Value) bool) func([]Node, lookup) Value {74+ return func(args []Node, get lookup) Value {75+ return boolean(test(eval(args[0], get)))76+ }77+}78+79+// sameKind reports whether two values can be equal in SWITCH and exact80+// lookups: numbers only equal numbers, text only text. A blank is 0 or "".81+func sameKind(a, b Value) bool {82+ ka, kb := a.Kind, b.Kind83+ if ka == Empty || kb == Empty {84+ return true85+ }86+ return ka == kb87+}
A internal/sheet/functions_logic_test.go +40 -0