1 /* 2 * [The "BSD licence"] 3 * Copyright (c) 2005-2008 Terence Parr 4 * All rights reserved. 5 * 6 * Conversion to C#: 7 * Copyright (c) 2008-2009 Sam Harwell, Pixel Mine, Inc. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 namespace Antlr.Runtime.Tree 34 { 35 using System.Collections.Generic; 36 37 using Console = System.Console; 38 using IList = System.Collections.IList; 39 using InvalidOperationException = System.InvalidOperationException; 40 using StringBuilder = System.Text.StringBuilder; 41 42 /** <summary>A buffered stream of tree nodes. Nodes can be from a tree of ANY kind.</summary> 43 * 44 * This node stream sucks all nodes out of the tree specified in 45 * the constructor during construction and makes pointers into 46 * the tree using an array of Object pointers. The stream necessarily 47 * includes pointers to DOWN and UP and EOF nodes. 48 * 49 * This stream knows how to mark/release for backtracking. 50 * 51 * This stream is most suitable for tree interpreters that need to 52 * jump around a lot or for tree parsers requiring speed (at cost of memory). 53 * There is some duplicated functionality here with UnBufferedTreeNodeStream 54 * but just in bookkeeping, not tree walking etc... 55 * 56 * TARGET DEVELOPERS: 57 * 58 * This is the old CommonTreeNodeStream that buffered up entire node stream. 59 * No need to implement really as new CommonTreeNodeStream is much better 60 * and covers what we need. 61 * 62 * @see CommonTreeNodeStream 63 */ 64 public class BufferedTreeNodeStream : ITreeNodeStream, ITokenStreamInformation 65 { 66 public const int DEFAULT_INITIAL_BUFFER_SIZE = 100; 67 public const int INITIAL_CALL_STACK_SIZE = 10; 68 69 protected sealed class StreamIterator : IEnumerator<object> 70 { 71 BufferedTreeNodeStream _outer; 72 int _index; 73 StreamIterator( BufferedTreeNodeStream outer )74 public StreamIterator( BufferedTreeNodeStream outer ) 75 { 76 _outer = outer; 77 _index = -1; 78 } 79 80 #region IEnumerator<object> Members 81 82 public object Current 83 { 84 get 85 { 86 if ( _index < _outer.nodes.Count ) 87 return _outer.nodes[_index]; 88 89 return _outer.eof; 90 } 91 } 92 93 #endregion 94 95 #region IDisposable Members 96 Dispose()97 public void Dispose() 98 { 99 } 100 101 #endregion 102 103 #region IEnumerator Members 104 MoveNext()105 public bool MoveNext() 106 { 107 if ( _index < _outer.nodes.Count ) 108 _index++; 109 110 return _index < _outer.nodes.Count; 111 } 112 Reset()113 public void Reset() 114 { 115 _index = -1; 116 } 117 118 #endregion 119 } 120 121 // all these navigation nodes are shared and hence they 122 // cannot contain any line/column info 123 124 protected object down; 125 protected object up; 126 protected object eof; 127 128 /** <summary>The complete mapping from stream index to tree node. 129 * This buffer includes pointers to DOWN, UP, and EOF nodes. 130 * It is built upon ctor invocation. The elements are type 131 * Object as we don't what the trees look like.</summary> 132 * 133 * Load upon first need of the buffer so we can set token types 134 * of interest for reverseIndexing. Slows us down a wee bit to 135 * do all of the if p==-1 testing everywhere though. 136 */ 137 protected IList nodes; 138 139 /** <summary>Pull nodes from which tree?</summary> */ 140 protected object root; 141 142 /** <summary>IF this tree (root) was created from a token stream, track it.</summary> */ 143 protected ITokenStream tokens; 144 145 /** <summary>What tree adaptor was used to build these trees</summary> */ 146 ITreeAdaptor adaptor; 147 148 /** <summary>Reuse same DOWN, UP navigation nodes unless this is true</summary> */ 149 bool uniqueNavigationNodes = false; 150 151 /** <summary>The index into the nodes list of the current node (next node 152 * to consume). If -1, nodes array not filled yet.</summary> 153 */ 154 protected int p = -1; 155 156 /** <summary>Track the last mark() call result value for use in rewind().</summary> */ 157 protected int lastMarker; 158 159 /** <summary>Stack of indexes used for push/pop calls</summary> */ 160 protected Stack<int> calls; 161 BufferedTreeNodeStream( object tree )162 public BufferedTreeNodeStream( object tree ) 163 : this( new CommonTreeAdaptor(), tree ) 164 { 165 } 166 BufferedTreeNodeStream( ITreeAdaptor adaptor, object tree )167 public BufferedTreeNodeStream( ITreeAdaptor adaptor, object tree ) 168 : this( adaptor, tree, DEFAULT_INITIAL_BUFFER_SIZE ) 169 { 170 } 171 BufferedTreeNodeStream( ITreeAdaptor adaptor, object tree, int initialBufferSize )172 public BufferedTreeNodeStream( ITreeAdaptor adaptor, object tree, int initialBufferSize ) 173 { 174 this.root = tree; 175 this.adaptor = adaptor; 176 nodes = new List<object>( initialBufferSize ); 177 down = adaptor.Create( TokenTypes.Down, "DOWN" ); 178 up = adaptor.Create( TokenTypes.Up, "UP" ); 179 eof = adaptor.Create( TokenTypes.EndOfFile, "EOF" ); 180 } 181 182 #region Properties 183 184 public virtual int Count 185 { 186 get 187 { 188 if ( p == -1 ) 189 { 190 throw new InvalidOperationException( "Cannot determine the Count before the buffer is filled." ); 191 } 192 return nodes.Count; 193 } 194 } 195 196 public virtual object TreeSource 197 { 198 get 199 { 200 return root; 201 } 202 } 203 204 public virtual string SourceName 205 { 206 get 207 { 208 return TokenStream.SourceName; 209 } 210 } 211 212 public virtual ITokenStream TokenStream 213 { 214 get 215 { 216 return tokens; 217 } 218 set 219 { 220 tokens = value; 221 } 222 } 223 224 public virtual ITreeAdaptor TreeAdaptor 225 { 226 get 227 { 228 return adaptor; 229 } 230 set 231 { 232 adaptor = value; 233 } 234 } 235 236 public virtual bool UniqueNavigationNodes 237 { 238 get 239 { 240 return uniqueNavigationNodes; 241 } 242 set 243 { 244 uniqueNavigationNodes = value; 245 } 246 } 247 248 public virtual IToken LastToken 249 { 250 get 251 { 252 return TreeAdaptor.GetToken(LB(1)); 253 } 254 } 255 256 public virtual IToken LastRealToken 257 { 258 get 259 { 260 int i = 0; 261 IToken token; 262 do 263 { 264 i++; 265 token = TreeAdaptor.GetToken(LB(i)); 266 } while (token != null && token.Line <= 0); 267 268 return token; 269 } 270 } 271 272 public virtual int MaxLookBehind 273 { 274 get 275 { 276 return int.MaxValue; 277 } 278 } 279 280 #endregion 281 282 /** Walk tree with depth-first-search and fill nodes buffer. 283 * Don't do DOWN, UP nodes if its a list (t is isNil). 284 */ FillBuffer()285 protected virtual void FillBuffer() 286 { 287 FillBuffer( root ); 288 //Console.Out.WriteLine( "revIndex=" + tokenTypeToStreamIndexesMap ); 289 p = 0; // buffer of nodes intialized now 290 } 291 FillBuffer( object t )292 public virtual void FillBuffer( object t ) 293 { 294 bool nil = adaptor.IsNil( t ); 295 if ( !nil ) 296 { 297 nodes.Add( t ); // add this node 298 } 299 // add DOWN node if t has children 300 int n = adaptor.GetChildCount( t ); 301 if ( !nil && n > 0 ) 302 { 303 AddNavigationNode( TokenTypes.Down ); 304 } 305 // and now add all its children 306 for ( int c = 0; c < n; c++ ) 307 { 308 object child = adaptor.GetChild( t, c ); 309 FillBuffer( child ); 310 } 311 // add UP node if t has children 312 if ( !nil && n > 0 ) 313 { 314 AddNavigationNode( TokenTypes.Up ); 315 } 316 } 317 318 /** What is the stream index for node? 0..n-1 319 * Return -1 if node not found. 320 */ GetNodeIndex( object node )321 protected virtual int GetNodeIndex( object node ) 322 { 323 if ( p == -1 ) 324 { 325 FillBuffer(); 326 } 327 for ( int i = 0; i < nodes.Count; i++ ) 328 { 329 object t = nodes[i]; 330 if ( t == node ) 331 { 332 return i; 333 } 334 } 335 return -1; 336 } 337 338 /** As we flatten the tree, we use UP, DOWN nodes to represent 339 * the tree structure. When debugging we need unique nodes 340 * so instantiate new ones when uniqueNavigationNodes is true. 341 */ AddNavigationNode( int ttype )342 protected virtual void AddNavigationNode( int ttype ) 343 { 344 object navNode = null; 345 if ( ttype == TokenTypes.Down ) 346 { 347 if ( UniqueNavigationNodes ) 348 { 349 navNode = adaptor.Create( TokenTypes.Down, "DOWN" ); 350 } 351 else 352 { 353 navNode = down; 354 } 355 } 356 else 357 { 358 if ( UniqueNavigationNodes ) 359 { 360 navNode = adaptor.Create( TokenTypes.Up, "UP" ); 361 } 362 else 363 { 364 navNode = up; 365 } 366 } 367 nodes.Add( navNode ); 368 } 369 370 public virtual object this[int i] 371 { 372 get 373 { 374 if ( p == -1 ) 375 { 376 throw new InvalidOperationException( "Cannot get the node at index i before the buffer is filled." ); 377 } 378 return nodes[i]; 379 } 380 } 381 LT( int k )382 public virtual object LT( int k ) 383 { 384 if ( p == -1 ) 385 { 386 FillBuffer(); 387 } 388 if ( k == 0 ) 389 { 390 return null; 391 } 392 if ( k < 0 ) 393 { 394 return LB( -k ); 395 } 396 //System.out.print("LT(p="+p+","+k+")="); 397 if ( ( p + k - 1 ) >= nodes.Count ) 398 { 399 return eof; 400 } 401 return nodes[p + k - 1]; 402 } 403 GetCurrentSymbol()404 public virtual object GetCurrentSymbol() 405 { 406 return LT( 1 ); 407 } 408 409 #if false getLastTreeNode()410 public virtual object getLastTreeNode() 411 { 412 int i = Index; 413 if ( i >= size() ) 414 { 415 i--; // if at EOF, have to start one back 416 } 417 Console.Out.WriteLine( "start last node: " + i + " size==" + nodes.Count ); 418 while ( i >= 0 && 419 ( adaptor.getType( this[i] ) == TokenTypes.EOF || 420 adaptor.getType( this[i] ) == TokenTypes.UP || 421 adaptor.getType( this[i] ) == TokenTypes.DOWN ) ) 422 { 423 i--; 424 } 425 Console.Out.WriteLine( "stop at node: " + i + " " + nodes[i] ); 426 return nodes[i]; 427 } 428 #endif 429 430 /** <summary>Look backwards k nodes</summary> */ LB( int k )431 protected virtual object LB( int k ) 432 { 433 if ( k == 0 ) 434 { 435 return null; 436 } 437 if ( ( p - k ) < 0 ) 438 { 439 return null; 440 } 441 return nodes[p - k]; 442 } 443 Consume()444 public virtual void Consume() 445 { 446 if ( p == -1 ) 447 { 448 FillBuffer(); 449 } 450 p++; 451 } 452 LA( int i )453 public virtual int LA( int i ) 454 { 455 return adaptor.GetType( LT( i ) ); 456 } 457 Mark()458 public virtual int Mark() 459 { 460 if ( p == -1 ) 461 { 462 FillBuffer(); 463 } 464 lastMarker = Index; 465 return lastMarker; 466 } 467 Release( int marker )468 public virtual void Release( int marker ) 469 { 470 // no resources to release 471 } 472 473 public virtual int Index 474 { 475 get 476 { 477 return p; 478 } 479 } 480 Rewind( int marker )481 public virtual void Rewind( int marker ) 482 { 483 Seek( marker ); 484 } 485 Rewind()486 public virtual void Rewind() 487 { 488 Seek( lastMarker ); 489 } 490 Seek( int index )491 public virtual void Seek( int index ) 492 { 493 if ( p == -1 ) 494 { 495 FillBuffer(); 496 } 497 p = index; 498 } 499 500 /** <summary> 501 * Make stream jump to a new location, saving old location. 502 * Switch back with pop(). 503 * </summary> 504 */ Push( int index )505 public virtual void Push( int index ) 506 { 507 if ( calls == null ) 508 { 509 calls = new Stack<int>(); 510 } 511 calls.Push( p ); // save current index 512 Seek( index ); 513 } 514 515 /** <summary> 516 * Seek back to previous index saved during last push() call. 517 * Return top of stack (return index). 518 * </summary> 519 */ Pop()520 public virtual int Pop() 521 { 522 int ret = calls.Pop(); 523 Seek( ret ); 524 return ret; 525 } 526 Reset()527 public virtual void Reset() 528 { 529 p = 0; 530 lastMarker = 0; 531 if ( calls != null ) 532 { 533 calls.Clear(); 534 } 535 } 536 Iterator()537 public virtual IEnumerator<object> Iterator() 538 { 539 if ( p == -1 ) 540 { 541 FillBuffer(); 542 } 543 544 return new StreamIterator( this ); 545 } 546 547 // TREE REWRITE INTERFACE 548 ReplaceChildren( object parent, int startChildIndex, int stopChildIndex, object t )549 public virtual void ReplaceChildren( object parent, int startChildIndex, int stopChildIndex, object t ) 550 { 551 if ( parent != null ) 552 { 553 adaptor.ReplaceChildren( parent, startChildIndex, stopChildIndex, t ); 554 } 555 } 556 557 /** <summary>Used for testing, just return the token type stream</summary> */ ToTokenTypeString()558 public virtual string ToTokenTypeString() 559 { 560 if ( p == -1 ) 561 { 562 FillBuffer(); 563 } 564 StringBuilder buf = new StringBuilder(); 565 for ( int i = 0; i < nodes.Count; i++ ) 566 { 567 object t = nodes[i]; 568 buf.Append( " " ); 569 buf.Append( adaptor.GetType( t ) ); 570 } 571 return buf.ToString(); 572 } 573 574 /** <summary>Debugging</summary> */ ToTokenString( int start, int stop )575 public virtual string ToTokenString( int start, int stop ) 576 { 577 if ( p == -1 ) 578 { 579 FillBuffer(); 580 } 581 StringBuilder buf = new StringBuilder(); 582 for ( int i = start; i < nodes.Count && i <= stop; i++ ) 583 { 584 object t = nodes[i]; 585 buf.Append( " " ); 586 buf.Append( adaptor.GetToken( t ) ); 587 } 588 return buf.ToString(); 589 } 590 ToString( object start, object stop )591 public virtual string ToString( object start, object stop ) 592 { 593 Console.Out.WriteLine( "toString" ); 594 if ( start == null || stop == null ) 595 { 596 return null; 597 } 598 if ( p == -1 ) 599 { 600 throw new InvalidOperationException( "Buffer is not yet filled." ); 601 } 602 //Console.Out.WriteLine( "stop: " + stop ); 603 if ( start is CommonTree ) 604 Console.Out.Write( "toString: " + ( (CommonTree)start ).Token + ", " ); 605 else 606 Console.Out.WriteLine( start ); 607 if ( stop is CommonTree ) 608 Console.Out.WriteLine( ( (CommonTree)stop ).Token ); 609 else 610 Console.Out.WriteLine( stop ); 611 // if we have the token stream, use that to dump text in order 612 if ( tokens != null ) 613 { 614 int beginTokenIndex = adaptor.GetTokenStartIndex( start ); 615 int endTokenIndex = adaptor.GetTokenStopIndex( stop ); 616 // if it's a tree, use start/stop index from start node 617 // else use token range from start/stop nodes 618 if ( adaptor.GetType( stop ) == TokenTypes.Up ) 619 { 620 endTokenIndex = adaptor.GetTokenStopIndex( start ); 621 } 622 else if ( adaptor.GetType( stop ) == TokenTypes.EndOfFile ) 623 { 624 endTokenIndex = Count - 2; // don't use EOF 625 } 626 return tokens.ToString( beginTokenIndex, endTokenIndex ); 627 } 628 // walk nodes looking for start 629 object t = null; 630 int i = 0; 631 for ( ; i < nodes.Count; i++ ) 632 { 633 t = nodes[i]; 634 if ( t == start ) 635 { 636 break; 637 } 638 } 639 // now walk until we see stop, filling string buffer with text 640 StringBuilder buf = new StringBuilder(); 641 t = nodes[i]; 642 while ( t != stop ) 643 { 644 string text = adaptor.GetText( t ); 645 if ( text == null ) 646 { 647 text = " " + adaptor.GetType( t ).ToString(); 648 } 649 buf.Append( text ); 650 i++; 651 t = nodes[i]; 652 } 653 // include stop node too 654 string text2 = adaptor.GetText( stop ); 655 if ( text2 == null ) 656 { 657 text2 = " " + adaptor.GetType( stop ).ToString(); 658 } 659 buf.Append( text2 ); 660 return buf.ToString(); 661 } 662 } 663 } 664