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