blob: 26a39b80daa954d6295737bf8fef59358686f9c1 [file] [log] [blame]
/*
* [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);
}
}