1 /*
2  * [The "BSD license"]
3  * Copyright (c) 2011 Terence Parr
4  * All rights reserved.
5  *
6  * Conversion to C#:
7  * Copyright (c) 2011 Sam Harwell, Tunnel Vision Laboratories, LLC
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 {
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 
BaseTree()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          */
BaseTree( ITree node )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 
GetChild( int i )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 
GetFirstChildWithType( int type )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          */
AddChild( ITree t )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> */
AddChildren( IEnumerable<ITree> kids )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 
SetChild( int i, ITree t )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         /** Insert child t at child position i (0..n-1) by shifting children
290          *  i+1..n-1 to the right one position. Set parent / indexes properly
291          *  but does NOT collapse nil-rooted t's that come in here like addChild.
292          */
InsertChild(int i, ITree t)293         public virtual void InsertChild(int i, ITree t)
294         {
295             if (i < 0)
296                 throw new ArgumentOutOfRangeException("i");
297             if (i > ChildCount)
298                 throw new ArgumentException();
299 
300             if (i == ChildCount)
301             {
302                 AddChild(t);
303                 return;
304             }
305 
306             Children.Insert(i, t);
307 
308             // walk others to increment their child indexes
309             // set index, parent of this one too
310             this.FreshenParentAndChildIndexes(i);
311         }
312 
DeleteChild( int i )313         public virtual object DeleteChild( int i )
314         {
315             if (i < 0)
316                 throw new ArgumentOutOfRangeException("i");
317             if (i >= ChildCount)
318                 throw new ArgumentException();
319 
320             if ( Children == null )
321                 return null;
322 
323             ITree killed = Children[i];
324             Children.RemoveAt( i );
325             // walk rest and decrement their child indexes
326             this.FreshenParentAndChildIndexes( i );
327             return killed;
328         }
329 
330         /** <summary>
331          *  Delete children from start to stop and replace with t even if t is
332          *  a list (nil-root tree).  num of children can increase or decrease.
333          *  For huge child lists, inserting children can force walking rest of
334          *  children to set their childindex; could be slow.
335          *  </summary>
336          */
ReplaceChildren( int startChildIndex, int stopChildIndex, object t )337         public virtual void ReplaceChildren( int startChildIndex, int stopChildIndex, object t )
338         {
339             if (startChildIndex < 0)
340                 throw new ArgumentOutOfRangeException();
341             if (stopChildIndex < 0)
342                 throw new ArgumentOutOfRangeException();
343             if (t == null)
344                 throw new ArgumentNullException("t");
345             if (stopChildIndex < startChildIndex)
346                 throw new ArgumentException();
347 
348             /*
349             System.out.println("replaceChildren "+startChildIndex+", "+stopChildIndex+
350                                " with "+((BaseTree)t).toStringTree());
351             System.out.println("in="+toStringTree());
352             */
353             if ( Children == null )
354             {
355                 throw new ArgumentException( "indexes invalid; no children in list" );
356             }
357             int replacingHowMany = stopChildIndex - startChildIndex + 1;
358             int replacingWithHowMany;
359             ITree newTree = (ITree)t;
360             IList<ITree> newChildren = null;
361             // normalize to a list of children to add: newChildren
362             if ( newTree.IsNil )
363             {
364                 BaseTree baseTree = newTree as BaseTree;
365                 if ( baseTree != null && baseTree.Children != null )
366                 {
367                     newChildren = baseTree.Children;
368                 }
369                 else
370                 {
371                     newChildren = CreateChildrenList();
372                     int n = newTree.ChildCount;
373                     for ( int i = 0; i < n; i++ )
374                         newChildren.Add( newTree.GetChild( i ) );
375                 }
376             }
377             else
378             {
379                 newChildren = new List<ITree>( 1 );
380                 newChildren.Add( newTree );
381             }
382             replacingWithHowMany = newChildren.Count;
383             int numNewChildren = newChildren.Count;
384             int delta = replacingHowMany - replacingWithHowMany;
385             // if same number of nodes, do direct replace
386             if ( delta == 0 )
387             {
388                 int j = 0; // index into new children
389                 for ( int i = startChildIndex; i <= stopChildIndex; i++ )
390                 {
391                     ITree child = newChildren[j];
392                     Children[i] = child;
393                     child.Parent = this;
394                     child.ChildIndex = i;
395                     j++;
396                 }
397             }
398             else if ( delta > 0 )
399             {
400                 // fewer new nodes than there were
401                 // set children and then delete extra
402                 for ( int j = 0; j < numNewChildren; j++ )
403                 {
404                     Children[startChildIndex + j] = newChildren[j];
405                 }
406                 int indexToDelete = startChildIndex + numNewChildren;
407                 for ( int c = indexToDelete; c <= stopChildIndex; c++ )
408                 {
409                     // delete same index, shifting everybody down each time
410                     Children.RemoveAt( indexToDelete );
411                 }
412                 FreshenParentAndChildIndexes( startChildIndex );
413             }
414             else
415             {
416                 // more new nodes than were there before
417                 // fill in as many children as we can (replacingHowMany) w/o moving data
418                 for ( int j = 0; j < replacingHowMany; j++ )
419                 {
420                     Children[startChildIndex + j] = newChildren[j];
421                 }
422                 int numToInsert = replacingWithHowMany - replacingHowMany;
423                 for ( int j = replacingHowMany; j < replacingWithHowMany; j++ )
424                 {
425                     Children.Insert( startChildIndex + j, newChildren[j] );
426                 }
427                 FreshenParentAndChildIndexes( startChildIndex );
428             }
429             //System.out.println("out="+toStringTree());
430         }
431 
432         /** <summary>Override in a subclass to change the impl of children list</summary> */
CreateChildrenList()433         protected virtual IList<ITree> CreateChildrenList()
434         {
435             return new List<ITree>();
436         }
437 
438         /** <summary>Set the parent and child index values for all child of t</summary> */
FreshenParentAndChildIndexes()439         public virtual void FreshenParentAndChildIndexes()
440         {
441             FreshenParentAndChildIndexes( 0 );
442         }
443 
FreshenParentAndChildIndexes( int offset )444         public virtual void FreshenParentAndChildIndexes( int offset )
445         {
446             int n = ChildCount;
447             for ( int c = offset; c < n; c++ )
448             {
449                 ITree child = GetChild( c );
450                 child.ChildIndex = c;
451                 child.Parent = this;
452             }
453         }
454 
FreshenParentAndChildIndexesDeeply()455         public virtual void FreshenParentAndChildIndexesDeeply()
456         {
457             FreshenParentAndChildIndexesDeeply(0);
458         }
459 
FreshenParentAndChildIndexesDeeply(int offset)460         public virtual void FreshenParentAndChildIndexesDeeply(int offset)
461         {
462             int n = ChildCount;
463             for (int c = offset; c < n; c++)
464             {
465                 ITree child = GetChild(c);
466                 child.ChildIndex = c;
467                 child.Parent = this;
468                 BaseTree baseTree = child as BaseTree;
469                 if (baseTree != null)
470                     baseTree.FreshenParentAndChildIndexesDeeply();
471             }
472         }
473 
SanityCheckParentAndChildIndexes()474         public virtual void SanityCheckParentAndChildIndexes()
475         {
476             SanityCheckParentAndChildIndexes( null, -1 );
477         }
478 
SanityCheckParentAndChildIndexes( ITree parent, int i )479         public virtual void SanityCheckParentAndChildIndexes( ITree parent, int i )
480         {
481             if ( parent != this.Parent )
482             {
483                 throw new InvalidOperationException( "parents don't match; expected " + parent + " found " + this.Parent );
484             }
485             if ( i != this.ChildIndex )
486             {
487                 throw new InvalidOperationException( "child indexes don't match; expected " + i + " found " + this.ChildIndex );
488             }
489             int n = this.ChildCount;
490             for ( int c = 0; c < n; c++ )
491             {
492                 BaseTree child = (BaseTree)this.GetChild( c );
493                 child.SanityCheckParentAndChildIndexes( this, c );
494             }
495         }
496 
497         /** <summary>Walk upwards looking for ancestor with this token type.</summary> */
HasAncestor( int ttype )498         public virtual bool HasAncestor( int ttype )
499         {
500             return GetAncestor( ttype ) != null;
501         }
502 
503         /** <summary>Walk upwards and get first ancestor with this token type.</summary> */
GetAncestor( int ttype )504         public virtual ITree GetAncestor( int ttype )
505         {
506             ITree t = this;
507             t = t.Parent;
508             while ( t != null )
509             {
510                 if ( t.Type == ttype )
511                     return t;
512                 t = t.Parent;
513             }
514             return null;
515         }
516 
517         /** <summary>
518          *  Return a list of all ancestors of this node.  The first node of
519          *  list is the root and the last is the parent of this node.
520          *  </summary>
521          */
GetAncestors()522         public virtual IList<ITree> GetAncestors()
523         {
524             if ( Parent == null )
525                 return null;
526 
527             List<ITree> ancestors = new List<ITree>();
528             ITree t = this;
529             t = t.Parent;
530             while ( t != null )
531             {
532                 ancestors.Insert( 0, t ); // insert at start
533                 t = t.Parent;
534             }
535             return ancestors;
536         }
537 
538         /** <summary>Print out a whole tree not just a node</summary> */
ToStringTree()539         public virtual string ToStringTree()
540         {
541             if ( Children == null || Children.Count == 0 )
542             {
543                 return this.ToString();
544             }
545             StringBuilder buf = new StringBuilder();
546             if ( !IsNil )
547             {
548                 buf.Append( "(" );
549                 buf.Append( this.ToString() );
550                 buf.Append( ' ' );
551             }
552             for ( int i = 0; Children != null && i < Children.Count; i++ )
553             {
554                 ITree t = Children[i];
555                 if ( i > 0 )
556                 {
557                     buf.Append( ' ' );
558                 }
559                 buf.Append( t.ToStringTree() );
560             }
561             if ( !IsNil )
562             {
563                 buf.Append( ")" );
564             }
565             return buf.ToString();
566         }
567 
568         /** <summary>Override to say how a node (not a tree) should look as text</summary> */
ToString()569         public override abstract string ToString();
570 
571         #region Tree Members
DupNode()572         public abstract ITree DupNode();
573         #endregion
574     }
575 }
576