/* * [The "BSD license"] * Copyright (c) 2011 Terence Parr * All rights reserved. * * Conversion to C#: * Copyright (c) 2011 Sam Harwell, Tunnel Vision Laboratories, LLC * 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; using System.Collections.Generic; using StringBuilder = System.Text.StringBuilder; /** * A generic tree implementation with no payload. You must subclass to * actually have any user data. ANTLR v3 uses a list of children approach * instead of the child-sibling approach in v2. A flat tree (a list) is * an empty node whose children represent the list. An empty, but * non-null node is called "nil". * */ [System.Serializable] [System.Diagnostics.DebuggerTypeProxy(typeof(AntlrRuntime_BaseTreeDebugView))] public abstract class BaseTree : ITree { private IList _children; public BaseTree() { } /** * Create a new node from an existing node does nothing for BaseTree * as there are no fields other than the children list, which cannot * be copied as the children are not considered part of this node. * */ public BaseTree( ITree node ) { } /** * Get the children internal List; note that if you directly mess with * the list, do so at your own risk. * */ public virtual IList Children { get { return _children; } private set { _children = value; } } #region ITree Members public virtual int ChildCount { get { if ( Children == null ) return 0; return Children.Count; } } /** BaseTree doesn't track parent pointers. */ public virtual ITree Parent { get { return null; } set { } } /** BaseTree doesn't track child indexes. */ public virtual int ChildIndex { get { return 0; } set { } } public virtual bool IsNil { get { return false; } } public abstract int TokenStartIndex { get; set; } public abstract int TokenStopIndex { get; set; } public abstract int Type { get; set; } public abstract string Text { get; set; } public virtual int Line { get; set; } public virtual int CharPositionInLine { get; set; } #endregion public virtual ITree GetChild( int i ) { if (i < 0) throw new ArgumentOutOfRangeException(); if ( Children == null || i >= Children.Count ) return null; return Children[i]; } public virtual ITree GetFirstChildWithType( int type ) { foreach ( ITree child in Children ) { if ( child.Type == type ) return child; } return null; } /** Add t as child of this node. * * * Warning: if t has no children, but child does * and child isNil then this routine moves children to t via * t.children = child.children; i.e., without copying the array. * */ public virtual void AddChild( ITree t ) { //System.out.println("add child "+t.toStringTree()+" "+this.toStringTree()); //System.out.println("existing children: "+children); if ( t == null ) { return; // do nothing upon addChild(null) } if ( t.IsNil ) { // t is an empty node possibly with children BaseTree childTree = t as BaseTree; if ( childTree != null && this.Children != null && this.Children == childTree.Children ) { throw new Exception( "attempt to add child list to itself" ); } // just add all of childTree's children to this if ( t.ChildCount > 0 ) { if ( this.Children != null || childTree == null ) { if ( this.Children == null ) this.Children = CreateChildrenList(); // must copy, this has children already int n = t.ChildCount; for ( int i = 0; i < n; i++ ) { ITree c = t.GetChild( i ); this.Children.Add( c ); // handle double-link stuff for each child of nil root c.Parent = this; c.ChildIndex = Children.Count - 1; } } else { // no children for this but t is a BaseTree with children; // just set pointer call general freshener routine this.Children = childTree.Children; this.FreshenParentAndChildIndexes(); } } } else { // child is not nil (don't care about children) if ( Children == null ) { Children = CreateChildrenList(); // create children list on demand } Children.Add( t ); t.Parent = this; t.ChildIndex = Children.Count - 1; } // System.out.println("now children are: "+children); } /** Add all elements of kids list as children of this node */ public virtual void AddChildren( IEnumerable kids ) { if (kids == null) throw new ArgumentNullException("kids"); foreach ( ITree t in kids ) AddChild( t ); } public virtual void SetChild( int i, ITree t ) { if (i < 0) throw new ArgumentOutOfRangeException("i"); if ( t == null ) { return; } if ( t.IsNil ) { throw new ArgumentException( "Can't set single child to a list" ); } if ( Children == null ) { Children = CreateChildrenList(); } Children[i] = t; t.Parent = this; t.ChildIndex = i; } /** Insert child t at child position i (0..n-1) by shifting children * i+1..n-1 to the right one position. Set parent / indexes properly * but does NOT collapse nil-rooted t's that come in here like addChild. */ public virtual void InsertChild(int i, ITree t) { if (i < 0) throw new ArgumentOutOfRangeException("i"); if (i > ChildCount) throw new ArgumentException(); if (i == ChildCount) { AddChild(t); return; } Children.Insert(i, t); // walk others to increment their child indexes // set index, parent of this one too this.FreshenParentAndChildIndexes(i); } public virtual object DeleteChild( int i ) { if (i < 0) throw new ArgumentOutOfRangeException("i"); if (i >= ChildCount) throw new ArgumentException(); if ( Children == null ) return null; ITree killed = Children[i]; Children.RemoveAt( i ); // walk rest and decrement their child indexes this.FreshenParentAndChildIndexes( i ); return killed; } /** * Delete children from start to stop and replace with t even if t is * a list (nil-root tree). num of children can increase or decrease. * For huge child lists, inserting children can force walking rest of * children to set their childindex; could be slow. * */ public virtual void ReplaceChildren( int startChildIndex, int stopChildIndex, object t ) { if (startChildIndex < 0) throw new ArgumentOutOfRangeException(); if (stopChildIndex < 0) throw new ArgumentOutOfRangeException(); if (t == null) throw new ArgumentNullException("t"); if (stopChildIndex < startChildIndex) throw new ArgumentException(); /* System.out.println("replaceChildren "+startChildIndex+", "+stopChildIndex+ " with "+((BaseTree)t).toStringTree()); System.out.println("in="+toStringTree()); */ if ( Children == null ) { throw new ArgumentException( "indexes invalid; no children in list" ); } int replacingHowMany = stopChildIndex - startChildIndex + 1; int replacingWithHowMany; ITree newTree = (ITree)t; IList newChildren = null; // normalize to a list of children to add: newChildren if ( newTree.IsNil ) { BaseTree baseTree = newTree as BaseTree; if ( baseTree != null && baseTree.Children != null ) { newChildren = baseTree.Children; } else { newChildren = CreateChildrenList(); int n = newTree.ChildCount; for ( int i = 0; i < n; i++ ) newChildren.Add( newTree.GetChild( i ) ); } } else { newChildren = new List( 1 ); newChildren.Add( newTree ); } replacingWithHowMany = newChildren.Count; int numNewChildren = newChildren.Count; int delta = replacingHowMany - replacingWithHowMany; // if same number of nodes, do direct replace if ( delta == 0 ) { int j = 0; // index into new children for ( int i = startChildIndex; i <= stopChildIndex; i++ ) { ITree child = newChildren[j]; Children[i] = child; child.Parent = this; child.ChildIndex = i; j++; } } else if ( delta > 0 ) { // fewer new nodes than there were // set children and then delete extra for ( int j = 0; j < numNewChildren; j++ ) { Children[startChildIndex + j] = newChildren[j]; } int indexToDelete = startChildIndex + numNewChildren; for ( int c = indexToDelete; c <= stopChildIndex; c++ ) { // delete same index, shifting everybody down each time Children.RemoveAt( indexToDelete ); } FreshenParentAndChildIndexes( startChildIndex ); } else { // more new nodes than were there before // fill in as many children as we can (replacingHowMany) w/o moving data for ( int j = 0; j < replacingHowMany; j++ ) { Children[startChildIndex + j] = newChildren[j]; } int numToInsert = replacingWithHowMany - replacingHowMany; for ( int j = replacingHowMany; j < replacingWithHowMany; j++ ) { Children.Insert( startChildIndex + j, newChildren[j] ); } FreshenParentAndChildIndexes( startChildIndex ); } //System.out.println("out="+toStringTree()); } /** Override in a subclass to change the impl of children list */ protected virtual IList CreateChildrenList() { return new List(); } /** Set the parent and child index values for all child of t */ public virtual void FreshenParentAndChildIndexes() { FreshenParentAndChildIndexes( 0 ); } public virtual void FreshenParentAndChildIndexes( int offset ) { int n = ChildCount; for ( int c = offset; c < n; c++ ) { ITree child = GetChild( c ); child.ChildIndex = c; child.Parent = this; } } public virtual void FreshenParentAndChildIndexesDeeply() { FreshenParentAndChildIndexesDeeply(0); } public virtual void FreshenParentAndChildIndexesDeeply(int offset) { int n = ChildCount; for (int c = offset; c < n; c++) { ITree child = GetChild(c); child.ChildIndex = c; child.Parent = this; BaseTree baseTree = child as BaseTree; if (baseTree != null) baseTree.FreshenParentAndChildIndexesDeeply(); } } public virtual void SanityCheckParentAndChildIndexes() { SanityCheckParentAndChildIndexes( null, -1 ); } public virtual void SanityCheckParentAndChildIndexes( ITree parent, int i ) { if ( parent != this.Parent ) { throw new InvalidOperationException( "parents don't match; expected " + parent + " found " + this.Parent ); } if ( i != this.ChildIndex ) { throw new InvalidOperationException( "child indexes don't match; expected " + i + " found " + this.ChildIndex ); } int n = this.ChildCount; for ( int c = 0; c < n; c++ ) { BaseTree child = (BaseTree)this.GetChild( c ); child.SanityCheckParentAndChildIndexes( this, c ); } } /** Walk upwards looking for ancestor with this token type. */ public virtual bool HasAncestor( int ttype ) { return GetAncestor( ttype ) != null; } /** Walk upwards and get first ancestor with this token type. */ public virtual ITree GetAncestor( int ttype ) { ITree t = this; t = t.Parent; while ( t != null ) { if ( t.Type == ttype ) return t; t = t.Parent; } return null; } /** * Return a list of all ancestors of this node. The first node of * list is the root and the last is the parent of this node. * */ public virtual IList GetAncestors() { if ( Parent == null ) return null; List ancestors = new List(); ITree t = this; t = t.Parent; while ( t != null ) { ancestors.Insert( 0, t ); // insert at start t = t.Parent; } return ancestors; } /** Print out a whole tree not just a node */ public virtual string ToStringTree() { if ( Children == null || Children.Count == 0 ) { return this.ToString(); } StringBuilder buf = new StringBuilder(); if ( !IsNil ) { buf.Append( "(" ); buf.Append( this.ToString() ); buf.Append( ' ' ); } for ( int i = 0; Children != null && i < Children.Count; i++ ) { ITree t = Children[i]; if ( i > 0 ) { buf.Append( ' ' ); } buf.Append( t.ToStringTree() ); } if ( !IsNil ) { buf.Append( ")" ); } return buf.ToString(); } /** Override to say how a node (not a tree) should look as text */ public override abstract string ToString(); #region Tree Members public abstract ITree DupNode(); #endregion } }