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:
parent
484dc9fe5a
commit
e55e9044aa
@ -1091,10 +1091,10 @@ public final class FormulaParser {
|
|||||||
return new ParseNode(ErrPtg.valueOf(parseErrorLiteral()));
|
return new ParseNode(ErrPtg.valueOf(parseErrorLiteral()));
|
||||||
case '-':
|
case '-':
|
||||||
Match('-');
|
Match('-');
|
||||||
return new ParseNode(UnaryMinusPtg.instance, powerFactor());
|
return parseUnary(false);
|
||||||
case '+':
|
case '+':
|
||||||
Match('+');
|
Match('+');
|
||||||
return new ParseNode(UnaryPlusPtg.instance, powerFactor());
|
return parseUnary(true);
|
||||||
case '(':
|
case '(':
|
||||||
Match('(');
|
Match('(');
|
||||||
ParseNode inside = comparisonExpression();
|
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() {
|
private ParseNode parseArray() {
|
||||||
List<Object[]> rowsData = new ArrayList<Object[]>();
|
List<Object[]> rowsData = new ArrayList<Object[]>();
|
||||||
while(true) {
|
while(true) {
|
||||||
|
@ -187,6 +187,43 @@ public final class TestFormulaParser extends TestCase {
|
|||||||
confirmTokenClasses("+A1", RefPtg.class, UnaryPlusPtg.class);
|
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() {
|
public void testLeadingSpaceInString() {
|
||||||
String value = " hi ";
|
String value = " hi ";
|
||||||
Ptg[] ptgs = parseFormula("\"" + value + "\"");
|
Ptg[] ptgs = parseFormula("\"" + value + "\"");
|
||||||
@ -325,7 +362,7 @@ public final class TestFormulaParser extends TestCase {
|
|||||||
|
|
||||||
cell.setCellFormula("+.1");
|
cell.setCellFormula("+.1");
|
||||||
formula = cell.getCellFormula();
|
formula = cell.getCellFormula();
|
||||||
assertEquals("+0.1", formula);
|
assertEquals("0.1", formula);
|
||||||
|
|
||||||
cell.setCellFormula("-.1");
|
cell.setCellFormula("-.1");
|
||||||
formula = cell.getCellFormula();
|
formula = cell.getCellFormula();
|
||||||
|
Loading…
Reference in New Issue
Block a user