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