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