77import org .slf4j .Logger ;
88import org .slf4j .LoggerFactory ;
99
10- import java .util .Stack ;
10+ import java .util .ArrayList ;
11+ import java .util .List ;
1112
1213public class FilterCompiler {
1314 private static final Logger logger = LoggerFactory .getLogger (FilterCompiler .class );
@@ -71,64 +72,14 @@ private FilterCompiler(String filterString) {
7172
7273 public Predicate compile () {
7374 try {
74- Stack <LogicalOperator > opsStack = new Stack <LogicalOperator >();
75- Stack <ExpressionNode > expStack = new Stack <ExpressionNode >();
76-
77- int unbalancedParenthesis = 0 ;
78-
79- while (filter .skipBlanks ().inBounds ()) {
80- int pos = filter .position ();
81-
82- switch (filter .currentChar ()) {
83- case OPEN_PARENTHESIS :
84- unbalancedParenthesis ++;
85- filter .incrementPosition (1 );
86- break ;
87- case CLOSE_PARENTHESIS :
88- unbalancedParenthesis --;
89- filter .incrementPosition (1 );
90- ExpressionNode expressionNode = expStack .pop ();
91- if (!opsStack .isEmpty ()) {
92- if (expStack .isEmpty ()) {
93- throw new InvalidPathException ("Expected expression on right hand side of operator " + opsStack .peek ().getOperatorString () + " in filter " + filter );
94- }
95- ExpressionNode right = expStack .pop ();
96- expressionNode = ExpressionNode .createExpressionNode (expressionNode , opsStack .pop (), right );
97- while (!opsStack .isEmpty ()) {
98- expressionNode = ExpressionNode .createExpressionNode (expressionNode , opsStack .pop (), expStack .pop ());
99- }
100- }
101- expStack .push (expressionNode );
102- break ;
103- case NOT :
104- filter .incrementPosition (1 );
105- break ;
106- case OR :
107- case AND :
108- LogicalOperator operatorNode = readLogicalOperator ();
109- opsStack .push (operatorNode );
110- break ;
111- default :
112- if (expStack .size () > 0 && opsStack .isEmpty ()){
113- throw new InvalidPathException ("Expected logical operator (&&, ||) to follow expression " + expStack .peek ().toString ());
114- }
115- RelationalExpressionNode relationalExpressionNode = readExpression ();
116- expStack .push (relationalExpressionNode );
117- break ;
118- }
119- if (pos >= filter .position ()) {
120- throw new InvalidPathException ("Failed to parse filter " + filter .toString ());
121- }
122- }
123- if (unbalancedParenthesis != 0 ) {
124- throw new InvalidPathException ("Failed to parse filter. Parenthesis are not balanced. " + filter .toString ());
125- }
126-
127- Predicate predicate = expStack .pop ();
128-
129- if (logger .isTraceEnabled ()) logger .trace (predicate .toString ());
130-
131- return predicate ;
75+ final ExpressionNode result = readLogicalOR ();
76+ filter .skipBlanks ();
77+ if (filter .inBounds ()) {
78+ throw new InvalidPathException (String .format ("Expected end of filter expression instead of: %s" ,
79+ filter .subSequence (filter .position (), filter .length ())));
80+ }
81+
82+ return result ;
13283 } catch (InvalidPathException e ){
13384 throw e ;
13485 } catch (Exception e ) {
@@ -140,6 +91,13 @@ private ValueNode readValueNode() {
14091 switch (filter .skipBlanks ().currentChar ()) {
14192 case DOC_CONTEXT : return readPath ();
14293 case EVAL_CONTEXT : return readPath ();
94+ case NOT :
95+ filter .incrementPosition (1 );
96+ switch (filter .skipBlanks ().currentChar ()) {
97+ case DOC_CONTEXT : return readPath ();
98+ case EVAL_CONTEXT : return readPath ();
99+ default : throw new InvalidPathException (String .format ("Unexpected character: %c" , NOT ));
100+ }
143101 default : return readLiteral ();
144102 }
145103 }
@@ -159,19 +117,80 @@ private ValueNode readLiteral(){
159117 }
160118 }
161119
120+ /*
121+ * LogicalOR = LogicalAND { '||' LogicalAND }
122+ * LogicalAND = LogicalANDOperand { '&&' LogicalANDOperand }
123+ * LogicalANDOperand = RelationalExpression | '(' LogicalOR ')'
124+ * RelationalExpression = Value [ RelationalOperator Value ]
125+ */
126+
127+ private ExpressionNode readLogicalOR () {
128+ final List <ExpressionNode > ops = new ArrayList <ExpressionNode >();
129+ ops .add (readLogicalAND ());
130+
131+ while (true ) {
132+ int savepoint = filter .position ();
133+ try {
134+ filter .readSignificantSubSequence (LogicalOperator .OR .getOperatorString ());
135+ ops .add (readLogicalAND ());
136+ }
137+ catch (InvalidPathException exc ) {
138+ filter .setPosition (savepoint );
139+ break ;
140+ }
141+ }
142+
143+ return 1 == ops .size () ? ops .get (0 ) : LogicalExpressionNode .createLogicalOr (ops );
144+ }
145+
146+ private ExpressionNode readLogicalAND () {
147+ /// @fixme copy-pasted
148+ final List <ExpressionNode > ops = new ArrayList <ExpressionNode >();
149+ ops .add (readLogicalANDOperand ());
150+
151+ while (true ) {
152+ int savepoint = filter .position ();
153+ try {
154+ filter .readSignificantSubSequence (LogicalOperator .AND .getOperatorString ());
155+ ops .add (readLogicalANDOperand ());
156+ }
157+ catch (InvalidPathException exc ) {
158+ filter .setPosition (savepoint );
159+ break ;
160+ }
161+ }
162+
163+ return 1 == ops .size () ? ops .get (0 ) : LogicalExpressionNode .createLogicalAnd (ops );
164+ }
165+
166+ private ExpressionNode readLogicalANDOperand () {
167+ if (filter .skipBlanks ().currentCharIs (OPEN_PARENTHESIS )) {
168+ filter .readSignificantChar (OPEN_PARENTHESIS );
169+ final ExpressionNode op = readLogicalOR ();
170+ filter .readSignificantChar (CLOSE_PARENTHESIS );
171+ return op ;
172+ }
173+
174+ return readExpression ();
175+ }
176+
162177 private RelationalExpressionNode readExpression () {
163178 ValueNode left = readValueNode ();
164- if (expressionIsTerminated ()) {
165- ValueNode .PathNode pathNode = left .asPathNode ();
166- left = pathNode .asExistsCheck (pathNode .shouldExists ());
167- RelationalOperator operator = RelationalOperator .EXISTS ;
168- ValueNode right = left .asPathNode ().shouldExists () ? ValueNode .TRUE : ValueNode .FALSE ;
169- return new RelationalExpressionNode (left , operator , right );
170- } else {
179+ int savepoint = filter .position ();
180+ try {
171181 RelationalOperator operator = readRelationalOperator ();
172182 ValueNode right = readValueNode ();
173183 return new RelationalExpressionNode (left , operator , right );
174184 }
185+ catch (InvalidPathException exc ) {
186+ filter .setPosition (savepoint );
187+ }
188+
189+ ValueNode .PathNode pathNode = left .asPathNode ();
190+ left = pathNode .asExistsCheck (pathNode .shouldExists ());
191+ RelationalOperator operator = RelationalOperator .EXISTS ;
192+ ValueNode right = left .asPathNode ().shouldExists () ? ValueNode .TRUE : ValueNode .FALSE ;
193+ return new RelationalExpressionNode (left , operator , right );
175194 }
176195
177196 private LogicalOperator readLogicalOperator (){
0 commit comments