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