/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Conversion to C#: * Copyright (c) 2011 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 Antlr.Runtime.Misc; using StringBuilder = System.Text.StringBuilder; [System.Serializable] public class CommonTreeNodeStream : LookaheadStream, ITreeNodeStream, IPositionTrackingStream { public const int DEFAULT_INITIAL_BUFFER_SIZE = 100; public const int INITIAL_CALL_STACK_SIZE = 10; /** Pull nodes from which tree? */ private readonly object _root; /** If this tree (root) was created from a token stream, track it. */ protected ITokenStream tokens; /** What tree adaptor was used to build these trees */ [System.NonSerialized] private ITreeAdaptor _adaptor; /** The tree iterator we are using */ private readonly TreeIterator _it; /** Stack of indexes used for push/pop calls */ private Stack _calls; /** Tree (nil A B C) trees like flat A B C streams */ private bool _hasNilRoot = false; /** Tracks tree depth. Level=0 means we're at root node level. */ private int _level = 0; /** * Tracks the last node before the start of {@link #data} which contains * position information to provide information for error reporting. This is * tracked in addition to {@link #prevElement} which may or may not contain * position information. * * @see #hasPositionInformation * @see RecognitionException#extractInformationFromTreeNodeStream */ private object _previousLocationElement; public CommonTreeNodeStream( object tree ) : this( new CommonTreeAdaptor(), tree ) { } public CommonTreeNodeStream( ITreeAdaptor adaptor, object tree ) { this._root = tree; this._adaptor = adaptor; _it = new TreeIterator( adaptor, _root ); } #region Properties public virtual string SourceName { get { if ( TokenStream == null ) return null; 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 object TreeSource { get { return _root; } } public virtual bool UniqueNavigationNodes { get { return false; } set { } } #endregion public override void Reset() { base.Reset(); _it.Reset(); _hasNilRoot = false; _level = 0; _previousLocationElement = null; if ( _calls != null ) _calls.Clear(); } public override object NextElement() { _it.MoveNext(); object t = _it.Current; //System.out.println("pulled "+adaptor.getType(t)); if ( t == _it.up ) { _level--; if ( _level == 0 && _hasNilRoot ) { _it.MoveNext(); return _it.Current; // don't give last UP; get EOF } } else if ( t == _it.down ) { _level++; } if ( _level == 0 && TreeAdaptor.IsNil( t ) ) { // if nil root, scarf nil, DOWN _hasNilRoot = true; _it.MoveNext(); t = _it.Current; // t is now DOWN, so get first real node next _level++; _it.MoveNext(); t = _it.Current; } return t; } public override object Dequeue() { object result = base.Dequeue(); if (_p == 0 && HasPositionInformation(PreviousElement)) _previousLocationElement = PreviousElement; return result; } public override bool IsEndOfFile(object o) { return TreeAdaptor.GetType(o) == CharStreamConstants.EndOfFile; } public virtual int LA( int i ) { return TreeAdaptor.GetType( LT( i ) ); } /** Make stream jump to a new location, saving old location. * Switch back with pop(). */ public virtual void Push( int index ) { if ( _calls == null ) _calls = new Stack(); _calls.Push( _p ); // save current index Seek( index ); } /** Seek back to previous index saved during last push() call. * Return top of stack (return index). */ public virtual int Pop() { int ret = _calls.Pop(); Seek( ret ); return ret; } /** * Returns an element containing position information. If {@code allowApproximateLocation} is {@code false}, then * this method will return the {@code LT(1)} element if it contains position information, and otherwise return {@code null}. * If {@code allowApproximateLocation} is {@code true}, then this method will return the last known element containing position information. * * @see #hasPositionInformation */ public object GetKnownPositionElement(bool allowApproximateLocation) { object node = _data[_p]; if (HasPositionInformation(node)) return node; if (!allowApproximateLocation) return null; for (int index = _p - 1; index >= 0; index--) { node = _data[index]; if (HasPositionInformation(node)) return node; } return _previousLocationElement; } public bool HasPositionInformation(object node) { IToken token = TreeAdaptor.GetToken(node); if (token == null) return false; if (token.Line <= 0) return false; return true; } #region Tree rewrite interface public virtual void ReplaceChildren( object parent, int startChildIndex, int stopChildIndex, object t ) { if ( parent != null ) { TreeAdaptor.ReplaceChildren( parent, startChildIndex, stopChildIndex, t ); } } #endregion public virtual string ToString( object start, object stop ) { // we'll have to walk from start to stop in tree; we're not keeping // a complete node stream buffer return "n/a"; } /** For debugging; destructive: moves tree iterator to end. */ public virtual string ToTokenTypeString() { Reset(); StringBuilder buf = new StringBuilder(); object o = LT( 1 ); int type = TreeAdaptor.GetType( o ); while ( type != TokenTypes.EndOfFile ) { buf.Append( " " ); buf.Append( type ); Consume(); o = LT( 1 ); type = TreeAdaptor.GetType( o ); } return buf.ToString(); } } }