Home | History | Annotate | Download | only in Antlr.Runtime.Tree
      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 
     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