• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
28 package org.antlr.runtime.tree;
29 
30 import org.antlr.runtime.Token;
31 import org.antlr.runtime.TokenStream;
32 import org.antlr.runtime.misc.IntArray;
33 import java.util.*;
34 
35 /** A buffered stream of tree nodes.  Nodes can be from a tree of ANY kind.
36  *
37  *  This node stream sucks all nodes out of the tree specified in
38  *  the constructor during construction and makes pointers into
39  *  the tree using an array of Object pointers. The stream necessarily
40  *  includes pointers to DOWN and UP and EOF nodes.
41  *
42  *  This stream knows how to mark/release for backtracking.
43  *
44  *  This stream is most suitable for tree interpreters that need to
45  *  jump around a lot or for tree parsers requiring speed (at cost of memory).
46  *  There is some duplicated functionality here with UnBufferedTreeNodeStream
47  *  but just in bookkeeping, not tree walking etc...
48  *
49  *  TARGET DEVELOPERS:
50  *
51  *  This is the old CommonTreeNodeStream that buffered up entire node stream.
52  *  No need to implement really as new CommonTreeNodeStream is much better
53  *  and covers what we need.
54  *
55  *  @see CommonTreeNodeStream
56  */
57 public class BufferedTreeNodeStream implements TreeNodeStream {
58 	public static final int DEFAULT_INITIAL_BUFFER_SIZE = 100;
59 	public static final int INITIAL_CALL_STACK_SIZE = 10;
60 
61     protected class StreamIterator implements Iterator<Object> {
62 		int i = 0;
63 		@Override
hasNext()64 		public boolean hasNext() {
65 			return i<nodes.size();
66 		}
67 
68 		@Override
next()69 		public Object next() {
70 			int current = i;
71 			i++;
72 			if ( current < nodes.size() ) {
73 				return nodes.get(current);
74 			}
75 			return eof;
76 		}
77 
78 		@Override
remove()79 		public void remove() {
80 			throw new RuntimeException("cannot remove nodes from stream");
81 		}
82 	}
83 
84 	// all these navigation nodes are shared and hence they
85 	// cannot contain any line/column info
86 
87 	protected Object down;
88 	protected Object up;
89 	protected Object eof;
90 
91 	/** The complete mapping from stream index to tree node.
92 	 *  This buffer includes pointers to DOWN, UP, and EOF nodes.
93 	 *  It is built upon ctor invocation.  The elements are type
94 	 *  Object as we don't what the trees look like.
95 	 *
96 	 *  Load upon first need of the buffer so we can set token types
97 	 *  of interest for reverseIndexing.  Slows us down a wee bit to
98 	 *  do all of the if p==-1 testing everywhere though.
99 	 */
100 	protected List<Object> nodes;
101 
102 	/** Pull nodes from which tree? */
103 	protected Object root;
104 
105 	/** IF this tree (root) was created from a token stream, track it. */
106 	protected TokenStream tokens;
107 
108 	/** What tree adaptor was used to build these trees */
109 	TreeAdaptor adaptor;
110 
111 	/** Reuse same DOWN, UP navigation nodes unless this is true */
112 	protected boolean uniqueNavigationNodes = false;
113 
114 	/** The index into the nodes list of the current node (next node
115 	 *  to consume).  If -1, nodes array not filled yet.
116 	 */
117 	protected int p = -1;
118 
119 	/** Track the last mark() call result value for use in rewind(). */
120 	protected int lastMarker;
121 
122 	/** Stack of indexes used for push/pop calls */
123 	protected IntArray calls;
124 
BufferedTreeNodeStream(Object tree)125 	public BufferedTreeNodeStream(Object tree) {
126 		this(new CommonTreeAdaptor(), tree);
127 	}
128 
BufferedTreeNodeStream(TreeAdaptor adaptor, Object tree)129 	public BufferedTreeNodeStream(TreeAdaptor adaptor, Object tree) {
130 		this(adaptor, tree, DEFAULT_INITIAL_BUFFER_SIZE);
131 	}
132 
BufferedTreeNodeStream(TreeAdaptor adaptor, Object tree, int initialBufferSize)133 	public BufferedTreeNodeStream(TreeAdaptor adaptor, Object tree, int initialBufferSize) {
134 		this.root = tree;
135 		this.adaptor = adaptor;
136 		nodes = new ArrayList<Object>(initialBufferSize);
137 		down = adaptor.create(Token.DOWN, "DOWN");
138 		up = adaptor.create(Token.UP, "UP");
139 		eof = adaptor.create(Token.EOF, "EOF");
140 	}
141 
142 	/** Walk tree with depth-first-search and fill nodes buffer.
143 	 *  Don't do DOWN, UP nodes if its a list (t is isNil).
144 	 */
fillBuffer()145 	protected void fillBuffer() {
146 		fillBuffer(root);
147 		//System.out.println("revIndex="+tokenTypeToStreamIndexesMap);
148 		p = 0; // buffer of nodes intialized now
149 	}
150 
fillBuffer(Object t)151 	public void fillBuffer(Object t) {
152 		boolean nil = adaptor.isNil(t);
153 		if ( !nil ) {
154 			nodes.add(t); // add this node
155 		}
156 		// add DOWN node if t has children
157 		int n = adaptor.getChildCount(t);
158 		if ( !nil && n>0 ) {
159 			addNavigationNode(Token.DOWN);
160 		}
161 		// and now add all its children
162 		for (int c=0; c<n; c++) {
163 			Object child = adaptor.getChild(t,c);
164 			fillBuffer(child);
165 		}
166 		// add UP node if t has children
167 		if ( !nil && n>0 ) {
168 			addNavigationNode(Token.UP);
169 		}
170 	}
171 
172 	/** What is the stream index for node? 0..n-1
173 	 *  Return -1 if node not found.
174 	 */
getNodeIndex(Object node)175 	protected int getNodeIndex(Object node) {
176 		if ( p==-1 ) {
177 			fillBuffer();
178 		}
179 		for (int i = 0; i < nodes.size(); i++) {
180 			Object t = nodes.get(i);
181 			if ( t==node ) {
182 				return i;
183 			}
184 		}
185 		return -1;
186 	}
187 
188 	/** As we flatten the tree, we use UP, DOWN nodes to represent
189 	 *  the tree structure.  When debugging we need unique nodes
190 	 *  so instantiate new ones when uniqueNavigationNodes is true.
191 	 */
addNavigationNode(final int ttype)192 	protected void addNavigationNode(final int ttype) {
193 		Object navNode;
194 		if ( ttype==Token.DOWN ) {
195 			if ( hasUniqueNavigationNodes() ) {
196 				navNode = adaptor.create(Token.DOWN, "DOWN");
197 			}
198 			else {
199 				navNode = down;
200 			}
201 		}
202 		else {
203 			if ( hasUniqueNavigationNodes() ) {
204 				navNode = adaptor.create(Token.UP, "UP");
205 			}
206 			else {
207 				navNode = up;
208 			}
209 		}
210 		nodes.add(navNode);
211 	}
212 
213 	@Override
get(int i)214 	public Object get(int i) {
215 		if ( p==-1 ) {
216 			fillBuffer();
217 		}
218 		return nodes.get(i);
219 	}
220 
221 	@Override
LT(int k)222 	public Object LT(int k) {
223 		if ( p==-1 ) {
224 			fillBuffer();
225 		}
226 		if ( k==0 ) {
227 			return null;
228 		}
229 		if ( k<0 ) {
230 			return LB(-k);
231 		}
232 		//System.out.print("LT(p="+p+","+k+")=");
233 		if ( (p+k-1) >= nodes.size() ) {
234 			return eof;
235 		}
236 		return nodes.get(p+k-1);
237 	}
238 
getCurrentSymbol()239 	public Object getCurrentSymbol() { return LT(1); }
240 
241 /*
242 	public Object getLastTreeNode() {
243 		int i = index();
244 		if ( i>=size() ) {
245 			i--; // if at EOF, have to start one back
246 		}
247 		System.out.println("start last node: "+i+" size=="+nodes.size());
248 		while ( i>=0 &&
249 			(adaptor.getType(get(i))==Token.EOF ||
250 			 adaptor.getType(get(i))==Token.UP ||
251 			 adaptor.getType(get(i))==Token.DOWN) )
252 		{
253 			i--;
254 		}
255 		System.out.println("stop at node: "+i+" "+nodes.get(i));
256 		return nodes.get(i);
257 	}
258 */
259 
260 	/** Look backwards k nodes */
LB(int k)261 	protected Object LB(int k) {
262 		if ( k==0 ) {
263 			return null;
264 		}
265 		if ( (p-k)<0 ) {
266 			return null;
267 		}
268 		return nodes.get(p-k);
269 	}
270 
271 	@Override
getTreeSource()272 	public Object getTreeSource() {
273 		return root;
274 	}
275 
276 	@Override
getSourceName()277 	public String getSourceName() {
278 		return getTokenStream().getSourceName();
279 	}
280 
281 	@Override
getTokenStream()282 	public TokenStream getTokenStream() {
283 		return tokens;
284 	}
285 
setTokenStream(TokenStream tokens)286 	public void setTokenStream(TokenStream tokens) {
287 		this.tokens = tokens;
288 	}
289 
290 	@Override
getTreeAdaptor()291 	public TreeAdaptor getTreeAdaptor() {
292 		return adaptor;
293 	}
294 
setTreeAdaptor(TreeAdaptor adaptor)295 	public void setTreeAdaptor(TreeAdaptor adaptor) {
296 		this.adaptor = adaptor;
297 	}
298 
hasUniqueNavigationNodes()299 	public boolean hasUniqueNavigationNodes() {
300 		return uniqueNavigationNodes;
301 	}
302 
303 	@Override
setUniqueNavigationNodes(boolean uniqueNavigationNodes)304 	public void setUniqueNavigationNodes(boolean uniqueNavigationNodes) {
305 		this.uniqueNavigationNodes = uniqueNavigationNodes;
306 	}
307 
308 	@Override
consume()309 	public void consume() {
310 		if ( p==-1 ) {
311 			fillBuffer();
312 		}
313 		p++;
314 	}
315 
316 	@Override
LA(int i)317 	public int LA(int i) {
318 		return adaptor.getType(LT(i));
319 	}
320 
321 	@Override
mark()322 	public int mark() {
323 		if ( p==-1 ) {
324 			fillBuffer();
325 		}
326 		lastMarker = index();
327 		return lastMarker;
328 	}
329 
330 	@Override
release(int marker)331 	public void release(int marker) {
332 		// no resources to release
333 	}
334 
335 	@Override
index()336 	public int index() {
337 		return p;
338 	}
339 
340 	@Override
rewind(int marker)341 	public void rewind(int marker) {
342 		seek(marker);
343 	}
344 
345 	@Override
rewind()346 	public void rewind() {
347 		seek(lastMarker);
348 	}
349 
350 	@Override
seek(int index)351 	public void seek(int index) {
352 		if ( p==-1 ) {
353 			fillBuffer();
354 		}
355 		p = index;
356 	}
357 
358 	/** Make stream jump to a new location, saving old location.
359 	 *  Switch back with pop().
360 	 */
push(int index)361 	public void push(int index) {
362 		if ( calls==null ) {
363 			calls = new IntArray();
364 		}
365 		calls.push(p); // save current index
366 		seek(index);
367 	}
368 
369 	/** Seek back to previous index saved during last push() call.
370 	 *  Return top of stack (return index).
371 	 */
pop()372 	public int pop() {
373 		int ret = calls.pop();
374 		seek(ret);
375 		return ret;
376 	}
377 
378 	@Override
reset()379 	public void reset() {
380 		p = 0;
381 		lastMarker = 0;
382         if (calls != null) {
383             calls.clear();
384         }
385     }
386 
387 	@Override
size()388 	public int size() {
389 		if ( p==-1 ) {
390 			fillBuffer();
391 		}
392 		return nodes.size();
393 	}
394 
iterator()395 	public Iterator<Object> iterator() {
396 		if ( p==-1 ) {
397 			fillBuffer();
398 		}
399 		return new StreamIterator();
400 	}
401 
402 	// TREE REWRITE INTERFACE
403 
404 	@Override
replaceChildren(Object parent, int startChildIndex, int stopChildIndex, Object t)405 	public void replaceChildren(Object parent, int startChildIndex, int stopChildIndex, Object t) {
406 		if ( parent!=null ) {
407 			adaptor.replaceChildren(parent, startChildIndex, stopChildIndex, t);
408 		}
409 	}
410 
411 	/** Used for testing, just return the token type stream */
toTokenTypeString()412 	public String toTokenTypeString() {
413 		if ( p==-1 ) {
414 			fillBuffer();
415 		}
416 		StringBuilder buf = new StringBuilder();
417 		for (int i = 0; i < nodes.size(); i++) {
418 			Object t = nodes.get(i);
419 			buf.append(" ");
420 			buf.append(adaptor.getType(t));
421 		}
422 		return buf.toString();
423 	}
424 
425 	/** Debugging */
toTokenString(int start, int stop)426 	public String toTokenString(int start, int stop) {
427 		if ( p==-1 ) {
428 			fillBuffer();
429 		}
430 		StringBuilder buf = new StringBuilder();
431 		for (int i = start; i < nodes.size() && i <= stop; i++) {
432 			Object t = nodes.get(i);
433 			buf.append(" ");
434 			buf.append(adaptor.getToken(t));
435 		}
436 		return buf.toString();
437 	}
438 
439 	@Override
toString(Object start, Object stop)440 	public String toString(Object start, Object stop) {
441 		System.out.println("toString");
442 		if ( start==null || stop==null ) {
443 			return null;
444 		}
445 		if ( p==-1 ) {
446 			fillBuffer();
447 		}
448 		//System.out.println("stop: "+stop);
449 		if ( start instanceof CommonTree )
450 			System.out.print("toString: "+((CommonTree)start).getToken()+", ");
451 		else
452 			System.out.println(start);
453 		if ( stop instanceof CommonTree )
454 			System.out.println(((CommonTree)stop).getToken());
455 		else
456 			System.out.println(stop);
457 		// if we have the token stream, use that to dump text in order
458 		if ( tokens!=null ) {
459 			int beginTokenIndex = adaptor.getTokenStartIndex(start);
460 			int endTokenIndex = adaptor.getTokenStopIndex(stop);
461 			// if it's a tree, use start/stop index from start node
462 			// else use token range from start/stop nodes
463 			if ( adaptor.getType(stop)==Token.UP ) {
464 				endTokenIndex = adaptor.getTokenStopIndex(start);
465 			}
466 			else if ( adaptor.getType(stop)==Token.EOF ) {
467 				endTokenIndex = size()-2; // don't use EOF
468 			}
469 			return tokens.toString(beginTokenIndex, endTokenIndex);
470 		}
471 		// walk nodes looking for start
472 		Object t;
473 		int i = 0;
474 		for (; i < nodes.size(); i++) {
475 			t = nodes.get(i);
476 			if ( t==start ) {
477 				break;
478 			}
479 		}
480 		// now walk until we see stop, filling string buffer with text
481 		StringBuilder buf = new StringBuilder();
482 		t = nodes.get(i);
483 		while ( t!=stop ) {
484 			String text = adaptor.getText(t);
485 			if ( text==null ) {
486 				text = " "+String.valueOf(adaptor.getType(t));
487 			}
488 			buf.append(text);
489 			i++;
490 			t = nodes.get(i);
491 		}
492 		// include stop node too
493 		String text = adaptor.getText(stop);
494 		if ( text==null ) {
495 			text = " "+String.valueOf(adaptor.getType(stop));
496 		}
497 		buf.append(text);
498 		return buf.toString();
499 	}
500 }
501