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 
BaseTree()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          */
BaseTree(ITree node)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 
GetChild(int i)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 
GetFirstChildWithType(int type)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          */
AddChild(ITree t)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> */
AddChildren(IEnumerable<ITree> kids)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 
SetChild(int i, ITree t)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 
DeleteChild(int i)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          */
ReplaceChildren(int startChildIndex, int stopChildIndex, object t)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> */
CreateChildrenList()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> */
FreshenParentAndChildIndexes()347         public virtual void FreshenParentAndChildIndexes() {
348             FreshenParentAndChildIndexes(0);
349         }
350 
FreshenParentAndChildIndexes(int offset)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 
SanityCheckParentAndChildIndexes()360         public virtual void SanityCheckParentAndChildIndexes() {
361             SanityCheckParentAndChildIndexes(null, -1);
362         }
363 
SanityCheckParentAndChildIndexes(ITree parent, int i)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> */
HasAncestor(int ttype)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> */
GetAncestor(int ttype)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          */
GetAncestors()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> */
ToStringTree()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> */
ToString()439         public override abstract string ToString();
440 
441         #region Tree Members
DupNode()442         public abstract ITree DupNode();
443         #endregion
444     }
445 }
446