Fix for bug 45348 - required tweaks to RVA formula logic

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@675079 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Josh Micich 2008-07-09 01:45:33 +00:00
parent 718befdc6a
commit 2262b7c5c8
5 changed files with 68 additions and 21 deletions

View File

@ -37,6 +37,7 @@
<!-- Don't forget to update status.xml too! --> <!-- Don't forget to update status.xml too! -->
<release version="3.1.1-alpha1" date="2008-??-??"> <release version="3.1.1-alpha1" date="2008-??-??">
<action dev="POI-DEVELOPERS" type="fix">45348 - Tweaks to RVA formula logic</action>
<action dev="POI-DEVELOPERS" type="fix">45354 - Fixed recognition of named ranges within formulas</action> <action dev="POI-DEVELOPERS" type="fix">45354 - Fixed recognition of named ranges within formulas</action>
<action dev="POI-DEVELOPERS" type="fix">45338 - Fix HSSFWorkbook to give you the same HSSFFont every time, and then fix it to find newly added fonts</action> <action dev="POI-DEVELOPERS" type="fix">45338 - Fix HSSFWorkbook to give you the same HSSFFont every time, and then fix it to find newly added fonts</action>
<action dev="POI-DEVELOPERS" type="fix">45336 - Fix HSSFColor.getTripletHash()</action> <action dev="POI-DEVELOPERS" type="fix">45336 - Fix HSSFColor.getTripletHash()</action>

View File

@ -34,6 +34,7 @@
<!-- Don't forget to update changes.xml too! --> <!-- Don't forget to update changes.xml too! -->
<changes> <changes>
<release version="3.1.1-alpha1" date="2008-??-??"> <release version="3.1.1-alpha1" date="2008-??-??">
<action dev="POI-DEVELOPERS" type="fix">45348 - Tweaks to RVA formula logic</action>
<action dev="POI-DEVELOPERS" type="fix">45354 - Fixed recognition of named ranges within formulas</action> <action dev="POI-DEVELOPERS" type="fix">45354 - Fixed recognition of named ranges within formulas</action>
<action dev="POI-DEVELOPERS" type="fix">45338 - Fix HSSFWorkbook to give you the same HSSFFont every time, and then fix it to find newly added fonts</action> <action dev="POI-DEVELOPERS" type="fix">45338 - Fix HSSFWorkbook to give you the same HSSFFont every time, and then fix it to find newly added fonts</action>
<action dev="POI-DEVELOPERS" type="fix">45336 - Fix HSSFColor.getTripletHash()</action> <action dev="POI-DEVELOPERS" type="fix">45336 - Fix HSSFColor.getTripletHash()</action>

View File

@ -71,11 +71,16 @@ final class OperandClassTransformer {
+ _formulaType + ") not supported yet"); + _formulaType + ") not supported yet");
} }
transformNode(rootNode, rootNodeOperandClass, false); transformNode(rootNode, rootNodeOperandClass, false, false);
} }
/**
* @param callerForceArrayFlag <code>true</code> if one of the current node's parents is a
* function Ptg which has been changed from default 'V' to 'A' type (due to requirements on
* the function return value).
*/
private void transformNode(ParseNode node, byte desiredOperandClass, private void transformNode(ParseNode node, byte desiredOperandClass,
boolean callerForceArrayFlag) { boolean callerForceArrayFlag, boolean isDirectChildOfValueOperator) {
Ptg token = node.getToken(); Ptg token = node.getToken();
ParseNode[] children = node.getChildren(); ParseNode[] children = node.getChildren();
if (token instanceof ValueOperatorPtg || token instanceof ControlPtg) { if (token instanceof ValueOperatorPtg || token instanceof ControlPtg) {
@ -84,7 +89,7 @@ final class OperandClassTransformer {
// but any child nodes are processed according to desiredOperandClass and callerForceArrayFlag // but any child nodes are processed according to desiredOperandClass and callerForceArrayFlag
for (int i = 0; i < children.length; i++) { for (int i = 0; i < children.length; i++) {
ParseNode child = children[i]; ParseNode child = children[i];
transformNode(child, desiredOperandClass, callerForceArrayFlag); transformNode(child, desiredOperandClass, callerForceArrayFlag, true);
} }
return; return;
} }
@ -101,22 +106,34 @@ final class OperandClassTransformer {
// nothing to do // nothing to do
return; return;
} }
if (callerForceArrayFlag) { if (isDirectChildOfValueOperator) {
switch (desiredOperandClass) { // As per OOO documentation Sec 3.2.4 "Token Class Transformation", "Step 1"
case Ptg.CLASS_VALUE: // All direct operands of value operators that are initially 'R' type will
case Ptg.CLASS_ARRAY: // be converted to 'V' type.
token.setClass(Ptg.CLASS_ARRAY); if (token.getPtgClass() == Ptg.CLASS_REF) {
break; token.setClass(Ptg.CLASS_VALUE);
case Ptg.CLASS_REF: }
token.setClass(Ptg.CLASS_REF); }
break; token.setClass(transformClass(token.getPtgClass(), desiredOperandClass, callerForceArrayFlag));
default: }
throw new IllegalStateException("Unexpected operand class ("
+ desiredOperandClass + ")"); private byte transformClass(byte currentOperandClass, byte desiredOperandClass,
} boolean callerForceArrayFlag) {
} else { switch (desiredOperandClass) {
token.setClass(desiredOperandClass); case Ptg.CLASS_VALUE:
} if (!callerForceArrayFlag) {
return Ptg.CLASS_VALUE;
}
// else fall through
case Ptg.CLASS_ARRAY:
return Ptg.CLASS_ARRAY;
case Ptg.CLASS_REF:
if (!callerForceArrayFlag) {
return currentOperandClass;
}
return Ptg.CLASS_REF;
}
throw new IllegalStateException("Unexpected operand class (" + desiredOperandClass + ")");
} }
private void transformFunctionNode(AbstractFunctionPtg afp, ParseNode[] children, private void transformFunctionNode(AbstractFunctionPtg afp, ParseNode[] children,
@ -200,7 +217,7 @@ final class OperandClassTransformer {
for (int i = 0; i < children.length; i++) { for (int i = 0; i < children.length; i++) {
ParseNode child = children[i]; ParseNode child = children[i];
byte paramOperandClass = afp.getParameterClass(i); byte paramOperandClass = afp.getParameterClass(i);
transformNode(child, paramOperandClass, localForceArrayFlag); transformNode(child, paramOperandClass, localForceArrayFlag, false);
} }
} }
} }

View File

@ -57,6 +57,31 @@ public final class TestOperandClassTransformer extends TestCase {
confirmFuncClass(ptgs, 2, "INDEX", Ptg.CLASS_VALUE); confirmFuncClass(ptgs, 2, "INDEX", Ptg.CLASS_VALUE);
} }
/**
* Even though count expects args of type R, because A1 is a direct operand of a
* value operator it must get type V
*/
public void testDirectOperandOfValueOperator() {
String formula = "COUNT(A1*1)";
Ptg[] ptgs = FormulaParser.parse(formula, null);
if (ptgs[0].getPtgClass() == Ptg.CLASS_REF) {
throw new AssertionFailedError("Identified bug 45348");
}
confirmTokenClass(ptgs, 0, Ptg.CLASS_VALUE);
confirmTokenClass(ptgs, 3, Ptg.CLASS_VALUE);
}
/**
* A cell ref passed to a function expecting type V should be converted to type V
*/
public void testRtoV() {
String formula = "lookup(A1, A3:A52, B3:B52)";
Ptg[] ptgs = FormulaParser.parse(formula, null);
confirmTokenClass(ptgs, 0, Ptg.CLASS_VALUE);
}
public void testComplexIRR_bug45041() { public void testComplexIRR_bug45041() {
String formula = "(1+IRR(SUMIF(A:A,ROW(INDIRECT(MIN(A:A)&\":\"&MAX(A:A))),B:B),0))^365-1"; String formula = "(1+IRR(SUMIF(A:A,ROW(INDIRECT(MIN(A:A)&\":\"&MAX(A:A))),B:B),0))^365-1";
Ptg[] ptgs = FormulaParser.parse(formula, null); Ptg[] ptgs = FormulaParser.parse(formula, null);
@ -89,8 +114,11 @@ public final class TestOperandClassTransformer extends TestCase {
private void confirmTokenClass(Ptg[] ptgs, int i, byte operandClass) { private void confirmTokenClass(Ptg[] ptgs, int i, byte operandClass) {
Ptg ptg = ptgs[i]; Ptg ptg = ptgs[i];
if (ptg.isBaseToken()) {
throw new AssertionFailedError("ptg[" + i + "] is a base token");
}
if (operandClass != ptg.getPtgClass()) { if (operandClass != ptg.getPtgClass()) {
throw new AssertionFailedError("Wrong operand class for function ptg (" throw new AssertionFailedError("Wrong operand class for ptg ("
+ ptg.toString() + "). Expected " + getOperandClassName(operandClass) + ptg.toString() + "). Expected " + getOperandClassName(operandClass)
+ " but got " + getOperandClassName(ptg.getPtgClass())); + " but got " + getOperandClassName(ptg.getPtgClass()));
} }