| /* |
| * [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); |
| } |
| } |