• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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 
DeleteChild( int i )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          */
ReplaceChildren( int startChildIndex, int stopChildIndex, object t )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> */
CreateChildrenList()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> */
FreshenParentAndChildIndexes()415         public virtual void FreshenParentAndChildIndexes()
416         {
417             FreshenParentAndChildIndexes( 0 );
418         }
419 
FreshenParentAndChildIndexes( int offset )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 
SanityCheckParentAndChildIndexes()431         public virtual void SanityCheckParentAndChildIndexes()
432         {
433             SanityCheckParentAndChildIndexes( null, -1 );
434         }
435 
SanityCheckParentAndChildIndexes( ITree parent, int i )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> */
HasAncestor( int ttype )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> */
GetAncestor( int ttype )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          */
GetAncestors()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> */
ToStringTree()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> */
ToString()526         public override abstract string ToString();
527 
528         #region Tree Members
DupNode()529         public abstract ITree DupNode();
530         #endregion
531     }
532 }
533