mirror of https://github.com/apache/poi.git
Bug 62904: Support array arguments in IF and logical IS*** functions
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1850646 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
f3eb4dd393
commit
81033fbad0
|
@ -56,6 +56,7 @@ import org.apache.poi.ss.formula.function.FunctionMetadataRegistry;
|
||||||
import org.apache.poi.ss.formula.functions.ArrayFunction;
|
import org.apache.poi.ss.formula.functions.ArrayFunction;
|
||||||
import org.apache.poi.ss.formula.functions.Function;
|
import org.apache.poi.ss.formula.functions.Function;
|
||||||
import org.apache.poi.ss.formula.functions.Indirect;
|
import org.apache.poi.ss.formula.functions.Indirect;
|
||||||
|
import org.apache.poi.ss.util.CellRangeAddress;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class creates <tt>OperationEval</tt> instances to help evaluate <tt>OperationPtg</tt>
|
* This class creates <tt>OperationEval</tt> instances to help evaluate <tt>OperationPtg</tt>
|
||||||
|
@ -138,8 +139,16 @@ final class OperationEvaluatorFactory {
|
||||||
EvaluationSheet evalSheet = ec.getWorkbook().getSheet(ec.getSheetIndex());
|
EvaluationSheet evalSheet = ec.getWorkbook().getSheet(ec.getSheetIndex());
|
||||||
EvaluationCell evalCell = evalSheet.getCell(ec.getRowIndex(), ec.getColumnIndex());
|
EvaluationCell evalCell = evalSheet.getCell(ec.getRowIndex(), ec.getColumnIndex());
|
||||||
|
|
||||||
if (evalCell != null && (evalCell.isPartOfArrayFormulaGroup() || ec.isArraymode()) && result instanceof ArrayFunction)
|
if (evalCell != null && result instanceof ArrayFunction) {
|
||||||
return ((ArrayFunction) result).evaluateArray(args, ec.getRowIndex(), ec.getColumnIndex());
|
ArrayFunction func = (ArrayFunction) result;
|
||||||
|
if(evalCell.isPartOfArrayFormulaGroup()){
|
||||||
|
// array arguments must be evaluated relative to the function defining range
|
||||||
|
CellRangeAddress ca = evalCell.getArrayFormulaRange();
|
||||||
|
return func.evaluateArray(args, ca.getFirstRow(), ca.getFirstColumn());
|
||||||
|
} else if (ec.isArraymode()){
|
||||||
|
return func.evaluateArray(args, ec.getRowIndex(), ec.getColumnIndex());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result.evaluate(args, ec.getRowIndex(), ec.getColumnIndex());
|
return result.evaluate(args, ec.getRowIndex(), ec.getColumnIndex());
|
||||||
} else if (udfFunc != null){
|
} else if (udfFunc != null){
|
||||||
|
|
|
@ -453,15 +453,24 @@ public final class WorkbookEvaluator {
|
||||||
// nothing to skip - true param follows
|
// nothing to skip - true param follows
|
||||||
} else {
|
} else {
|
||||||
int dist = attrPtg.getData();
|
int dist = attrPtg.getData();
|
||||||
|
Ptg currPtg = ptgs[i+1];
|
||||||
i+= countTokensToBeSkipped(ptgs, i, dist);
|
i+= countTokensToBeSkipped(ptgs, i, dist);
|
||||||
Ptg nextPtg = ptgs[i+1];
|
Ptg nextPtg = ptgs[i+1];
|
||||||
|
|
||||||
if (ptgs[i] instanceof AttrPtg && nextPtg instanceof FuncVarPtg &&
|
if (ptgs[i] instanceof AttrPtg && nextPtg instanceof FuncVarPtg &&
|
||||||
// in order to verify that there is no third param, we need to check
|
// in order to verify that there is no third param, we need to check
|
||||||
// if we really have the IF next or some other FuncVarPtg as third param, e.g. ROW()/COLUMN()!
|
// if we really have the IF next or some other FuncVarPtg as third param, e.g. ROW()/COLUMN()!
|
||||||
((FuncVarPtg)nextPtg).getFunctionIndex() == FunctionMetadataRegistry.FUNCTION_INDEX_IF) {
|
((FuncVarPtg)nextPtg).getFunctionIndex() == FunctionMetadataRegistry.FUNCTION_INDEX_IF) {
|
||||||
// this is an if statement without a false param (as opposed to MissingArgPtg as the false param)
|
// this is an if statement without a false param (as opposed to MissingArgPtg as the false param)
|
||||||
i++;
|
//i++;
|
||||||
stack.push(BoolEval.FALSE);
|
stack.push(arg0);
|
||||||
|
if(currPtg instanceof AreaPtg){
|
||||||
|
// IF in array mode. See Bug 62904
|
||||||
|
ValueEval currEval = getEvalForPtg(currPtg, ec);
|
||||||
|
stack.push(currEval);
|
||||||
|
} else {
|
||||||
|
stack.push(BoolEval.FALSE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
@ -759,7 +768,7 @@ public final class WorkbookEvaluator {
|
||||||
return evaluateNameFormula(nameRecord.getNameDefinition(), ec);
|
return evaluateNameFormula(nameRecord.getNameDefinition(), ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new RuntimeException("Don't now how to evalate name '" + nameRecord.getNameText() + "'");
|
throw new RuntimeException("Don't now how to evaluate name '" + nameRecord.getNameText() + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
package org.apache.poi.ss.formula.eval;
|
package org.apache.poi.ss.formula.eval;
|
||||||
|
|
||||||
import org.apache.poi.ss.formula.CacheAreaEval;
|
|
||||||
import org.apache.poi.ss.formula.functions.ArrayFunction;
|
import org.apache.poi.ss.formula.functions.ArrayFunction;
|
||||||
import org.apache.poi.ss.formula.functions.Fixed2ArgFunction;
|
import org.apache.poi.ss.formula.functions.Fixed2ArgFunction;
|
||||||
import org.apache.poi.ss.formula.functions.Function;
|
import org.apache.poi.ss.formula.functions.Function;
|
||||||
|
@ -74,84 +73,16 @@ public abstract class RelationalOperationEval extends Fixed2ArgFunction implemen
|
||||||
return BoolEval.valueOf(result);
|
return BoolEval.valueOf(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
|
public ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
|
||||||
ValueEval arg0 = args[0];
|
ValueEval arg0 = args[0];
|
||||||
ValueEval arg1 = args[1];
|
ValueEval arg1 = args[1];
|
||||||
|
return evaluateTwoArrayArgs(arg0, arg1, srcRowIndex, srcColumnIndex, (vA, vB) -> {
|
||||||
|
int cmpResult = doCompare(vA, vB);
|
||||||
|
boolean result = convertComparisonResult(cmpResult);
|
||||||
|
return BoolEval.valueOf(result);
|
||||||
|
});
|
||||||
|
|
||||||
int w1, w2, h1, h2;
|
|
||||||
int a1FirstCol = 0, a1FirstRow = 0;
|
|
||||||
if (arg0 instanceof AreaEval) {
|
|
||||||
AreaEval ae = (AreaEval)arg0;
|
|
||||||
w1 = ae.getWidth();
|
|
||||||
h1 = ae.getHeight();
|
|
||||||
a1FirstCol = ae.getFirstColumn();
|
|
||||||
a1FirstRow = ae.getFirstRow();
|
|
||||||
} else if (arg0 instanceof RefEval){
|
|
||||||
RefEval ref = (RefEval)arg0;
|
|
||||||
w1 = 1;
|
|
||||||
h1 = 1;
|
|
||||||
a1FirstCol = ref.getColumn();
|
|
||||||
a1FirstRow = ref.getRow();
|
|
||||||
} else {
|
|
||||||
w1 = 1;
|
|
||||||
h1 = 1;
|
|
||||||
}
|
|
||||||
int a2FirstCol = 0, a2FirstRow = 0;
|
|
||||||
if (arg1 instanceof AreaEval) {
|
|
||||||
AreaEval ae = (AreaEval)arg1;
|
|
||||||
w2 = ae.getWidth();
|
|
||||||
h2 = ae.getHeight();
|
|
||||||
a2FirstCol = ae.getFirstColumn();
|
|
||||||
a2FirstRow = ae.getFirstRow();
|
|
||||||
} else if (arg1 instanceof RefEval){
|
|
||||||
RefEval ref = (RefEval)arg1;
|
|
||||||
w2 = 1;
|
|
||||||
h2 = 1;
|
|
||||||
a2FirstCol = ref.getColumn();
|
|
||||||
a2FirstRow = ref.getRow();
|
|
||||||
} else {
|
|
||||||
w2 = 1;
|
|
||||||
h2 = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int width = Math.max(w1, w2);
|
|
||||||
int height = Math.max(h1, h2);
|
|
||||||
|
|
||||||
ValueEval[] vals = new ValueEval[height * width];
|
|
||||||
|
|
||||||
int idx = 0;
|
|
||||||
for(int i = 0; i < height; i++){
|
|
||||||
for(int j = 0; j < width; j++){
|
|
||||||
ValueEval vA;
|
|
||||||
try {
|
|
||||||
vA = OperandResolver.getSingleValue(arg0, a1FirstRow + i, a1FirstCol + j);
|
|
||||||
} catch (EvaluationException e) {
|
|
||||||
vA = e.getErrorEval();
|
|
||||||
}
|
|
||||||
ValueEval vB;
|
|
||||||
try {
|
|
||||||
vB = OperandResolver.getSingleValue(arg1, a2FirstRow + i, a2FirstCol + j);
|
|
||||||
} catch (EvaluationException e) {
|
|
||||||
vB = e.getErrorEval();
|
|
||||||
}
|
|
||||||
if(vA instanceof ErrorEval){
|
|
||||||
vals[idx++] = vA;
|
|
||||||
} else if (vB instanceof ErrorEval) {
|
|
||||||
vals[idx++] = vB;
|
|
||||||
} else {
|
|
||||||
int cmpResult = doCompare(vA, vB);
|
|
||||||
boolean result = convertComparisonResult(cmpResult);
|
|
||||||
vals[idx++] = BoolEval.valueOf(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vals.length == 1) {
|
|
||||||
return vals[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
return new CacheAreaEval(srcRowIndex, srcColumnIndex, srcRowIndex + height - 1, srcColumnIndex + width - 1, vals);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int doCompare(ValueEval va, ValueEval vb) {
|
private static int doCompare(ValueEval va, ValueEval vb) {
|
||||||
|
|
|
@ -37,7 +37,20 @@ public abstract class TwoOperandNumericOperation extends Fixed2ArgFunction imple
|
||||||
if (args.length != 2) {
|
if (args.length != 2) {
|
||||||
return ErrorEval.VALUE_INVALID;
|
return ErrorEval.VALUE_INVALID;
|
||||||
}
|
}
|
||||||
return new ArrayEval().evaluate(srcRowIndex, srcColumnIndex, args[0], args[1]);
|
//return new ArrayEval().evaluate(srcRowIndex, srcColumnIndex, args[0], args[1]);
|
||||||
|
|
||||||
|
return evaluateTwoArrayArgs(args[0], args[1], srcRowIndex, srcColumnIndex,
|
||||||
|
(vA, vB) -> {
|
||||||
|
try {
|
||||||
|
double d0 = OperandResolver.coerceValueToDouble(vA);
|
||||||
|
double d1 = OperandResolver.coerceValueToDouble(vB);
|
||||||
|
double result = evaluate(d0, d1);
|
||||||
|
return new NumberEval(result);
|
||||||
|
} catch (EvaluationException e){
|
||||||
|
return e.getErrorEval();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
|
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
|
||||||
|
|
|
@ -17,13 +17,14 @@
|
||||||
|
|
||||||
package org.apache.poi.ss.formula.eval;
|
package org.apache.poi.ss.formula.eval;
|
||||||
|
|
||||||
|
import org.apache.poi.ss.formula.functions.ArrayFunction;
|
||||||
import org.apache.poi.ss.formula.functions.Fixed1ArgFunction;
|
import org.apache.poi.ss.formula.functions.Fixed1ArgFunction;
|
||||||
import org.apache.poi.ss.formula.functions.Function;
|
import org.apache.poi.ss.formula.functions.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||||
*/
|
*/
|
||||||
public final class UnaryMinusEval extends Fixed1ArgFunction {
|
public final class UnaryMinusEval extends Fixed1ArgFunction implements ArrayFunction {
|
||||||
|
|
||||||
public static final Function instance = new UnaryMinusEval();
|
public static final Function instance = new UnaryMinusEval();
|
||||||
|
|
||||||
|
@ -44,4 +45,12 @@ public final class UnaryMinusEval extends Fixed1ArgFunction {
|
||||||
}
|
}
|
||||||
return new NumberEval(-d);
|
return new NumberEval(-d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex){
|
||||||
|
return evaluateOneArrayArg(args, srcRowIndex, srcColumnIndex, (valA) ->
|
||||||
|
evaluate(srcRowIndex, srcColumnIndex, valA)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
package org.apache.poi.ss.formula.eval;
|
package org.apache.poi.ss.formula.eval;
|
||||||
|
|
||||||
|
import org.apache.poi.ss.formula.functions.ArrayFunction;
|
||||||
import org.apache.poi.ss.formula.functions.Fixed1ArgFunction;
|
import org.apache.poi.ss.formula.functions.Fixed1ArgFunction;
|
||||||
import org.apache.poi.ss.formula.functions.Function;
|
import org.apache.poi.ss.formula.functions.Function;
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@ import org.apache.poi.ss.formula.functions.Function;
|
||||||
/**
|
/**
|
||||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||||
*/
|
*/
|
||||||
public final class UnaryPlusEval extends Fixed1ArgFunction {
|
public final class UnaryPlusEval extends Fixed1ArgFunction implements ArrayFunction {
|
||||||
|
|
||||||
public static final Function instance = new UnaryPlusEval();
|
public static final Function instance = new UnaryPlusEval();
|
||||||
|
|
||||||
|
@ -48,4 +49,12 @@ public final class UnaryPlusEval extends Fixed1ArgFunction {
|
||||||
}
|
}
|
||||||
return new NumberEval(+d);
|
return new NumberEval(+d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex){
|
||||||
|
return evaluateOneArrayArg(args, srcRowIndex, srcColumnIndex, (valA) ->
|
||||||
|
evaluate(srcRowIndex, srcColumnIndex, valA)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,11 @@
|
||||||
|
|
||||||
package org.apache.poi.ss.formula.functions;
|
package org.apache.poi.ss.formula.functions;
|
||||||
|
|
||||||
import org.apache.poi.ss.formula.eval.BlankEval;
|
import org.apache.poi.ss.formula.CacheAreaEval;
|
||||||
import org.apache.poi.ss.formula.eval.ErrorEval;
|
import org.apache.poi.ss.formula.FormulaParseException;
|
||||||
import org.apache.poi.ss.formula.eval.MissingArgEval;
|
import org.apache.poi.ss.formula.eval.*;
|
||||||
import org.apache.poi.ss.formula.eval.ValueEval;
|
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Robert Hulbert
|
* @author Robert Hulbert
|
||||||
|
@ -41,4 +42,153 @@ public interface ArrayFunction {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex);
|
ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluate an array function with two arguments.
|
||||||
|
*
|
||||||
|
* @param arg0 the first function argument. Empty values are represented with
|
||||||
|
* {@link BlankEval} or {@link MissingArgEval}, never <code>null</code>
|
||||||
|
* @param arg1 the first function argument. Empty values are represented with
|
||||||
|
* @link BlankEval} or {@link MissingArgEval}, never <code>null</code>
|
||||||
|
*
|
||||||
|
* @param srcRowIndex row index of the cell containing the formula under evaluation
|
||||||
|
* @param srcColumnIndex column index of the cell containing the formula under evaluation
|
||||||
|
* @return The evaluated result, possibly an {@link ErrorEval}, never <code>null</code>.
|
||||||
|
* <b>Note</b> - Excel uses the error code <i>#NUM!</i> instead of IEEE <i>NaN</i>, so when
|
||||||
|
* numeric functions evaluate to {@link Double#NaN} be sure to translate the result to {@link
|
||||||
|
* ErrorEval#NUM_ERROR}.
|
||||||
|
*/
|
||||||
|
default ValueEval evaluateTwoArrayArgs(ValueEval arg0, ValueEval arg1, int srcRowIndex, int srcColumnIndex,
|
||||||
|
BiFunction<ValueEval, ValueEval, ValueEval> evalFunc) {
|
||||||
|
int w1, w2, h1, h2;
|
||||||
|
int a1FirstCol = 0, a1FirstRow = 0;
|
||||||
|
if (arg0 instanceof AreaEval) {
|
||||||
|
AreaEval ae = (AreaEval)arg0;
|
||||||
|
w1 = ae.getWidth();
|
||||||
|
h1 = ae.getHeight();
|
||||||
|
a1FirstCol = ae.getFirstColumn();
|
||||||
|
a1FirstRow = ae.getFirstRow();
|
||||||
|
} else if (arg0 instanceof RefEval){
|
||||||
|
RefEval ref = (RefEval)arg0;
|
||||||
|
w1 = 1;
|
||||||
|
h1 = 1;
|
||||||
|
a1FirstCol = ref.getColumn();
|
||||||
|
a1FirstRow = ref.getRow();
|
||||||
|
} else {
|
||||||
|
w1 = 1;
|
||||||
|
h1 = 1;
|
||||||
|
}
|
||||||
|
int a2FirstCol = 0, a2FirstRow = 0;
|
||||||
|
if (arg1 instanceof AreaEval) {
|
||||||
|
AreaEval ae = (AreaEval)arg1;
|
||||||
|
w2 = ae.getWidth();
|
||||||
|
h2 = ae.getHeight();
|
||||||
|
a2FirstCol = ae.getFirstColumn();
|
||||||
|
a2FirstRow = ae.getFirstRow();
|
||||||
|
} else if (arg1 instanceof RefEval){
|
||||||
|
RefEval ref = (RefEval)arg1;
|
||||||
|
w2 = 1;
|
||||||
|
h2 = 1;
|
||||||
|
a2FirstCol = ref.getColumn();
|
||||||
|
a2FirstRow = ref.getRow();
|
||||||
|
} else {
|
||||||
|
w2 = 1;
|
||||||
|
h2 = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int width = Math.max(w1, w2);
|
||||||
|
int height = Math.max(h1, h2);
|
||||||
|
|
||||||
|
ValueEval[] vals = new ValueEval[height * width];
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
for(int i = 0; i < height; i++){
|
||||||
|
for(int j = 0; j < width; j++){
|
||||||
|
ValueEval vA;
|
||||||
|
try {
|
||||||
|
vA = OperandResolver.getSingleValue(arg0, a1FirstRow + i, a1FirstCol + j);
|
||||||
|
} catch (FormulaParseException e) {
|
||||||
|
vA = ErrorEval.NAME_INVALID;
|
||||||
|
} catch (EvaluationException e) {
|
||||||
|
vA = e.getErrorEval();
|
||||||
|
}
|
||||||
|
ValueEval vB;
|
||||||
|
try {
|
||||||
|
vB = OperandResolver.getSingleValue(arg1, a2FirstRow + i, a2FirstCol + j);
|
||||||
|
} catch (FormulaParseException e) {
|
||||||
|
vB = ErrorEval.NAME_INVALID;
|
||||||
|
} catch (EvaluationException e) {
|
||||||
|
vB = e.getErrorEval();
|
||||||
|
}
|
||||||
|
if(vA instanceof ErrorEval){
|
||||||
|
vals[idx++] = vA;
|
||||||
|
} else if (vB instanceof ErrorEval) {
|
||||||
|
vals[idx++] = vB;
|
||||||
|
} else {
|
||||||
|
vals[idx++] = evalFunc.apply(vA, vB);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vals.length == 1) {
|
||||||
|
return vals[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CacheAreaEval(srcRowIndex, srcColumnIndex, srcRowIndex + height - 1, srcColumnIndex + width - 1, vals);
|
||||||
|
}
|
||||||
|
|
||||||
|
default ValueEval evaluateOneArrayArg(ValueEval[] args, int srcRowIndex, int srcColumnIndex,
|
||||||
|
java.util.function.Function<ValueEval, ValueEval> evalFunc){
|
||||||
|
ValueEval arg0 = args[0];
|
||||||
|
|
||||||
|
int w1, w2, h1, h2;
|
||||||
|
int a1FirstCol = 0, a1FirstRow = 0;
|
||||||
|
if (arg0 instanceof AreaEval) {
|
||||||
|
AreaEval ae = (AreaEval)arg0;
|
||||||
|
w1 = ae.getWidth();
|
||||||
|
h1 = ae.getHeight();
|
||||||
|
a1FirstCol = ae.getFirstColumn();
|
||||||
|
a1FirstRow = ae.getFirstRow();
|
||||||
|
} else if (arg0 instanceof RefEval){
|
||||||
|
RefEval ref = (RefEval)arg0;
|
||||||
|
w1 = 1;
|
||||||
|
h1 = 1;
|
||||||
|
a1FirstCol = ref.getColumn();
|
||||||
|
a1FirstRow = ref.getRow();
|
||||||
|
} else {
|
||||||
|
w1 = 1;
|
||||||
|
h1 = 1;
|
||||||
|
}
|
||||||
|
w2 = 1;
|
||||||
|
h2 = 1;
|
||||||
|
|
||||||
|
int width = Math.max(w1, w2);
|
||||||
|
int height = Math.max(h1, h2);
|
||||||
|
|
||||||
|
ValueEval[] vals = new ValueEval[height * width];
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
for(int i = 0; i < height; i++){
|
||||||
|
for(int j = 0; j < width; j++){
|
||||||
|
ValueEval vA;
|
||||||
|
try {
|
||||||
|
vA = OperandResolver.getSingleValue(arg0, a1FirstRow + i, a1FirstCol + j);
|
||||||
|
} catch (FormulaParseException e) {
|
||||||
|
vA = ErrorEval.NAME_INVALID;
|
||||||
|
} catch (EvaluationException e) {
|
||||||
|
vA = e.getErrorEval();
|
||||||
|
}
|
||||||
|
vals[idx++] = evalFunc.apply(vA);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vals.length == 1) {
|
||||||
|
return vals[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CacheAreaEval(srcRowIndex, srcColumnIndex, srcRowIndex + height - 1, srcColumnIndex + width - 1, vals);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,7 @@
|
||||||
|
|
||||||
package org.apache.poi.ss.formula.functions;
|
package org.apache.poi.ss.formula.functions;
|
||||||
|
|
||||||
import org.apache.poi.ss.formula.eval.BlankEval;
|
import org.apache.poi.ss.formula.eval.*;
|
||||||
import org.apache.poi.ss.formula.eval.BoolEval;
|
|
||||||
import org.apache.poi.ss.formula.eval.EvaluationException;
|
|
||||||
import org.apache.poi.ss.formula.eval.MissingArgEval;
|
|
||||||
import org.apache.poi.ss.formula.eval.OperandResolver;
|
|
||||||
import org.apache.poi.ss.formula.eval.ValueEval;
|
|
||||||
import org.apache.poi.ss.formula.ptg.Ptg;
|
import org.apache.poi.ss.formula.ptg.Ptg;
|
||||||
import org.apache.poi.ss.formula.ptg.RefPtg;
|
import org.apache.poi.ss.formula.ptg.RefPtg;
|
||||||
|
|
||||||
|
@ -36,8 +31,9 @@ import org.apache.poi.ss.formula.ptg.RefPtg;
|
||||||
* See bug numbers #55324 and #55747 for the full details on this.
|
* See bug numbers #55324 and #55747 for the full details on this.
|
||||||
* TODO Fix this...
|
* TODO Fix this...
|
||||||
*/
|
*/
|
||||||
public final class IfFunc extends Var2or3ArgFunction {
|
public final class IfFunc extends Var2or3ArgFunction implements ArrayFunction {
|
||||||
|
|
||||||
|
@Override
|
||||||
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
|
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
|
||||||
boolean b;
|
boolean b;
|
||||||
try {
|
try {
|
||||||
|
@ -54,6 +50,7 @@ public final class IfFunc extends Var2or3ArgFunction {
|
||||||
return BoolEval.FALSE;
|
return BoolEval.FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
|
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
|
||||||
ValueEval arg2) {
|
ValueEval arg2) {
|
||||||
boolean b;
|
boolean b;
|
||||||
|
@ -83,4 +80,29 @@ public final class IfFunc extends Var2or3ArgFunction {
|
||||||
}
|
}
|
||||||
return b.booleanValue();
|
return b.booleanValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
|
||||||
|
ValueEval arg0 = args[0];
|
||||||
|
ValueEval arg1 = args[1];
|
||||||
|
return evaluateTwoArrayArgs(arg0, arg1, srcRowIndex, srcColumnIndex,
|
||||||
|
(vA, vB) -> {
|
||||||
|
Boolean b;
|
||||||
|
try {
|
||||||
|
b = OperandResolver.coerceValueToBoolean(vA, false);
|
||||||
|
} catch (EvaluationException e) {
|
||||||
|
return e.getErrorEval();
|
||||||
|
}
|
||||||
|
if (b != null && b) {
|
||||||
|
if (vB == MissingArgEval.instance) {
|
||||||
|
return BlankEval.instance;
|
||||||
|
}
|
||||||
|
return vB;
|
||||||
|
}
|
||||||
|
return BoolEval.FALSE;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ import org.apache.poi.ss.formula.eval.*;
|
||||||
* Implementation of the various ISxxx Logical Functions, which
|
* Implementation of the various ISxxx Logical Functions, which
|
||||||
* take a single expression argument, and return True or False.
|
* take a single expression argument, and return True or False.
|
||||||
*/
|
*/
|
||||||
public abstract class LogicalFunction extends Fixed1ArgFunction {
|
public abstract class LogicalFunction extends Fixed1ArgFunction implements ArrayFunction{
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
|
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
|
||||||
|
@ -41,6 +41,14 @@ public abstract class LogicalFunction extends Fixed1ArgFunction {
|
||||||
return BoolEval.valueOf(evaluate(ve));
|
return BoolEval.valueOf(evaluate(ve));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex){
|
||||||
|
return evaluateOneArrayArg(args, srcRowIndex, srcColumnIndex, (valA) ->
|
||||||
|
BoolEval.valueOf(evaluate(valA))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param arg any {@link ValueEval}, potentially {@link BlankEval} or {@link ErrorEval}.
|
* @param arg any {@link ValueEval}, potentially {@link BlankEval} or {@link ErrorEval}.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/* ====================================================================
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
==================================================================== */
|
||||||
|
|
||||||
|
package org.apache.poi.ss.formula.functions;
|
||||||
|
|
||||||
|
import org.junit.runners.Parameterized.Parameters;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests IF() as loaded from a test data spreadsheet.<p>
|
||||||
|
*/
|
||||||
|
public class TestIFFunctionFromSpreadsheet extends BaseTestFunctionsFromSpreadsheet {
|
||||||
|
@Parameters(name="{0}")
|
||||||
|
public static Collection<Object[]> data() throws Exception {
|
||||||
|
return data(TestIFFunctionFromSpreadsheet.class, "IfFunctionTestCaseData.xls");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/* ====================================================================
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
==================================================================== */
|
||||||
|
|
||||||
|
package org.apache.poi.ss.formula.functions;
|
||||||
|
|
||||||
|
import org.junit.runners.Parameterized.Parameters;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for logical ISxxx functions as loaded from a test data spreadsheet.<p>
|
||||||
|
*/
|
||||||
|
public class TestLogicalFunctionsFromSpreadsheet extends BaseTestFunctionsFromSpreadsheet {
|
||||||
|
@Parameters(name="{0}")
|
||||||
|
public static Collection<Object[]> data() throws Exception {
|
||||||
|
return data(TestLogicalFunctionsFromSpreadsheet.class, "LogicalFunctionsTestCaseData.xls");
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue