aboutsummaryrefslogtreecommitdiff
path: root/runtime/CSharp2/Sources/Antlr3.Runtime/Antlr.Runtime.Tree/BaseTreeAdaptor.cs
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/CSharp2/Sources/Antlr3.Runtime/Antlr.Runtime.Tree/BaseTreeAdaptor.cs')
-rw-r--r--runtime/CSharp2/Sources/Antlr3.Runtime/Antlr.Runtime.Tree/BaseTreeAdaptor.cs317
1 files changed, 317 insertions, 0 deletions
diff --git a/runtime/CSharp2/Sources/Antlr3.Runtime/Antlr.Runtime.Tree/BaseTreeAdaptor.cs b/runtime/CSharp2/Sources/Antlr3.Runtime/Antlr.Runtime.Tree/BaseTreeAdaptor.cs
new file mode 100644
index 0000000..26a39b8
--- /dev/null
+++ b/runtime/CSharp2/Sources/Antlr3.Runtime/Antlr.Runtime.Tree/BaseTreeAdaptor.cs
@@ -0,0 +1,317 @@
+/*
+ * [The "BSD licence"]
+ * Copyright (c) 2005-2008 Terence Parr
+ * All rights reserved.
+ *
+ * Conversion to C#:
+ * Copyright (c) 2008-2009 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 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 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);
+ //((ClassicToken)fromToken).setType(tokenType);
+ fromToken.Type = tokenType;
+ ITree t = (ITree)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;
+ ITree t = (ITree)Create(fromToken);
+ return t;
+ }
+
+ public virtual object Create(int tokenType, string text) {
+ IToken fromToken = CreateToken(tokenType, text);
+ ITree t = (ITree)Create(fromToken);
+ return t;
+ }
+
+ public virtual int GetType(object t) {
+ return ((ITree)t).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) {
+ return ((ITree)t).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) {
+ return ((ITree)t).GetChild(i);
+ }
+
+ public virtual void SetChild(object t, int i, object child) {
+ ((ITree)t).SetChild(i, (ITree)child);
+ }
+
+ public virtual object DeleteChild(object t, int i) {
+ return ((ITree)t).DeleteChild(i);
+ }
+
+ public virtual int GetChildCount(object t) {
+ return ((ITree)t).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);
+ public abstract object DupNode(object treeNode);
+ public abstract IToken GetToken(object t);
+ public abstract void SetTokenBoundaries(object t, IToken startToken, IToken stopToken);
+ public abstract int GetTokenStartIndex(object t);
+ public abstract int GetTokenStopIndex(object t);
+ public abstract object GetParent(object t);
+ public abstract void SetParent(object t, object parent);
+ public abstract int GetChildIndex(object t);
+ public abstract void SetChildIndex(object t, int index);
+ public abstract void ReplaceChildren(object parent, int startChildIndex, int stopChildIndex, object t);
+ }
+}