BaseTree.cs revision 324c4644fee44b9898524c09511bd33c3f12e2df
1/*
2 * [The "BSD licence"]
3 * Copyright (c) 2011 Terence Parr
4 * All rights reserved.
5 *
6 * Conversion to C#:
7 * Copyright (c) 2011 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{
35    using System;
36    using System.Collections.Generic;
37
38    using StringBuilder = System.Text.StringBuilder;
39
40    /** <summary>
41     *  A generic tree implementation with no payload.  You must subclass to
42     *  actually have any user data.  ANTLR v3 uses a list of children approach
43     *  instead of the child-sibling approach in v2.  A flat tree (a list) is
44     *  an empty node whose children represent the list.  An empty, but
45     *  non-null node is called "nil".
46     *  </summary>
47     */
48    [System.Serializable]
49    [System.Diagnostics.DebuggerTypeProxy(typeof(AntlrRuntime_BaseTreeDebugView))]
50    public abstract class BaseTree : ITree
51    {
52        private IList<ITree> _children;
53
54        public BaseTree()
55        {
56        }
57
58        /** <summary>
59         *  Create a new node from an existing node does nothing for BaseTree
60         *  as there are no fields other than the children list, which cannot
61         *  be copied as the children are not considered part of this node.
62         *  </summary>
63         */
64        public BaseTree( ITree node )
65        {
66        }
67
68        /** <summary>
69         *  Get the children internal List; note that if you directly mess with
70         *  the list, do so at your own risk.
71         *  </summary>
72         */
73        public virtual IList<ITree> Children
74        {
75            get
76            {
77                return _children;
78            }
79
80            private set
81            {
82                _children = value;
83            }
84        }
85
86        #region ITree Members
87
88        public virtual int ChildCount
89        {
90            get
91            {
92                if ( Children == null )
93                    return 0;
94
95                return Children.Count;
96            }
97        }
98
99        /** <summary>BaseTree doesn't track parent pointers.</summary> */
100        public virtual ITree Parent
101        {
102            get
103            {
104                return null;
105            }
106            set
107            {
108            }
109        }
110
111        /** <summary>BaseTree doesn't track child indexes.</summary> */
112        public virtual int ChildIndex
113        {
114            get
115            {
116                return 0;
117            }
118            set
119            {
120            }
121        }
122
123        public virtual bool IsNil
124        {
125            get
126            {
127                return false;
128            }
129        }
130
131        public abstract int TokenStartIndex
132        {
133            get;
134            set;
135        }
136
137        public abstract int TokenStopIndex
138        {
139            get;
140            set;
141        }
142
143        public abstract int Type
144        {
145            get;
146            set;
147        }
148
149        public abstract string Text
150        {
151            get;
152            set;
153        }
154
155        public virtual int Line
156        {
157            get;
158            set;
159        }
160
161        public virtual int CharPositionInLine
162        {
163            get;
164            set;
165        }
166
167        #endregion
168
169        public virtual ITree GetChild( int i )
170        {
171            if (i < 0)
172                throw new ArgumentOutOfRangeException();
173
174            if ( Children == null || i >= Children.Count )
175                return null;
176
177            return Children[i];
178        }
179
180        public virtual ITree GetFirstChildWithType( int type )
181        {
182            foreach ( ITree child in Children )
183            {
184                if ( child.Type == type )
185                    return child;
186            }
187
188            return null;
189        }
190
191        /** <summary>Add t as child of this node.</summary>
192         *
193         *  <remarks>
194         *  Warning: if t has no children, but child does
195         *  and child isNil then this routine moves children to t via
196         *  t.children = child.children; i.e., without copying the array.
197         *  </remarks>
198         */
199        public virtual void AddChild( ITree t )
200        {
201            //System.out.println("add child "+t.toStringTree()+" "+this.toStringTree());
202            //System.out.println("existing children: "+children);
203            if ( t == null )
204            {
205                return; // do nothing upon addChild(null)
206            }
207            if ( t.IsNil )
208            {
209                // t is an empty node possibly with children
210                BaseTree childTree = t as BaseTree;
211                if ( childTree != null && this.Children != null && this.Children == childTree.Children )
212                {
213                    throw new Exception( "attempt to add child list to itself" );
214                }
215                // just add all of childTree's children to this
216                if ( t.ChildCount > 0 )
217                {
218                    if ( this.Children != null || childTree == null )
219                    {
220                        if ( this.Children == null )
221                            this.Children = CreateChildrenList();
222
223                        // must copy, this has children already
224                        int n = t.ChildCount;
225                        for ( int i = 0; i < n; i++ )
226                        {
227                            ITree c = t.GetChild( i );
228                            this.Children.Add( c );
229                            // handle double-link stuff for each child of nil root
230                            c.Parent = this;
231                            c.ChildIndex = Children.Count - 1;
232                        }
233                    }
234                    else
235                    {
236                        // no children for this but t is a BaseTree with children;
237                        // just set pointer call general freshener routine
238                        this.Children = childTree.Children;
239                        this.FreshenParentAndChildIndexes();
240                    }
241                }
242            }
243            else
244            {
245                // child is not nil (don't care about children)
246                if ( Children == null )
247                {
248                    Children = CreateChildrenList(); // create children list on demand
249                }
250                Children.Add( t );
251                t.Parent = this;
252                t.ChildIndex = Children.Count - 1;
253            }
254            // System.out.println("now children are: "+children);
255        }
256
257        /** <summary>Add all elements of kids list as children of this node</summary> */
258        public virtual void AddChildren( IEnumerable<ITree> kids )
259        {
260            if (kids == null)
261                throw new ArgumentNullException("kids");
262
263            foreach ( ITree t in kids )
264                AddChild( t );
265        }
266
267        public virtual void SetChild( int i, ITree t )
268        {
269            if (i < 0)
270                throw new ArgumentOutOfRangeException("i");
271
272            if ( t == null )
273            {
274                return;
275            }
276            if ( t.IsNil )
277            {
278                throw new ArgumentException( "Can't set single child to a list" );
279            }
280            if ( Children == null )
281            {
282                Children = CreateChildrenList();
283            }
284            Children[i] = t;
285            t.Parent = this;
286            t.ChildIndex = i;
287        }
288
289        public virtual object DeleteChild( int i )
290        {
291            if (i < 0)
292                throw new ArgumentOutOfRangeException("i");
293            if (i >= ChildCount)
294                throw new ArgumentException();
295
296            if ( Children == null )
297                return null;
298
299            ITree killed = Children[i];
300            Children.RemoveAt( i );
301            // walk rest and decrement their child indexes
302            this.FreshenParentAndChildIndexes( i );
303            return killed;
304        }
305
306        /** <summary>
307         *  Delete children from start to stop and replace with t even if t is
308         *  a list (nil-root tree).  num of children can increase or decrease.
309         *  For huge child lists, inserting children can force walking rest of
310         *  children to set their childindex; could be slow.
311         *  </summary>
312         */
313        public virtual void ReplaceChildren( int startChildIndex, int stopChildIndex, object t )
314        {
315            if (startChildIndex < 0)
316                throw new ArgumentOutOfRangeException();
317            if (stopChildIndex < 0)
318                throw new ArgumentOutOfRangeException();
319            if (t == null)
320                throw new ArgumentNullException("t");
321            if (stopChildIndex < startChildIndex)
322                throw new ArgumentException();
323
324            /*
325            System.out.println("replaceChildren "+startChildIndex+", "+stopChildIndex+
326                               " with "+((BaseTree)t).toStringTree());
327            System.out.println("in="+toStringTree());
328            */
329            if ( Children == null )
330            {
331                throw new ArgumentException( "indexes invalid; no children in list" );
332            }
333            int replacingHowMany = stopChildIndex - startChildIndex + 1;
334            int replacingWithHowMany;
335            ITree newTree = (ITree)t;
336            IList<ITree> newChildren = null;
337            // normalize to a list of children to add: newChildren
338            if ( newTree.IsNil )
339            {
340                BaseTree baseTree = newTree as BaseTree;
341                if ( baseTree != null && baseTree.Children != null )
342                {
343                    newChildren = baseTree.Children;
344                }
345                else
346                {
347                    newChildren = CreateChildrenList();
348                    int n = newTree.ChildCount;
349                    for ( int i = 0; i < n; i++ )
350                        newChildren.Add( newTree.GetChild( i ) );
351                }
352            }
353            else
354            {
355                newChildren = new List<ITree>( 1 );
356                newChildren.Add( newTree );
357            }
358            replacingWithHowMany = newChildren.Count;
359            int numNewChildren = newChildren.Count;
360            int delta = replacingHowMany - replacingWithHowMany;
361            // if same number of nodes, do direct replace
362            if ( delta == 0 )
363            {
364                int j = 0; // index into new children
365                for ( int i = startChildIndex; i <= stopChildIndex; i++ )
366                {
367                    ITree child = newChildren[j];
368                    Children[i] = child;
369                    child.Parent = this;
370                    child.ChildIndex = i;
371                    j++;
372                }
373            }
374            else if ( delta > 0 )
375            {
376                // fewer new nodes than there were
377                // set children and then delete extra
378                for ( int j = 0; j < numNewChildren; j++ )
379                {
380                    Children[startChildIndex + j] = newChildren[j];
381                }
382                int indexToDelete = startChildIndex + numNewChildren;
383                for ( int c = indexToDelete; c <= stopChildIndex; c++ )
384                {
385                    // delete same index, shifting everybody down each time
386                    Children.RemoveAt( indexToDelete );
387                }
388                FreshenParentAndChildIndexes( startChildIndex );
389            }
390            else
391            {
392                // more new nodes than were there before
393                // fill in as many children as we can (replacingHowMany) w/o moving data
394                for ( int j = 0; j < replacingHowMany; j++ )
395                {
396                    Children[startChildIndex + j] = newChildren[j];
397                }
398                int numToInsert = replacingWithHowMany - replacingHowMany;
399                for ( int j = replacingHowMany; j < replacingWithHowMany; j++ )
400                {
401                    Children.Insert( startChildIndex + j, newChildren[j] );
402                }
403                FreshenParentAndChildIndexes( startChildIndex );
404            }
405            //System.out.println("out="+toStringTree());
406        }
407
408        /** <summary>Override in a subclass to change the impl of children list</summary> */
409        protected virtual IList<ITree> CreateChildrenList()
410        {
411            return new List<ITree>();
412        }
413
414        /** <summary>Set the parent and child index values for all child of t</summary> */
415        public virtual void FreshenParentAndChildIndexes()
416        {
417            FreshenParentAndChildIndexes( 0 );
418        }
419
420        public virtual void FreshenParentAndChildIndexes( int offset )
421        {
422            int n = ChildCount;
423            for ( int c = offset; c < n; c++ )
424            {
425                ITree child = GetChild( c );
426                child.ChildIndex = c;
427                child.Parent = this;
428            }
429        }
430
431        public virtual void SanityCheckParentAndChildIndexes()
432        {
433            SanityCheckParentAndChildIndexes( null, -1 );
434        }
435
436        public virtual void SanityCheckParentAndChildIndexes( ITree parent, int i )
437        {
438            if ( parent != this.Parent )
439            {
440                throw new InvalidOperationException( "parents don't match; expected " + parent + " found " + this.Parent );
441            }
442            if ( i != this.ChildIndex )
443            {
444                throw new InvalidOperationException( "child indexes don't match; expected " + i + " found " + this.ChildIndex );
445            }
446            int n = this.ChildCount;
447            for ( int c = 0; c < n; c++ )
448            {
449                BaseTree child = (BaseTree)this.GetChild( c );
450                child.SanityCheckParentAndChildIndexes( this, c );
451            }
452        }
453
454        /** <summary>Walk upwards looking for ancestor with this token type.</summary> */
455        public virtual bool HasAncestor( int ttype )
456        {
457            return GetAncestor( ttype ) != null;
458        }
459
460        /** <summary>Walk upwards and get first ancestor with this token type.</summary> */
461        public virtual ITree GetAncestor( int ttype )
462        {
463            ITree t = this;
464            t = t.Parent;
465            while ( t != null )
466            {
467                if ( t.Type == ttype )
468                    return t;
469                t = t.Parent;
470            }
471            return null;
472        }
473
474        /** <summary>
475         *  Return a list of all ancestors of this node.  The first node of
476         *  list is the root and the last is the parent of this node.
477         *  </summary>
478         */
479        public virtual IList<ITree> GetAncestors()
480        {
481            if ( Parent == null )
482                return null;
483
484            List<ITree> ancestors = new List<ITree>();
485            ITree t = this;
486            t = t.Parent;
487            while ( t != null )
488            {
489                ancestors.Insert( 0, t ); // insert at start
490                t = t.Parent;
491            }
492            return ancestors;
493        }
494
495        /** <summary>Print out a whole tree not just a node</summary> */
496        public virtual string ToStringTree()
497        {
498            if ( Children == null || Children.Count == 0 )
499            {
500                return this.ToString();
501            }
502            StringBuilder buf = new StringBuilder();
503            if ( !IsNil )
504            {
505                buf.Append( "(" );
506                buf.Append( this.ToString() );
507                buf.Append( ' ' );
508            }
509            for ( int i = 0; Children != null && i < Children.Count; i++ )
510            {
511                ITree t = Children[i];
512                if ( i > 0 )
513                {
514                    buf.Append( ' ' );
515                }
516                buf.Append( t.ToStringTree() );
517            }
518            if ( !IsNil )
519            {
520                buf.Append( ")" );
521            }
522            return buf.ToString();
523        }
524
525        /** <summary>Override to say how a node (not a tree) should look as text</summary> */
526        public override abstract string ToString();
527
528        #region Tree Members
529        public abstract ITree DupNode();
530        #endregion
531    }
532}
533