+ _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,
- boolean callerForceArrayFlag) {
+ boolean callerForceArrayFlag, boolean isDirectChildOfValueOperator) {
Ptg token = node.getToken();
ParseNode[] children = node.getChildren();
if (token instanceof ValueOperatorPtg || token instanceof ControlPtg) {
// but any child nodes are processed according to desiredOperandClass and callerForceArrayFlag
for (int i = 0; i < children.length; i++) {
ParseNode child = children[i];
- transformNode(child, desiredOperandClass, callerForceArrayFlag);
+ transformNode(child, desiredOperandClass, callerForceArrayFlag, true);
}
return;
}
// nothing to do
return;
}
- if (callerForceArrayFlag) {
- switch (desiredOperandClass) {
- case Ptg.CLASS_VALUE:
- case Ptg.CLASS_ARRAY:
- token.setClass(Ptg.CLASS_ARRAY);
- break;
- case Ptg.CLASS_REF:
- token.setClass(Ptg.CLASS_REF);
- break;
- default:
- throw new IllegalStateException("Unexpected operand class ("
- + desiredOperandClass + ")");
- }
- } else {
- token.setClass(desiredOperandClass);
- }
+ if (isDirectChildOfValueOperator) {
+ // As per OOO documentation Sec 3.2.4 "Token Class Transformation", "Step 1"
+ // All direct operands of value operators that are initially 'R' type will
+ // be converted to 'V' type.
+ if (token.getPtgClass() == Ptg.CLASS_REF) {
+ token.setClass(Ptg.CLASS_VALUE);
+ }
+ }
+ token.setClass(transformClass(token.getPtgClass(), desiredOperandClass, callerForceArrayFlag));
+ }
+
+ private byte transformClass(byte currentOperandClass, byte desiredOperandClass,
+ boolean callerForceArrayFlag) {
+ switch (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,
for (int i = 0; i < children.length; i++) {
ParseNode child = children[i];
byte paramOperandClass = afp.getParameterClass(i);
- transformNode(child, paramOperandClass, localForceArrayFlag);
+ transformNode(child, paramOperandClass, localForceArrayFlag, false);
}
}
}
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() {
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);
private void confirmTokenClass(Ptg[] ptgs, int i, byte operandClass) {
Ptg ptg = ptgs[i];
+ if (ptg.isBaseToken()) {
+ throw new AssertionFailedError("ptg[" + i + "] is a base token");
+ }
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)
+ " but got " + getOperandClassName(ptg.getPtgClass()));
}