Home | History | Annotate | Download | only in Antlr.Runtime.Tree
      1 /*
      2  * [The "BSD licence"]
      3  * Copyright (c) 2005-2008 Terence Parr
      4  * All rights reserved.
      5  *
      6  * Conversion to C#:
      7  * Copyright (c) 2008-2009 Sam Harwell, Pixel Mine, Inc.
      8  * All rights reserved.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. The name of the author may not be used to endorse or promote products
     19  *    derived from this software without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 namespace Antlr.Runtime.Tree {
     34     using System;
     35     using System.Collections.Generic;
     36 
     37     using StringBuilder = System.Text.StringBuilder;
     38 
     39     /** <summary>
     40      *  A generic tree implementation with no payload.  You must subclass to
     41      *  actually have any user data.  ANTLR v3 uses a list of children approach
     42      *  instead of the child-sibling approach in v2.  A flat tree (a list) is
     43      *  an empty node whose children represent the list.  An empty, but
     44      *  non-null node is called "nil".
     45      *  </summary>
     46      */
     47     [System.Serializable]
     48     public abstract class BaseTree : ITree {
     49         List<ITree> children;
     50 
     51         public BaseTree() {
     52         }
     53 
     54         /** <summary>
     55          *  Create a new node from an existing node does nothing for BaseTree
     56          *  as there are no fields other than the children list, which cannot
     57          *  be copied as the children are not considered part of this node.
     58          *  </summary>
     59          */
     60         public BaseTree(ITree node) {
     61         }
     62 
     63         /** <summary>
     64          *  Get the children internal List; note that if you directly mess with
     65          *  the list, do so at your own risk.
     66          *  </summary>
     67          */
     68         public virtual IList<ITree> Children {
     69             get {
     70                 return children;
     71             }
     72         }
     73 
     74         #region ITree Members
     75 
     76         public virtual int ChildCount {
     77             get {
     78                 if (Children == null)
     79                     return 0;
     80 
     81                 return Children.Count;
     82             }
     83         }
     84 
     85         /** <summary>BaseTree doesn't track parent pointers.</summary> */
     86         public virtual ITree Parent {
     87             get {
     88                 return null;
     89             }
     90             set {
     91             }
     92         }
     93 
     94         /** <summary>BaseTree doesn't track child indexes.</summary> */
     95         public virtual int ChildIndex {
     96             get {
     97                 return 0;
     98             }
     99             set {
    100             }
    101         }
    102 
    103         public virtual bool IsNil {
    104             get {
    105                 return false;
    106             }
    107         }
    108 
    109         public abstract int TokenStartIndex {
    110             get;
    111             set;
    112         }
    113 
    114         public abstract int TokenStopIndex {
    115             get;
    116             set;
    117         }
    118 
    119         public abstract int Type {
    120             get;
    121             set;
    122         }
    123 
    124         public abstract string Text {
    125             get;
    126             set;
    127         }
    128 
    129         public virtual int Line {
    130             get;
    131             set;
    132         }
    133 
    134         public virtual int CharPositionInLine {
    135             get;
    136             set;
    137         }
    138 
    139         #endregion
    140 
    141         public virtual ITree GetChild(int i) {
    142             if (i < 0)
    143                 throw new ArgumentOutOfRangeException();
    144 
    145             if (children == null || i >= children.Count)
    146                 return null;
    147 
    148             return children[i];
    149         }
    150 
    151         public virtual ITree GetFirstChildWithType(int type) {
    152             foreach (ITree child in children) {
    153                 if (child.Type == type)
    154                     return child;
    155             }
    156 
    157             return null;
    158         }
    159 
    160         /** <summary>Add t as child of this node.</summary>
    161          *
    162          *  <remarks>
    163          *  Warning: if t has no children, but child does
    164          *  and child isNil then this routine moves children to t via
    165          *  t.children = child.children; i.e., without copying the array.
    166          *  </remarks>
    167          */
    168         public virtual void AddChild(ITree t) {
    169             //System.out.println("add child "+t.toStringTree()+" "+this.toStringTree());
    170             //System.out.println("existing children: "+children);
    171             if (t == null) {
    172                 return; // do nothing upon addChild(null)
    173             }
    174             if (t.IsNil) {
    175                 // t is an empty node possibly with children
    176                 BaseTree childTree = t as BaseTree;
    177                 if (childTree != null && this.children != null && this.children == childTree.children) {
    178                     throw new Exception("attempt to add child list to itself");
    179                 }
    180                 // just add all of childTree's children to this
    181                 if (t.ChildCount > 0) {
    182                     if (this.children != null || childTree == null) {
    183                         if (this.children == null)
    184                             this.children = CreateChildrenList();
    185 
    186                         // must copy, this has children already
    187                         int n = t.ChildCount;
    188                         for (int i = 0; i < n; i++) {
    189                             ITree c = t.GetChild(i);
    190                             this.children.Add(c);
    191                             // handle double-link stuff for each child of nil root
    192                             c.Parent = this;
    193                             c.ChildIndex = children.Count - 1;
    194                         }
    195                     } else {
    196                         // no children for this but t is a BaseTree with children;
    197                         // just set pointer call general freshener routine
    198                         this.children = childTree.children;
    199                         this.FreshenParentAndChildIndexes();
    200                     }
    201                 }
    202             } else {
    203                 // child is not nil (don't care about children)
    204                 if (children == null) {
    205                     children = CreateChildrenList(); // create children list on demand
    206                 }
    207                 children.Add(t);
    208                 t.Parent = this;
    209                 t.ChildIndex = children.Count - 1;
    210             }
    211             // System.out.println("now children are: "+children);
    212         }
    213 
    214         /** <summary>Add all elements of kids list as children of this node</summary> */
    215         public virtual void AddChildren(IEnumerable<ITree> kids) {
    216             if (kids == null)
    217                 throw new ArgumentNullException("kids");
    218 
    219             foreach (ITree t in kids)
    220                 AddChild(t);
    221         }
    222 
    223         public virtual void SetChild(int i, ITree t) {
    224             if (i < 0)
    225                 throw new ArgumentOutOfRangeException("i");
    226 
    227             if (t == null) {
    228                 return;
    229             }
    230             if (t.IsNil) {
    231                 throw new ArgumentException("Can't set single child to a list");
    232             }
    233             if (children == null) {
    234                 children = CreateChildrenList();
    235             }
    236             children[i] = t;
    237             t.Parent = this;
    238             t.ChildIndex = i;
    239         }
    240 
    241         public virtual object DeleteChild(int i) {
    242             if (i < 0)
    243                 throw new ArgumentOutOfRangeException("i");
    244             if (i >= ChildCount)
    245                 throw new ArgumentException();
    246 
    247             if (children == null)
    248                 return null;
    249 
    250             ITree killed = children[i];
    251             children.RemoveAt(i);
    252             // walk rest and decrement their child indexes
    253             this.FreshenParentAndChildIndexes(i);
    254             return killed;
    255         }
    256 
    257         /** <summary>
    258          *  Delete children from start to stop and replace with t even if t is
    259          *  a list (nil-root tree).  num of children can increase or decrease.
    260          *  For huge child lists, inserting children can force walking rest of
    261          *  children to set their childindex; could be slow.
    262          *  </summary>
    263          */
    264         public virtual void ReplaceChildren(int startChildIndex, int stopChildIndex, object t) {
    265             if (startChildIndex < 0)
    266                 throw new ArgumentOutOfRangeException();
    267             if (stopChildIndex < 0)
    268                 throw new ArgumentOutOfRangeException();
    269             if (t == null)
    270                 throw new ArgumentNullException("t");
    271             if (stopChildIndex < startChildIndex)
    272                 throw new ArgumentException();
    273 
    274             /*
    275             System.out.println("replaceChildren "+startChildIndex+", "+stopChildIndex+
    276                                " with "+((BaseTree)t).toStringTree());
    277             System.out.println("in="+toStringTree());
    278             */
    279             if (children == null) {
    280                 throw new ArgumentException("indexes invalid; no children in list");
    281             }
    282             int replacingHowMany = stopChildIndex - startChildIndex + 1;
    283             int replacingWithHowMany;
    284             ITree newTree = (ITree)t;
    285             List<ITree> newChildren = null;
    286             // normalize to a list of children to add: newChildren
    287             if (newTree.IsNil) {
    288                 BaseTree baseTree = newTree as BaseTree;
    289                 if (baseTree != null && baseTree.children != null) {
    290                     newChildren = baseTree.children;
    291                 } else {
    292                     newChildren = CreateChildrenList();
    293                     int n = newTree.ChildCount;
    294                     for (int i = 0; i < n; i++)
    295                         newChildren.Add(newTree.GetChild(i));
    296                 }
    297             } else {
    298                 newChildren = new List<ITree>(1);
    299                 newChildren.Add(newTree);
    300             }
    301             replacingWithHowMany = newChildren.Count;
    302             int numNewChildren = newChildren.Count;
    303             int delta = replacingHowMany - replacingWithHowMany;
    304             // if same number of nodes, do direct replace
    305             if (delta == 0) {
    306                 int j = 0; // index into new children
    307                 for (int i = startChildIndex; i <= stopChildIndex; i++) {
    308                     ITree child = newChildren[j];
    309                     children[i] = child;
    310                     child.Parent = this;
    311                     child.ChildIndex = i;
    312                     j++;
    313                 }
    314             } else if (delta > 0) {
    315                 // fewer new nodes than there were
    316                 // set children and then delete extra
    317                 for (int j = 0; j < numNewChildren; j++) {
    318                     children[startChildIndex + j] = newChildren[j];
    319                 }
    320                 int indexToDelete = startChildIndex + numNewChildren;
    321                 for (int c = indexToDelete; c <= stopChildIndex; c++) {
    322                     // delete same index, shifting everybody down each time
    323                     children.RemoveAt(indexToDelete);
    324                 }
    325                 FreshenParentAndChildIndexes(startChildIndex);
    326             } else {
    327                 // more new nodes than were there before
    328                 // fill in as many children as we can (replacingHowMany) w/o moving data
    329                 for (int j = 0; j < replacingHowMany; j++) {
    330                     children[startChildIndex + j] = newChildren[j];
    331                 }
    332                 int numToInsert = replacingWithHowMany - replacingHowMany;
    333                 for (int j = replacingHowMany; j < replacingWithHowMany; j++) {
    334                     children.Insert(startChildIndex + j, newChildren[j]);
    335                 }
    336                 FreshenParentAndChildIndexes(startChildIndex);
    337             }
    338             //System.out.println("out="+toStringTree());
    339         }
    340 
    341         /** <summary>Override in a subclass to change the impl of children list</summary> */
    342         protected virtual List<ITree> CreateChildrenList() {
    343             return new List<ITree>();
    344         }
    345 
    346         /** <summary>Set the parent and child index values for all child of t</summary> */
    347         public virtual void FreshenParentAndChildIndexes() {
    348             FreshenParentAndChildIndexes(0);
    349         }
    350 
    351         public virtual void FreshenParentAndChildIndexes(int offset) {
    352             int n = ChildCount;
    353             for (int c = offset; c < n; c++) {
    354                 ITree child = GetChild(c);
    355                 child.ChildIndex = c;
    356                 child.Parent = this;
    357             }
    358         }
    359 
    360         public virtual void SanityCheckParentAndChildIndexes() {
    361             SanityCheckParentAndChildIndexes(null, -1);
    362         }
    363 
    364         public virtual void SanityCheckParentAndChildIndexes(ITree parent, int i) {
    365             if (parent != this.Parent) {
    366                 throw new InvalidOperationException("parents don't match; expected " + parent + " found " + this.Parent);
    367             }
    368             if (i != this.ChildIndex) {
    369                 throw new InvalidOperationException("child indexes don't match; expected " + i + " found " + this.ChildIndex);
    370             }
    371             int n = this.ChildCount;
    372             for (int c = 0; c < n; c++) {
    373                 BaseTree child = (BaseTree)this.GetChild(c);
    374                 child.SanityCheckParentAndChildIndexes(this, c);
    375             }
    376         }
    377 
    378         /** <summary>Walk upwards looking for ancestor with this token type.</summary> */
    379         public virtual bool HasAncestor(int ttype) {
    380             return GetAncestor(ttype) != null;
    381         }
    382 
    383         /** <summary>Walk upwards and get first ancestor with this token type.</summary> */
    384         public virtual ITree GetAncestor(int ttype) {
    385             ITree t = this;
    386             t = t.Parent;
    387             while (t != null) {
    388                 if (t.Type == ttype)
    389                     return t;
    390                 t = t.Parent;
    391             }
    392             return null;
    393         }
    394 
    395         /** <summary>
    396          *  Return a list of all ancestors of this node.  The first node of
    397          *  list is the root and the last is the parent of this node.
    398          *  </summary>
    399          */
    400         public virtual IList<ITree> GetAncestors() {
    401             if (Parent == null)
    402                 return null;
    403 
    404             List<ITree> ancestors = new List<ITree>();
    405             ITree t = this;
    406             t = t.Parent;
    407             while (t != null) {
    408                 ancestors.Insert(0, t); // insert at start
    409                 t = t.Parent;
    410             }
    411             return ancestors;
    412         }
    413 
    414         /** <summary>Print out a whole tree not just a node</summary> */
    415         public virtual string ToStringTree() {
    416             if (children == null || children.Count == 0) {
    417                 return this.ToString();
    418             }
    419             StringBuilder buf = new StringBuilder();
    420             if (!IsNil) {
    421                 buf.Append("(");
    422                 buf.Append(this.ToString());
    423                 buf.Append(' ');
    424             }
    425             for (int i = 0; children != null && i < children.Count; i++) {
    426                 ITree t = children[i];
    427                 if (i > 0) {
    428                     buf.Append(' ');
    429                 }
    430                 buf.Append(t.ToStringTree());
    431             }
    432             if (!IsNil) {
    433                 buf.Append(")");
    434             }
    435             return buf.ToString();
    436         }
    437 
    438         /** <summary>Override to say how a node (not a tree) should look as text</summary> */
    439         public override abstract string ToString();
    440 
    441         #region Tree Members
    442         public abstract ITree DupNode();
    443         #endregion
    444     }
    445 }
    446