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    using CLSCompliant = System.CLSCompliantAttribute;
37    using IndexOutOfRangeException = System.IndexOutOfRangeException;
38    using StringBuilder = System.Text.StringBuilder;
39
40    /** Buffer all input tokens but do on-demand fetching of new tokens from
41     *  lexer. Useful when the parser or lexer has to set context/mode info before
42     *  proper lexing of future tokens. The ST template parser needs this,
43     *  for example, because it has to constantly flip back and forth between
44     *  inside/output templates. E.g., <names:{hi, <it>}> has to parse names
45     *  as part of an expression but "hi, <it>" as a nested template.
46     *
47     *  You can't use this stream if you pass whitespace or other off-channel
48     *  tokens to the parser. The stream can't ignore off-channel tokens.
49     *  (UnbufferedTokenStream is the same way.)
50     *
51     *  This is not a subclass of UnbufferedTokenStream because I don't want
52     *  to confuse small moving window of tokens it uses for the full buffer.
53     */
54    [System.Serializable]
55    public class BufferedTokenStream : ITokenStream, ITokenStreamInformation
56    {
57        private ITokenSource _tokenSource;
58
59        /** Record every single token pulled from the source so we can reproduce
60         *  chunks of it later.  The buffer in LookaheadStream overlaps sometimes
61         *  as its moving window moves through the input.  This list captures
62         *  everything so we can access complete input text.
63         */
64        [CLSCompliant(false)]
65        protected List<IToken> _tokens = new List<IToken>(100);
66
67        /** Track the last mark() call result value for use in rewind(). */
68        private int _lastMarker;
69
70        /** The index into the tokens list of the current token (next token
71         *  to consume).  tokens[p] should be LT(1).  p=-1 indicates need
72         *  to initialize with first token.  The ctor doesn't get a token.
73         *  First call to LT(1) or whatever gets the first token and sets p=0;
74         */
75        [CLSCompliant(false)]
76        protected int _p = -1;
77
78        public BufferedTokenStream()
79        {
80        }
81
82        public BufferedTokenStream(ITokenSource tokenSource)
83        {
84            this._tokenSource = tokenSource;
85        }
86
87        public virtual ITokenSource TokenSource
88        {
89            get
90            {
91                return _tokenSource;
92            }
93            set
94            {
95                this._tokenSource = value;
96                _tokens.Clear();
97                _p = -1;
98            }
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        public virtual int Count
119        {
120            get
121            {
122                return _tokens.Count;
123            }
124        }
125
126        public virtual string SourceName
127        {
128            get
129            {
130                return _tokenSource.SourceName;
131            }
132        }
133
134        public virtual IToken LastToken
135        {
136            get
137            {
138                return LB(1);
139            }
140        }
141
142        public virtual IToken LastRealToken
143        {
144            get
145            {
146                int i = 0;
147                IToken token;
148                do
149                {
150                    i++;
151                    token = LB(i);
152                } while (token != null && token.Line <= 0);
153
154                return token;
155            }
156        }
157
158        public virtual int MaxLookBehind
159        {
160            get
161            {
162                return int.MaxValue;
163            }
164        }
165
166        public virtual int Mark()
167        {
168            if (_p == -1)
169                Setup();
170            _lastMarker = Index;
171            return _lastMarker;
172        }
173
174        public virtual void Release(int marker)
175        {
176            // no resources to release
177        }
178
179        public virtual void Rewind(int marker)
180        {
181            Seek(marker);
182        }
183
184        public virtual void Rewind()
185        {
186            Seek(_lastMarker);
187        }
188
189        public virtual void Reset()
190        {
191            _p = 0;
192            _lastMarker = 0;
193        }
194
195        public virtual void Seek(int index)
196        {
197            _p = index;
198        }
199
200        /** Move the input pointer to the next incoming token.  The stream
201         *  must become active with LT(1) available.  consume() simply
202         *  moves the input pointer so that LT(1) points at the next
203         *  input symbol. Consume at least one token.
204         *
205         *  Walk past any token not on the channel the parser is listening to.
206         */
207        public virtual void Consume()
208        {
209            if (_p == -1)
210                Setup();
211            _p++;
212            Sync(_p);
213        }
214
215        /** Make sure index i in tokens has a token. */
216        protected virtual void Sync(int i)
217        {
218            int n = i - _tokens.Count + 1; // how many more elements we need?
219            if (n > 0)
220                Fetch(n);
221        }
222
223        /** add n elements to buffer */
224        protected virtual void Fetch(int n)
225        {
226            for (int i = 0; i < n; i++)
227            {
228                IToken t = TokenSource.NextToken();
229                t.TokenIndex = _tokens.Count;
230                _tokens.Add(t);
231                if (t.Type == CharStreamConstants.EndOfFile)
232                    break;
233            }
234        }
235
236        public virtual IToken Get(int i)
237        {
238            if (i < 0 || i >= _tokens.Count)
239            {
240                throw new IndexOutOfRangeException("token index " + i + " out of range 0.." + (_tokens.Count - 1));
241            }
242            return _tokens[i];
243        }
244
245#if false // why is this different from GetTokens(start, count) ?
246        /// <summary>
247        /// Get all tokens from start..(start+count-1) inclusively
248        /// </summary>
249        public virtual List<IToken> Get(int start, int count)
250        {
251            if (start < 0)
252                throw new ArgumentOutOfRangeException("start");
253            if (count < 0)
254                throw new ArgumentOutOfRangeException("count");
255            if (start + count >= _tokens.Count)
256                throw new ArgumentException();
257
258            if (_p == -1)
259                Setup();
260
261            List<IToken> subset = new List<IToken>(count);
262            for (int i = 0; i < count; i++)
263            {
264                IToken token = _tokens[i];
265                if (token.Type == TokenTypes.EndOfFile)
266                    break;
267
268                subset.Add(token);
269            }
270
271            return subset;
272        }
273#endif
274
275        public virtual int LA(int i)
276        {
277            return LT(i).Type;
278        }
279
280        protected virtual IToken LB(int k)
281        {
282            if ((_p - k) < 0)
283                return null;
284
285            return _tokens[_p - k];
286        }
287
288        public virtual IToken LT(int k)
289        {
290            if (_p == -1)
291                Setup();
292            if (k == 0)
293                return null;
294            if (k < 0)
295                return LB(-k);
296
297            int i = _p + k - 1;
298            Sync(i);
299            if (i >= _tokens.Count)
300            {
301                // EOF must be last token
302                return _tokens[_tokens.Count - 1];
303            }
304
305            if (i > Range)
306                Range = i;
307
308            return _tokens[_p + k - 1];
309        }
310
311        protected virtual void Setup()
312        {
313            Sync(0);
314            _p = 0;
315        }
316
317        public virtual List<IToken> GetTokens()
318        {
319            return _tokens;
320        }
321
322        public virtual List<IToken> GetTokens(int start, int stop)
323        {
324            return GetTokens(start, stop, default(BitSet));
325        }
326
327        /** Given a start and stop index, return a List of all tokens in
328         *  the token type BitSet.  Return null if no tokens were found.  This
329         *  method looks at both on and off channel tokens.
330         */
331        public virtual List<IToken> GetTokens(int start, int stop, BitSet types)
332        {
333            if (_p == -1)
334                Setup();
335            if (stop >= _tokens.Count)
336                stop = _tokens.Count - 1;
337            if (start < 0)
338                start = 0;
339            if (start > stop)
340                return null;
341
342            // list = tokens[start:stop]:{Token t, t.getType() in types}
343            List<IToken> filteredTokens = new List<IToken>();
344            for (int i = start; i <= stop; i++)
345            {
346                IToken t = _tokens[i];
347                if (types == null || types.Member(t.Type))
348                {
349                    filteredTokens.Add(t);
350                }
351            }
352            if (filteredTokens.Count == 0)
353            {
354                filteredTokens = null;
355            }
356            return filteredTokens;
357        }
358
359        public virtual List<IToken> GetTokens(int start, int stop, IEnumerable<int> types)
360        {
361            return GetTokens(start, stop, new BitSet(types));
362        }
363
364        public virtual List<IToken> GetTokens(int start, int stop, int ttype)
365        {
366            return GetTokens(start, stop, BitSet.Of(ttype));
367        }
368
369        public override string ToString()
370        {
371            if (_p == -1)
372                Setup();
373
374            Fill();
375            return ToString(0, _tokens.Count - 1);
376        }
377
378        public virtual string ToString(int start, int stop)
379        {
380            if (start < 0 || stop < 0)
381                return null;
382            if (_p == -1)
383                Setup();
384            if (stop >= _tokens.Count)
385                stop = _tokens.Count - 1;
386
387            StringBuilder buf = new StringBuilder();
388            for (int i = start; i <= stop; i++)
389            {
390                IToken t = _tokens[i];
391                if (t.Type == CharStreamConstants.EndOfFile)
392                    break;
393                buf.Append(t.Text);
394            }
395
396            return buf.ToString();
397        }
398
399        public virtual string ToString(IToken start, IToken stop)
400        {
401            if (start != null && stop != null)
402            {
403                return ToString(start.TokenIndex, stop.TokenIndex);
404            }
405            return null;
406        }
407
408        public virtual void Fill()
409        {
410            if (_p == -1)
411                Setup();
412
413            if (_tokens[_p].Type == CharStreamConstants.EndOfFile)
414                return;
415
416            int i = _p + 1;
417            Sync(i);
418            while (_tokens[i].Type != CharStreamConstants.EndOfFile)
419            {
420                i++;
421                Sync(i);
422            }
423        }
424    }
425}
426