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