Clover coverage report - groovy - 1.0-beta-8
Coverage timestamp: Fri Dec 17 2004 14:55:55 GMT
file stats: LOC: 405   Methods: 8
NCLOC: 269   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  0
                                     c = '\\';
 241  0
                                     width = 2;
 242  0
                                     break ESCAPE_SWITCH;
 243   
                                 case '$':
 244   
                                 {
 245  0
                                     if( allowGStrings )
 246   
                                     {
 247  0
                                         c = c1;
 248  0
                                         width = 1;
 249   
                                     }
 250   
                                     else
 251   
                                     {
 252  0
                                         c = c2;
 253  0
                                         width = 2;
 254   
                                     }
 255  0
                                     break ESCAPE_SWITCH;
 256   
                                 }
 257   
 
 258   
                                 case 'r':
 259  0
                                     c = '\r';
 260  0
                                     width = 2;
 261  0
                                     break ESCAPE_SWITCH;
 262   
 
 263   
                                 case 't':
 264  0
                                     c = '\t';
 265  0
                                     width = 2;
 266  0
                                     break ESCAPE_SWITCH;
 267   
 
 268   
                                 case 'n':
 269  0
                                     c = '\n';
 270  0
                                     width = 2;
 271  0
                                     break ESCAPE_SWITCH;
 272   
 
 273   
 
 274   
                                 default:
 275  0
                                     c = c2;
 276  0
                                     width = 2;
 277  0
                                     break ESCAPE_SWITCH;
 278   
                             }
 279  0
                             break C1_SWITCH;
 280   
                         }
 281   
 
 282   
                         default:
 283   
                         {
 284  0
                             if( c1 == watchFor )
 285   
                             {
 286  0
                                 boolean atEnd = true;
 287  0
                                 for( int j = 1; j < delimiter.length(); j++ )
 288   
                                 {
 289  0
                                     if( source.la(offset+j) != delimiter.charAt(j) )
 290   
                                     {
 291  0
                                         atEnd = false;
 292  0
                                         break;
 293   
                                     }
 294   
                                 }
 295   
 
 296  0
                                 if( atEnd )
 297   
                                 {
 298  0
                                     return CharStream.EOS;
 299   
                                 }
 300   
                             }
 301   
 
 302  0
                             c = c1;
 303  0
                             width = 1;
 304  0
                             break C1_SWITCH;
 305   
                         }
 306   
                     }
 307   
 
 308   
 
 309  0
                     characters[lookahead] = c;
 310  0
                     widths[lookahead]     = width;
 311   
 
 312  0
                     offset += width;
 313  0
                     lookahead += 1;
 314   
                 }
 315   
 
 316  0
                 return c;                                         // <<< FLOW CONTROL <<<<<<<<<
 317   
             }
 318   
 
 319  0
             lookahead = 0;
 320  0
             return source.la(k);
 321   
         }
 322   
 
 323  0
         return CharStream.EOS;
 324   
 
 325   
     }
 326   
 
 327   
 
 328   
 
 329   
    /**
 330   
     *  Eats a character from the input stream.  Searches for the delimiter if
 331   
     *  delimited.  Note that turning delimiting on also checks if we are at the
 332   
     *  delimiter, so if we aren't finished, there is something to consume.
 333   
     */
 334   
 
 335  0
     public char consume() throws LexerException, ReadException
 336   
     {
 337  0
         if( !finished && source != null )
 338   
         {
 339  0
             char c = CharStream.EOS;
 340   
 
 341  0
             if( delimited )
 342   
             {
 343  0
                 if( lookahead < 1 )
 344   
                 {
 345  0
                     la( 1 );
 346   
                 }
 347   
 
 348  0
                 if( lookahead >= 1 )
 349   
                 {
 350  0
                     c = characters[0];
 351  0
                     for( int i = 0; i < widths[0]; i++ )
 352   
                     {
 353  0
                         source.consume();
 354   
                     }
 355   
 
 356  0
                     lookahead = 0;
 357   
                 }
 358   
 
 359  0
                 if( la(1) == CharStream.EOS )
 360   
                 {
 361  0
                     finishUp();
 362   
                 }
 363   
             }
 364   
             else
 365   
             {
 366  0
                 c = source.consume();
 367   
             }
 368   
 
 369  0
             lookahead = 0;
 370  0
             return c;
 371   
         }
 372   
 
 373  0
         return CharStream.EOS;
 374   
     }
 375   
 
 376   
 
 377   
 
 378   
    /**
 379   
     *  Eats our delimiter from the stream and marks us finished.
 380   
     */
 381   
 
 382  0
     protected void finishUp() throws LexerException, ReadException
 383   
     {
 384  0
         for( int i = 0; i < delimiter.length(); i++ )
 385   
         {
 386  0
             char c = source.la(1);
 387  0
             if( c == CharStream.EOS )
 388   
             {
 389  0
                 throw new UnterminatedStringLiteralException(getStartLine(), getStartColumn());
 390   
             }
 391  0
             else if( c == delimiter.charAt(i) )
 392   
             {
 393  0
                 source.consume();
 394   
             }
 395   
             else
 396   
             {
 397  0
                 throw new GroovyBugError( "la() said delimiter [" + delimiter + "], finishUp() found [" + c + "]" );
 398   
             }
 399   
         }
 400   
 
 401  0
         finish();
 402   
     }
 403   
 
 404   
 }
 405