318 lines
13 KiB
C#
318 lines
13 KiB
C#
/*
|
|
* [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);
|
|
}
|
|
}
|