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