1/*
2 * [The "BSD licence"]
3 * Copyright (c) 2005-2008 Terence Parr
4 * All rights reserved.
5 *
6 * Conversion to C#:
7 * Copyright (c) 2008-2009 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
33namespace Antlr.Runtime
34{
35    using System.Collections.Generic;
36
37    using InvalidOperationException = System.InvalidOperationException;
38    using StringBuilder = System.Text.StringBuilder;
39
40    /** <summary>
41     *  The most common stream of tokens is one where every token is buffered up
42     *  and tokens are prefiltered for a certain channel (the parser will only
43     *  see these tokens and cannot change the filter channel number during the
44     *  parse).
45     *  </summary>
46     *
47     *  <remarks>TODO: how to access the full token stream?  How to track all tokens matched per rule?</remarks>
48     */
49    [System.Serializable]
50    public class LegacyCommonTokenStream : ITokenStream
51    {
52        [System.NonSerialized]
53        ITokenSource _tokenSource;
54
55        /** <summary>
56         *  Record every single token pulled from the source so we can reproduce
57         *  chunks of it later.
58         *  </summary>
59         */
60        protected List<IToken> tokens;
61
62        /** <summary>Map<tokentype, channel> to override some Tokens' channel numbers</summary> */
63        protected IDictionary<int, int> channelOverrideMap;
64
65        /** <summary>Set<tokentype>; discard any tokens with this type</summary> */
66        protected List<int> discardSet;
67
68        /** <summary>Skip tokens on any channel but this one; this is how we skip whitespace...</summary> */
69        protected int channel = TokenChannels.Default;
70
71        /** <summary>By default, track all incoming tokens</summary> */
72        protected bool discardOffChannelTokens = false;
73
74        /** <summary>Track the last mark() call result value for use in rewind().</summary> */
75        protected int lastMarker;
76
77        /** <summary>
78         *  The index into the tokens list of the current token (next token
79         *  to consume).  p==-1 indicates that the tokens list is empty
80         *  </summary>
81         */
82        protected int p = -1;
83
84        public LegacyCommonTokenStream()
85        {
86            tokens = new List<IToken>( 500 );
87        }
88
89        public LegacyCommonTokenStream(ITokenSource tokenSource)
90            : this()
91        {
92            this._tokenSource = tokenSource;
93        }
94
95        public LegacyCommonTokenStream( ITokenSource tokenSource, int channel )
96            : this( tokenSource )
97        {
98            this.channel = channel;
99        }
100
101        public virtual int Index
102        {
103            get
104            {
105                return p;
106            }
107        }
108
109        /// <summary>
110        /// How deep have we gone?
111        /// </summary>
112        public virtual int Range
113        {
114            get;
115            protected set;
116        }
117
118        /** <summary>Reset this token stream by setting its token source.</summary> */
119        public virtual void SetTokenSource( ITokenSource tokenSource )
120        {
121            this._tokenSource = tokenSource;
122            tokens.Clear();
123            p = -1;
124            channel = TokenChannels.Default;
125        }
126
127        /** <summary>
128         *  Load all tokens from the token source and put in tokens.
129         *  This is done upon first LT request because you might want to
130         *  set some token type / channel overrides before filling buffer.
131         *  </summary>
132         */
133        public virtual void FillBuffer()
134        {
135            // fast return if the buffer is already full
136            if ( p != -1 )
137                return;
138
139            int index = 0;
140            IToken t = _tokenSource.NextToken();
141            while ( t != null && t.Type != CharStreamConstants.EndOfFile )
142            {
143                bool discard = false;
144                // is there a channel override for token type?
145                int channelI;
146                if ( channelOverrideMap != null && channelOverrideMap.TryGetValue( t.Type, out channelI ) )
147                    t.Channel = channelI;
148
149                //if ( channelOverrideMap != null && channelOverrideMap.ContainsKey( t.getType() ) )
150                //{
151                //    object channelI = channelOverrideMap.get( t.getType() );
152                //    if ( channelI != null )
153                //    {
154                //        t.setChannel( (int)channelI );
155                //    }
156                //}
157                if ( discardSet != null &&
158                     discardSet.Contains( t.Type ) )
159                {
160                    discard = true;
161                }
162                else if ( discardOffChannelTokens && t.Channel != this.channel )
163                {
164                    discard = true;
165                }
166                if ( !discard )
167                {
168                    t.TokenIndex = index;
169                    tokens.Add( t );
170                    index++;
171                }
172                t = _tokenSource.NextToken();
173            }
174            // leave p pointing at first token on channel
175            p = 0;
176            p = SkipOffTokenChannels( p );
177        }
178
179        /** <summary>
180         *  Move the input pointer to the next incoming token.  The stream
181         *  must become active with LT(1) available.  consume() simply
182         *  moves the input pointer so that LT(1) points at the next
183         *  input symbol. Consume at least one token.
184         *  </summary>
185         *
186         *  <remarks>
187         *  Walk past any token not on the channel the parser is listening to.
188         *  </remarks>
189         */
190        public virtual void Consume()
191        {
192            if ( p < tokens.Count )
193            {
194                p++;
195                p = SkipOffTokenChannels( p ); // leave p on valid token
196            }
197        }
198
199        /** <summary>Given a starting index, return the index of the first on-channel token.</summary> */
200        protected virtual int SkipOffTokenChannels( int i )
201        {
202            int n = tokens.Count;
203            while ( i < n && ( (IToken)tokens[i] ).Channel != channel )
204            {
205                i++;
206            }
207            return i;
208        }
209
210        protected virtual int SkipOffTokenChannelsReverse( int i )
211        {
212            while ( i >= 0 && ( (IToken)tokens[i] ).Channel != channel )
213            {
214                i--;
215            }
216            return i;
217        }
218
219        /** <summary>
220         *  A simple filter mechanism whereby you can tell this token stream
221         *  to force all tokens of type ttype to be on channel.  For example,
222         *  when interpreting, we cannot exec actions so we need to tell
223         *  the stream to force all WS and NEWLINE to be a different, ignored
224         *  channel.
225         *  </summary>
226         */
227        public virtual void SetTokenTypeChannel( int ttype, int channel )
228        {
229            if ( channelOverrideMap == null )
230            {
231                channelOverrideMap = new Dictionary<int, int>();
232            }
233            channelOverrideMap[ttype] = channel;
234        }
235
236        public virtual void DiscardTokenType( int ttype )
237        {
238            if ( discardSet == null )
239            {
240                discardSet = new List<int>();
241            }
242            discardSet.Add( ttype );
243        }
244
245        public virtual void SetDiscardOffChannelTokens( bool discardOffChannelTokens )
246        {
247            this.discardOffChannelTokens = discardOffChannelTokens;
248        }
249
250        public virtual IList<IToken> GetTokens()
251        {
252            if ( p == -1 )
253            {
254                FillBuffer();
255            }
256            return tokens;
257        }
258
259        public virtual IList<IToken> GetTokens( int start, int stop )
260        {
261            return GetTokens( start, stop, (BitSet)null );
262        }
263
264        /** <summary>
265         *  Given a start and stop index, return a List of all tokens in
266         *  the token type BitSet.  Return null if no tokens were found.  This
267         *  method looks at both on and off channel tokens.
268         *  </summary>
269         */
270        public virtual IList<IToken> GetTokens( int start, int stop, BitSet types )
271        {
272            if ( p == -1 )
273            {
274                FillBuffer();
275            }
276            if ( stop >= tokens.Count )
277            {
278                stop = tokens.Count - 1;
279            }
280            if ( start < 0 )
281            {
282                start = 0;
283            }
284            if ( start > stop )
285            {
286                return null;
287            }
288
289            // list = tokens[start:stop]:{Token t, t.getType() in types}
290            IList<IToken> filteredTokens = new List<IToken>();
291            for ( int i = start; i <= stop; i++ )
292            {
293                IToken t = tokens[i];
294                if ( types == null || types.Member( t.Type ) )
295                {
296                    filteredTokens.Add( t );
297                }
298            }
299            if ( filteredTokens.Count == 0 )
300            {
301                filteredTokens = null;
302            }
303            return filteredTokens;
304        }
305
306        public virtual IList<IToken> GetTokens( int start, int stop, IList<int> types )
307        {
308            return GetTokens( start, stop, new BitSet( types ) );
309        }
310
311        public virtual IList<IToken> GetTokens( int start, int stop, int ttype )
312        {
313            return GetTokens( start, stop, BitSet.Of( ttype ) );
314        }
315
316        /** <summary>
317         *  Get the ith token from the current position 1..n where k=1 is the
318         *  first symbol of lookahead.
319         *  </summary>
320         */
321        public virtual IToken LT( int k )
322        {
323            if ( p == -1 )
324            {
325                FillBuffer();
326            }
327            if ( k == 0 )
328            {
329                return null;
330            }
331            if ( k < 0 )
332            {
333                return LB( -k );
334            }
335            //System.out.print("LT(p="+p+","+k+")=");
336            if ( ( p + k - 1 ) >= tokens.Count )
337            {
338                return tokens[tokens.Count - 1];
339            }
340            //System.out.println(tokens.get(p+k-1));
341            int i = p;
342            int n = 1;
343            // find k good tokens
344            while ( n < k )
345            {
346                // skip off-channel tokens
347                i = SkipOffTokenChannels( i + 1 ); // leave p on valid token
348                n++;
349            }
350            if ( i >= tokens.Count )
351            {
352                return tokens[tokens.Count - 1];
353            }
354
355            if (i > Range)
356                Range = i;
357
358            return (IToken)tokens[i];
359        }
360
361        /** <summary>Look backwards k tokens on-channel tokens</summary> */
362        protected virtual IToken LB( int k )
363        {
364            //System.out.print("LB(p="+p+","+k+") ");
365            if ( p == -1 )
366            {
367                FillBuffer();
368            }
369            if ( k == 0 )
370            {
371                return null;
372            }
373            if ( ( p - k ) < 0 )
374            {
375                return null;
376            }
377
378            int i = p;
379            int n = 1;
380            // find k good tokens looking backwards
381            while ( n <= k )
382            {
383                // skip off-channel tokens
384                i = SkipOffTokenChannelsReverse( i - 1 ); // leave p on valid token
385                n++;
386            }
387            if ( i < 0 )
388            {
389                return null;
390            }
391            return (IToken)tokens[i];
392        }
393
394        /** <summary>
395         *  Return absolute token i; ignore which channel the tokens are on;
396         *  that is, count all tokens not just on-channel tokens.
397         *  </summary>
398         */
399        public virtual IToken Get( int i )
400        {
401            return (IToken)tokens[i];
402        }
403
404#if false
405        /** Get all tokens from start..stop inclusively */
406        public virtual List<IToken> Get(int start, int count)
407        {
408            if (start < 0)
409                throw new ArgumentOutOfRangeException("start");
410            if (count < 0)
411                throw new ArgumentOutOfRangeException("count");
412
413            if (p == -1)
414                FillBuffer();
415
416            return new List<IToken>(tokens.Skip(start).Take(count));
417        }
418#endif
419
420        public virtual int LA( int i )
421        {
422            return LT( i ).Type;
423        }
424
425        public virtual int Mark()
426        {
427            if ( p == -1 )
428            {
429                FillBuffer();
430            }
431            lastMarker = Index;
432            return lastMarker;
433        }
434
435        public virtual void Release( int marker )
436        {
437            // no resources to release
438        }
439
440        public virtual int Count
441        {
442            get
443            {
444                return tokens.Count;
445            }
446        }
447
448        public virtual void Rewind( int marker )
449        {
450            Seek( marker );
451        }
452
453        public virtual void Rewind()
454        {
455            Seek( lastMarker );
456        }
457
458        public virtual void Reset()
459        {
460            p = 0;
461            lastMarker = 0;
462        }
463
464        public virtual void Seek( int index )
465        {
466            p = index;
467        }
468
469        public virtual ITokenSource TokenSource
470        {
471            get
472            {
473                return _tokenSource;
474            }
475        }
476
477        public virtual string SourceName
478        {
479            get
480            {
481                return TokenSource.SourceName;
482            }
483        }
484
485        public override string ToString()
486        {
487            if ( p == -1 )
488            {
489                throw new InvalidOperationException( "Buffer is not yet filled." );
490            }
491            return ToString( 0, tokens.Count - 1 );
492        }
493
494        public virtual string ToString( int start, int stop )
495        {
496            if ( start < 0 || stop < 0 )
497            {
498                return null;
499            }
500            if ( p == -1 )
501            {
502                throw new InvalidOperationException( "Buffer is not yet filled." );
503            }
504            if ( stop >= tokens.Count )
505            {
506                stop = tokens.Count - 1;
507            }
508            StringBuilder buf = new StringBuilder();
509            for ( int i = start; i <= stop; i++ )
510            {
511                IToken t = tokens[i];
512                buf.Append( t.Text );
513            }
514            return buf.ToString();
515        }
516
517        public virtual string ToString( IToken start, IToken stop )
518        {
519            if ( start != null && stop != null )
520            {
521                return ToString( start.TokenIndex, stop.TokenIndex );
522            }
523            return null;
524        }
525    }
526}
527