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
33namespace 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
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
97            public void Dispose()
98            {
99            }
100
101            #endregion
102
103            #region IEnumerator Members
104
105            public bool MoveNext()
106            {
107                if ( _index < _outer.nodes.Count )
108                    _index++;
109
110                return _index < _outer.nodes.Count;
111            }
112
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
162        public BufferedTreeNodeStream( object tree )
163            : this( new CommonTreeAdaptor(), tree )
164        {
165        }
166
167        public BufferedTreeNodeStream( ITreeAdaptor adaptor, object tree )
168            : this( adaptor, tree, DEFAULT_INITIAL_BUFFER_SIZE )
169        {
170        }
171
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         */
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
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         */
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         */
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
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
404        public virtual object GetCurrentSymbol()
405        {
406            return LT( 1 );
407        }
408
409#if false
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> */
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
444        public virtual void Consume()
445        {
446            if ( p == -1 )
447            {
448                FillBuffer();
449            }
450            p++;
451        }
452
453        public virtual int LA( int i )
454        {
455            return adaptor.GetType( LT( i ) );
456        }
457
458        public virtual int Mark()
459        {
460            if ( p == -1 )
461            {
462                FillBuffer();
463            }
464            lastMarker = Index;
465            return lastMarker;
466        }
467
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
481        public virtual void Rewind( int marker )
482        {
483            Seek( marker );
484        }
485
486        public virtual void Rewind()
487        {
488            Seek( lastMarker );
489        }
490
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         */
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         */
520        public virtual int Pop()
521        {
522            int ret = calls.Pop();
523            Seek( ret );
524            return ret;
525        }
526
527        public virtual void Reset()
528        {
529            p = 0;
530            lastMarker = 0;
531            if ( calls != null )
532            {
533                calls.Clear();
534            }
535        }
536
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
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> */
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> */
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
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