Coverage Report - org.jaxen.saxpath.base.XPathLexer
 
Classes in this File Line Coverage Branch Coverage Complexity
XPathLexer
100%
421/421
100%
53/53
4.2
 
 1  
 /*
 2  
  * $Header$
 3  
  * $Revision: 1334 $
 4  
  * $Date: 2008-11-29 09:58:48 -0800 (Sat, 29 Nov 2008) $
 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: XPathLexer.java 1334 2008-11-29 17:58:48Z elharo $
 47  
  */
 48  
 
 49  
 package org.jaxen.saxpath.base;
 50  
 
 51  
 class XPathLexer
 52  
 {
 53  
     private String xpath;
 54  
     private int    currentPosition;
 55  
     private int    endPosition;
 56  12528
     private boolean expectOperator = false;
 57  
 
 58  
     XPathLexer(String xpath)
 59  12528
     {
 60  12528
         setXPath( xpath );
 61  12528
     }
 62  
 
 63  3118
     private void setXPath(String xpath)
 64  3118
     {
 65  15646
         this.xpath           = xpath;
 66  12528
         this.currentPosition = 0;
 67  12528
         this.endPosition     = xpath.length();
 68  12528
     }
 69  3118
 
 70  3118
     String getXPath()
 71  3118
     {
 72  591094
         return this.xpath;
 73  
     }
 74  
 
 75  
     Token nextToken()
 76  146404
     {
 77  119468
         Token token = null;
 78  
 
 79  
         do
 80  
         {
 81  161835
             token = null;
 82  
 
 83  132064
             switch ( LA(1) )
 84  
             {
 85  32891
                 case '$':
 86  
                 {
 87  33059
                     token = dollar();
 88  168
                     break;
 89  
                 }
 90  
                     
 91  42
                 case '"':
 92  42
                 case '\'':
 93  
                 {
 94  4532
                     token = literal();
 95  4532
                     break;
 96  
                 }
 97  
                     
 98  1127
                 case '/':
 99  1127
                 {
 100  14056
                     token = slashes();
 101  14056
                     break;
 102  
                 }
 103  
 
 104  3500
                 case ',':
 105  3500
                 {
 106  2060
                     token = comma();
 107  2060
                     break;
 108  
                 }
 109  
                     
 110  513
                 case '(':
 111  513
                 {
 112  10308
                     token = leftParen();
 113  10308
                     break;
 114  
                 }
 115  
                     
 116  2569
                 case ')':
 117  2569
                 {
 118  10256
                     token = rightParen();
 119  10256
                     break;
 120  
                 }
 121  
                     
 122  2556
                 case '[':
 123  2556
                 {
 124  2760
                     token = leftBracket();
 125  2760
                     break;
 126  
                 }
 127  
                     
 128  688
                 case ']':
 129  688
                 {
 130  2716
                     token = rightBracket();
 131  2716
                     break;
 132  
                 }
 133  
                     
 134  677
                 case '+':
 135  677
                 {
 136  600
                     token = plus();
 137  600
                     break;
 138  
                 }
 139  
                     
 140  150
                 case '-':
 141  150
                 {
 142  688
                     token = minus();
 143  688
                     break;
 144  
                 }
 145  
                     
 146  172
                 case '<':
 147  172
                 case '>':
 148  
                 {
 149  920
                     token = relationalOperator();
 150  920
                     break;
 151  
                 }        
 152  
 
 153  230
                 case '=':
 154  230
                 {
 155  2280
                     token = equals();
 156  2280
                     break;
 157  
                 }
 158  
                     
 159  565
                 case '!':
 160  565
                 {
 161  308
                     if ( LA(2) == '=' )
 162  
                     {
 163  292
                         token = notEquals();
 164  
                     }
 165  72
                     break;
 166  
                 }
 167  68
                     
 168  
                 case '|':
 169  
                 {
 170  80
                     token = pipe();
 171  80
                     break;
 172  
                 }
 173  
                     
 174  20
                 case '@':
 175  20
                 {
 176  876
                     token = at();
 177  876
                     break;
 178  
                 }
 179  
                     
 180  219
                 case ':':
 181  219
                 {
 182  9940
                     if ( LA(2) == ':' )
 183  
                     {
 184  9252
                         token = doubleColon();
 185  
                     }
 186  2485
                     else
 187  
                     {
 188  3001
                         token = colon();
 189  
                     }
 190  688
                     break;
 191  
                 }
 192  172
                     
 193  
                 case '*':
 194  172
                 {
 195  3272
                     token = star();
 196  3272
                     break;
 197  
                 }
 198  
                     
 199  814
                 case '.':
 200  814
                 {
 201  468
                     switch ( LA(2) )
 202  
                     {
 203  
                         case '0':
 204  
                         case '1':
 205  117
                         case '2':
 206  
                         case '3':
 207  
                         case '4':
 208  
                         case '5':
 209  
                         case '6':
 210  
                         case '7':
 211  
                         case '8':
 212  
                         case '9':
 213  
                         {
 214  24
                             token = number();
 215  24
                             break;
 216  
                         }
 217  
                         default:
 218  6
                         {
 219  450
                             token = dots();
 220  444
                             break;
 221  
                         }
 222  
                     }
 223  111
                     break;
 224  111
                 }
 225  
 
 226  
                 case '0':
 227  
                 case '1':
 228  
                 case '2':
 229  
                 case '3':
 230  
                 case '4':
 231  
                 case '5':
 232  
                 case '6':
 233  
                 case '7':
 234  
                 case '8':
 235  
                 case '9':
 236  
                 {
 237  6304
                     token = number();
 238  6304
                     break;
 239  
                 }
 240  
 
 241  1574
                 case ' ':
 242  1574
                 case '\t':
 243  
                 case '\n':
 244  
                 case '\r':
 245  
                 {
 246  12596
                     token = whitespace();
 247  12596
                     break;
 248  
                 }
 249  
                     
 250  3120
                 default:
 251  3120
                 {
 252  46876
                     if ( Verifier.isXMLNCNameStartCharacter( LA(1) ) )
 253  
                     {
 254  30920
                         token = identifierOrOperatorName();
 255  
                     }
 256  11681
                 }
 257  
             }
 258  7708
 
 259  132064
             if ( token == null )
 260  
             {
 261  16036
                 if (!hasMoreChars())
 262  
                 {
 263  48863
                     token = new Token( TokenTypes.EOF,
 264  
                                    getXPath(),
 265  3993
                                    this.currentPosition,
 266  
                                    this.endPosition );
 267  3977
             }
 268  
                 else
 269  
                 {
 270  64
                     token = new Token( TokenTypes.ERROR,
 271  
                                    getXPath(),
 272  
                                    this.currentPosition,
 273  
                                    this.endPosition );
 274  16
                 }
 275  
             }
 276  
 
 277  
         }
 278  132064
         while (token.getTokenType() == TokenTypes.SKIP );
 279  
         
 280  
         // For some reason, section 3.7, Lexical structure,
 281  
         // doesn't seem to feel like it needs to mention the
 282  32891
         // SLASH, DOUBLE_SLASH, and COLON tokens for the test
 283  
         // if an NCName is an operator or not.
 284  29771
         //
 285  
         // According to section 3.7, "/foo" should be considered
 286  29771
         // as a SLASH following by an OperatorName being 'foo'.
 287  
         // Which is just simply, clearly, wrong, in my mind.
 288  
         //
 289  
         //     -bob
 290  
 
 291  127176
         switch ( token.getTokenType() )
 292  
         {
 293  7708
             case TokenTypes.AT:
 294  
             case TokenTypes.DOUBLE_COLON:
 295  
             case TokenTypes.LEFT_PAREN:
 296  
             case TokenTypes.LEFT_BRACKET:
 297  
             case TokenTypes.AND:
 298  
             case TokenTypes.OR:
 299  
             case TokenTypes.MOD:
 300  
             case TokenTypes.DIV:
 301  
             case TokenTypes.COLON:
 302  
             case TokenTypes.SLASH:
 303  
             case TokenTypes.DOUBLE_SLASH:
 304  
             case TokenTypes.PIPE:
 305  
             case TokenTypes.DOLLAR:
 306  6325
             case TokenTypes.PLUS:
 307  
             case TokenTypes.MINUS:
 308  
             case TokenTypes.STAR_OPERATOR:
 309  
             case TokenTypes.COMMA:
 310  
             case TokenTypes.LESS_THAN_SIGN:
 311  
             case TokenTypes.GREATER_THAN_SIGN:
 312  
             case TokenTypes.LESS_THAN_OR_EQUALS_SIGN:
 313  
             case TokenTypes.GREATER_THAN_OR_EQUALS_SIGN:
 314  
             case TokenTypes.EQUALS:
 315  
             case TokenTypes.NOT_EQUALS:
 316  
             {
 317  46332
                 expectOperator = false;
 318  46332
                 break;
 319  
             }
 320  
             default:
 321  
             {
 322  73136
                 expectOperator = true;
 323  
                 break;
 324  
             }
 325  
         }
 326  
 
 327  119468
          return token;
 328  
      }
 329  
 
 330  
     private Token identifierOrOperatorName()
 331  
     {
 332  36970
         Token token = null;
 333  36970
         if ( expectOperator ) {
 334  1108
             token = operatorName();
 335  
         } else {
 336  29812
             token = identifier();
 337  275
         }
 338  31195
         return token;
 339  
     }
 340  
     
 341  
     private Token identifier()
 342  
     {
 343  29812
         Token token = null;
 344  1383
     
 345  29812
         int start = this.currentPosition;
 346  
     
 347  220632
         while ( hasMoreChars() )
 348  
         {
 349  210200
             if ( Verifier.isXMLNCNameCharacter( LA(1) ) )
 350  
             {
 351  183112
                 consume();
 352  7433
             }
 353  
             else
 354  7433
             {
 355  
                 break;
 356  53115
             }
 357  
         }
 358  52436
     
 359  29812
         token = new Token( TokenTypes.IDENTIFIER,
 360  45682
                            getXPath(),
 361  
                            start,
 362  
                            this.currentPosition );
 363  
     
 364  29812
         return token;
 365  
     }
 366  
     
 367  
     private Token operatorName()
 368  7433
     {
 369  1108
         Token token = null;
 370  
     
 371  1108
         switch ( LA(1) )
 372  
         {
 373  7433
             case 'a':
 374  
             {
 375  508
                 token = and();
 376  508
                 break;
 377  
             }
 378  275
     
 379  
             case 'o':
 380  275
             {
 381  40
                 token = or();
 382  40
                 break;
 383  
             }
 384  127
     
 385  127
             case 'm':
 386  
             {
 387  140
                 token = mod();
 388  140
                 break;
 389  
             }
 390  8
     
 391  8
             case 'd':
 392  
             {
 393  372
                 token = div();
 394  
                 break;
 395  
             }
 396  35
         }
 397  35
     
 398  1108
         return token;
 399  
     }
 400  
     
 401  
     private Token mod()
 402  93
     {
 403  140
         Token token = null;
 404  
     
 405  140
         if ( ( LA(1) == 'm' )
 406  
              &&
 407  275
              ( LA(2) == 'o' )
 408  
              &&
 409  
              ( LA(3) == 'd' )
 410  
            )
 411  
         {
 412  175
             token = new Token( TokenTypes.MOD,
 413  
                                getXPath(),
 414  35
                                this.currentPosition,
 415  
                                this.currentPosition+3 );
 416  
     
 417  140
             consume();
 418  140
             consume();
 419  140
             consume();
 420  
         }
 421  35
     
 422  140
         return token;
 423  
     }
 424  
     
 425  
     private Token div()
 426  35
     {
 427  407
         Token token = null;
 428  35
     
 429  372
         if ( ( LA(1) == 'd' )
 430  
              &&
 431  35
              ( LA(2) == 'i' )
 432  
              &&
 433  
              ( LA(3) == 'v' )
 434  
             )
 435  
         {
 436  465
             token = new Token( TokenTypes.DIV,
 437  
                                getXPath(),
 438  93
                                this.currentPosition,
 439  
                                this.currentPosition+3 );
 440  
     
 441  372
             consume();
 442  372
             consume();
 443  372
             consume();
 444  
         }
 445  93
     
 446  372
         return token;
 447  
     }
 448  
     
 449  
     private Token and()
 450  93
     {
 451  601
         Token token = null;
 452  93
     
 453  508
         if ( ( LA(1) == 'a' )
 454  
              &&
 455  93
              ( LA(2) == 'n' )
 456  
              &&
 457  
              ( LA(3) == 'd' )
 458  
            )
 459  
         {
 460  635
             token = new Token( TokenTypes.AND,
 461  
                                getXPath(),
 462  127
                                this.currentPosition,
 463  
                                this.currentPosition+3 );
 464  
     
 465  508
             consume();
 466  508
             consume();
 467  508
             consume();
 468  
         }
 469  127
     
 470  508
         return token;
 471  
     }
 472  
     
 473  
     private Token or()
 474  127
     {
 475  167
         Token token = null;
 476  127
     
 477  40
         if ( ( LA(1) == 'o' )
 478  
              &&
 479  127
              ( LA(2) == 'r' )
 480  
            )
 481  
         {
 482  40
             token = new Token( TokenTypes.OR,
 483  
                                getXPath(),
 484  8
                                this.currentPosition,
 485  
                                this.currentPosition+2 );
 486  8
     
 487  40
             consume();
 488  40
             consume();
 489  
         }
 490  
     
 491  48
         return token;
 492  
     }
 493  
     
 494  
     private Token number()
 495  
     {
 496  6336
         int     start         = this.currentPosition;
 497  6336
         boolean periodAllowed = true;
 498  
     
 499  
       loop:
 500  8
         while( true )
 501  
         {
 502  20180
             switch ( LA(1) )
 503  
             {
 504  
                 case '.':
 505  4948
                     if ( periodAllowed )
 506  1580
                     {
 507  3368
                         periodAllowed = false;
 508  3368
                         consume();
 509  
                     }
 510  
                     else
 511  5038
                     {
 512  
                         break loop;
 513  
                     }
 514  842
                     break;
 515  
                 case '0':
 516  842
                 case '1':
 517  842
                 case '2':
 518  
                 case '3':
 519  
                 case '4':
 520  
                 case '5':
 521  
                 case '6':
 522  
                 case '7':
 523  
                 case '8':
 524  
                 case '9':
 525  10484
                     consume();
 526  10484
                     break;
 527  
                 default:
 528  6328
                     break loop;
 529  
             }
 530  
         }
 531  
     
 532  6328
         return new Token( TokenTypes.DOUBLE,
 533  
                                getXPath(),
 534  2616
                                start,
 535  2616
                                this.currentPosition );
 536  
     }
 537  1580
     
 538  
     private Token whitespace()
 539  
     {
 540  12596
         consume();
 541  1580
             
 542  
       loop:
 543  12600
         while( hasMoreChars() )
 544  
         {
 545  12564
             switch ( LA(1) )
 546  
             {
 547  
                 case ' ':
 548  
                 case '\t':
 549  3120
                 case '\n':
 550  
                 case '\r':
 551  
                 {
 552  3125
                     consume();
 553  4
                     break;
 554  3112
                 }
 555  
                     
 556  
                 default:
 557  
                 {
 558  12560
                     break loop;
 559  
                 }
 560  
             }
 561  1
         }
 562  1
     
 563  12596
         return new Token( TokenTypes.SKIP,
 564  
                           getXPath(),
 565  
                           0,
 566  
                           0 );
 567  3111
     }
 568  
     
 569  
     private Token comma()
 570  
     {
 571  2060
         Token token = new Token( TokenTypes.COMMA,
 572  3120
                                  getXPath(),
 573  
                                  this.currentPosition,
 574  
                                  this.currentPosition+1 );
 575  
     
 576  2060
         consume();
 577  
     
 578  2060
         return token;
 579  
     }
 580  513
     
 581  
     private Token equals()
 582  
     {
 583  2280
         Token token = new Token( TokenTypes.EQUALS,
 584  
                                  getXPath(),
 585  513
                                  this.currentPosition,
 586  
                                  this.currentPosition+1 );
 587  513
     
 588  2280
         consume();
 589  
     
 590  2280
         return token;
 591  
     }
 592  565
     
 593  
     private Token minus()
 594  
     {
 595  688
         Token token = new Token( TokenTypes.MINUS,
 596  
                                  getXPath(),
 597  565
                                  this.currentPosition,
 598  
                                  this.currentPosition+1 );
 599  1253
         consume();
 600  
             
 601  688
         return token;
 602  
     }
 603  
     
 604  172
     private Token plus()
 605  
     {
 606  600
         Token token = new Token( TokenTypes.PLUS,
 607  
                                  getXPath(),
 608  172
                                  this.currentPosition,
 609  
                                  this.currentPosition+1 );
 610  772
         consume();
 611  
     
 612  600
         return token;
 613  
     }
 614  
     
 615  150
     private Token dollar()
 616  
     {
 617  168
         Token token = new Token( TokenTypes.DOLLAR,
 618  
                                  getXPath(),
 619  150
                                  this.currentPosition,
 620  
                                  this.currentPosition+1 );
 621  318
         consume();
 622  
     
 623  168
         return token;
 624  
     }
 625  
     
 626  42
     private Token pipe()
 627  
     {
 628  80
         Token token = new Token( TokenTypes.PIPE,
 629  
                                  getXPath(),
 630  42
                                  this.currentPosition,
 631  
                                  this.currentPosition+1 );
 632  42
     
 633  80
         consume();
 634  
     
 635  80
         return token;
 636  
     }
 637  20
     
 638  
     private Token at()
 639  
     {
 640  876
         Token token = new Token( TokenTypes.AT,
 641  
                                  getXPath(),
 642  20
                                  this.currentPosition,
 643  
                                  this.currentPosition+1 );
 644  20
     
 645  876
         consume();
 646  
     
 647  876
         return token;
 648  
     }
 649  219
     
 650  
     private Token colon()
 651  
     {
 652  688
         Token token = new Token( TokenTypes.COLON,
 653  
                                  getXPath(),
 654  219
                                  this.currentPosition,
 655  
                                  this.currentPosition+1 );
 656  907
         consume();
 657  
     
 658  688
         return token;
 659  
     }
 660  
     
 661  172
     private Token doubleColon()
 662  
     {
 663  9252
         Token token = new Token( TokenTypes.DOUBLE_COLON,
 664  
                                  getXPath(),
 665  172
                                  this.currentPosition,
 666  
                                  this.currentPosition+2 );
 667  172
     
 668  9252
         consume();
 669  9252
         consume();
 670  
     
 671  9252
         return token;
 672  2313
     }
 673  
     
 674  
     private Token notEquals()
 675  
     {
 676  292
         Token token = new Token( TokenTypes.NOT_EQUALS,
 677  2313
                                  getXPath(),
 678  2313
                                  this.currentPosition,
 679  
                                  this.currentPosition + 2 );
 680  2313
     
 681  292
         consume();
 682  292
         consume();
 683  
     
 684  292
         return token;
 685  68
     }
 686  
     
 687  
     private Token relationalOperator()
 688  
     {
 689  920
         Token token = null;
 690  68
     
 691  988
         switch ( LA(1) )
 692  
         {
 693  68
             case '<':
 694  
             {
 695  436
                 if ( LA(2) == '=' )
 696  
                 {
 697  192
                     token = new Token( TokenTypes.LESS_THAN_OR_EQUALS_SIGN,
 698  230
                                        getXPath(),
 699  
                                        this.currentPosition,
 700  230
                                        this.currentPosition + 2 );
 701  192
                     consume();
 702  
                 }
 703  
                 else
 704  109
                 {
 705  244
                     token = new Token( TokenTypes.LESS_THAN_SIGN,
 706  48
                                        getXPath(),
 707  
                                        this.currentPosition,
 708  
                                        this.currentPosition + 1);
 709  
                 }
 710  48
     
 711  436
                 consume();
 712  436
                 break;
 713  
             }
 714  61
             case '>':
 715  
             {
 716  484
                 if ( LA(2) == '=' )
 717  
                 {
 718  232
                     token = new Token( TokenTypes.GREATER_THAN_OR_EQUALS_SIGN,
 719  
                                        getXPath(),
 720  109
                                        this.currentPosition,
 721  109
                                        this.currentPosition + 2 );
 722  232
                     consume();
 723  
                 }
 724  
                 else
 725  121
                 {
 726  252
                     token = new Token( TokenTypes.GREATER_THAN_SIGN,
 727  58
                                        getXPath(),
 728  
                                        this.currentPosition,
 729  
                                        this.currentPosition + 1 );
 730  
                 }
 731  58
     
 732  484
                 consume();
 733  
                 break;
 734  
             }
 735  63
         }
 736  
     
 737  920
         return token;
 738  
                 
 739  
     }
 740  
     
 741  121
     // ????
 742  
     private Token star()
 743  
     {
 744  3272
         int tokenType = expectOperator ? TokenTypes.STAR_OPERATOR : TokenTypes.STAR;
 745  3272
          Token token = new Token( tokenType,
 746  230
                          getXPath(),
 747  
                          this.currentPosition,
 748  
                          this.currentPosition+1 );
 749  
     
 750  3272
         consume();
 751  
             
 752  4086
         return token;
 753  
     }
 754  
     
 755  
     private Token literal()
 756  
     {
 757  5346
         Token token = null;
 758  
     
 759  5346
         char match  = LA(1);
 760  
     
 761  4532
         consume();
 762  
     
 763  4532
         int start = this.currentPosition;
 764  1127
             
 765  
         while ( ( token == null )
 766  36967
                 &&
 767  
                 hasMoreChars() )
 768  1127
         {
 769  31308
             if ( LA(1) == match )
 770  1127
             {
 771  4516
                 token = new Token( TokenTypes.LITERAL,
 772  
                                    getXPath(),
 773  8799
                                    start,
 774  
                                    this.currentPosition );
 775  
             }
 776  38980
             consume();
 777  
         }
 778  1123
     
 779  4532
         return token;
 780  
     }
 781  
     
 782  
     private Token dots()
 783  7672
     {
 784  444
         Token token = null;
 785  
     
 786  1571
         switch ( LA(2) )
 787  
         {
 788  
             case '.':
 789  
             {
 790  132
                 token = new Token( TokenTypes.DOT_DOT,
 791  111
                                    getXPath(),
 792  
                                    this.currentPosition,
 793  111
                                    this.currentPosition+2 ) ;
 794  132
                 consume();
 795  132
                 consume();
 796  132
                 break;
 797  33
             }
 798  
             default:
 799  
             {
 800  312
                 token = new Token( TokenTypes.DOT,
 801  33
                                    getXPath(),
 802  33
                                    this.currentPosition,
 803  33
                                    this.currentPosition+1 );
 804  312
                 consume();
 805  
                 break;
 806  
             }
 807  78
         }
 808  
     
 809  444
         return token;
 810  
     }
 811  78
     
 812  
     private Token leftBracket()
 813  
     {
 814  2760
         Token token = new Token( TokenTypes.LEFT_BRACKET,
 815  
                                  getXPath(),
 816  111
                                  this.currentPosition,
 817  
                                  this.currentPosition+1 );
 818  
     
 819  2760
         consume();
 820  
     
 821  3448
         return token;
 822  
     }
 823  
     
 824  
     private Token rightBracket()
 825  
     {
 826  3404
         Token token = new Token( TokenTypes.RIGHT_BRACKET,
 827  
                                  getXPath(),
 828  688
                                  this.currentPosition,
 829  
                                  this.currentPosition+1 );
 830  
     
 831  2716
         consume();
 832  
     
 833  3393
         return token;
 834  
     }
 835  
     
 836  
     private Token leftParen()
 837  
     {
 838  10985
         Token token = new Token( TokenTypes.LEFT_PAREN,
 839  
                                  getXPath(),
 840  677
                                  this.currentPosition,
 841  
                                  this.currentPosition+1 );
 842  
     
 843  10308
         consume();
 844  
     
 845  12877
         return token;
 846  
     }
 847  
     
 848  
     private Token rightParen()
 849  
     {
 850  12825
         Token token = new Token( TokenTypes.RIGHT_PAREN,
 851  
                                  getXPath(),
 852  2569
                                  this.currentPosition,
 853  
                                  this.currentPosition+1 );
 854  
     
 855  10256
         consume();
 856  
     
 857  12812
         return token;
 858  
     }
 859  
     
 860  
     private Token slashes()
 861  
     {
 862  16612
         Token token = null;
 863  
     
 864  16612
         switch ( LA(2) )
 865  
         {
 866  
             case '/':
 867  
             {
 868  808
                 token = new Token( TokenTypes.DOUBLE_SLASH,
 869  3500
                                    getXPath(),
 870  
                                    this.currentPosition,
 871  3500
                                    this.currentPosition+2 );
 872  808
                 consume();
 873  808
                 consume();
 874  808
                 break;
 875  190
             }
 876  
             default:
 877  
             {
 878  13248
                 token = new Token( TokenTypes.SLASH,
 879  190
                                    getXPath(),
 880  190
                                    this.currentPosition,
 881  190
                                    this.currentPosition+1 );
 882  13248
                 consume();
 883  
             }
 884  
         }
 885  3310
     
 886  14056
         return token;
 887  
     }
 888  
     
 889  3310
     private char LA(int i) 
 890  
     {
 891  489028
         if ( currentPosition + ( i - 1 ) >= this.endPosition )
 892  
         {
 893  36840
             return (char) -1;
 894  
         }
 895  
     
 896  455688
         return getXPath().charAt( this.currentPosition + (i - 1) );
 897  
     }
 898  121758
     
 899  
     private void consume()
 900  8301
     {
 901  321168
         ++this.currentPosition;
 902  321168
     }
 903  113457
     
 904  
     private boolean hasMoreChars()
 905  
     {
 906  272884
         return this.currentPosition < this.endPosition;
 907  
     }
 908  79930
 
 909  79930
 }