BaseTreeAdaptor.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.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
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         */
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
77        public virtual bool IsNil(object tree) {
78            return ((ITree)tree).IsNil;
79        }
80
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         */
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         */
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         */
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> */
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
194        public virtual object BecomeRoot(IToken newRoot, object oldRoot) {
195            return BecomeRoot(Create(newRoot), oldRoot);
196        }
197
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
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
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
223        public virtual int GetType(object t) {
224            return ((ITree)t).Type;
225        }
226
227        public virtual void SetType(object t, int type) {
228            throw new NotSupportedException("don't know enough about Tree node");
229        }
230
231        public virtual string GetText(object t) {
232            return ((ITree)t).Text;
233        }
234
235        public virtual void SetText(object t, string text) {
236            throw new NotSupportedException("don't know enough about Tree node");
237        }
238
239        public virtual object GetChild(object t, int i) {
240            return ((ITree)t).GetChild(i);
241        }
242
243        public virtual void SetChild(object t, int i, object child) {
244            ((ITree)t).SetChild(i, (ITree)child);
245        }
246
247        public virtual object DeleteChild(object t, int i) {
248            return ((ITree)t).DeleteChild(i);
249        }
250
251        public virtual int GetChildCount(object t) {
252            return ((ITree)t).ChildCount;
253        }
254
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         */
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         */
303        public abstract IToken CreateToken(IToken fromToken);
304
305        public abstract object Create(IToken payload);
306        public abstract object DupNode(object treeNode);
307        public abstract IToken GetToken(object t);
308        public abstract void SetTokenBoundaries(object t, IToken startToken, IToken stopToken);
309        public abstract int GetTokenStartIndex(object t);
310        public abstract int GetTokenStopIndex(object t);
311        public abstract object GetParent(object t);
312        public abstract void SetParent(object t, object parent);
313        public abstract int GetChildIndex(object t);
314        public abstract void SetChildIndex(object t, int index);
315        public abstract void ReplaceChildren(object parent, int startChildIndex, int stopChildIndex, object t);
316    }
317}
318