summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxuri <xuri.me@gmail.com>2021-02-19 00:03:51 +0800
committerxuri <xuri.me@gmail.com>2021-02-19 00:20:27 +0800
commit9154d500cf50621e15bf4a2bb9f6b5045d7b72d2 (patch)
tree102031d4b81c3d62a6d103d12544b96ea54d937c
parentae6f56b9531d6dce437a719523c1a9c67b97f776 (diff)
ref: #756, set cell as blank when SetCellValue with nil #756, new formula fn: BITAND, BITLSHIFT, BITOR, BITRSHIFT, BITXOR
-rw-r--r--calc.go102
-rw-r--r--calc_test.go53
-rw-r--r--cell.go9
3 files changed, 141 insertions, 23 deletions
diff --git a/calc.go b/calc.go
index a11315a..f49477f 100644
--- a/calc.go
+++ b/calc.go
@@ -222,6 +222,11 @@ var tokenPriority = map[string]int{
// AVERAGE
// AVERAGEA
// BASE
+// BITAND
+// BITLSHIFT
+// BITOR
+// BITRSHIFT
+// BITXOR
// CEILING
// CEILING.MATH
// CEILING.PRECISE
@@ -1146,18 +1151,82 @@ func formulaCriteriaEval(val string, criteria *formulaCriteria) (result bool, er
// Engineering Functions
+// BITAND function returns the bitwise 'AND' for two supplied integers. The
+// syntax of the function is:
+//
+// BITAND(number1,number2)
+//
+func (fn *formulaFuncs) BITAND(argsList *list.List) formulaArg {
+ return fn.bitwise("BITAND", argsList)
+}
+
+// BITLSHIFT function returns a supplied integer, shifted left by a specified
+// number of bits. The syntax of the function is:
+//
+// BITLSHIFT(number1,shift_amount)
+//
+func (fn *formulaFuncs) BITLSHIFT(argsList *list.List) formulaArg {
+ return fn.bitwise("BITLSHIFT", argsList)
+}
+
+// BITOR function returns the bitwise 'OR' for two supplied integers. The
+// syntax of the function is:
+//
+// BITOR(number1,number2)
+//
+func (fn *formulaFuncs) BITOR(argsList *list.List) formulaArg {
+ return fn.bitwise("BITOR", argsList)
+}
+
+// BITRSHIFT function returns a supplied integer, shifted right by a specified
+// number of bits. The syntax of the function is:
+//
+// BITRSHIFT(number1,shift_amount)
+//
+func (fn *formulaFuncs) BITRSHIFT(argsList *list.List) formulaArg {
+ return fn.bitwise("BITRSHIFT", argsList)
+}
+
+// BITXOR function returns the bitwise 'XOR' (exclusive 'OR') for two supplied
+// integers. The syntax of the function is:
+//
+// BITXOR(number1,number2)
+//
+func (fn *formulaFuncs) BITXOR(argsList *list.List) formulaArg {
+ return fn.bitwise("BITXOR", argsList)
+}
+
+// bitwise is an implementation of the formula function BITAND, BITLSHIFT,
+// BITOR, BITRSHIFT and BITXOR.
+func (fn *formulaFuncs) bitwise(name string, argsList *list.List) formulaArg {
+ if argsList.Len() != 2 {
+ return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 2 numeric arguments", name))
+ }
+ num1, num2 := argsList.Front().Value.(formulaArg).ToNumber(), argsList.Back().Value.(formulaArg).ToNumber()
+ if num1.Type != ArgNumber || num2.Type != ArgNumber {
+ return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
+ }
+ max := math.Pow(2, 48) - 1
+ if num1.Number < 0 || num1.Number > max || num2.Number < 0 || num2.Number > max {
+ return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
+ }
+ bitwiseFuncMap := map[string]func(a, b int) int{
+ "BITAND": func(a, b int) int { return a & b },
+ "BITLSHIFT": func(a, b int) int { return a << uint(b) },
+ "BITOR": func(a, b int) int { return a | b },
+ "BITRSHIFT": func(a, b int) int { return a >> uint(b) },
+ "BITXOR": func(a, b int) int { return a ^ b },
+ }
+ bitwiseFunc, _ := bitwiseFuncMap[name]
+ return newNumberFormulaArg(float64(bitwiseFunc(int(num1.Number), int(num2.Number))))
+}
+
// DEC2BIN function converts a decimal number into a Binary (Base 2) number.
// The syntax of the function is:
//
// DEC2BIN(number,[places])
//
func (fn *formulaFuncs) DEC2BIN(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "DEC2BIN requires at least 1 argument")
- }
- if argsList.Len() > 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "DEC2BIN allows at most 2 arguments")
- }
return fn.dec2x("DEC2BIN", argsList)
}
@@ -1167,12 +1236,6 @@ func (fn *formulaFuncs) DEC2BIN(argsList *list.List) formulaArg {
// DEC2HEX(number,[places])
//
func (fn *formulaFuncs) DEC2HEX(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "DEC2HEX requires at least 1 argument")
- }
- if argsList.Len() > 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "DEC2HEX allows at most 2 arguments")
- }
return fn.dec2x("DEC2HEX", argsList)
}
@@ -1182,17 +1245,18 @@ func (fn *formulaFuncs) DEC2HEX(argsList *list.List) formulaArg {
// DEC2OCT(number,[places])
//
func (fn *formulaFuncs) DEC2OCT(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "DEC2OCT requires at least 1 argument")
- }
- if argsList.Len() > 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "DEC2OCT allows at most 2 arguments")
- }
return fn.dec2x("DEC2OCT", argsList)
}
-// dec2x is an implementation of the formula function DEC2BIN, DEC2HEX and DEC2OCT.
+// dec2x is an implementation of the formula function DEC2BIN, DEC2HEX and
+// DEC2OCT.
func (fn *formulaFuncs) dec2x(name string, argsList *list.List) formulaArg {
+ if argsList.Len() < 1 {
+ return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires at least 1 argument", name))
+ }
+ if argsList.Len() > 2 {
+ return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s allows at most 2 arguments", name))
+ }
decimal := argsList.Front().Value.(formulaArg).ToNumber()
if decimal.Type != ArgNumber {
return newErrorFormulaArg(formulaErrorVALUE, decimal.Error)
diff --git a/calc_test.go b/calc_test.go
index 28ffb6c..04dce37 100644
--- a/calc_test.go
+++ b/calc_test.go
@@ -47,6 +47,19 @@ func TestCalcCellValue(t *testing.T) {
"=2>=3": "FALSE",
"=1&2": "12",
// Engineering Functions
+ // BITAND
+ "=BITAND(13,14)": "12",
+ // BITLSHIFT
+ "=BITLSHIFT(5,2)": "20",
+ "=BITLSHIFT(3,5)": "96",
+ // BITOR
+ "=BITOR(9,12)": "13",
+ // BITRSHIFT
+ "=BITRSHIFT(20,2)": "5",
+ "=BITRSHIFT(52,4)": "3",
+ // BITXOR
+ "=BITXOR(5,6)": "3",
+ "=BITXOR(9,12)": "5",
// DEC2BIN
"=DEC2BIN(2)": "10",
"=DEC2BIN(3)": "11",
@@ -727,6 +740,46 @@ func TestCalcCellValue(t *testing.T) {
mathCalcError := map[string]string{
"=1/0": "#DIV/0!",
// Engineering Functions
+ // BITAND
+ "=BITAND()": "BITAND requires 2 numeric arguments",
+ "=BITAND(-1,2)": "#NUM!",
+ "=BITAND(2^48,2)": "#NUM!",
+ "=BITAND(1,-1)": "#NUM!",
+ "=BITAND(\"\",-1)": "#NUM!",
+ "=BITAND(1,\"\")": "#NUM!",
+ "=BITAND(1,2^48)": "#NUM!",
+ // BITLSHIFT
+ "=BITLSHIFT()": "BITLSHIFT requires 2 numeric arguments",
+ "=BITLSHIFT(-1,2)": "#NUM!",
+ "=BITLSHIFT(2^48,2)": "#NUM!",
+ "=BITLSHIFT(1,-1)": "#NUM!",
+ "=BITLSHIFT(\"\",-1)": "#NUM!",
+ "=BITLSHIFT(1,\"\")": "#NUM!",
+ "=BITLSHIFT(1,2^48)": "#NUM!",
+ // BITOR
+ "=BITOR()": "BITOR requires 2 numeric arguments",
+ "=BITOR(-1,2)": "#NUM!",
+ "=BITOR(2^48,2)": "#NUM!",
+ "=BITOR(1,-1)": "#NUM!",
+ "=BITOR(\"\",-1)": "#NUM!",
+ "=BITOR(1,\"\")": "#NUM!",
+ "=BITOR(1,2^48)": "#NUM!",
+ // BITRSHIFT
+ "=BITRSHIFT()": "BITRSHIFT requires 2 numeric arguments",
+ "=BITRSHIFT(-1,2)": "#NUM!",
+ "=BITRSHIFT(2^48,2)": "#NUM!",
+ "=BITRSHIFT(1,-1)": "#NUM!",
+ "=BITRSHIFT(\"\",-1)": "#NUM!",
+ "=BITRSHIFT(1,\"\")": "#NUM!",
+ "=BITRSHIFT(1,2^48)": "#NUM!",
+ // BITXOR
+ "=BITXOR()": "BITXOR requires 2 numeric arguments",
+ "=BITXOR(-1,2)": "#NUM!",
+ "=BITXOR(2^48,2)": "#NUM!",
+ "=BITXOR(1,-1)": "#NUM!",
+ "=BITXOR(\"\",-1)": "#NUM!",
+ "=BITXOR(1,\"\")": "#NUM!",
+ "=BITXOR(1,2^48)": "#NUM!",
// DEC2BIN
"=DEC2BIN()": "DEC2BIN requires at least 1 argument",
"=DEC2BIN(1,1,1)": "DEC2BIN allows at most 2 arguments",
diff --git a/cell.go b/cell.go
index 3e63565..4617b76 100644
--- a/cell.go
+++ b/cell.go
@@ -1,4 +1,4 @@
-// Copyright 2016 - 2020 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2021 The excelize Authors. All rights reserved. Use of
// this source code is governed by a BSD-style license that can be found in
// the LICENSE file.
//
@@ -44,8 +44,9 @@ func (f *File) GetCellValue(sheet, axis string) (string, error) {
}
// SetCellValue provides a function to set value of a cell. The specified
-// coordinates should not be in the first row of the table. The following
-// shows the supported data types:
+// coordinates should not be in the first row of the table, a complex number
+// can be set with string text. The following shows the supported data
+// types:
//
// int
// int8
@@ -93,7 +94,7 @@ func (f *File) SetCellValue(sheet, axis string, value interface{}) error {
case bool:
err = f.SetCellBool(sheet, axis, v)
case nil:
- break
+ err = f.SetCellDefault(sheet, axis, "")
default:
err = f.SetCellStr(sheet, axis, fmt.Sprint(value))
}