/* * [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; /** A TreeAdaptor that works with any Tree implementation. */ public abstract class BaseTreeAdaptor : ITreeAdaptor { /** * 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. * */ protected IDictionary treeToUniqueIDMap; protected int uniqueNodeID = 1; public virtual object Nil() { return Create(null); } /** * Create tree node that holds the start and stop tokens associated * with an error. * * * * 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. * */ 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); } /** * 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. * */ 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; } /** * 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. * */ public virtual void AddChild(object t, object child) { if (t != null && child != null) { ((ITree)t).AddChild((ITree)child); } } /** * 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. * * * * 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. * */ 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; } /** Transform ^(nil x) to x and nil to null */ 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(); } 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); } /** * 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). * * * * If you care what the token payload objects' type is, you should * override this method and any other createToken variant. * */ public abstract IToken CreateToken(int tokenType, string text); /** * 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). * * * * 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. * */ 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); } }