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.Collections.Generic;
35 
36     using Exception = System.Exception;
37     using IDictionary = System.Collections.IDictionary;
38     using NotSupportedException = System.NotSupportedException;
39 
40     /** <summary>A TreeAdaptor that works with any Tree implementation.</summary> */
41     public abstract class BaseTreeAdaptor : ITreeAdaptor {
42         /** <summary>
43          *  System.identityHashCode() is not always unique; we have to
44          *  track ourselves.  That's ok, it's only for debugging, though it's
45          *  expensive: we have to create a hashtable with all tree nodes in it.
46          *  </summary>
47          */
48         protected IDictionary<object, int> treeToUniqueIDMap;
49         protected int uniqueNodeID = 1;
50 
Nil()51         public virtual object Nil() {
52             return Create(null);
53         }
54 
55         /** <summary>
56          *  Create tree node that holds the start and stop tokens associated
57          *  with an error.
58          *  </summary>
59          *
60          *  <remarks>
61          *  If you specify your own kind of tree nodes, you will likely have to
62          *  override this method. CommonTree returns Token.INVALID_TOKEN_TYPE
63          *  if no token payload but you might have to set token type for diff
64          *  node type.
65          *
66          *  You don't have to subclass CommonErrorNode; you will likely need to
67          *  subclass your own tree node class to avoid class cast exception.
68          *  </remarks>
69          */
ErrorNode(ITokenStream input, IToken start, IToken stop, RecognitionException e)70         public virtual object ErrorNode(ITokenStream input, IToken start, IToken stop,
71                                 RecognitionException e) {
72             CommonErrorNode t = new CommonErrorNode(input, start, stop, e);
73             //System.out.println("returning error node '"+t+"' @index="+input.index());
74             return t;
75         }
76 
IsNil(object tree)77         public virtual bool IsNil(object tree) {
78             return ((ITree)tree).IsNil;
79         }
80 
DupTree(object tree)81         public virtual object DupTree(object tree) {
82             return DupTree(tree, null);
83         }
84 
85         /** <summary>
86          *  This is generic in the sense that it will work with any kind of
87          *  tree (not just ITree interface).  It invokes the adaptor routines
88          *  not the tree node routines to do the construction.
89          *  </summary>
90          */
DupTree(object t, object parent)91         public virtual object DupTree(object t, object parent) {
92             if (t == null) {
93                 return null;
94             }
95             object newTree = DupNode(t);
96             // ensure new subtree root has parent/child index set
97             SetChildIndex(newTree, GetChildIndex(t)); // same index in new tree
98             SetParent(newTree, parent);
99             int n = GetChildCount(t);
100             for (int i = 0; i < n; i++) {
101                 object child = GetChild(t, i);
102                 object newSubTree = DupTree(child, t);
103                 AddChild(newTree, newSubTree);
104             }
105             return newTree;
106         }
107 
108         /** <summary>
109          *  Add a child to the tree t.  If child is a flat tree (a list), make all
110          *  in list children of t.  Warning: if t has no children, but child does
111          *  and child isNil then you can decide it is ok to move children to t via
112          *  t.children = child.children; i.e., without copying the array.  Just
113          *  make sure that this is consistent with have the user will build
114          *  ASTs.
115          *  </summary>
116          */
AddChild(object t, object child)117         public virtual void AddChild(object t, object child) {
118             if (t != null && child != null) {
119                 ((ITree)t).AddChild((ITree)child);
120             }
121         }
122 
123         /** <summary>
124          *  If oldRoot is a nil root, just copy or move the children to newRoot.
125          *  If not a nil root, make oldRoot a child of newRoot.
126          *  </summary>
127          *
128          *  <remarks>
129          *    old=^(nil a b c), new=r yields ^(r a b c)
130          *    old=^(a b c), new=r yields ^(r ^(a b c))
131          *
132          *  If newRoot is a nil-rooted single child tree, use the single
133          *  child as the new root node.
134          *
135          *    old=^(nil a b c), new=^(nil r) yields ^(r a b c)
136          *    old=^(a b c), new=^(nil r) yields ^(r ^(a b c))
137          *
138          *  If oldRoot was null, it's ok, just return newRoot (even if isNil).
139          *
140          *    old=null, new=r yields r
141          *    old=null, new=^(nil r) yields ^(nil r)
142          *
143          *  Return newRoot.  Throw an exception if newRoot is not a
144          *  simple node or nil root with a single child node--it must be a root
145          *  node.  If newRoot is ^(nil x) return x as newRoot.
146          *
147          *  Be advised that it's ok for newRoot to point at oldRoot's
148          *  children; i.e., you don't have to copy the list.  We are
149          *  constructing these nodes so we should have this control for
150          *  efficiency.
151          *  </remarks>
152          */
BecomeRoot(object newRoot, object oldRoot)153         public virtual object BecomeRoot(object newRoot, object oldRoot) {
154             //System.out.println("becomeroot new "+newRoot.toString()+" old "+oldRoot);
155             ITree newRootTree = (ITree)newRoot;
156             ITree oldRootTree = (ITree)oldRoot;
157             if (oldRoot == null) {
158                 return newRoot;
159             }
160             // handle ^(nil real-node)
161             if (newRootTree.IsNil) {
162                 int nc = newRootTree.ChildCount;
163                 if (nc == 1)
164                     newRootTree = (ITree)newRootTree.GetChild(0);
165                 else if (nc > 1) {
166                     // TODO: make tree run time exceptions hierarchy
167                     throw new Exception("more than one node as root (TODO: make exception hierarchy)");
168                 }
169             }
170             // add oldRoot to newRoot; addChild takes care of case where oldRoot
171             // is a flat list (i.e., nil-rooted tree).  All children of oldRoot
172             // are added to newRoot.
173             newRootTree.AddChild(oldRootTree);
174             return newRootTree;
175         }
176 
177         /** <summary>Transform ^(nil x) to x and nil to null</summary> */
RulePostProcessing(object root)178         public virtual object RulePostProcessing(object root) {
179             //System.out.println("rulePostProcessing: "+((Tree)root).toStringTree());
180             ITree r = (ITree)root;
181             if (r != null && r.IsNil) {
182                 if (r.ChildCount == 0) {
183                     r = null;
184                 } else if (r.ChildCount == 1) {
185                     r = (ITree)r.GetChild(0);
186                     // whoever invokes rule will set parent and child index
187                     r.Parent = null;
188                     r.ChildIndex = -1;
189                 }
190             }
191             return r;
192         }
193 
BecomeRoot(IToken newRoot, object oldRoot)194         public virtual object BecomeRoot(IToken newRoot, object oldRoot) {
195             return BecomeRoot(Create(newRoot), oldRoot);
196         }
197 
Create(int tokenType, IToken fromToken)198         public virtual object Create(int tokenType, IToken fromToken) {
199             fromToken = CreateToken(fromToken);
200             //((ClassicToken)fromToken).setType(tokenType);
201             fromToken.Type = tokenType;
202             ITree t = (ITree)Create(fromToken);
203             return t;
204         }
205 
Create(int tokenType, IToken fromToken, string text)206         public virtual object Create(int tokenType, IToken fromToken, string text) {
207             if (fromToken == null)
208                 return Create(tokenType, text);
209 
210             fromToken = CreateToken(fromToken);
211             fromToken.Type = tokenType;
212             fromToken.Text = text;
213             ITree t = (ITree)Create(fromToken);
214             return t;
215         }
216 
Create(int tokenType, string text)217         public virtual object Create(int tokenType, string text) {
218             IToken fromToken = CreateToken(tokenType, text);
219             ITree t = (ITree)Create(fromToken);
220             return t;
221         }
222 
GetType(object t)223         public virtual int GetType(object t) {
224             return ((ITree)t).Type;
225         }
226 
SetType(object t, int type)227         public virtual void SetType(object t, int type) {
228             throw new NotSupportedException("don't know enough about Tree node");
229         }
230 
GetText(object t)231         public virtual string GetText(object t) {
232             return ((ITree)t).Text;
233         }
234 
SetText(object t, string text)235         public virtual void SetText(object t, string text) {
236             throw new NotSupportedException("don't know enough about Tree node");
237         }
238 
GetChild(object t, int i)239         public virtual object GetChild(object t, int i) {
240             return ((ITree)t).GetChild(i);
241         }
242 
SetChild(object t, int i, object child)243         public virtual void SetChild(object t, int i, object child) {
244             ((ITree)t).SetChild(i, (ITree)child);
245         }
246 
DeleteChild(object t, int i)247         public virtual object DeleteChild(object t, int i) {
248             return ((ITree)t).DeleteChild(i);
249         }
250 
GetChildCount(object t)251         public virtual int GetChildCount(object t) {
252             return ((ITree)t).ChildCount;
253         }
254 
GetUniqueID(object node)255         public virtual int GetUniqueID(object node) {
256             if (treeToUniqueIDMap == null) {
257                 treeToUniqueIDMap = new Dictionary<object, int>();
258             }
259             int id;
260             if (treeToUniqueIDMap.TryGetValue(node, out id))
261                 return id;
262 
263             id = uniqueNodeID;
264             treeToUniqueIDMap[node] = id;
265             uniqueNodeID++;
266             return id;
267             // GC makes these nonunique:
268             // return System.identityHashCode(node);
269         }
270 
271         /** <summary>
272          *  Tell me how to create a token for use with imaginary token nodes.
273          *  For example, there is probably no input symbol associated with imaginary
274          *  token DECL, but you need to create it as a payload or whatever for
275          *  the DECL node as in ^(DECL type ID).
276          *  </summary>
277          *
278          *  <remarks>
279          *  If you care what the token payload objects' type is, you should
280          *  override this method and any other createToken variant.
281          *  </remarks>
282          */
CreateToken(int tokenType, string text)283         public abstract IToken CreateToken(int tokenType, string text);
284 
285         /** <summary>
286          *  Tell me how to create a token for use with imaginary token nodes.
287          *  For example, there is probably no input symbol associated with imaginary
288          *  token DECL, but you need to create it as a payload or whatever for
289          *  the DECL node as in ^(DECL type ID).
290          *  </summary>
291          *
292          *  <remarks>
293          *  This is a variant of createToken where the new token is derived from
294          *  an actual real input token.  Typically this is for converting '{'
295          *  tokens to BLOCK etc...  You'll see
296          *
297          *    r : lc='{' ID+ '}' -> ^(BLOCK[$lc] ID+) ;
298          *
299          *  If you care what the token payload objects' type is, you should
300          *  override this method and any other createToken variant.
301          *  </remarks>
302          */
CreateToken(IToken fromToken)303         public abstract IToken CreateToken(IToken fromToken);
304 
Create(IToken payload)305         public abstract object Create(IToken payload);
DupNode(object treeNode)306         public abstract object DupNode(object treeNode);
GetToken(object t)307         public abstract IToken GetToken(object t);
SetTokenBoundaries(object t, IToken startToken, IToken stopToken)308         public abstract void SetTokenBoundaries(object t, IToken startToken, IToken stopToken);
GetTokenStartIndex(object t)309         public abstract int GetTokenStartIndex(object t);
GetTokenStopIndex(object t)310         public abstract int GetTokenStopIndex(object t);
GetParent(object t)311         public abstract object GetParent(object t);
SetParent(object t, object parent)312         public abstract void SetParent(object t, object parent);
GetChildIndex(object t)313         public abstract int GetChildIndex(object t);
SetChildIndex(object t, int index)314         public abstract void SetChildIndex(object t, int index);
ReplaceChildren(object parent, int startChildIndex, int stopChildIndex, object t)315         public abstract void ReplaceChildren(object parent, int startChildIndex, int stopChildIndex, object t);
316     }
317 }
318