View Javadoc

    1   package org.codehaus.groovy.syntax;
    2
    3   import org.codehaus.groovy.GroovyBugError;
    4
    5
    6   /***
    7    *  Provides the common code for <code>{@link TokenStream}</code> implementations.
    8    */
    9
    10  public abstract class AbstractTokenStream
    11      implements TokenStream
    12  {
    13      private Token[] buf;             // A circular buffer of tokens
    14      private int first;               // la(1) points to this offset into buf
    15      private int avail;               // the number of ahead tokens in buf
    16
    17      private int checkpoint_first;    // last checkpoint() copy of first
    18      private int checkpoint_avail;    // last checkpoint() copy of avail
    19
    20      private String sourceLocator;    // A descriptor of the source of the stream
    21
    22
    23     /***
    24      *  Default constructor.
    25      */
    26
    27      public AbstractTokenStream()
    28      {
    29          this( "<unknown>" );
    30      }
    31
    32
    33     /***
    34      *  Initializes the stream with information about the source.
    35      */
    36
    37      public AbstractTokenStream(String sourceLocator)
    38      {
    39          this.buf           = new Token[8 * 1024];
    40          this.first         = -1;
    41          this.avail         = 0;
    42          this.sourceLocator = sourceLocator;
    43      }
    44
    45
    46     /***
    47      *  Returns a description of the source (typically a file name).
    48      */
    49
    50      public String getSourceLocator()
    51      {
    52          return this.sourceLocator;
    53      }
    54
    55
    56     /***
    57      *  Implemented by concrete subtypes, provides access to the next
    58      *  token in the underlying stream.
    59      */
    60
    61      protected abstract Token nextToken()
    62          throws ReadException, SyntaxException;
    63
    64
    65     /***
    66      *  Returns the next token in the stream without consuming it.
    67      */
    68
    69      public Token la()
    70          throws ReadException, SyntaxException
    71      {
    72          return la( 1 );
    73      }
    74
    75
    76     /***
    77      *  Returns the <code>k</code>th token in the stream without consuming
    78      *  it (or any other unconsumed tokens).
    79      */
    80
    81      public Token la(int k)
    82          throws ReadException, SyntaxException
    83      {
    84          if ( k > buf.length )
    85          {
    86              throw new GroovyBugError( "Lookahead [" + k + "] is larger than lookahead buffer [" + buf.length + "]" );
    87          }
    88
    89
    90          //
    91          // If necessary, read more tokens from the underlying stream.
    92
    93          if ( k > this.avail )
    94          {
    95              int numToPopulate = k - this.avail;
    96
    97              for ( int i = 0 ; i < numToPopulate ; ++i )
    98              {
    99                  if ( this.first < 0 )
    100                 {
    101                     this.first = 0;
    102                 }
    103                 int pop = ( ( this.first + this.avail ) % this.buf.length );
    104                 this.buf[ pop ] = nextToken();
    105                 ++this.avail;
    106                 ++this.checkpoint_avail;
    107             }
    108         }
    109
    110
    111         //
    112         // Return the requested token.
    113
    114         int pos = ( ( k + this.first - 1 ) % this.buf.length );
    115
    116         return this.buf[ pos ];
    117     }
    118
    119
    120    /***
    121     *  Removes and returns the first token in the stream, provided it
    122     *  matches the specified type.
    123     */
    124
    125     public Token consume(int type)
    126         throws ReadException, SyntaxException
    127     {
    128         Token token = la();
    129
    130         if( token == null )
    131         {
    132             return null;
    133         }
    134
    135         if( !token.isA(type) )
    136         {
    137             throw new TokenMismatchException( token, type );
    138         }
    139
    140         ++this.first;
    141         --this.avail;
    142
    143         this.first %= this.buf.length;
    144
    145         return token;
    146     }
    147
    148
    149
    150    /***
    151     *  Removes and returns the first token in the stream, provided it
    152     *  isn't the EOF.
    153     */
    154
    155     public Token consume() throws ReadException, SyntaxException
    156     {
    157         return consume( Types.NOT_EOF );
    158     }
    159
    160
    161
    162    /***
    163     *  Saves the look-ahead state for <code>restore()</code>ing later.
    164     */
    165
    166     public void checkpoint() {
    167         checkpoint_first = first;
    168         checkpoint_avail = avail;
    169     }
    170
    171
    172    /***
    173     *  Restores the look-ahead state saved by <code>checkpoint()</code>.
    174     */
    175
    176     public void restore() {
    177         first = checkpoint_first;
    178         avail = checkpoint_avail;
    179     }
    180
    181
    182     /***
    183      * Returns true if the stream is out of tokens.
    184      */
    185
    186     public boolean atEnd( boolean ignoringWhitespace ) {
    187
    188         try {
    189             int offset = 1;
    190
    191             if( ignoringWhitespace ) {
    192                 try {
    193                     while( la(offset).isA(Types.NEWLINE) ) {
    194                         offset++;
    195                     }
    196                 }
    197                 catch( Exception e ) {}
    198             }
    199
    200             if( la(offset) == null ) {
    201                 return true;
    202             }
    203         }
    204         catch( Exception e ) {}
    205
    206         return false;
    207     }
    208
    209
    210     /***
    211      * A synonym for <code>atEnd(true)</code>.
    212      */
    213
    214     public boolean atEnd() {
    215         return atEnd(true);
    216     }
    217
    218 }