BaseTree.cs revision 324c4644fee44b9898524c09511bd33c3f12e2df
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
33namespace 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