/* * [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; 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] public abstract class BaseTree : ITree { List 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; } } #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; } 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; List 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 List 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 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 } }