Browse Source

ref: #756, set cell as blank when SetCellValue with nil #756, new formula fn: BITAND, BITLSHIFT, BITOR, BITRSHIFT, BITXOR

xuri 4 years ago
parent
commit
9154d500cf
3 changed files with 141 additions and 23 deletions
  1. 83 19
      calc.go
  2. 53 0
      calc_test.go
  3. 5 4
      cell.go

+ 83 - 19
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)

+ 53 - 0
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",

+ 5 - 4
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))
 	}