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