]> source.dussan.org Git - poi.git/commitdiff
Made POI follow the rules for encoding unary +/- operators more closely.
authorJosh Micich <josh@apache.org>
Fri, 4 Dec 2009 01:25:34 +0000 (01:25 +0000)
committerJosh Micich <josh@apache.org>
Fri, 4 Dec 2009 01:25:34 +0000 (01:25 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@887028 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/ss/formula/FormulaParser.java
src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java

index adb4bd87795b2dabc63efbe8746d1ca80bc472b0..46d7fbfee1c0c53f2818f2307d9c8c52e854e551 100644 (file)
@@ -1091,10 +1091,10 @@ public final class FormulaParser {
                                return new ParseNode(ErrPtg.valueOf(parseErrorLiteral()));
                        case '-':
                                Match('-');
-                               return new ParseNode(UnaryMinusPtg.instance, powerFactor());
+                               return parseUnary(false);
                        case '+':
                                Match('+');
-                               return new ParseNode(UnaryPlusPtg.instance, powerFactor());
+                               return parseUnary(true);
                        case '(':
                                Match('(');
                                ParseNode inside = comparisonExpression();
@@ -1118,6 +1118,35 @@ public final class FormulaParser {
        }
 
 
+       private ParseNode parseUnary(boolean isPlus) {
+
+               boolean numberFollows = IsDigit(look) || look=='.';
+               ParseNode factor = powerFactor();
+
+               if (numberFollows) {
+                       // + or - directly next to a number is parsed with the number
+
+                       Ptg token = factor.getToken();
+                       if (token instanceof NumberPtg) {
+                               if (isPlus) {
+                                       return factor;
+                               }
+                               token = new NumberPtg(-((NumberPtg)token).getValue());
+                               return new ParseNode(token);
+                       }
+                       if (token instanceof IntPtg) {
+                               if (isPlus) {
+                                       return factor;
+                               }
+                               int intVal = ((IntPtg)token).getValue();
+                               // note - cannot use IntPtg for negatives
+                               token = new NumberPtg(-intVal);
+                               return new ParseNode(token);
+                       }
+               }
+               return new ParseNode(isPlus ? UnaryPlusPtg.instance : UnaryMinusPtg.instance, factor);
+       }
+
        private ParseNode parseArray() {
                List<Object[]> rowsData = new ArrayList<Object[]>();
                while(true) {
index 76dce58da4d5990dda384bf760fff1147354975d..cdf42e07f571227e9485040324b0d16f855bf538 100644 (file)
@@ -187,6 +187,43 @@ public final class TestFormulaParser extends TestCase {
                confirmTokenClasses("+A1", RefPtg.class, UnaryPlusPtg.class);
        }
 
+       /**
+        * There may be multiple ways to encode an expression involving {@link UnaryPlusPtg}
+        * or {@link UnaryMinusPtg}.  These may be perfectly equivalent from a formula
+        * evaluation perspective, or formula rendering.  However, differences in the way
+        * POI encodes formulas may cause unnecessary confusion.  These non-critical tests
+        * check that POI follows the same encoding rules as Excel.
+        */
+       public void testExactEncodingOfUnaryPlusAndMinus() {
+               // as tested in Excel:
+               confirmUnary("-3", -3, NumberPtg.class);
+               confirmUnary("--4", -4, NumberPtg.class, UnaryMinusPtg.class);
+               confirmUnary("+++5", 5, IntPtg.class, UnaryPlusPtg.class, UnaryPlusPtg.class);
+               confirmUnary("++-6", -6, NumberPtg.class, UnaryPlusPtg.class, UnaryPlusPtg.class);
+
+               // Spaces muck things up a bit.  It would be clearer why the following cases are
+               // reasonable if POI encoded tAttrSpace in the right places.
+               // Otherwise these differences look capricious.
+               confirmUnary("+ 12", 12, IntPtg.class, UnaryPlusPtg.class);
+               confirmUnary("- 13", 13, IntPtg.class, UnaryMinusPtg.class);
+       }
+
+       private static void confirmUnary(String formulaText, double val, Class<?>...expectedTokenTypes) {
+               Ptg[] ptgs = parseFormula(formulaText);
+               confirmTokenClasses(ptgs, expectedTokenTypes);
+               Ptg ptg0 = ptgs[0];
+               if (ptg0 instanceof IntPtg) {
+                       IntPtg intPtg = (IntPtg) ptg0;
+                       assertEquals((int)val, intPtg.getValue());
+               } else if (ptg0 instanceof NumberPtg) {
+                       NumberPtg numberPtg = (NumberPtg) ptg0;
+                       assertEquals(val, numberPtg.getValue(), 0.0);
+               } else {
+                       fail("bad ptg0 " + ptg0);
+               }
+       }
+
+
        public void testLeadingSpaceInString() {
                String value = "  hi  ";
                Ptg[] ptgs = parseFormula("\"" + value + "\"");
@@ -325,7 +362,7 @@ public final class TestFormulaParser extends TestCase {
 
                cell.setCellFormula("+.1");
                formula = cell.getCellFormula();
-               assertEquals("+0.1", formula);
+               assertEquals("0.1", formula);
 
                cell.setCellFormula("-.1");
                formula = cell.getCellFormula();