blob: 155e4dff78d944332d9a98b82a03854a9edeb957 [file] [log] [blame]
/*
* [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;
/** <summary>
* 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".
* </summary>
*/
[System.Serializable]
public abstract class BaseTree : ITree {
List<ITree> children;
public BaseTree() {
}
/** <summary>
* 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.
* </summary>
*/
public BaseTree(ITree node) {
}
/** <summary>
* Get the children internal List; note that if you directly mess with
* the list, do so at your own risk.
* </summary>
*/
public virtual IList<ITree> Children {
get {
return children;
}
}
#region ITree Members
public virtual int ChildCount {
get {
if (Children == null)
return 0;
return Children.Count;
}
}
/** <summary>BaseTree doesn't track parent pointers.</summary> */
public virtual ITree Parent {
get {
return null;
}
set {
}
}
/** <summary>BaseTree doesn't track child indexes.</summary> */
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;
}
/** <summary>Add t as child of this node.</summary>
*
* <remarks>
* 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.
* </remarks>
*/
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);
}
/** <summary>Add all elements of kids list as children of this node</summary> */
public virtual void AddChildren(IEnumerable<ITree> 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;
}
/** <summary>
* 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.
* </summary>
*/
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<ITree> 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<ITree>(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());
}
/** <summary>Override in a subclass to change the impl of children list</summary> */
protected virtual List<ITree> CreateChildrenList() {
return new List<ITree>();
}
/** <summary>Set the parent and child index values for all child of t</summary> */
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);
}
}
/** <summary>Walk upwards looking for ancestor with this token type.</summary> */
public virtual bool HasAncestor(int ttype) {
return GetAncestor(ttype) != null;
}
/** <summary>Walk upwards and get first ancestor with this token type.</summary> */
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;
}
/** <summary>
* 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.
* </summary>
*/
public virtual IList<ITree> GetAncestors() {
if (Parent == null)
return null;
List<ITree> ancestors = new List<ITree>();
ITree t = this;
t = t.Parent;
while (t != null) {
ancestors.Insert(0, t); // insert at start
t = t.Parent;
}
return ancestors;
}
/** <summary>Print out a whole tree not just a node</summary> */
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();
}
/** <summary>Override to say how a node (not a tree) should look as text</summary> */
public override abstract string ToString();
#region Tree Members
public abstract ITree DupNode();
#endregion
}
}