Made POI follow the rules for encoding unary +/- operators more closely.

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@887028 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Josh Micich 2009-12-04 01:25:34 +00:00
parent 484dc9fe5a
commit e55e9044aa
2 changed files with 69 additions and 3 deletions

View 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) {

View 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();