##### Coverage Report - org.jaxen.saxpath.base.XPathReader

Classes in this File | Line Coverage | Branch Coverage | Complexity
XPathReader |
98% |
100% |
| 4.170731707317073;4.171

1 |  |
     /*
2 |  |
      * $Header: /home/projects/jaxen/scm/jaxen/src/java/main/org/jaxen/saxpath/base/XPathReader.java,v 1.27 2005/08/09 12:01:49 elharo Exp $
3 |  |
      * $Revision: 1.27 $
4 |  |
      * $Date: 2005/08/09 12:01:49 $
5 |  |
      *
6 |  |
      * ====================================================================
7 |  |
      *
8 |  |
      * Copyright (C) 2000-2002 bob mcwhirter & James Strachan.
9 |  |
      * All rights reserved.
10 |  |
      *
11 |  |
      * Redistribution and use in source and binary forms, with or without
12 |  |
      * modification, are permitted provided that the following conditions
13 |  |
      * are met:
14 |  |
      *
15 |  |
      * 1. Redistributions of source code must retain the above copyright
16 |  |
      *    notice, this list of conditions, and the following disclaimer.
17 |  |
      *
18 |  |
      * 2. Redistributions in binary form must reproduce the above copyright
19 |  |
      *    notice, this list of conditions, and the disclaimer that follows
20 |  |
      *    these conditions in the documentation and/or other materials
21 |  |
      *    provided with the distribution.
22 |  |
      *
23 |  |
      * 3. The name "Jaxen" must not be used to endorse or promote products
24 |  |
      *    derived from this software without prior written permission.  For
25 |  |
      *    written permission, please contact license@jaxen.org.
26 |  |
      *
27 |  |
      * 4. Products derived from this software may not be called "Jaxen", nor
28 |  |
      *    may "Jaxen" appear in their name, without prior written permission
29 |  |
      *    from the Jaxen Project Management (pm@jaxen.org).
30 |  |
      *
31 |  |
      * In addition, we request (but do not require) that you include in the
32 |  |
      * end-user documentation provided with the redistribution and/or in the
33 |  |
      * software itself an acknowledgement equivalent to the following:
34 |  |
      *     "This product includes software developed by the
35 |  |
      *      Jaxen Project <http://www.jaxen.org/>."
36 |  |
      * Alternatively, the acknowledgment may be graphical using the logos
37 |  |
      * available at http://www.jaxen.org/
38 |  |
      *
39 |  |
      * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED TokenTypes.OR IMPLIED
40 |  |
      * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
41 |  |
      * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
42 |  |
      * DISCLAIMED.  IN NO EVENT SHALL THE Jaxen AUTHORS TokenTypes.OR THE PROJECT
43 |  |
      * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44 |  |
      * SPECIAL, EXEMPLARY, TokenTypes.OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
45 |  |
      * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS TokenTypes.OR SERVICES; LOSS OF
46 |  |
      * USE, DATA, TokenTypes.OR PROFITS; TokenTypes.OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
47 |  |
      * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
48 |  |
      * TokenTypes.OR TORT (INCLUDING NEGLIGENCE TokenTypes.OR OTHERWISE) ARISING IN ANY WAY OUT
49 |  |
      * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50 |  |
      * SUCH DAMAGE.
51 |  |
      *
52 |  |
      * ====================================================================
53 |  |
      * This software consists of voluntary contributions made by many
54 |  |
      * individuals on behalf of the Jaxen Project and was originally
55 |  |
      * created by bob mcwhirter <bob@werken.com> and
56 |  |
      * James Strachan <jstrachan@apache.org>.  For more information on the
57 |  |
      * Jaxen Project, please see <http://www.jaxen.org/>.
58 |  |
      *
59 |  |
      * $Id: XPathReader.java,v 1.27 2005/08/09 12:01:49 elharo Exp $
60 |  |
      */
61 |  |
62 |  |
63 |  |
     package org.jaxen.saxpath.base;
64 |  |
65 |  |
     import java.util.LinkedList;
66 |  |
67 |  |
     import org.jaxen.saxpath.Axis;
68 |  |
     import org.jaxen.saxpath.Operator;
69 |  |
     import org.jaxen.saxpath.SAXPathException;
70 |  |
     import org.jaxen.saxpath.XPathHandler;
71 |  |
     import org.jaxen.saxpath.XPathSyntaxException;
72 |  |
     import org.jaxen.saxpath.helpers.DefaultXPathHandler;
73 |  |
74 |  |
     /** Implementation of SAXPath's <code>XPathReader</code> which
75 |  |
      *  generates callbacks to an <code>XPathHandler</code>.
76 |  |
      *
77 |  |
      *  @author bob mcwhirter (bob@werken.com)
78 |  |
      */
79 |  |
     public class XPathReader implements org.jaxen.saxpath.XPathReader
80 |  |
     {
81 |  |
         private LinkedList tokens;
82 |  |
         private XPathLexer lexer;
83 |  |
84 |  |
         private XPathHandler handler;
85 |  |
86 | 318 |
         private static XPathHandler defaultHandler = new DefaultXPathHandler();
87 |  |
88 |  |
         /**
89 |  |
          * Create a new <code>XPathReader</code> with a do-nothing
90 |  |
          * <code>XPathHandler</code>.
91 |  |
          */
92 |  |
         public XPathReader()
93 | 10896 |
         {
94 | 10896 |
             setXPathHandler( defaultHandler );
95 | 10896 |
         }
96 |  |
97 |  |
         public void setXPathHandler(XPathHandler handler)
98 |  |
         {
99 | 21786 |
             this.handler = handler;
100 | 21786 |
         }
101 |  |
102 |  |
         public XPathHandler getXPathHandler()
103 |  |
         {
104 | 303654 |
             return this.handler;
105 |  |
         }
106 |  |
107 |  |
         public void parse(String xpath) throws SAXPathException
108 |  |
         {
109 | 11076 |
             setUpParse( xpath );
110 |  |
111 | 11076 |
             getXPathHandler().startXPath();
112 |  |
113 | 11076 |
             expr();
114 |  |
115 | 10818 |
             getXPathHandler().endXPath();
116 |  |
117 | 10818 |
             if ( LA(1) != TokenTypes.EOF )
118 |  |
             {
119 | 54 |
                 XPathSyntaxException ex = createSyntaxException( "Unexpected '" + LT(1).getTokenText() + "'" );
120 | 54 |
                 throw ex;
121 |  |
             }
122 |  |
123 | 10764 |
             lexer  = null;
124 | 10764 |
             tokens = null;
125 | 10764 |
         }
126 |  |
127 |  |
         void setUpParse(String xpath)
128 |  |
         {
129 | 11136 |
             this.tokens = new LinkedList();
130 | 11136 |
             this.lexer = new XPathLexer( xpath );
131 | 11136 |
         }
132 |  |
133 |  |
         private void pathExpr() throws SAXPathException
134 |  |
         {
135 | 23544 |
             getXPathHandler().startPathExpr();
136 |  |
137 | 23544 |
             switch ( LA(1) )
138 |  |
             {
139 |  |
                 case TokenTypes.INTEGER:
140 |  |
                 case TokenTypes.DOUBLE:
141 |  |
                 case TokenTypes.LITERAL:
142 |  |
                 {
143 | 8502 |
                     filterExpr();
144 |  |
145 | 8502 |
                     if ( LA(1) == TokenTypes.SLASH || LA(1) == TokenTypes.DOUBLE_SLASH )
146 |  |
                     {
147 | 6 |
                         XPathSyntaxException ex = createSyntaxException("Node-set expected");
148 | 6 |
                         throw ex;
149 |  |
                     }
150 |  |
151 |  |
                     break;
152 |  |
                 }
153 |  |
                 case TokenTypes.LEFT_PAREN:
154 |  |
                 case TokenTypes.DOLLAR:
155 |  |
                 {
156 | 444 |
                     filterExpr();
157 |  |
158 | 414 |
                     if ( LA(1) == TokenTypes.SLASH || LA(1) == TokenTypes.DOUBLE_SLASH)
159 |  |
                     {
160 | 30 |
                         locationPath( false );
161 |  |
                     }
162 |  |
                     break;
163 |  |
                 }
164 |  |
                 case TokenTypes.IDENTIFIER:
165 |  |
                 {
166 |  |
167 | 6852 |
                     if ( ( LA(2) == TokenTypes.LEFT_PAREN
168 |  |
                          &&
169 |  |
                            ! isNodeTypeName( LT(1) ) )
170 |  |
                          ||
171 |  |
                         ( LA(2) == TokenTypes.COLON
172 |  |
                           &&
173 |  |
                           LA(4) == TokenTypes.LEFT_PAREN) )
174 |  |
                     {
175 | 4632 |
                         filterExpr();
176 |  |
177 | 4608 |
                         if ( LA(1) == TokenTypes.SLASH || LA(1) == TokenTypes.DOUBLE_SLASH)
178 |  |
                         {
179 | 156 |
                             locationPath( false );
180 |  |
                         }
181 |  |
                     }
182 |  |
                     else
183 |  |
                     {
184 | 2220 |
                         locationPath( false );
185 |  |
                     }
186 | 2184 |
                     break;
187 |  |
                 }
188 |  |
                 case TokenTypes.DOT:
189 |  |
                 case TokenTypes.DOT_DOT:
190 |  |
                 case TokenTypes.STAR:
191 |  |
                 case TokenTypes.AT:
192 |  |
                 {
193 | 1638 |
                     locationPath( false );
194 | 1638 |
                     break;
195 |  |
                 }
196 |  |
                 case TokenTypes.SLASH:
197 |  |
                 case TokenTypes.DOUBLE_SLASH:
198 |  |
                 {
199 | 6078 |
                     locationPath( true );
200 | 5928 |
                     break;
201 |  |
                 }
202 |  |
                 default:
203 |  |
                 {
204 | 30 |
                     XPathSyntaxException ex = createSyntaxException( "Unexpected '" + LT(1).getTokenText() + "'" );
205 | 30 |
                     throw ex;
206 |  |
                 }
207 |  |
             }
208 |  |
209 | 23256 |
             getXPathHandler().endPathExpr();
210 | 23256 |
         }
211 |  |
212 |  |
         private void numberDouble() throws SAXPathException
213 |  |
         {
214 | 276 |
             Token token = match( TokenTypes.DOUBLE );
215 |  |
216 | 276 |
             getXPathHandler().number( Double.parseDouble( token.getTokenText() ) );
217 | 276 |
         }
218 |  |
219 |  |
         private void numberInteger() throws SAXPathException
220 |  |
         {
221 | 4278 |
             Token token = match( TokenTypes.INTEGER );
222 |  |
223 | 4278 |
             String text = token.getTokenText();
224 |  |
             try {
225 | 4278 |
                 getXPathHandler().number( Integer.parseInt( text ) );
226 |  |
             }
227 | 0 |
             catch (NumberFormatException ex) {
228 | 0 |
                 getXPathHandler().number( Double.parseDouble( text ) );
229 | 4278 |
             }
230 |  |
231 | 4278 |
         }
232 |  |
233 |  |
         private void literal() throws SAXPathException
234 |  |
         {
235 | 3948 |
             Token token = match( TokenTypes.LITERAL );
236 |  |
237 | 3948 |
             getXPathHandler().literal( token.getTokenText() );
238 | 3948 |
         }
239 |  |
240 |  |
         private void functionCall() throws SAXPathException
241 |  |
         {
242 | 4632 |
             String prefix       = null;
243 | 4632 |
             String functionName = null;
244 |  |
245 | 4632 |
             if ( LA(2) == TokenTypes.COLON )
246 |  |
             {
247 | 6 |
                 prefix = match( TokenTypes.IDENTIFIER ).getTokenText();
248 | 6 |
                 match( TokenTypes.COLON );
249 |  |
             }
250 |  |
             else
251 |  |
             {
252 | 4626 |
                 prefix = "";
253 |  |
             }
254 |  |
255 | 4632 |
             functionName = match( TokenTypes.IDENTIFIER ).getTokenText();
256 |  |
257 | 4632 |
             getXPathHandler().startFunction( prefix,
258 |  |
                                              functionName );
259 |  |
260 | 4632 |
             match ( TokenTypes.LEFT_PAREN );
261 |  |
262 | 4632 |
             arguments();
263 |  |
264 | 4608 |
             match ( TokenTypes.RIGHT_PAREN );
265 |  |
266 | 4608 |
             getXPathHandler().endFunction();
267 | 4608 |
         }
268 |  |
269 |  |
         private void arguments() throws SAXPathException
270 |  |
         {
271 | 6534 |
             while ( LA(1) != TokenTypes.RIGHT_PAREN )
272 |  |
             {
273 | 5496 |
                 expr();
274 |  |
275 | 5472 |
                 if ( LA(1) == TokenTypes.COMMA )
276 |  |
                 {
277 | 1902 |
                     match( TokenTypes.COMMA );
278 |  |
                 }
279 |  |
                 else
280 |  |
                 {
281 |  |
                     break;
282 |  |
                 }
283 |  |
             }
284 | 4608 |
         }
285 |  |
286 |  |
         private void filterExpr() throws SAXPathException
287 |  |
         {
288 |  |
289 | 13578 |
             getXPathHandler().startFilterExpr();
290 |  |
291 | 13578 |
             switch ( LA(1) )
292 |  |
             {
293 |  |
                 case TokenTypes.INTEGER:
294 |  |
                 {
295 | 4278 |
                     numberInteger();
296 | 4278 |
                     break;
297 |  |
                 }
298 |  |
                 case TokenTypes.DOUBLE:
299 |  |
                 {
300 | 276 |
                     numberDouble();
301 | 276 |
                     break;
302 |  |
                 }
303 |  |
                 case TokenTypes.LITERAL:
304 |  |
                 {
305 | 3948 |
                     literal();
306 | 3948 |
                     break;
307 |  |
                 }
308 |  |
                 case TokenTypes.LEFT_PAREN:
309 |  |
                 {
310 | 306 |
                     match( TokenTypes.LEFT_PAREN );
311 | 306 |
                     expr();
312 | 306 |
                     match( TokenTypes.RIGHT_PAREN );
313 | 276 |
                     break;
314 |  |
                 }
315 |  |
                 case TokenTypes.IDENTIFIER:
316 |  |
                 {
317 | 4632 |
                     functionCall();
318 | 4608 |
                     break;
319 |  |
                 }
320 |  |
                 case TokenTypes.DOLLAR:
321 |  |
                 {
322 | 138 |
                     variableReference();
323 |  |
                     break;
324 |  |
                 }
325 |  |
             }
326 |  |
327 | 13524 |
             predicates();
328 |  |
329 | 13524 |
             getXPathHandler().endFilterExpr();
330 | 13524 |
         }
331 |  |
332 |  |
         private void variableReference() throws SAXPathException
333 |  |
         {
334 | 138 |
             match( TokenTypes.DOLLAR );
335 |  |
336 | 138 |
             String prefix       = null;
337 | 138 |
             String variableName = null;
338 |  |
339 | 138 |
             if ( LA(2) == TokenTypes.COLON )
340 |  |
             {
341 | 6 |
                 prefix = match( TokenTypes.IDENTIFIER ).getTokenText();
342 | 6 |
                 match( TokenTypes.COLON );
343 |  |
             }
344 |  |
             else
345 |  |
             {
346 | 132 |
                 prefix = "";
347 |  |
             }
348 |  |
349 | 138 |
             variableName = match( TokenTypes.IDENTIFIER ).getTokenText();
350 |  |
351 | 138 |
             getXPathHandler().variableReference( prefix,
352 |  |
                                                  variableName );
353 | 138 |
         }
354 |  |
355 |  |
         void locationPath(boolean isAbsolute) throws SAXPathException
356 |  |
         {
357 | 10134 |
             switch ( LA(1) )
358 |  |
             {
359 |  |
                 case TokenTypes.SLASH:
360 |  |
                 case TokenTypes.DOUBLE_SLASH:
361 |  |
                 {
362 | 6270 |
                     if ( isAbsolute )
363 |  |
                     {
364 | 6084 |
                         absoluteLocationPath();
365 |  |
                     }
366 |  |
                     else
367 |  |
                     {
368 | 186 |
                         relativeLocationPath();
369 |  |
                     }
370 | 174 |
                     break;
371 |  |
                 }
372 |  |
                 case TokenTypes.AT:
373 |  |
                 case TokenTypes.IDENTIFIER:
374 |  |
                 case TokenTypes.DOT:
375 |  |
                 case TokenTypes.DOT_DOT:
376 |  |
                 case TokenTypes.STAR:
377 |  |
                 {
378 | 3864 |
                     relativeLocationPath();
379 | 3828 |
                     break;
380 |  |
                 }
381 |  |
                 default:
382 |  |
                 {
383 | 0 |
                     XPathSyntaxException ex = createSyntaxException( "Unexpected '" + LT(1).getTokenText() + "'" );
384 | 0 |
                     throw ex;
385 |  |
                 }
386 |  |
             }
387 | 9936 |
         }
388 |  |
389 |  |
         private void absoluteLocationPath() throws SAXPathException
390 |  |
         {
391 | 6084 |
             getXPathHandler().startAbsoluteLocationPath();
392 |  |
393 | 6084 |
             switch ( LA(1) )
394 |  |
             {
395 |  |
                 case TokenTypes.SLASH:
396 |  |
                 {
397 | 5070 |
                     match( TokenTypes.SLASH );
398 |  |
399 | 5070 |
                     switch ( LA(1) )
400 |  |
                     {
401 |  |
402 |  |
                         case TokenTypes.DOT:
403 |  |
                         case TokenTypes.DOT_DOT:
404 |  |
                         case TokenTypes.AT:
405 |  |
                         case TokenTypes.IDENTIFIER:
406 |  |
                         case TokenTypes.STAR:
407 |  |
                         {
408 | 4104 |
                             steps();
409 |  |
                             break;
410 |  |
                         }
411 |  |
                     }
412 | 4950 |
                     break;
413 |  |
                 }
414 |  |
                 case TokenTypes.DOUBLE_SLASH:
415 |  |
                 {
416 | 1014 |
                     getXPathHandler().startAllNodeStep( Axis.DESCENDANT_OR_SELF );
417 | 1014 |
                     getXPathHandler().endAllNodeStep();
418 |  |
419 | 1014 |
                     match( TokenTypes.DOUBLE_SLASH );
420 | 1014 |
                     switch ( LA(1) )
421 |  |
                     {
422 |  |
                         case TokenTypes.DOT:
423 |  |
                         case TokenTypes.DOT_DOT:
424 |  |
                         case TokenTypes.AT:
425 |  |
                         case TokenTypes.IDENTIFIER:
426 |  |
                         case TokenTypes.STAR:
427 |  |
                         {
428 | 984 |
                             steps();
429 | 984 |
                             break;
430 |  |
                         }
431 |  |
                         default:
432 | 30 |
                             XPathSyntaxException ex = this.createSyntaxException("Location path cannot end with //");
433 | 30 |
                             throw ex;
434 |  |
                     }
435 |  |
                     break;
436 |  |
                 }
437 |  |
             }
438 |  |
439 | 5934 |
             getXPathHandler().endAbsoluteLocationPath();
440 | 5934 |
         }
441 |  |
442 |  |
         private void relativeLocationPath() throws SAXPathException
443 |  |
         {
444 | 4050 |
             getXPathHandler().startRelativeLocationPath();
445 |  |
446 | 4050 |
             switch ( LA(1) )
447 |  |
             {
448 |  |
                 case TokenTypes.SLASH:
449 |  |
                 {
450 | 186 |
                     match( TokenTypes.SLASH );
451 | 186 |
                     break;
452 |  |
                 }
453 |  |
                 case TokenTypes.DOUBLE_SLASH:
454 |  |
                 {
455 | 0 |
                     getXPathHandler().startAllNodeStep( Axis.DESCENDANT_OR_SELF );
456 | 0 |
                     getXPathHandler().endAllNodeStep();
457 |  |
458 | 0 |
                     match( TokenTypes.DOUBLE_SLASH );
459 |  |
460 |  |
                     break;
461 |  |
                 }
462 |  |
             }
463 |  |
464 | 4050 |
             steps();
465 |  |
466 | 4002 |
             getXPathHandler().endRelativeLocationPath();
467 | 4002 |
         }
468 |  |
469 |  |
         private void steps() throws SAXPathException
470 |  |
         {
471 | 9138 |
             switch ( LA(1) )
472 |  |
             {
473 |  |
474 |  |
                 case TokenTypes.DOT:
475 |  |
                 case TokenTypes.DOT_DOT:
476 |  |
                 case TokenTypes.AT:
477 |  |
                 case TokenTypes.IDENTIFIER:
478 |  |
                 case TokenTypes.STAR:
479 |  |
                 {
480 | 9126 |
                     step();
481 | 9090 |
                     break;
482 |  |
                 }
483 |  |
                 case TokenTypes.EOF:
484 |  |
                 {
485 | 0 |
                     return;
486 |  |
                 }
487 |  |
                 default:
488 |  |
                 {
489 | 12 |
                     XPathSyntaxException ex = createSyntaxException( "Expected one of '.', '..', '@', '*', <QName>" );
490 | 12 |
                     throw ex;
491 |  |
                 }
492 |  |
             }
493 |  |
494 |  |
             do
495 |  |
             {
496 | 15102 |
                 if ( ( LA(1) == TokenTypes.SLASH)
497 |  |
                      ||
498 |  |
                      ( LA(1) == TokenTypes.DOUBLE_SLASH ) )
499 |  |
                 {
500 | 6132 |
                     switch ( LA(1) )
501 |  |
                     {
502 |  |
                         case TokenTypes.SLASH:
503 |  |
                         {
504 | 6060 |
                             match( TokenTypes.SLASH );
505 | 6060 |
                             break;
506 |  |
                         }
507 |  |
                         case TokenTypes.DOUBLE_SLASH:
508 |  |
                         {
509 | 72 |
                             getXPathHandler().startAllNodeStep( Axis.DESCENDANT_OR_SELF );
510 | 72 |
                             getXPathHandler().endAllNodeStep();
511 |  |
512 | 72 |
                             match( TokenTypes.DOUBLE_SLASH );
513 | 6132 |
                             break;
514 |  |
                         }
515 |  |
                     }
516 |  |
                 }
517 |  |
                 else
518 |  |
                 {
519 | 8970 |
                     return;
520 |  |
                 }
521 |  |
522 | 6132 |
                 switch ( LA(1) )
523 |  |
                 {
524 |  |
                     case TokenTypes.DOT:
525 |  |
                     case TokenTypes.DOT_DOT:
526 |  |
                     case TokenTypes.AT:
527 |  |
                     case TokenTypes.IDENTIFIER:
528 |  |
                     case TokenTypes.STAR:
529 |  |
                     {
530 | 6108 |
                         step();
531 | 6012 |
                         break;
532 |  |
                     }
533 |  |
                     default:
534 |  |
                     {
535 | 24 |
                         XPathSyntaxException ex = createSyntaxException( "Expected one of '.', '..', '@', '*', <QName>" );
536 | 24 |
                         throw ex;
537 |  |
                     }
538 |  |
                 }
539 |  |
540 |  |
             } while ( true );
541 |  |
         }
542 |  |
543 |  |
         void step() throws SAXPathException
544 |  |
         {
545 | 15282 |
             int axis = 0;
546 |  |
547 | 15282 |
             switch ( LA(1) )
548 |  |
             {
549 |  |
                 case TokenTypes.DOT:
550 |  |
                 case TokenTypes.DOT_DOT:
551 |  |
                 {
552 | 648 |
                     abbrStep();
553 | 648 |
                     return;
554 |  |
                 }
555 |  |
                 case TokenTypes.AT:
556 |  |
                 {
557 | 1308 |
                     axis = axisSpecifier();
558 | 1308 |
                     break;
559 |  |
                 }
560 |  |
                 case TokenTypes.IDENTIFIER:
561 |  |
                 {
562 | 11916 |
                     if ( LA(2) == TokenTypes.DOUBLE_COLON )
563 |  |
                     {
564 | 2622 |
                         axis = axisSpecifier();
565 |  |
                     }
566 |  |
                     else
567 |  |
                     {
568 | 9294 |
                         axis = Axis.CHILD;
569 |  |
                     }
570 | 9294 |
                     break;
571 |  |
                 }
572 |  |
                 case TokenTypes.STAR:
573 |  |
                 {
574 | 1410 |
                     axis = Axis.CHILD;
575 |  |
                     break;
576 |  |
                 }
577 |  |
             }
578 |  |
579 | 14622 |
             nodeTest( axis );
580 | 14502 |
         }
581 |  |
582 |  |
         private int axisSpecifier() throws SAXPathException
583 |  |
         {
584 | 3930 |
             int axis = 0;
585 |  |
586 | 3930 |
             switch ( LA(1) )
587 |  |
             {
588 |  |
                 case TokenTypes.AT:
589 |  |
                 {
590 | 1308 |
                     match( TokenTypes.AT );
591 | 1308 |
                     axis = Axis.ATTRIBUTE;
592 | 1308 |
                     break;
593 |  |
                 }
594 |  |
                 case TokenTypes.IDENTIFIER:
595 |  |
                 {
596 | 2622 |
                     Token token = LT( 1 );
597 |  |
598 | 2622 |
                     axis = Axis.lookup( token.getTokenText() );
599 |  |
600 | 2622 |
                     if ( axis == Axis.INVALID_AXIS )
601 |  |
                     {
602 | 12 |
                         throwInvalidAxis( token.getTokenText() );
603 |  |
                     }
604 |  |
605 | 2610 |
                     match( TokenTypes.IDENTIFIER );
606 | 2610 |
                     match( TokenTypes.DOUBLE_COLON );
607 |  |
608 | 2610 |
                     break;
609 |  |
                 }
610 |  |
             }
611 |  |
612 | 3918 |
             return axis;
613 |  |
         }
614 |  |
615 |  |
         private void nodeTest(int axis) throws SAXPathException
616 |  |
         {
617 | 14622 |
             switch ( LA(1) )
618 |  |
             {
619 |  |
                 case TokenTypes.IDENTIFIER:
620 |  |
                 {
621 | 11976 |
                     switch ( LA(2) )
622 |  |
                     {
623 |  |
                         case TokenTypes.LEFT_PAREN:
624 |  |
                         {
625 | 1206 |
                             nodeTypeTest( axis );
626 | 1194 |
                             break;
627 |  |
                         }
628 |  |
                         default:
629 |  |
                         {
630 | 10770 |
                             nameTest( axis );
631 | 10710 |
                             break;
632 |  |
                         }
633 |  |
                     }
634 |  |
                     break;
635 |  |
                 }
636 |  |
                 case TokenTypes.STAR:
637 |  |
                 {
638 | 2598 |
                     nameTest( axis );
639 | 2598 |
                     break;
640 |  |
                 }
641 |  |
                 default:
642 | 48 |
                     XPathSyntaxException ex = createSyntaxException("Expected <QName> or *");
643 | 48 |
                     throw ex;
644 |  |
             }
645 | 14502 |
         }
646 |  |
647 |  |
         private void nodeTypeTest(int axis) throws SAXPathException
648 |  |
         {
649 | 1206 |
             Token  nodeTypeToken = match( TokenTypes.IDENTIFIER );
650 | 1206 |
             String nodeType      = nodeTypeToken.getTokenText();
651 |  |
652 | 1206 |
             match( TokenTypes.LEFT_PAREN );
653 |  |
654 | 1206 |
             if ( "processing-instruction".equals( nodeType ) )
655 |  |
             {
656 | 222 |
                 String piName = "";
657 |  |
658 | 222 |
                 if ( LA(1) == TokenTypes.LITERAL )
659 |  |
                 {
660 | 54 |
                     piName = match( TokenTypes.LITERAL ).getTokenText();
661 |  |
                 }
662 |  |
663 | 222 |
                 match( TokenTypes.RIGHT_PAREN );
664 |  |
665 | 222 |
                 getXPathHandler().startProcessingInstructionNodeStep( axis,
666 |  |
                                                                       piName );
667 |  |
668 | 222 |
                 predicates();
669 |  |
670 | 222 |
                 getXPathHandler().endProcessingInstructionNodeStep();
671 |  |
             }
672 | 984 |
             else if ( "node".equals( nodeType ) )
673 |  |
             {
674 | 570 |
                 match( TokenTypes.RIGHT_PAREN );
675 |  |
676 | 570 |
                 getXPathHandler().startAllNodeStep( axis );
677 |  |
678 | 570 |
                 predicates();
679 |  |
680 | 570 |
                 getXPathHandler().endAllNodeStep();
681 |  |
             }
682 | 414 |
             else if ( "text".equals( nodeType ) )
683 |  |
             {
684 | 246 |
                 match( TokenTypes.RIGHT_PAREN );
685 |  |
686 | 246 |
                 getXPathHandler().startTextNodeStep( axis );
687 |  |
688 | 246 |
                 predicates();
689 |  |
690 | 246 |
                 getXPathHandler().endTextNodeStep();
691 |  |
             }
692 | 168 |
             else if ( "comment".equals( nodeType ) )
693 |  |
             {
694 | 156 |
                 match( TokenTypes.RIGHT_PAREN );
695 |  |
696 | 156 |
                 getXPathHandler().startCommentNodeStep( axis );
697 |  |
698 | 156 |
                 predicates();
699 |  |
700 | 156 |
                 getXPathHandler().endCommentNodeStep();
701 |  |
             }
702 |  |
             else
703 |  |
             {
704 | 12 |
                 XPathSyntaxException ex = createSyntaxException( "Expected node-type" );
705 | 12 |
                 throw ex;
706 |  |
             }
707 | 1194 |
         }
708 |  |
709 |  |
         private void nameTest(int axis) throws SAXPathException
710 |  |
         {
711 | 13368 |
             String prefix    = null;
712 | 13368 |
             String localName = null;
713 |  |
714 | 13368 |
             switch ( LA(2) )
715 |  |
             {
716 |  |
                 case TokenTypes.COLON:
717 |  |
                 {
718 | 540 |
                     switch ( LA(1) )
719 |  |
                     {
720 |  |
                         case TokenTypes.IDENTIFIER:
721 |  |
                         {
722 | 534 |
                             prefix = match( TokenTypes.IDENTIFIER ).getTokenText();
723 | 534 |
                             match( TokenTypes.COLON );
724 |  |
                             break;
725 |  |
                         }
726 |  |
                     }
727 |  |
                     break;
728 |  |
                 }
729 |  |
             }
730 |  |
731 | 13368 |
             switch ( LA(1) )
732 |  |
             {
733 |  |
                 case TokenTypes.IDENTIFIER:
734 |  |
                 {
735 | 10758 |
                     localName = match( TokenTypes.IDENTIFIER ).getTokenText();
736 | 10758 |
                     break;
737 |  |
                 }
738 |  |
                 case TokenTypes.STAR:
739 |  |
                 {
740 | 2610 |
                     match( TokenTypes.STAR );
741 | 2610 |
                     localName = "*";
742 |  |
                     break;
743 |  |
                 }
744 |  |
             }
745 |  |
746 | 13368 |
             if ( prefix == null )
747 |  |
             {
748 | 12834 |
                 prefix = "";
749 |  |
             }
750 |  |
751 | 13368 |
             getXPathHandler().startNameStep( axis,
752 |  |
                                              prefix,
753 |  |
                                              localName );
754 |  |
755 | 13368 |
             predicates();
756 |  |
757 | 13308 |
             getXPathHandler().endNameStep();
758 | 13308 |
         }
759 |  |
760 |  |
         private void abbrStep() throws SAXPathException
761 |  |
         {
762 | 648 |
             switch ( LA(1) )
763 |  |
             {
764 |  |
                 case TokenTypes.DOT:
765 |  |
                 {
766 | 450 |
                     match( TokenTypes.DOT );
767 | 450 |
                     getXPathHandler().startAllNodeStep( Axis.SELF );
768 | 450 |
                     predicates();
769 | 450 |
                     getXPathHandler().endAllNodeStep();
770 | 450 |
                     break;
771 |  |
                 }
772 |  |
                 case TokenTypes.DOT_DOT:
773 |  |
                 {
774 | 198 |
                     match( TokenTypes.DOT_DOT );
775 | 198 |
                     getXPathHandler().startAllNodeStep( Axis.PARENT );
776 | 198 |
                     predicates();
777 | 198 |
                     getXPathHandler().endAllNodeStep();
778 |  |
                     break;
779 |  |
                 }
780 |  |
             }
781 | 648 |
         }
782 |  |
783 |  |
         private void predicates() throws SAXPathException
784 |  |
         {
785 |  |
             while (true )
786 |  |
             {
787 | 31074 |
                 if ( LA(1) == TokenTypes.LEFT_BRACKET )
788 |  |
                 {
789 | 2400 |
                     predicate();
790 |  |
                 }
791 |  |
                 else
792 |  |
                 {
793 |  |
                     break;
794 |  |
                 }
795 |  |
             }
796 | 28674 |
         }
797 |  |
798 |  |
         void predicate() throws SAXPathException
799 |  |
         {
800 | 2400 |
             getXPathHandler().startPredicate();
801 |  |
802 | 2400 |
             match( TokenTypes.LEFT_BRACKET );
803 |  |
804 | 2400 |
             predicateExpr();
805 |  |
806 | 2394 |
             match( TokenTypes.RIGHT_BRACKET );
807 |  |
808 | 2340 |
             getXPathHandler().endPredicate();
809 | 2340 |
         }
810 |  |
811 |  |
         private void predicateExpr() throws SAXPathException
812 |  |
         {
813 | 2400 |
             expr();
814 | 2394 |
         }
815 |  |
816 |  |
         private void expr() throws SAXPathException
817 |  |
         {
818 | 19398 |
             orExpr();
819 | 19110 |
         }
820 |  |
821 |  |
         private void orExpr() throws SAXPathException
822 |  |
         {
823 | 19428 |
             getXPathHandler().startOrExpr();
824 |  |
825 | 19428 |
             andExpr();
826 |  |
827 | 19140 |
             boolean create = false;
828 |  |
829 | 19140 |
             switch ( LA(1) )
830 |  |
             {
831 |  |
                 case TokenTypes.OR:
832 |  |
                 {
833 | 30 |
                     create = true;
834 | 30 |
                     match( TokenTypes.OR );
835 | 30 |
                     orExpr();
836 |  |
                     break;
837 |  |
                 }
838 |  |
             }
839 |  |
840 | 19140 |
             getXPathHandler().endOrExpr( create );
841 | 19140 |
         }
842 |  |
843 |  |
         private void andExpr() throws SAXPathException
844 |  |
         {
845 | 19836 |
             getXPathHandler().startAndExpr();
846 |  |
847 | 19836 |
             equalityExpr();
848 |  |
849 | 19548 |
             boolean create = false;
850 |  |
851 | 19548 |
             switch ( LA(1) )
852 |  |
             {
853 |  |
                 case TokenTypes.AND:
854 |  |
                 {
855 | 408 |
                     create = true;
856 | 408 |
                     match( TokenTypes.AND );
857 | 408 |
                     andExpr();
858 |  |
                     break;
859 |  |
                 }
860 |  |
             }
861 |  |
862 | 19542 |
             getXPathHandler().endAndExpr( create );
863 | 19542 |
         }
864 |  |
865 |  |
         private void equalityExpr() throws SAXPathException
866 |  |
         {
867 | 19836 |
             relationalExpr();
868 |  |
869 | 19548 |
             int la = LA(1);
870 | 21486 |
             while (la == TokenTypes.EQUALS || la == TokenTypes.NOT_EQUALS)
871 |  |
             {
872 | 1938 |
                 switch ( la )
873 |  |
                 {
874 |  |
                     case TokenTypes.EQUALS:
875 |  |
                     {
876 | 1722 |
                         match( TokenTypes.EQUALS );
877 | 1722 |
                         getXPathHandler().startEqualityExpr();
878 | 1722 |
                         relationalExpr();
879 | 1722 |
                         getXPathHandler().endEqualityExpr( Operator.EQUALS );
880 | 1722 |
                         break;
881 |  |
                     }
882 |  |
                     case TokenTypes.NOT_EQUALS:
883 |  |
                     {
884 | 216 |
                         match( TokenTypes.NOT_EQUALS );
885 | 216 |
                         getXPathHandler().startEqualityExpr();
886 | 216 |
                         relationalExpr();
887 | 216 |
                         getXPathHandler().endEqualityExpr( Operator.NOT_EQUALS );
888 |  |
                         break;
889 |  |
                     }
890 |  |
                 }
891 | 1938 |
                 la = LA(1);
892 |  |
             }
893 | 19548 |
         }
894 |  |
895 |  |
         private void relationalExpr() throws SAXPathException
896 |  |
         {
897 |  |
898 | 21774 |
             additiveExpr();
899 |  |
900 | 21486 |
             int la = LA(1);
901 |  |
             // Very important: TokenTypes.LESS_THAN != Operator.LESS_THAN
902 |  |
             //                 TokenTypes.GREATER_THAN != Operator.GREATER_THAN
903 |  |
             //                 TokenTypes.GREATER_THAN_EQUALS != Operator.GREATER_THAN_EQUALS
904 |  |
             //                 TokenTypes.LESS_THAN_EQUALS != Operator.LESS_THAN_EQUALS
905 |  |
             while (la == TokenTypes.LESS_THAN_SIGN
906 |  |
                 || la == TokenTypes.GREATER_THAN_SIGN
907 |  |
                 || la == TokenTypes.LESS_THAN_OR_EQUALS_SIGN
908 | 22092 |
                 || la == TokenTypes.GREATER_THAN_OR_EQUALS_SIGN ) {
909 | 606 |
                 switch ( la )
910 |  |
                 {
911 |  |
                     case TokenTypes.LESS_THAN_SIGN:
912 |  |
                     {
913 | 150 |
                         match( TokenTypes.LESS_THAN_SIGN );
914 | 150 |
                         getXPathHandler().startRelationalExpr();
915 | 150 |
                         additiveExpr();
916 | 150 |
                         getXPathHandler().endRelationalExpr( Operator.LESS_THAN );
917 | 150 |
                         break;
918 |  |
                     }
919 |  |
                     case TokenTypes.GREATER_THAN_SIGN:
920 |  |
                     {
921 | 204 |
                         match( TokenTypes.GREATER_THAN_SIGN );
922 | 204 |
                         getXPathHandler().startRelationalExpr();
923 | 204 |
                         additiveExpr();
924 | 204 |
                         getXPathHandler().endRelationalExpr( Operator.GREATER_THAN );
925 | 204 |
                         break;
926 |  |
                     }
927 |  |
                     case TokenTypes.GREATER_THAN_OR_EQUALS_SIGN:
928 |  |
                     {
929 | 156 |
                         match( TokenTypes.GREATER_THAN_OR_EQUALS_SIGN );
930 | 156 |
                         getXPathHandler().startRelationalExpr();
931 | 156 |
                         additiveExpr();
932 | 156 |
                         getXPathHandler().endRelationalExpr( Operator.GREATER_THAN_EQUALS );
933 | 156 |
                         break;
934 |  |
                     }
935 |  |
                     case TokenTypes.LESS_THAN_OR_EQUALS_SIGN:
936 |  |
                     {
937 | 96 |
                         match( TokenTypes.LESS_THAN_OR_EQUALS_SIGN );
938 | 96 |
                         getXPathHandler().startRelationalExpr();
939 | 96 |
                         additiveExpr();
940 | 96 |
                         getXPathHandler().endRelationalExpr( Operator.LESS_THAN_EQUALS );
941 |  |
                         break;
942 |  |
                     }
943 |  |
                 }
944 | 606 |
                 la = LA(1);
945 |  |
             }
946 | 21486 |
         }
947 |  |
948 |  |
949 |  |
         private void additiveExpr() throws SAXPathException
950 |  |
         {
951 | 22380 |
             multiplicativeExpr();
952 |  |
953 | 22098 |
             int la = LA(1);
954 | 22746 |
             while (la == TokenTypes.PLUS || la == TokenTypes.MINUS)
955 |  |
             {
956 | 654 |
                 switch ( la )
957 |  |
                 {
958 |  |
                     case TokenTypes.PLUS:
959 |  |
                     {
960 | 438 |
                         match( TokenTypes.PLUS );
961 | 438 |
                         getXPathHandler().startAdditiveExpr();
962 | 438 |
                         multiplicativeExpr();
963 | 432 |
                         getXPathHandler().endAdditiveExpr( Operator.ADD );
964 | 432 |
                         break;
965 |  |
                     }
966 |  |
                     case TokenTypes.MINUS:
967 |  |
                     {
968 | 216 |
                         match( TokenTypes.MINUS );
969 | 216 |
                         getXPathHandler().startAdditiveExpr();
970 | 216 |
                         multiplicativeExpr();
971 | 216 |
                         getXPathHandler().endAdditiveExpr( Operator.SUBTRACT );
972 |  |
                         break;
973 |  |
                     }
974 |  |
                 }
975 | 648 |
                 la = LA(1);
976 |  |
             }
977 | 22092 |
         }
978 |  |
979 |  |
         private void multiplicativeExpr() throws SAXPathException
980 |  |
         {
981 | 23034 |
             unaryExpr();
982 |  |
983 | 22746 |
             int la = LA(1);
984 | 23256 |
             while (la == TokenTypes.STAR || la == TokenTypes.DIV || la == TokenTypes.MOD)
985 |  |
             {
986 | 510 |
                 switch ( la )
987 |  |
                 {
988 |  |
                     case TokenTypes.STAR:
989 |  |
                     {
990 | 150 |
                         match( TokenTypes.STAR );
991 | 150 |
                         getXPathHandler().startMultiplicativeExpr();
992 | 150 |
                         unaryExpr();
993 | 150 |
                         getXPathHandler().endMultiplicativeExpr( Operator.MULTIPLY );
994 | 150 |
                         break;
995 |  |
                     }
996 |  |
                     case TokenTypes.DIV:
997 |  |
                     {
998 | 294 |
                         match( TokenTypes.DIV );
999 | 294 |
                         getXPathHandler().startMultiplicativeExpr();
1000 | 294 |
                         unaryExpr();
1001 | 294 |
                         getXPathHandler().endMultiplicativeExpr( Operator.DIV );
1002 | 294 |
                         break;
1003 |  |
                     }
1004 |  |
                     case TokenTypes.MOD:
1005 |  |
                     {
1006 | 66 |
                         match( TokenTypes.MOD );
1007 | 66 |
                         getXPathHandler().startMultiplicativeExpr();
1008 | 66 |
                         unaryExpr();
1009 | 66 |
                         getXPathHandler().endMultiplicativeExpr( Operator.MOD );
1010 |  |
                         break;
1011 |  |
                     }
1012 |  |
                 }
1013 | 510 |
                 la = LA(1);
1014 |  |
             }
1015 |  |
1016 | 22746 |
         }
1017 |  |
1018 |  |
         private void unaryExpr() throws SAXPathException
1019 |  |
         {
1020 | 23784 |
             switch ( LA(1) )
1021 |  |
             {
1022 |  |
                 case TokenTypes.MINUS:
1023 |  |
                 {
1024 | 240 |
                     getXPathHandler().startUnaryExpr();
1025 | 240 |
                     match( TokenTypes.MINUS );
1026 | 240 |
                     unaryExpr();
1027 | 240 |
                     getXPathHandler().endUnaryExpr( Operator.NEGATIVE );
1028 | 240 |
                     break;
1029 |  |
                 }
1030 |  |
                 default:
1031 |  |
                 {
1032 | 23544 |
                     unionExpr();
1033 |  |
                     break;
1034 |  |
                 }
1035 |  |
             }
1036 |  |
1037 |  |
1038 | 23496 |
         }
1039 |  |
1040 |  |
         private void unionExpr() throws SAXPathException
1041 |  |
         {
1042 | 23544 |
             getXPathHandler().startUnionExpr();
1043 |  |
1044 | 23544 |
             pathExpr();
1045 |  |
1046 | 23256 |
             boolean create = false;
1047 |  |
1048 | 23256 |
             switch ( LA(1) )
1049 |  |
             {
1050 |  |
                 case TokenTypes.PIPE:
1051 |  |
                 {
1052 | 120 |
                     match( TokenTypes.PIPE );
1053 | 120 |
                     create = true;
1054 | 120 |
                     expr();
1055 |  |
                     break;
1056 |  |
                 }
1057 |  |
             }
1058 |  |
1059 | 23256 |
             getXPathHandler().endUnionExpr( create );
1060 | 23256 |
         }
1061 |  |
1062 |  |
         private Token match(int tokenType) throws XPathSyntaxException
1063 |  |
         {
1064 | 72162 |
             LT(1);
1065 |  |
1066 | 72162 |
             Token token = (Token) tokens.get( 0 );
1067 |  |
1068 | 72162 |
             if ( token.getTokenType() == tokenType )
1069 |  |
             {
1070 | 72078 |
                 tokens.removeFirst();
1071 | 72078 |
                 return token;
1072 |  |
             }
1073 |  |
1074 |  |
1075 | 84 |
             XPathSyntaxException ex = createSyntaxException( "Expected: " + TokenTypes.getTokenText( tokenType ) );
1076 | 84 |
             throw ex;
1077 |  |
         }
1078 |  |
1079 |  |
         private int LA(int position)
1080 |  |
         {
1081 | 464820 |
             return LT(position).getTokenType();
1082 |  |
         }
1083 |  |
1084 |  |
         private Token LT(int position)
1085 |  |
         {
1086 | 544710 |
             if ( tokens.size() <= ( position - 1 ) )
1087 |  |
             {
1088 | 151062 |
                 for ( int i = 0 ; i < position ; ++i )
1089 |  |
                 {
1090 | 86538 |
                     tokens.add( lexer.nextToken() );
1091 |  |
                 }
1092 |  |
             }
1093 |  |
1094 | 544710 |
             return (Token) tokens.get( position - 1 );
1095 |  |
         }
1096 |  |
1097 |  |
         private boolean isNodeTypeName(Token name)
1098 |  |
         {
1099 | 4710 |
             String text = name.getTokenText();
1100 |  |
1101 | 4710 |
             if ( "node".equals( text )
1102 |  |
                  ||
1103 |  |
                  "comment".equals( text )
1104 |  |
                  ||
1105 |  |
                  "text".equals( text )
1106 |  |
                  ||
1107 |  |
                  "processing-instruction".equals( text ) )
1108 |  |
             {
1109 | 84 |
                 return true;
1110 |  |
             }
1111 |  |
1112 | 4626 |
             return false;
1113 |  |
         }
1114 |  |
1115 |  |
         private XPathSyntaxException createSyntaxException(String message)
1116 |  |
         {
1117 | 300 |
             String xpath    = this.lexer.getXPath();
1118 | 300 |
             int    position = LT(1).getTokenBegin();
1119 |  |
1120 | 300 |
             return new XPathSyntaxException( xpath,
1121 |  |
                                              position,
1122 |  |
                                              message );
1123 |  |
         }
1124 |  |
1125 |  |
         private void throwInvalidAxis(String invalidAxis) throws SAXPathException
1126 |  |
         {
1127 | 12 |
             String xpath    = this.lexer.getXPath();
1128 | 12 |
             int    position = LT(1).getTokenBegin();
1129 |  |
1130 | 12 |
             String message  = "Expected valid axis name instead of [" + invalidAxis + "]";
1131 |  |
1132 | 12 |
             throw new XPathSyntaxException( xpath,
1133 |  |
                                             position,
1134 |  |
                                             message );
1135 |  |
         }
1136 |  |
     }