Clover coverage report - groovy - 1.0-beta-7
Coverage timestamp: Wed Sep 29 2004 16:55:52 BST
file stats: LOC: 402   Methods: 8
NCLOC: 266   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
StringLexer.java 0% 0% 0% 0%
coverage
 1   
 package org.codehaus.groovy.syntax.lexer;
 2   
 
 3   
 //{{{ imports
 4   
 import org.codehaus.groovy.syntax.ReadException;
 5   
 import org.codehaus.groovy.syntax.Token;
 6   
 import org.codehaus.groovy.GroovyBugError;
 7   
 //}}}
 8   
 
 9   
 /**
 10   
  *  A Lexer for processing standard strings.
 11   
  *
 12   
  *  @author Chris Poirier
 13   
  */
 14   
 
 15   
 public class StringLexer extends TextLexerBase
 16   
 {
 17   
 
 18   
     protected String  delimiter = null;
 19   
     protected char    watchFor;
 20   
     protected boolean allowGStrings = false;
 21   
     protected boolean emptyString   = true;   // If set, we need to send an empty string
 22   
 
 23   
 
 24   
    /**
 25   
     *  If set true, the filter will allow \\ and \$ to pass through unchanged.
 26   
     *  You should set this appropriately BEFORE setting source!
 27   
     */
 28   
 
 29  0
     public void allowGStrings( boolean allow )
 30   
     {
 31  0
         allowGStrings = allow;
 32   
     }
 33   
 
 34   
 
 35   
 
 36   
    /**
 37   
     *  Returns a single STRING, then null.   The STRING is all of the processed
 38   
     *  input.  Backslashes are stripped, with the \r, \n, and \t converted
 39   
     *  appropriately.
 40   
     */
 41   
 
 42  0
     public Token undelegatedNextToken( ) throws ReadException, LexerException
 43   
     {
 44  0
         if( emptyString )
 45   
         {
 46  0
             emptyString = false;
 47  0
             return Token.newString( "", getStartLine(), getStartColumn() );
 48   
         }
 49  0
         else if( finished )
 50   
         {
 51  0
             return null;
 52   
         }
 53   
         else
 54   
         {
 55  0
             StringBuffer string = new StringBuffer();
 56   
 
 57  0
             while( la(1) != CharStream.EOS )
 58   
             {
 59  0
                 string.append( consume() );
 60   
             }
 61   
             
 62  0
             if( la(1) == CharStream.EOS && string.length() == 0 )
 63   
             {
 64  0
                 finished = true;
 65   
             }
 66   
 
 67  0
             return Token.newString( string.toString(), getStartLine(), getStartColumn() );
 68   
         }
 69   
     }
 70   
 
 71   
 
 72   
 
 73   
    /**
 74   
     *  Controls delimiter search.  When turned on, the first thing we do
 75   
     *  is check for and eat our delimiter.
 76   
     */
 77   
 
 78  0
     public void delimit( boolean delimit )
 79   
     {
 80  0
         super.delimit( delimit );
 81   
 
 82  0
         if( delimit )
 83   
         {
 84  0
             try
 85   
             {
 86  0
                 if( !finished && la(1) == CharStream.EOS )
 87   
                 {
 88  0
                     finishUp();
 89   
 
 90   
                     //
 91   
                     // The GStringLexer will correctly handle the empty string.
 92   
                     // We don't.  In order to ensure that an empty string is
 93   
                     // supplied, we set a flag that is checked during
 94   
                     // undelegatedNextToken().
 95   
 
 96  0
                     if( !allowGStrings )
 97   
                     {
 98  0
                         emptyString = true;
 99   
                     }
 100   
                 }
 101   
             }
 102   
             catch( Exception e )
 103   
             {
 104  0
                 finished = true;
 105   
             }
 106   
         }
 107   
     }
 108   
 
 109   
 
 110   
 
 111   
 
 112   
    /**
 113   
     *  Sets the source lexer and identifies and consumes the opening delimiter.
 114   
     */
 115   
 
 116  0
     public void setSource( Lexer source )
 117   
     {
 118  0
         super.setSource( source );
 119   
 
 120  0
         emptyString = false;
 121   
 
 122  0
         try
 123   
         {
 124  0
             char c = source.la();
 125  0
             switch( c )
 126   
             {
 127   
                 case '\'':
 128   
                 case '"':
 129  0
                     mark();
 130  0
                     source.consume();
 131   
 
 132  0
                     if( source.la() == c && source.la(2) == c )
 133   
                     {
 134  0
                         source.consume(); source.consume();
 135  0
                         delimiter = new StringBuffer().append(c).append(c).append(c).toString();
 136   
                     }
 137   
                     else
 138   
                     {
 139  0
                         delimiter = new StringBuffer().append(c).toString();
 140   
                     }
 141   
 
 142  0
                     watchFor = delimiter.charAt(0);
 143  0
                     break;
 144   
 
 145   
 
 146   
                 default:
 147   
                 {
 148  0
                     throw new GroovyBugError( "at the time of StringLexer.setSource(), the source must be on a single or double quote" );
 149   
                 }
 150   
             }
 151   
 
 152  0
             restart();
 153  0
             delimit( true );
 154   
         }
 155   
         catch( Exception e )
 156   
         {
 157   
             //
 158   
             // If we couldn't read our delimiter, we'll just
 159   
             // cancel our source.  nextToken() will return null.
 160   
 
 161  0
             e.printStackTrace();
 162  0
             unsetSource( );
 163   
         }
 164   
     }
 165   
 
 166   
 
 167   
 
 168   
    /**
 169   
     *  Unsets our source.
 170   
     */
 171   
 
 172  0
     public void unsetSource()
 173   
     {
 174  0
         super.unsetSource();
 175  0
         delimiter   = null;
 176  0
         finished    = true;
 177  0
         emptyString = false;
 178   
     }
 179   
 
 180   
 
 181   
 
 182   
 
 183   
   //---------------------------------------------------------------------------
 184   
   // STREAM ROUTINES
 185   
 
 186   
     private int    lookahead  = 0;             // the number of characters identified
 187   
     private char[] characters = new char[3];   // the next characters identified by la()
 188   
     private int[]  widths     = new int[3];    // the source widths of the next characters
 189   
 
 190   
 
 191   
 
 192   
    /**
 193   
     *  Returns the next <code>k</code>th character, without consuming any.
 194   
     */
 195   
 
 196  0
     public char la(int k) throws LexerException, ReadException
 197   
     {
 198   
 
 199  0
         if( !finished && source != null )
 200   
         {
 201   
 
 202  0
             if( delimited )
 203   
             {
 204   
 
 205  0
                 if( k > characters.length )
 206   
                 {
 207  0
                     throw new GroovyBugError( "StringLexer lookahead tolerance exceeded" );
 208   
                 }
 209   
 
 210  0
                 if( lookahead >= k )
 211   
                 {
 212  0
                     return characters[k-1];
 213   
                 }
 214   
 
 215  0
                 lookahead = 0;
 216   
 
 217  0
                 char c = ' ', c1 = ' ', c2 = ' ';
 218  0
                 int offset = 1, width = 0;
 219  0
                 for( int i = 1; i <= k; i++ )
 220   
                 {
 221  0
                     c1 = source.la(offset);
 222  0
                     C1_SWITCH: switch( c1 )
 223   
                     {
 224   
                         case CharStream.EOS:
 225   
                         {
 226  0
                             return c1;
 227   
                         }
 228   
 
 229   
                         case '\\':
 230   
                         {
 231  0
                             c2 = source.la( offset + 1 );
 232   
 
 233  0
                             ESCAPE_SWITCH: switch( c2 )
 234   
                             {
 235   
 
 236   
                                 case CharStream.EOS:
 237  0
                                     return c2;
 238   
 
 239   
                                 case '\\':
 240   
                                 case '$':
 241   
                                 {
 242  0
                                     if( allowGStrings )
 243   
                                     {
 244  0
                                         c = c1;
 245  0
                                         width = 1;
 246   
                                     }
 247   
                                     else
 248   
                                     {
 249  0
                                         c = c2;
 250  0
                                         width = 2;
 251   
                                     }
 252  0
                                     break ESCAPE_SWITCH;
 253   
                                 }
 254   
 
 255   
                                 case 'r':
 256  0
                                     c = '\r';
 257  0
                                     width = 2;
 258  0
                                     break ESCAPE_SWITCH;
 259   
 
 260   
                                 case 't':
 261  0
                                     c = '\t';
 262  0
                                     width = 2;
 263  0
                                     break ESCAPE_SWITCH;
 264   
 
 265   
                                 case 'n':
 266  0
                                     c = '\n';
 267  0
                                     width = 2;
 268  0
                                     break ESCAPE_SWITCH;
 269   
 
 270   
 
 271   
                                 default:
 272  0
                                     c = c2;
 273  0
                                     width = 2;
 274  0
                                     break ESCAPE_SWITCH;
 275   
                             }
 276  0
                             break C1_SWITCH;
 277   
                         }
 278   
 
 279   
                         default:
 280   
                         {
 281  0
                             if( c1 == watchFor )
 282   
                             {
 283  0
                                 boolean atEnd = true;
 284  0
                                 for( int j = 1; j < delimiter.length(); j++ )
 285   
                                 {
 286  0
                                     if( source.la(offset+j) != delimiter.charAt(j) )
 287   
                                     {
 288  0
                                         atEnd = false;
 289  0
                                         break;
 290   
                                     }
 291   
                                 }
 292   
 
 293  0
                                 if( atEnd )
 294   
                                 {
 295  0
                                     return CharStream.EOS;
 296   
                                 }
 297   
                             }
 298   
 
 299  0
                             c = c1;
 300  0
                             width = 1;
 301  0
                             break C1_SWITCH;
 302   
                         }
 303   
                     }
 304   
 
 305   
 
 306  0
                     characters[lookahead] = c;
 307  0
                     widths[lookahead]     = width;
 308   
 
 309  0
                     offset += width;
 310  0
                     lookahead += 1;
 311   
                 }
 312   
 
 313  0
                 return c;                                         // <<< FLOW CONTROL <<<<<<<<<
 314   
             }
 315   
 
 316  0
             lookahead = 0;
 317  0
             return source.la(k);
 318   
         }
 319   
 
 320  0
         return CharStream.EOS;
 321   
 
 322   
     }
 323   
 
 324   
 
 325   
 
 326   
    /**
 327   
     *  Eats a character from the input stream.  Searches for the delimiter if
 328   
     *  delimited.  Note that turning delimiting on also checks if we are at the
 329   
     *  delimiter, so if we aren't finished, there is something to consume.
 330   
     */
 331   
 
 332  0
     public char consume() throws LexerException, ReadException
 333   
     {
 334  0
         if( !finished && source != null )
 335   
         {
 336  0
             char c = CharStream.EOS;
 337   
 
 338  0
             if( delimited )
 339   
             {
 340  0
                 if( lookahead < 1 )
 341   
                 {
 342  0
                     la( 1 );
 343   
                 }
 344   
 
 345  0
                 if( lookahead >= 1 )
 346   
                 {
 347  0
                     c = characters[0];
 348  0
                     for( int i = 0; i < widths[0]; i++ )
 349   
                     {
 350  0
                         source.consume();
 351   
                     }
 352   
 
 353  0
                     lookahead = 0;
 354   
                 }
 355   
 
 356  0
                 if( la(1) == CharStream.EOS )
 357   
                 {
 358  0
                     finishUp();
 359   
                 }
 360   
             }
 361   
             else
 362   
             {
 363  0
                 c = source.consume();
 364   
             }
 365   
 
 366  0
             lookahead = 0;
 367  0
             return c;
 368   
         }
 369   
 
 370  0
         return CharStream.EOS;
 371   
     }
 372   
 
 373   
 
 374   
 
 375   
    /**
 376   
     *  Eats our delimiter from the stream and marks us finished.
 377   
     */
 378   
 
 379  0
     protected void finishUp() throws LexerException, ReadException
 380   
     {
 381  0
         for( int i = 0; i < delimiter.length(); i++ )
 382   
         {
 383  0
             char c = source.la(1);
 384  0
             if( c == CharStream.EOS )
 385   
             {
 386  0
                 throw new UnterminatedStringLiteralException(getStartLine(), getStartColumn());
 387   
             }
 388  0
             else if( c == delimiter.charAt(i) )
 389   
             {
 390  0
                 source.consume();
 391   
             }
 392   
             else
 393   
             {
 394  0
                 throw new GroovyBugError( "la() said delimiter [" + delimiter + "], finishUp() found [" + c + "]" );
 395   
             }
 396   
         }
 397   
 
 398  0
         finish();
 399   
     }
 400   
 
 401   
 }
 402