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 }