View | Details | Raw Unified | Return to bug 52111
Collapse All | Expand All

(-)src/java/org/apache/poi/ss/formula/FormulaParser.java (-4 / +42 lines)
Lines 131-136 Link Here
131
	 */
131
	 */
132
	private char look;
132
	private char look;
133
133
134
    /**
135
     * Tracks whether the run of whitespace preceeding "look" could be an
136
     * intersection operator.  See GetChar.
137
     */
138
	private boolean _inIntersection = false;
139
134
	private FormulaParsingWorkbook _book;
140
	private FormulaParsingWorkbook _book;
135
	private SpreadsheetVersion _ssVersion;
141
	private SpreadsheetVersion _ssVersion;
136
142
Lines 176-184 Link Here
176
		fp.parse();
182
		fp.parse();
177
		return fp.getRPNPtg(formulaType);
183
		return fp.getRPNPtg(formulaType);
178
	}
184
	}
179
185
	
180
	/** Read New Character From Input Stream */
186
	/** Read New Character From Input Stream */
181
	private void GetChar() {
187
	private void GetChar() {
188
		// The intersection operator is a space.  We track whether the run of 
189
		// whitespace preceeding "look" counts as an intersection operator.  
190
		if (IsWhite(look)) {
191
			if (look == ' ') {
192
				_inIntersection = true;
193
			}
194
		}
195
		else {
196
			_inIntersection = false;
197
		}
198
		
182
		// Check to see if we've walked off the end of the string.
199
		// Check to see if we've walked off the end of the string.
183
		if (_pointer > _formulaLength) {
200
		if (_pointer > _formulaLength) {
184
			throw new RuntimeException("too far");
201
			throw new RuntimeException("too far");
Lines 189-194 Link Here
189
			// Just return if so and reset 'look' to something to keep
206
			// Just return if so and reset 'look' to something to keep
190
			// SkipWhitespace from spinning
207
			// SkipWhitespace from spinning
191
			look = (char)0;
208
			look = (char)0;
209
			_inIntersection = false;
192
		}
210
		}
193
		_pointer++;
211
		_pointer++;
194
		//System.out.println("Got char: "+ look);
212
		//System.out.println("Got char: "+ look);
Lines 1104-1110 Link Here
1104
				return parseUnary(true);
1122
				return parseUnary(true);
1105
			case '(':
1123
			case '(':
1106
				Match('(');
1124
				Match('(');
1107
				ParseNode inside = comparisonExpression();
1125
				ParseNode inside = unionExpression();
1108
				Match(')');
1126
				Match(')');
1109
				return new ParseNode(ParenthesisPtg.instance, inside);
1127
				return new ParseNode(ParenthesisPtg.instance, inside);
1110
			case '"':
1128
			case '"':
Lines 1443-1450 Link Here
1443
			result = new ParseNode(operator, result, other);
1461
			result = new ParseNode(operator, result, other);
1444
		}
1462
		}
1445
	}
1463
	}
1464
1446
	private ParseNode unionExpression() {
1465
	private ParseNode unionExpression() {
1447
		ParseNode result = comparisonExpression();
1466
		ParseNode result = intersectionExpression();
1448
		boolean hasUnions = false;
1467
		boolean hasUnions = false;
1449
		while (true) {
1468
		while (true) {
1450
			SkipWhite();
1469
			SkipWhite();
Lines 1452-1458 Link Here
1452
				case ',':
1471
				case ',':
1453
					GetChar();
1472
					GetChar();
1454
					hasUnions = true;
1473
					hasUnions = true;
1455
					ParseNode other = comparisonExpression();
1474
					ParseNode other = intersectionExpression();
1456
					result = new ParseNode(UnionPtg.instance, result, other);
1475
					result = new ParseNode(UnionPtg.instance, result, other);
1457
					continue;
1476
					continue;
1458
			}
1477
			}
Lines 1463-1468 Link Here
1463
		}
1482
		}
1464
	}
1483
	}
1465
1484
1485
   private ParseNode intersectionExpression() {
1486
		ParseNode result = comparisonExpression();
1487
		boolean hasIntersections = false;
1488
		while (true) {
1489
			SkipWhite();
1490
			if (_inIntersection) {
1491
				// Don't getChar() as the space has already been eaten and recorded by SkipWhite().
1492
				hasIntersections = true;
1493
				ParseNode other = comparisonExpression();
1494
				result = new ParseNode(IntersectionPtg.instance, result, other);
1495
				continue;
1496
			}
1497
			if (hasIntersections) {
1498
				return augmentWithMemPtg(result);
1499
			}
1500
			return result;
1501
		}
1502
	}
1503
	
1466
	private ParseNode comparisonExpression() {
1504
	private ParseNode comparisonExpression() {
1467
		ParseNode result = concatExpression();
1505
		ParseNode result = concatExpression();
1468
		while (true) {
1506
		while (true) {
(-)src/java/org/apache/poi/ss/formula/OperandClassTransformer.java (-1 / +3 lines)
Lines 21-26 Link Here
21
import org.apache.poi.ss.formula.ptg.AttrPtg;
21
import org.apache.poi.ss.formula.ptg.AttrPtg;
22
import org.apache.poi.ss.formula.ptg.ControlPtg;
22
import org.apache.poi.ss.formula.ptg.ControlPtg;
23
import org.apache.poi.ss.formula.ptg.FuncVarPtg;
23
import org.apache.poi.ss.formula.ptg.FuncVarPtg;
24
import org.apache.poi.ss.formula.ptg.IntersectionPtg;
24
import org.apache.poi.ss.formula.ptg.MemAreaPtg;
25
import org.apache.poi.ss.formula.ptg.MemAreaPtg;
25
import org.apache.poi.ss.formula.ptg.MemFuncPtg;
26
import org.apache.poi.ss.formula.ptg.MemFuncPtg;
26
import org.apache.poi.ss.formula.ptg.Ptg;
27
import org.apache.poi.ss.formula.ptg.Ptg;
Lines 117-123 Link Here
117
		if (token instanceof ValueOperatorPtg || token instanceof ControlPtg
118
		if (token instanceof ValueOperatorPtg || token instanceof ControlPtg
118
				|| token instanceof MemFuncPtg
119
				|| token instanceof MemFuncPtg
119
				|| token instanceof MemAreaPtg
120
				|| token instanceof MemAreaPtg
120
				|| token instanceof UnionPtg) {
121
				|| token instanceof UnionPtg
122
				|| token instanceof IntersectionPtg) {
121
			// Value Operator Ptgs and Control are base tokens, so token will be unchanged
123
			// Value Operator Ptgs and Control are base tokens, so token will be unchanged
122
			// but any child nodes are processed according to desiredOperandClass and callerForceArrayFlag
124
			// but any child nodes are processed according to desiredOperandClass and callerForceArrayFlag
123
125
(-)src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java (-1 / +59 lines)
Lines 41-47 Link Here
41
import org.apache.poi.ss.formula.ptg.ErrPtg;
41
import org.apache.poi.ss.formula.ptg.ErrPtg;
42
import org.apache.poi.ss.formula.ptg.FuncPtg;
42
import org.apache.poi.ss.formula.ptg.FuncPtg;
43
import org.apache.poi.ss.formula.ptg.FuncVarPtg;
43
import org.apache.poi.ss.formula.ptg.FuncVarPtg;
44
import org.apache.poi.ss.formula.ptg.GreaterThanPtg;
44
import org.apache.poi.ss.formula.ptg.IntPtg;
45
import org.apache.poi.ss.formula.ptg.IntPtg;
46
import org.apache.poi.ss.formula.ptg.IntersectionPtg;
45
import org.apache.poi.ss.formula.ptg.MemAreaPtg;
47
import org.apache.poi.ss.formula.ptg.MemAreaPtg;
46
import org.apache.poi.ss.formula.ptg.MemFuncPtg;
48
import org.apache.poi.ss.formula.ptg.MemFuncPtg;
47
import org.apache.poi.ss.formula.ptg.MissingArgPtg;
49
import org.apache.poi.ss.formula.ptg.MissingArgPtg;
Lines 664-670 Link Here
664
		assertEquals("IF(1<2,SUM(5,2,IF(3>2,SUM(A1:A2),6)),4)", formulaString);
666
		assertEquals("IF(1<2,SUM(5,2,IF(3>2,SUM(A1:A2),6)),4)", formulaString);
665
	}
667
	}
666
	public void testParserErrors() {
668
	public void testParserErrors() {
667
		parseExpectedException("1 2");
668
		parseExpectedException(" 12 . 345  ");
669
		parseExpectedException(" 12 . 345  ");
669
		parseExpectedException("1 .23  ");
670
		parseExpectedException("1 .23  ");
670
671
Lines 1017-1024 Link Here
1017
		);
1018
		);
1018
		MemFuncPtg mf = (MemFuncPtg)ptgs[0];
1019
		MemFuncPtg mf = (MemFuncPtg)ptgs[0];
1019
		assertEquals(45, mf.getLenRefSubexpression());
1020
		assertEquals(45, mf.getLenRefSubexpression());
1021
1022
        // We don't check the type of the operands.
1023
        confirmTokenClasses("1,2", MemAreaPtg.class, IntPtg.class, IntPtg.class, UnionPtg.class);
1020
	}
1024
	}
1021
1025
1026
	public void testIntersection() {
1027
       String formula = "Sheet1!$B$2:$C$3 OFFSET(Sheet1!$E$2:$E$4, 1,Sheet1!$A$1) Sheet1!$D$6";
1028
        HSSFWorkbook wb = new HSSFWorkbook();
1029
        wb.createSheet("Sheet1");
1030
        Ptg[] ptgs = FormulaParser.parse(formula, HSSFEvaluationWorkbook.create(wb), FormulaType.CELL, -1);
1031
1032
        confirmTokenClasses(ptgs,
1033
                // TODO - AttrPtg.class, // Excel prepends this
1034
                MemFuncPtg.class,
1035
                Area3DPtg.class,
1036
                Area3DPtg.class,
1037
                IntPtg.class,
1038
                Ref3DPtg.class,
1039
                FuncVarPtg.class,
1040
                IntersectionPtg.class,
1041
                Ref3DPtg.class,
1042
                IntersectionPtg.class
1043
        );
1044
        MemFuncPtg mf = (MemFuncPtg)ptgs[0];
1045
        assertEquals(45, mf.getLenRefSubexpression());
1046
1047
        // This used to be an error but now parses.  Union has the same behaviour.
1048
        confirmTokenClasses("1 2", MemAreaPtg.class, IntPtg.class, IntPtg.class, IntersectionPtg.class);
1049
	}
1050
	
1051
	public void testComparisonInParen() {
1052
	    confirmTokenClasses("(A1 > B2)", 
1053
            RefPtg.class, 
1054
            RefPtg.class, 
1055
            GreaterThanPtg.class, 
1056
            ParenthesisPtg.class
1057
        );
1058
	}
1059
	
1060
	public void testUnionInParen() {
1061
	    confirmTokenClasses("(A1:B2,B2:C3)", 
1062
          MemAreaPtg.class, 
1063
          AreaPtg.class, 
1064
          AreaPtg.class, 
1065
          UnionPtg.class, 
1066
          ParenthesisPtg.class
1067
        );
1068
	}
1069
1070
    public void testIntersectionInParen() {
1071
        confirmTokenClasses("(A1:B2 B2:C3)", 
1072
            MemAreaPtg.class, 
1073
            AreaPtg.class, 
1074
            AreaPtg.class, 
1075
            IntersectionPtg.class, 
1076
            ParenthesisPtg.class
1077
        );
1078
    }
1079
    
1022
	public void testRange_bug46643() {
1080
	public void testRange_bug46643() {
1023
		String formula = "Sheet1!A1:Sheet1!B3";
1081
		String formula = "Sheet1!A1:Sheet1!B3";
1024
		HSSFWorkbook wb = new HSSFWorkbook();
1082
		HSSFWorkbook wb = new HSSFWorkbook();

Return to bug 52111