1 /*
2  * [The "BSD license"]
3  * Copyright (c) 2011 Terence Parr
4  * All rights reserved.
5  *
6  * Conversion to C#:
7  * Copyright (c) 2011 Sam Harwell, Pixel Mine, Inc.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 namespace Antlr.Runtime
34 {
35     using System.Collections.Generic;
36     using System;
37     using System.Text;
38 
39     /** <summary>
40      *  A pretty quick CharStream that pulls all data from an array
41      *  directly.  Every method call counts in the lexer.  Java's
42      *  strings aren't very good so I'm avoiding.
43      *  </summary>
44      */
45     [System.Serializable]
46     public class FastTokenStream
47         : ITokenStream<SlimToken>
48     {
49         [System.NonSerialized]
50         ITokenSource<SlimToken> _tokenSource;
51 
52         /** <summary>
53          *  Record every single token pulled from the source so we can reproduce
54          *  chunks of it later.
55          *  </summary>
56          */
57         protected List<SlimToken> tokens;
58 
59         /** <summary>Skip tokens on any channel but this one; this is how we skip whitespace...</summary> */
60         protected int channel = TokenChannels.Default;
61 
62         /** <summary>Track the last mark() call result value for use in rewind().</summary> */
63         protected int lastMarker;
64 
65         /** <summary>
66          *  The index into the tokens list of the current token (next token
67          *  to consume).  p==-1 indicates that the tokens list is empty
68          *  </summary>
69          */
70         protected int p = -1;
71 
FastTokenStream()72         public FastTokenStream()
73         {
74             tokens = new List<SlimToken>( 500 );
75         }
76 
FastTokenStream( ITokenSource<SlimToken> tokenSource )77         public FastTokenStream( ITokenSource<SlimToken> tokenSource )
78             : this()
79         {
80             this._tokenSource = tokenSource;
81         }
82 
FastTokenStream( ITokenSource<SlimToken> tokenSource, int channel )83         public FastTokenStream( ITokenSource<SlimToken> tokenSource, int channel )
84             : this( tokenSource )
85         {
86             this.channel = channel;
87         }
88 
89         public int Index
90         {
91             get
92             {
93                 return p;
94             }
95         }
96 
97         /** <summary>Reset this token stream by setting its token source.</summary> */
SetTokenSource( ITokenSource<SlimToken> tokenSource )98         public void SetTokenSource( ITokenSource<SlimToken> tokenSource )
99         {
100             this._tokenSource = tokenSource;
101             tokens.Clear();
102             p = -1;
103             channel = TokenChannels.Default;
104         }
105 
106         /** <summary>
107          *  Load all tokens from the token source and put in tokens.
108          *  This is done upon first LT request because you might want to
109          *  set some token type / channel overrides before filling buffer.
110          *  </summary>
111          */
FillBuffer()112         public void FillBuffer()
113         {
114             // fast return if the buffer is already full
115             if ( p != -1 )
116                 return;
117 
118             int index = 0;
119             SlimToken t = _tokenSource.NextToken();
120             while ( t.Type != CharStreamConstants.EndOfFile )
121             {
122                 //t.TokenIndex = index;
123                 tokens.Add( t );
124                 index++;
125 
126                 t = _tokenSource.NextToken();
127             }
128             // leave p pointing at first token on channel
129             p = 0;
130             p = SkipOffTokenChannels( p );
131         }
132 
133         /** <summary>
134          *  Move the input pointer to the next incoming token.  The stream
135          *  must become active with LT(1) available.  consume() simply
136          *  moves the input pointer so that LT(1) points at the next
137          *  input symbol. Consume at least one token.
138          *  </summary>
139          *
140          *  <remarks>
141          *  Walk past any token not on the channel the parser is listening to.
142          *  </remarks>
143          */
Consume()144         public void Consume()
145         {
146             if ( p < tokens.Count )
147             {
148                 p++;
149                 p = SkipOffTokenChannels( p ); // leave p on valid token
150             }
151         }
152 
153         /** <summary>Given a starting index, return the index of the first on-channel token.</summary> */
SkipOffTokenChannels( int i )154         protected int SkipOffTokenChannels( int i )
155         {
156             int n = tokens.Count;
157             while ( i < n && tokens[i].Channel != channel )
158             {
159                 i++;
160             }
161             return i;
162         }
163 
SkipOffTokenChannelsReverse( int i )164         protected int SkipOffTokenChannelsReverse( int i )
165         {
166             while ( i >= 0 && tokens[i].Channel != channel )
167             {
168                 i--;
169             }
170             return i;
171         }
172 
GetTokens()173         public IList<SlimToken> GetTokens()
174         {
175             if ( p == -1 )
176             {
177                 FillBuffer();
178             }
179             return tokens;
180         }
181 
GetTokens( int start, int stop )182         public IList<SlimToken> GetTokens( int start, int stop )
183         {
184             return GetTokens( start, stop, (BitSet)null );
185         }
186 
187         /** <summary>
188          *  Given a start and stop index, return a List of all tokens in
189          *  the token type BitSet.  Return null if no tokens were found.  This
190          *  method looks at both on and off channel tokens.
191          *  </summary>
192          */
GetTokens( int start, int stop, BitSet types )193         public IList<SlimToken> GetTokens( int start, int stop, BitSet types )
194         {
195             if ( p == -1 )
196             {
197                 FillBuffer();
198             }
199             if ( stop >= tokens.Count )
200             {
201                 stop = tokens.Count - 1;
202             }
203             if ( start < 0 )
204             {
205                 start = 0;
206             }
207             if ( start > stop )
208             {
209                 return null;
210             }
211 
212             // list = tokens[start:stop]:{Token t, t.getType() in types}
213             List<SlimToken> filteredTokens = new List<SlimToken>();
214             for ( int i = start; i <= stop; i++ )
215             {
216                 SlimToken t = tokens[i];
217                 if ( types == null || types.Member( t.Type ) )
218                 {
219                     filteredTokens.Add( t );
220                 }
221             }
222             if ( filteredTokens.Count == 0 )
223             {
224                 filteredTokens = null;
225             }
226             return filteredTokens;
227         }
228 
GetTokens( int start, int stop, IList<int> types )229         public IList<SlimToken> GetTokens( int start, int stop, IList<int> types )
230         {
231             return GetTokens( start, stop, new BitSet( types ) );
232         }
233 
GetTokens( int start, int stop, int ttype )234         public IList<SlimToken> GetTokens( int start, int stop, int ttype )
235         {
236             return GetTokens( start, stop, BitSet.Of( ttype ) );
237         }
238 
239         /** <summary>
240          *  Get the ith token from the current position 1..n where k=1 is the
241          *  first symbol of lookahead.
242          *  </summary>
243          */
LT( int k )244         public SlimToken LT( int k )
245         {
246             if ( p == -1 )
247             {
248                 FillBuffer();
249             }
250             if ( k == 0 )
251             {
252                 return default( SlimToken );
253             }
254             if ( k < 0 )
255             {
256                 return LB( -k );
257             }
258             //System.out.print("LT(p="+p+","+k+")=");
259             if ( ( p + k - 1 ) >= tokens.Count )
260             {
261                 return new SlimToken(TokenTypes.EndOfFile);
262             }
263             //System.out.println(tokens.get(p+k-1));
264             int i = p;
265             int n = 1;
266             // find k good tokens
267             while ( n < k )
268             {
269                 // skip off-channel tokens
270                 i = SkipOffTokenChannels( i + 1 ); // leave p on valid token
271                 n++;
272             }
273             if ( i >= tokens.Count )
274             {
275                 return new SlimToken(TokenTypes.EndOfFile);
276             }
277             return tokens[i];
278         }
279 
280         /** <summary>Look backwards k tokens on-channel tokens</summary> */
LB( int k )281         protected SlimToken LB( int k )
282         {
283             //System.out.print("LB(p="+p+","+k+") ");
284             if ( p == -1 )
285             {
286                 FillBuffer();
287             }
288             if ( k == 0 )
289             {
290                 return default( SlimToken );
291             }
292             if ( ( p - k ) < 0 )
293             {
294                 return default( SlimToken );
295             }
296 
297             int i = p;
298             int n = 1;
299             // find k good tokens looking backwards
300             while ( n <= k )
301             {
302                 // skip off-channel tokens
303                 i = SkipOffTokenChannelsReverse( i - 1 ); // leave p on valid token
304                 n++;
305             }
306             if ( i < 0 )
307             {
308                 return default( SlimToken );
309             }
310             return tokens[i];
311         }
312 
313         /** <summary>
314          *  Return absolute token i; ignore which channel the tokens are on;
315          *  that is, count all tokens not just on-channel tokens.
316          *  </summary>
317          */
Get( int i )318         public SlimToken Get( int i )
319         {
320             return tokens[i];
321         }
322 
LA( int i )323         public int LA( int i )
324         {
325             return LT( i ).Type;
326         }
327 
Mark()328         public int Mark()
329         {
330             if ( p == -1 )
331             {
332                 FillBuffer();
333             }
334             lastMarker = Index;
335             return lastMarker;
336         }
337 
Release( int marker )338         public void Release( int marker )
339         {
340             // no resources to release
341         }
342 
343         public int Count
344         {
345             get
346             {
347                 return tokens.Count;
348             }
349         }
350 
Rewind( int marker )351         public void Rewind( int marker )
352         {
353             Seek( marker );
354         }
355 
Rewind()356         public void Rewind()
357         {
358             Seek( lastMarker );
359         }
360 
Reset()361         public void Reset()
362         {
363             p = 0;
364             lastMarker = 0;
365         }
366 
Seek( int index )367         public void Seek( int index )
368         {
369             p = index;
370         }
371 
372         public ITokenSource<SlimToken> TokenSource
373         {
374             get
375             {
376                 return _tokenSource;
377             }
378         }
379 
380         public string SourceName
381         {
382             get
383             {
384                 return TokenSource.SourceName;
385             }
386         }
387 
ToString()388         public override string ToString()
389         {
390             if ( p == -1 )
391             {
392                 throw new InvalidOperationException( "Buffer is not yet filled." );
393             }
394             return ToString( 0, tokens.Count - 1 );
395         }
396 
ToString( int start, int stop )397         public virtual string ToString( int start, int stop )
398         {
399             if ( start < 0 || stop < 0 )
400             {
401                 return null;
402             }
403             if ( p == -1 )
404             {
405                 throw new InvalidOperationException( "Buffer is not yet filled." );
406             }
407             if ( stop >= tokens.Count )
408             {
409                 stop = tokens.Count - 1;
410             }
411             StringBuilder buf = new StringBuilder();
412             for ( int i = start; i <= stop; i++ )
413             {
414                 SlimToken t = tokens[i];
415                 SlimLexer lexer = _tokenSource as SlimLexer;
416                 if ( lexer != null )
417                 {
418                     SlimStringStream input = lexer.CharStream as SlimStringStream;
419                     if ( input != null )
420                     {
421                         string text = input.Substring( t.StartIndex, t.StopIndex - t.StartIndex + 1 );
422                         buf.Append( text );
423                     }
424                 }
425             }
426             return buf.ToString();
427         }
428 
ToString( IToken start, IToken stop )429         public virtual string ToString( IToken start, IToken stop )
430         {
431             if ( start != null && stop != null )
432             {
433                 return ToString( start.TokenIndex, stop.TokenIndex );
434             }
435             return null;
436         }
437     }
438 }
439