From 2262b7c5c8e04f02f0be655dd4d9d4e5da71a866 Mon Sep 17 00:00:00 2001 From: Josh Micich Date: Wed, 9 Jul 2008 01:45:33 +0000 Subject: [PATCH] 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 --- src/documentation/content/xdocs/changes.xml | 1 + src/documentation/content/xdocs/status.xml | 1 + .../hssf/model/OperandClassTransformer.java | 57 ++++++++++++------ .../org/apache/poi/hssf/data/testRVA.xls | Bin 32256 -> 32256 bytes .../model/TestOperandClassTransformer.java | 30 ++++++++- 5 files changed, 68 insertions(+), 21 deletions(-) diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml index 54bfcfee8..2507fafbe 100644 --- a/src/documentation/content/xdocs/changes.xml +++ b/src/documentation/content/xdocs/changes.xml @@ -37,6 +37,7 @@ + 45348 - Tweaks to RVA formula logic 45354 - Fixed recognition of named ranges within formulas 45338 - Fix HSSFWorkbook to give you the same HSSFFont every time, and then fix it to find newly added fonts 45336 - Fix HSSFColor.getTripletHash() diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index bde398a9c..013b3b3bd 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + 45348 - Tweaks to RVA formula logic 45354 - Fixed recognition of named ranges within formulas 45338 - Fix HSSFWorkbook to give you the same HSSFFont every time, and then fix it to find newly added fonts 45336 - Fix HSSFColor.getTripletHash() diff --git a/src/java/org/apache/poi/hssf/model/OperandClassTransformer.java b/src/java/org/apache/poi/hssf/model/OperandClassTransformer.java index 5358324a3..07d2bd2fd 100644 --- a/src/java/org/apache/poi/hssf/model/OperandClassTransformer.java +++ b/src/java/org/apache/poi/hssf/model/OperandClassTransformer.java @@ -71,11 +71,16 @@ final class OperandClassTransformer { + _formulaType + ") not supported yet"); } - transformNode(rootNode, rootNodeOperandClass, false); + transformNode(rootNode, rootNodeOperandClass, false, false); } + /** + * @param callerForceArrayFlag true 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) { @@ -84,7 +89,7 @@ final class OperandClassTransformer { // 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; } @@ -101,22 +106,34 @@ final class OperandClassTransformer { // 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, @@ -200,7 +217,7 @@ final class OperandClassTransformer { 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); } } } diff --git a/src/testcases/org/apache/poi/hssf/data/testRVA.xls b/src/testcases/org/apache/poi/hssf/data/testRVA.xls index f23821117e96c2c5e9649a8c5227748bb519ae5a..17aa9fd7108c2f6cf471f36780a549725365e6c4 100644 GIT binary patch delta 1147 zcmZ`%-Ahwp9Dd&8&YEY_nICI{b2GQxhqj&NR~9-yy6D3`$Ot0A(3?tgId!6ec9B>? zL@yC_QBW5V-2?{;N@3kae?Z<9(On36o#yHHzT4EIIPmiRp5OEQKA!W=t+Tmx_G;K- zO?-Oo8T!h{Eb~g`QRAn@EKqGv2r)Kn@jdJ#*P}K6Io(i51EY<@{l+D0h38ySez6m|bEnhXoGVfaUwOZ|~>U8n?nzdbYTW z-_*16a{fXW#oy#IZcW>y8*6$pqWGKnNdN5}kJK=Y95&4UDb?oyx=)-r-WTlF+q&Z+ z`&Jm%Lnh*UdN5*5Hv!jG{%r7Cu};#t1Hj55;LZ`FVd%WdbmP{=UZugNl)xj+@CnZV z=7hki|ABdp50~v0%j(Ox%9lsO_7%FACQu6S&!d$*kX&Mne@nJ8W>jCDVl2QPjJ3qg zR?LXMv8pH;B{L0FK+V`Ia#%s8Ad6WEQ?uZ`)UH`8YUN-~IaT(k0?Z-=Xh?`sT{Q78 zXhdV^Mvyo{Bqq;`Ry!byY!sn~CdgDXsCiMf6orV)6f3+kS|(bf1`I2$e0QqFK7c0r zgdILUma1cZKA)=N?^7pPgm2Jo|9Hu)$VRD(0^c77#{R-Y7oY4RMy{o7r`%6Oeu|v( z6dc-*B6mYi-&##!0%9>!!-X=?_+5%et{k9BPI|W_5(Vm{L~L$FuXMtR_IgKh$@iTc z2=TY$32#tJY?5;yVsR&)-B`HP;crgR%i@(23*M0AkONd_8sf#}o!m#92+vH6c*Bw- za4QZYvW+9$uII-l4|*e#QzAJtsNdpb1`Z;}xM;YTcqhhiF)@PFnQ5V1oMhk3_r33XZ}#mj?yg># z0@VY+%Aj%e)(w@l8SicnDMrWmp2_@t;|-`I6}DSn$JKlus064dRYOaubrzuh$qOuC zEKFt?tEb;n=i>Vvm>0AAsVF%mmj$Yz=Im8P&XhA1I1A_00!hi~YTFjN@xTT|>DTmm z)v7oVpo+ULRwp7|O1mkYcC(;F%jwJXgQJK*PiLG9f1x43-=h~^9tEo7dpR0-w4fIC z66ultYr6qk0tf*V3A7&@~ zA*m6(1%qhf`+;VMcMj9QT$jH|YMfFtk8nwo8%Y2WdNFq|5|)|@o)hzEks3db7Tz}^ z5f8=HN}ZV#9m#!*~PTM6<&Ca?Tm-f K&e-nDtoa{If4A-c diff --git a/src/testcases/org/apache/poi/hssf/model/TestOperandClassTransformer.java b/src/testcases/org/apache/poi/hssf/model/TestOperandClassTransformer.java index 90a5d8b13..47cfb574c 100644 --- a/src/testcases/org/apache/poi/hssf/model/TestOperandClassTransformer.java +++ b/src/testcases/org/apache/poi/hssf/model/TestOperandClassTransformer.java @@ -57,6 +57,31 @@ public final class TestOperandClassTransformer extends TestCase { 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); @@ -89,8 +114,11 @@ public final class TestOperandClassTransformer extends TestCase { 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())); }