aboutsummaryrefslogtreecommitdiff
path: root/runtime/CSharp3/Sources/Antlr3.Runtime/Tree/BaseTreeAdaptor.cs
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/CSharp3/Sources/Antlr3.Runtime/Tree/BaseTreeAdaptor.cs')
-rw-r--r--runtime/CSharp3/Sources/Antlr3.Runtime/Tree/BaseTreeAdaptor.cs517
1 files changed, 517 insertions, 0 deletions
diff --git a/runtime/CSharp3/Sources/Antlr3.Runtime/Tree/BaseTreeAdaptor.cs b/runtime/CSharp3/Sources/Antlr3.Runtime/Tree/BaseTreeAdaptor.cs
new file mode 100644
index 0000000..d77e031
--- /dev/null
+++ b/runtime/CSharp3/Sources/Antlr3.Runtime/Tree/BaseTreeAdaptor.cs
@@ -0,0 +1,517 @@
+/*
+ * [The "BSD licence"]
+ * Copyright (c) 2011 Terence Parr
+ * All rights reserved.
+ *
+ * Conversion to C#:
+ * Copyright (c) 2011 Sam Harwell, Pixel Mine, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Antlr.Runtime.Tree
+{
+ using System.Collections.Generic;
+
+ using ArgumentNullException = System.ArgumentNullException;
+ using Exception = System.Exception;
+ using IDictionary = System.Collections.IDictionary;
+ using NotSupportedException = System.NotSupportedException;
+
+ /** <summary>A TreeAdaptor that works with any Tree implementation.</summary> */
+ public abstract class BaseTreeAdaptor : ITreeAdaptor
+ {
+ /** <summary>
+ * System.identityHashCode() is not always unique; we have to
+ * track ourselves. That's ok, it's only for debugging, though it's
+ * expensive: we have to create a hashtable with all tree nodes in it.
+ * </summary>
+ */
+ protected IDictionary<object, int> treeToUniqueIDMap;
+ protected int uniqueNodeID = 1;
+
+ public virtual object Nil()
+ {
+ return Create( null );
+ }
+
+ /** <summary>
+ * Create tree node that holds the start and stop tokens associated
+ * with an error.
+ * </summary>
+ *
+ * <remarks>
+ * If you specify your own kind of tree nodes, you will likely have to
+ * override this method. CommonTree returns Token.INVALID_TOKEN_TYPE
+ * if no token payload but you might have to set token type for diff
+ * node type.
+ *
+ * You don't have to subclass CommonErrorNode; you will likely need to
+ * subclass your own tree node class to avoid class cast exception.
+ * </remarks>
+ */
+ public virtual object ErrorNode( ITokenStream input, IToken start, IToken stop,
+ RecognitionException e )
+ {
+ CommonErrorNode t = new CommonErrorNode( input, start, stop, e );
+ //System.out.println("returning error node '"+t+"' @index="+input.index());
+ return t;
+ }
+
+ public virtual bool IsNil( object tree )
+ {
+ return ( (ITree)tree ).IsNil;
+ }
+
+ public virtual object DupNode(int type, object treeNode)
+ {
+ object t = DupNode(treeNode);
+ SetType(t, type);
+ return t;
+ }
+
+ public virtual object DupNode(object treeNode, string text)
+ {
+ object t = DupNode(treeNode);
+ SetText(t, text);
+ return t;
+ }
+
+ public virtual object DupNode(int type, object treeNode, string text)
+ {
+ object t = DupNode(treeNode);
+ SetType(t, type);
+ SetText(t, text);
+ return t;
+ }
+
+ public virtual object DupTree( object tree )
+ {
+ return DupTree( tree, null );
+ }
+
+ /** <summary>
+ * This is generic in the sense that it will work with any kind of
+ * tree (not just ITree interface). It invokes the adaptor routines
+ * not the tree node routines to do the construction.
+ * </summary>
+ */
+ public virtual object DupTree( object t, object parent )
+ {
+ if ( t == null )
+ {
+ return null;
+ }
+ object newTree = DupNode( t );
+ // ensure new subtree root has parent/child index set
+ SetChildIndex( newTree, GetChildIndex( t ) ); // same index in new tree
+ SetParent( newTree, parent );
+ int n = GetChildCount( t );
+ for ( int i = 0; i < n; i++ )
+ {
+ object child = GetChild( t, i );
+ object newSubTree = DupTree( child, t );
+ AddChild( newTree, newSubTree );
+ }
+ return newTree;
+ }
+
+ /** <summary>
+ * Add a child to the tree t. If child is a flat tree (a list), make all
+ * in list children of t. Warning: if t has no children, but child does
+ * and child isNil then you can decide it is ok to move children to t via
+ * t.children = child.children; i.e., without copying the array. Just
+ * make sure that this is consistent with have the user will build
+ * ASTs.
+ * </summary>
+ */
+ public virtual void AddChild( object t, object child )
+ {
+ if ( t != null && child != null )
+ {
+ ( (ITree)t ).AddChild( (ITree)child );
+ }
+ }
+
+ /** <summary>
+ * If oldRoot is a nil root, just copy or move the children to newRoot.
+ * If not a nil root, make oldRoot a child of newRoot.
+ * </summary>
+ *
+ * <remarks>
+ * old=^(nil a b c), new=r yields ^(r a b c)
+ * old=^(a b c), new=r yields ^(r ^(a b c))
+ *
+ * If newRoot is a nil-rooted single child tree, use the single
+ * child as the new root node.
+ *
+ * old=^(nil a b c), new=^(nil r) yields ^(r a b c)
+ * old=^(a b c), new=^(nil r) yields ^(r ^(a b c))
+ *
+ * If oldRoot was null, it's ok, just return newRoot (even if isNil).
+ *
+ * old=null, new=r yields r
+ * old=null, new=^(nil r) yields ^(nil r)
+ *
+ * Return newRoot. Throw an exception if newRoot is not a
+ * simple node or nil root with a single child node--it must be a root
+ * node. If newRoot is ^(nil x) return x as newRoot.
+ *
+ * Be advised that it's ok for newRoot to point at oldRoot's
+ * children; i.e., you don't have to copy the list. We are
+ * constructing these nodes so we should have this control for
+ * efficiency.
+ * </remarks>
+ */
+ public virtual object BecomeRoot( object newRoot, object oldRoot )
+ {
+ //System.out.println("becomeroot new "+newRoot.toString()+" old "+oldRoot);
+ ITree newRootTree = (ITree)newRoot;
+ ITree oldRootTree = (ITree)oldRoot;
+ if ( oldRoot == null )
+ {
+ return newRoot;
+ }
+ // handle ^(nil real-node)
+ if ( newRootTree.IsNil )
+ {
+ int nc = newRootTree.ChildCount;
+ if ( nc == 1 )
+ newRootTree = (ITree)newRootTree.GetChild( 0 );
+ else if ( nc > 1 )
+ {
+ // TODO: make tree run time exceptions hierarchy
+ throw new Exception( "more than one node as root (TODO: make exception hierarchy)" );
+ }
+ }
+ // add oldRoot to newRoot; addChild takes care of case where oldRoot
+ // is a flat list (i.e., nil-rooted tree). All children of oldRoot
+ // are added to newRoot.
+ newRootTree.AddChild( oldRootTree );
+ return newRootTree;
+ }
+
+ /** <summary>Transform ^(nil x) to x and nil to null</summary> */
+ public virtual object RulePostProcessing( object root )
+ {
+ //System.out.println("rulePostProcessing: "+((Tree)root).toStringTree());
+ ITree r = (ITree)root;
+ if ( r != null && r.IsNil )
+ {
+ if ( r.ChildCount == 0 )
+ {
+ r = null;
+ }
+ else if ( r.ChildCount == 1 )
+ {
+ r = (ITree)r.GetChild( 0 );
+ // whoever invokes rule will set parent and child index
+ r.Parent = null;
+ r.ChildIndex = -1;
+ }
+ }
+ return r;
+ }
+
+ public virtual object BecomeRoot( IToken newRoot, object oldRoot )
+ {
+ return BecomeRoot( Create( newRoot ), oldRoot );
+ }
+
+ public virtual object Create( int tokenType, IToken fromToken )
+ {
+ fromToken = CreateToken( fromToken );
+ fromToken.Type = tokenType;
+ object t = Create( fromToken );
+ return t;
+ }
+
+ public virtual object Create( int tokenType, IToken fromToken, string text )
+ {
+ if ( fromToken == null )
+ return Create( tokenType, text );
+
+ fromToken = CreateToken( fromToken );
+ fromToken.Type = tokenType;
+ fromToken.Text = text;
+ object result = Create(fromToken);
+ return result;
+ }
+
+ public virtual object Create(IToken fromToken, string text)
+ {
+ if (fromToken == null)
+ throw new ArgumentNullException("fromToken");
+
+ fromToken = CreateToken(fromToken);
+ fromToken.Text = text;
+ object result = Create(fromToken);
+ return result;
+ }
+
+ public virtual object Create( int tokenType, string text )
+ {
+ IToken fromToken = CreateToken( tokenType, text );
+ object t = Create( fromToken );
+ return t;
+ }
+
+ public virtual int GetType( object t )
+ {
+ ITree tree = GetTree(t);
+ if (tree == null)
+ return TokenTypes.Invalid;
+
+ return tree.Type;
+ }
+
+ public virtual void SetType( object t, int type )
+ {
+ throw new NotSupportedException( "don't know enough about Tree node" );
+ }
+
+ public virtual string GetText( object t )
+ {
+ ITree tree = GetTree(t);
+ if (tree == null)
+ return null;
+
+ return tree.Text;
+ }
+
+ public virtual void SetText( object t, string text )
+ {
+ throw new NotSupportedException( "don't know enough about Tree node" );
+ }
+
+ public virtual object GetChild( object t, int i )
+ {
+ ITree tree = GetTree(t);
+ if (tree == null)
+ return null;
+
+ return tree.GetChild(i);
+ }
+
+ public virtual void SetChild( object t, int i, object child )
+ {
+ ITree tree = GetTree(t);
+ if (tree == null)
+ return;
+
+ ITree childTree = GetTree(child);
+ tree.SetChild(i, childTree);
+ }
+
+ public virtual object DeleteChild( object t, int i )
+ {
+ return ( (ITree)t ).DeleteChild( i );
+ }
+
+ public virtual int GetChildCount( object t )
+ {
+ ITree tree = GetTree(t);
+ if (tree == null)
+ return 0;
+
+ return tree.ChildCount;
+ }
+
+ public virtual int GetUniqueID( object node )
+ {
+ if ( treeToUniqueIDMap == null )
+ {
+ treeToUniqueIDMap = new Dictionary<object, int>();
+ }
+ int id;
+ if ( treeToUniqueIDMap.TryGetValue( node, out id ) )
+ return id;
+
+ id = uniqueNodeID;
+ treeToUniqueIDMap[node] = id;
+ uniqueNodeID++;
+ return id;
+ // GC makes these nonunique:
+ // return System.identityHashCode(node);
+ }
+
+ /** <summary>
+ * Tell me how to create a token for use with imaginary token nodes.
+ * For example, there is probably no input symbol associated with imaginary
+ * token DECL, but you need to create it as a payload or whatever for
+ * the DECL node as in ^(DECL type ID).
+ * </summary>
+ *
+ * <remarks>
+ * If you care what the token payload objects' type is, you should
+ * override this method and any other createToken variant.
+ * </remarks>
+ */
+ public abstract IToken CreateToken( int tokenType, string text );
+
+ /** <summary>
+ * Tell me how to create a token for use with imaginary token nodes.
+ * For example, there is probably no input symbol associated with imaginary
+ * token DECL, but you need to create it as a payload or whatever for
+ * the DECL node as in ^(DECL type ID).
+ * </summary>
+ *
+ * <remarks>
+ * This is a variant of createToken where the new token is derived from
+ * an actual real input token. Typically this is for converting '{'
+ * tokens to BLOCK etc... You'll see
+ *
+ * r : lc='{' ID+ '}' -> ^(BLOCK[$lc] ID+) ;
+ *
+ * If you care what the token payload objects' type is, you should
+ * override this method and any other createToken variant.
+ * </remarks>
+ */
+ public abstract IToken CreateToken( IToken fromToken );
+
+ public abstract object Create( IToken payload );
+
+ /** <summary>
+ * Duplicate a node. This is part of the factory;
+ * override if you want another kind of node to be built.
+ * </summary>
+ *
+ * <remarks>
+ * I could use reflection to prevent having to override this
+ * but reflection is slow.
+ * </remarks>
+ */
+ public virtual object DupNode(object treeNode)
+ {
+ ITree tree = GetTree(treeNode);
+ if (tree == null)
+ return null;
+
+ return tree.DupNode();
+ }
+
+ public abstract IToken GetToken( object t );
+
+ /** <summary>
+ * Track start/stop token for subtree root created for a rule.
+ * Only works with Tree nodes. For rules that match nothing,
+ * seems like this will yield start=i and stop=i-1 in a nil node.
+ * Might be useful info so I'll not force to be i..i.
+ * </summary>
+ */
+ public virtual void SetTokenBoundaries(object t, IToken startToken, IToken stopToken)
+ {
+ ITree tree = GetTree(t);
+ if (tree == null)
+ return;
+
+ int start = 0;
+ int stop = 0;
+
+ if (startToken != null)
+ start = startToken.TokenIndex;
+ if (stopToken != null)
+ stop = stopToken.TokenIndex;
+
+ tree.TokenStartIndex = start;
+ tree.TokenStopIndex = stop;
+ }
+
+ public virtual int GetTokenStartIndex(object t)
+ {
+ ITree tree = GetTree(t);
+ if (tree == null)
+ return -1;
+
+ return tree.TokenStartIndex;
+ }
+
+ public virtual int GetTokenStopIndex(object t)
+ {
+ ITree tree = GetTree(t);
+ if (tree == null)
+ return -1;
+
+ return tree.TokenStopIndex;
+ }
+
+ public virtual object GetParent(object t)
+ {
+ ITree tree = GetTree(t);
+ if (tree == null)
+ return null;
+
+ return tree.Parent;
+ }
+
+ public virtual void SetParent(object t, object parent)
+ {
+ ITree tree = GetTree(t);
+ if (tree == null)
+ return;
+
+ ITree parentTree = GetTree(parent);
+ tree.Parent = parentTree;
+ }
+
+ public virtual int GetChildIndex(object t)
+ {
+ ITree tree = GetTree(t);
+ if (tree == null)
+ return 0;
+
+ return tree.ChildIndex;
+ }
+
+ public virtual void SetChildIndex(object t, int index)
+ {
+ ITree tree = GetTree(t);
+ if (tree == null)
+ return;
+
+ tree.ChildIndex = index;
+ }
+
+ public virtual void ReplaceChildren(object parent, int startChildIndex, int stopChildIndex, object t)
+ {
+ ITree tree = GetTree(parent);
+ if (tree == null)
+ return;
+
+ tree.ReplaceChildren(startChildIndex, stopChildIndex, t);
+ }
+
+ protected virtual ITree GetTree(object t)
+ {
+ if (t == null)
+ return null;
+
+ ITree tree = t as ITree;
+ if (tree == null)
+ throw new NotSupportedException();
+
+ return tree;
+ }
+ }
+}