| /* |
| * [The "BSD licence"] |
| * Copyright (c) 2005-2008 Terence Parr |
| * All rights reserved. |
| * |
| * Conversion to C#: |
| * Copyright (c) 2008-2009 Sam Harwell, Pixel Mine, Inc. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. The name of the author may not be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
| * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
| * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| namespace Antlr.Runtime.Tree |
| { |
| using System.Collections.Generic; |
| |
| using Console = System.Console; |
| using IList = System.Collections.IList; |
| using InvalidOperationException = System.InvalidOperationException; |
| using StringBuilder = System.Text.StringBuilder; |
| |
| /** <summary>A buffered stream of tree nodes. Nodes can be from a tree of ANY kind.</summary> |
| * |
| * This node stream sucks all nodes out of the tree specified in |
| * the constructor during construction and makes pointers into |
| * the tree using an array of Object pointers. The stream necessarily |
| * includes pointers to DOWN and UP and EOF nodes. |
| * |
| * This stream knows how to mark/release for backtracking. |
| * |
| * This stream is most suitable for tree interpreters that need to |
| * jump around a lot or for tree parsers requiring speed (at cost of memory). |
| * There is some duplicated functionality here with UnBufferedTreeNodeStream |
| * but just in bookkeeping, not tree walking etc... |
| * |
| * TARGET DEVELOPERS: |
| * |
| * This is the old CommonTreeNodeStream that buffered up entire node stream. |
| * No need to implement really as new CommonTreeNodeStream is much better |
| * and covers what we need. |
| * |
| * @see CommonTreeNodeStream |
| */ |
| public class BufferedTreeNodeStream : ITreeNodeStream, ITokenStreamInformation |
| { |
| public const int DEFAULT_INITIAL_BUFFER_SIZE = 100; |
| public const int INITIAL_CALL_STACK_SIZE = 10; |
| |
| protected sealed class StreamIterator : IEnumerator<object> |
| { |
| BufferedTreeNodeStream _outer; |
| int _index; |
| |
| public StreamIterator( BufferedTreeNodeStream outer ) |
| { |
| _outer = outer; |
| _index = -1; |
| } |
| |
| #region IEnumerator<object> Members |
| |
| public object Current |
| { |
| get |
| { |
| if ( _index < _outer.nodes.Count ) |
| return _outer.nodes[_index]; |
| |
| return _outer.eof; |
| } |
| } |
| |
| #endregion |
| |
| #region IDisposable Members |
| |
| public void Dispose() |
| { |
| } |
| |
| #endregion |
| |
| #region IEnumerator Members |
| |
| public bool MoveNext() |
| { |
| if ( _index < _outer.nodes.Count ) |
| _index++; |
| |
| return _index < _outer.nodes.Count; |
| } |
| |
| public void Reset() |
| { |
| _index = -1; |
| } |
| |
| #endregion |
| } |
| |
| // all these navigation nodes are shared and hence they |
| // cannot contain any line/column info |
| |
| protected object down; |
| protected object up; |
| protected object eof; |
| |
| /** <summary>The complete mapping from stream index to tree node. |
| * This buffer includes pointers to DOWN, UP, and EOF nodes. |
| * It is built upon ctor invocation. The elements are type |
| * Object as we don't what the trees look like.</summary> |
| * |
| * Load upon first need of the buffer so we can set token types |
| * of interest for reverseIndexing. Slows us down a wee bit to |
| * do all of the if p==-1 testing everywhere though. |
| */ |
| protected IList nodes; |
| |
| /** <summary>Pull nodes from which tree?</summary> */ |
| protected object root; |
| |
| /** <summary>IF this tree (root) was created from a token stream, track it.</summary> */ |
| protected ITokenStream tokens; |
| |
| /** <summary>What tree adaptor was used to build these trees</summary> */ |
| ITreeAdaptor adaptor; |
| |
| /** <summary>Reuse same DOWN, UP navigation nodes unless this is true</summary> */ |
| bool uniqueNavigationNodes = false; |
| |
| /** <summary>The index into the nodes list of the current node (next node |
| * to consume). If -1, nodes array not filled yet.</summary> |
| */ |
| protected int p = -1; |
| |
| /** <summary>Track the last mark() call result value for use in rewind().</summary> */ |
| protected int lastMarker; |
| |
| /** <summary>Stack of indexes used for push/pop calls</summary> */ |
| protected Stack<int> calls; |
| |
| public BufferedTreeNodeStream( object tree ) |
| : this( new CommonTreeAdaptor(), tree ) |
| { |
| } |
| |
| public BufferedTreeNodeStream( ITreeAdaptor adaptor, object tree ) |
| : this( adaptor, tree, DEFAULT_INITIAL_BUFFER_SIZE ) |
| { |
| } |
| |
| public BufferedTreeNodeStream( ITreeAdaptor adaptor, object tree, int initialBufferSize ) |
| { |
| this.root = tree; |
| this.adaptor = adaptor; |
| nodes = new List<object>( initialBufferSize ); |
| down = adaptor.Create( TokenTypes.Down, "DOWN" ); |
| up = adaptor.Create( TokenTypes.Up, "UP" ); |
| eof = adaptor.Create( TokenTypes.EndOfFile, "EOF" ); |
| } |
| |
| #region Properties |
| |
| public virtual int Count |
| { |
| get |
| { |
| if ( p == -1 ) |
| { |
| throw new InvalidOperationException( "Cannot determine the Count before the buffer is filled." ); |
| } |
| return nodes.Count; |
| } |
| } |
| |
| public virtual object TreeSource |
| { |
| get |
| { |
| return root; |
| } |
| } |
| |
| public virtual string SourceName |
| { |
| get |
| { |
| return TokenStream.SourceName; |
| } |
| } |
| |
| public virtual ITokenStream TokenStream |
| { |
| get |
| { |
| return tokens; |
| } |
| set |
| { |
| tokens = value; |
| } |
| } |
| |
| public virtual ITreeAdaptor TreeAdaptor |
| { |
| get |
| { |
| return adaptor; |
| } |
| set |
| { |
| adaptor = value; |
| } |
| } |
| |
| public virtual bool UniqueNavigationNodes |
| { |
| get |
| { |
| return uniqueNavigationNodes; |
| } |
| set |
| { |
| uniqueNavigationNodes = value; |
| } |
| } |
| |
| public virtual IToken LastToken |
| { |
| get |
| { |
| return TreeAdaptor.GetToken(LB(1)); |
| } |
| } |
| |
| public virtual IToken LastRealToken |
| { |
| get |
| { |
| int i = 0; |
| IToken token; |
| do |
| { |
| i++; |
| token = TreeAdaptor.GetToken(LB(i)); |
| } while (token != null && token.Line <= 0); |
| |
| return token; |
| } |
| } |
| |
| public virtual int MaxLookBehind |
| { |
| get |
| { |
| return int.MaxValue; |
| } |
| } |
| |
| #endregion |
| |
| /** Walk tree with depth-first-search and fill nodes buffer. |
| * Don't do DOWN, UP nodes if its a list (t is isNil). |
| */ |
| protected virtual void FillBuffer() |
| { |
| FillBuffer( root ); |
| //Console.Out.WriteLine( "revIndex=" + tokenTypeToStreamIndexesMap ); |
| p = 0; // buffer of nodes intialized now |
| } |
| |
| public virtual void FillBuffer( object t ) |
| { |
| bool nil = adaptor.IsNil( t ); |
| if ( !nil ) |
| { |
| nodes.Add( t ); // add this node |
| } |
| // add DOWN node if t has children |
| int n = adaptor.GetChildCount( t ); |
| if ( !nil && n > 0 ) |
| { |
| AddNavigationNode( TokenTypes.Down ); |
| } |
| // and now add all its children |
| for ( int c = 0; c < n; c++ ) |
| { |
| object child = adaptor.GetChild( t, c ); |
| FillBuffer( child ); |
| } |
| // add UP node if t has children |
| if ( !nil && n > 0 ) |
| { |
| AddNavigationNode( TokenTypes.Up ); |
| } |
| } |
| |
| /** What is the stream index for node? 0..n-1 |
| * Return -1 if node not found. |
| */ |
| protected virtual int GetNodeIndex( object node ) |
| { |
| if ( p == -1 ) |
| { |
| FillBuffer(); |
| } |
| for ( int i = 0; i < nodes.Count; i++ ) |
| { |
| object t = nodes[i]; |
| if ( t == node ) |
| { |
| return i; |
| } |
| } |
| return -1; |
| } |
| |
| /** As we flatten the tree, we use UP, DOWN nodes to represent |
| * the tree structure. When debugging we need unique nodes |
| * so instantiate new ones when uniqueNavigationNodes is true. |
| */ |
| protected virtual void AddNavigationNode( int ttype ) |
| { |
| object navNode = null; |
| if ( ttype == TokenTypes.Down ) |
| { |
| if ( UniqueNavigationNodes ) |
| { |
| navNode = adaptor.Create( TokenTypes.Down, "DOWN" ); |
| } |
| else |
| { |
| navNode = down; |
| } |
| } |
| else |
| { |
| if ( UniqueNavigationNodes ) |
| { |
| navNode = adaptor.Create( TokenTypes.Up, "UP" ); |
| } |
| else |
| { |
| navNode = up; |
| } |
| } |
| nodes.Add( navNode ); |
| } |
| |
| public virtual object this[int i] |
| { |
| get |
| { |
| if ( p == -1 ) |
| { |
| throw new InvalidOperationException( "Cannot get the node at index i before the buffer is filled." ); |
| } |
| return nodes[i]; |
| } |
| } |
| |
| public virtual object LT( int k ) |
| { |
| if ( p == -1 ) |
| { |
| FillBuffer(); |
| } |
| if ( k == 0 ) |
| { |
| return null; |
| } |
| if ( k < 0 ) |
| { |
| return LB( -k ); |
| } |
| //System.out.print("LT(p="+p+","+k+")="); |
| if ( ( p + k - 1 ) >= nodes.Count ) |
| { |
| return eof; |
| } |
| return nodes[p + k - 1]; |
| } |
| |
| public virtual object GetCurrentSymbol() |
| { |
| return LT( 1 ); |
| } |
| |
| #if false |
| public virtual object getLastTreeNode() |
| { |
| int i = Index; |
| if ( i >= size() ) |
| { |
| i--; // if at EOF, have to start one back |
| } |
| Console.Out.WriteLine( "start last node: " + i + " size==" + nodes.Count ); |
| while ( i >= 0 && |
| ( adaptor.getType( this[i] ) == TokenTypes.EOF || |
| adaptor.getType( this[i] ) == TokenTypes.UP || |
| adaptor.getType( this[i] ) == TokenTypes.DOWN ) ) |
| { |
| i--; |
| } |
| Console.Out.WriteLine( "stop at node: " + i + " " + nodes[i] ); |
| return nodes[i]; |
| } |
| #endif |
| |
| /** <summary>Look backwards k nodes</summary> */ |
| protected virtual object LB( int k ) |
| { |
| if ( k == 0 ) |
| { |
| return null; |
| } |
| if ( ( p - k ) < 0 ) |
| { |
| return null; |
| } |
| return nodes[p - k]; |
| } |
| |
| public virtual void Consume() |
| { |
| if ( p == -1 ) |
| { |
| FillBuffer(); |
| } |
| p++; |
| } |
| |
| public virtual int LA( int i ) |
| { |
| return adaptor.GetType( LT( i ) ); |
| } |
| |
| public virtual int Mark() |
| { |
| if ( p == -1 ) |
| { |
| FillBuffer(); |
| } |
| lastMarker = Index; |
| return lastMarker; |
| } |
| |
| public virtual void Release( int marker ) |
| { |
| // no resources to release |
| } |
| |
| public virtual int Index |
| { |
| get |
| { |
| return p; |
| } |
| } |
| |
| public virtual void Rewind( int marker ) |
| { |
| Seek( marker ); |
| } |
| |
| public virtual void Rewind() |
| { |
| Seek( lastMarker ); |
| } |
| |
| public virtual void Seek( int index ) |
| { |
| if ( p == -1 ) |
| { |
| FillBuffer(); |
| } |
| p = index; |
| } |
| |
| /** <summary> |
| * Make stream jump to a new location, saving old location. |
| * Switch back with pop(). |
| * </summary> |
| */ |
| public virtual void Push( int index ) |
| { |
| if ( calls == null ) |
| { |
| calls = new Stack<int>(); |
| } |
| calls.Push( p ); // save current index |
| Seek( index ); |
| } |
| |
| /** <summary> |
| * Seek back to previous index saved during last push() call. |
| * Return top of stack (return index). |
| * </summary> |
| */ |
| public virtual int Pop() |
| { |
| int ret = calls.Pop(); |
| Seek( ret ); |
| return ret; |
| } |
| |
| public virtual void Reset() |
| { |
| p = 0; |
| lastMarker = 0; |
| if ( calls != null ) |
| { |
| calls.Clear(); |
| } |
| } |
| |
| public virtual IEnumerator<object> Iterator() |
| { |
| if ( p == -1 ) |
| { |
| FillBuffer(); |
| } |
| |
| return new StreamIterator( this ); |
| } |
| |
| // TREE REWRITE INTERFACE |
| |
| public virtual void ReplaceChildren( object parent, int startChildIndex, int stopChildIndex, object t ) |
| { |
| if ( parent != null ) |
| { |
| adaptor.ReplaceChildren( parent, startChildIndex, stopChildIndex, t ); |
| } |
| } |
| |
| /** <summary>Used for testing, just return the token type stream</summary> */ |
| public virtual string ToTokenTypeString() |
| { |
| if ( p == -1 ) |
| { |
| FillBuffer(); |
| } |
| StringBuilder buf = new StringBuilder(); |
| for ( int i = 0; i < nodes.Count; i++ ) |
| { |
| object t = nodes[i]; |
| buf.Append( " " ); |
| buf.Append( adaptor.GetType( t ) ); |
| } |
| return buf.ToString(); |
| } |
| |
| /** <summary>Debugging</summary> */ |
| public virtual string ToTokenString( int start, int stop ) |
| { |
| if ( p == -1 ) |
| { |
| FillBuffer(); |
| } |
| StringBuilder buf = new StringBuilder(); |
| for ( int i = start; i < nodes.Count && i <= stop; i++ ) |
| { |
| object t = nodes[i]; |
| buf.Append( " " ); |
| buf.Append( adaptor.GetToken( t ) ); |
| } |
| return buf.ToString(); |
| } |
| |
| public virtual string ToString( object start, object stop ) |
| { |
| Console.Out.WriteLine( "toString" ); |
| if ( start == null || stop == null ) |
| { |
| return null; |
| } |
| if ( p == -1 ) |
| { |
| throw new InvalidOperationException( "Buffer is not yet filled." ); |
| } |
| //Console.Out.WriteLine( "stop: " + stop ); |
| if ( start is CommonTree ) |
| Console.Out.Write( "toString: " + ( (CommonTree)start ).Token + ", " ); |
| else |
| Console.Out.WriteLine( start ); |
| if ( stop is CommonTree ) |
| Console.Out.WriteLine( ( (CommonTree)stop ).Token ); |
| else |
| Console.Out.WriteLine( stop ); |
| // if we have the token stream, use that to dump text in order |
| if ( tokens != null ) |
| { |
| int beginTokenIndex = adaptor.GetTokenStartIndex( start ); |
| int endTokenIndex = adaptor.GetTokenStopIndex( stop ); |
| // if it's a tree, use start/stop index from start node |
| // else use token range from start/stop nodes |
| if ( adaptor.GetType( stop ) == TokenTypes.Up ) |
| { |
| endTokenIndex = adaptor.GetTokenStopIndex( start ); |
| } |
| else if ( adaptor.GetType( stop ) == TokenTypes.EndOfFile ) |
| { |
| endTokenIndex = Count - 2; // don't use EOF |
| } |
| return tokens.ToString( beginTokenIndex, endTokenIndex ); |
| } |
| // walk nodes looking for start |
| object t = null; |
| int i = 0; |
| for ( ; i < nodes.Count; i++ ) |
| { |
| t = nodes[i]; |
| if ( t == start ) |
| { |
| break; |
| } |
| } |
| // now walk until we see stop, filling string buffer with text |
| StringBuilder buf = new StringBuilder(); |
| t = nodes[i]; |
| while ( t != stop ) |
| { |
| string text = adaptor.GetText( t ); |
| if ( text == null ) |
| { |
| text = " " + adaptor.GetType( t ).ToString(); |
| } |
| buf.Append( text ); |
| i++; |
| t = nodes[i]; |
| } |
| // include stop node too |
| string text2 = adaptor.GetText( stop ); |
| if ( text2 == null ) |
| { |
| text2 = " " + adaptor.GetType( stop ).ToString(); |
| } |
| buf.Append( text2 ); |
| return buf.ToString(); |
| } |
| } |
| } |