001: package org.antlr.runtime.tree;
002:
003: import org.antlr.runtime.Token;
004:
005: import java.util.Map;
006: import java.util.HashMap;
007:
008: public abstract class BaseTreeAdaptor implements TreeAdaptor {
009: /** System.identityHashCode() is not always unique due to GC; we have to
010: * track ourselves. That's ok, it's only for debugging, though it's
011: * expensive: we have to create a hashtable with all tree nodes in it.
012: */
013: protected Map treeToUniqueIDMap;
014: protected int uniqueNodeID = 1;
015:
016: public Object nil() {
017: return create(null);
018: }
019:
020: public boolean isNil(Object tree) {
021: return ((Tree) tree).isNil();
022: }
023:
024: public Object dupTree(Object tree) {
025: return ((Tree) tree).dupTree();
026: }
027:
028: /** Add a child to the tree t. If child is a flat tree (a list), make all
029: * in list children of t. Warning: if t has no children, but child does
030: * and child isNil then you can decide it is ok to move children to t via
031: * t.children = child.children; i.e., without copying the array. Just
032: * make sure that this is consistent with have the user will build
033: * ASTs.
034: */
035: public void addChild(Object t, Object child) {
036: if (t != null && child != null) {
037: ((Tree) t).addChild((Tree) child);
038: }
039: }
040:
041: /** If oldRoot is a nil root, just copy or move the children to newRoot.
042: * If not a nil root, make oldRoot a child of newRoot.
043: *
044: * old=^(nil a b c), new=r yields ^(r a b c)
045: * old=^(a b c), new=r yields ^(r ^(a b c))
046: *
047: * If newRoot is a nil-rooted single child tree, use the single
048: * child as the new root node.
049: *
050: * old=^(nil a b c), new=^(nil r) yields ^(r a b c)
051: * old=^(a b c), new=^(nil r) yields ^(r ^(a b c))
052: *
053: * If oldRoot was null, it's ok, just return newRoot (even if isNil).
054: *
055: * old=null, new=r yields r
056: * old=null, new=^(nil r) yields ^(nil r)
057: *
058: * Return newRoot. Throw an exception if newRoot is not a
059: * simple node or nil root with a single child node--it must be a root
060: * node. If newRoot is ^(nil x) return x as newRoot.
061: *
062: * Be advised that it's ok for newRoot to point at oldRoot's
063: * children; i.e., you don't have to copy the list. We are
064: * constructing these nodes so we should have this control for
065: * efficiency.
066: */
067: public Object becomeRoot(Object newRoot, Object oldRoot) {
068: Tree newRootTree = (Tree) newRoot;
069: Tree oldRootTree = (Tree) oldRoot;
070: if (oldRoot == null) {
071: return newRoot;
072: }
073: // handle ^(nil real-node)
074: if (newRootTree.isNil()) {
075: if (newRootTree.getChildCount() > 1) {
076: // TODO: make tree run time exceptions hierarchy
077: throw new RuntimeException(
078: "more than one node as root (TODO: make exception hierarchy)");
079: }
080: newRootTree = (Tree) newRootTree.getChild(0);
081: }
082: // add oldRoot to newRoot; addChild takes care of case where oldRoot
083: // is a flat list (i.e., nil-rooted tree). All children of oldRoot
084: // are added to newRoot.
085: newRootTree.addChild(oldRootTree);
086: return newRootTree;
087: }
088:
089: /** Transform ^(nil x) to x */
090: public Object rulePostProcessing(Object root) {
091: Tree r = (Tree) root;
092: if (r != null && r.isNil() && r.getChildCount() == 1) {
093: r = (Tree) r.getChild(0);
094: }
095: return r;
096: }
097:
098: public Object becomeRoot(Token newRoot, Object oldRoot) {
099: return becomeRoot(create(newRoot), oldRoot);
100: }
101:
102: public Object create(int tokenType, Token fromToken) {
103: fromToken = createToken(fromToken);
104: //((ClassicToken)fromToken).setType(tokenType);
105: fromToken.setType(tokenType);
106: Tree t = (Tree) create(fromToken);
107: return t;
108: }
109:
110: public Object create(int tokenType, Token fromToken, String text) {
111: fromToken = createToken(fromToken);
112: fromToken.setType(tokenType);
113: fromToken.setText(text);
114: Tree t = (Tree) create(fromToken);
115: return t;
116: }
117:
118: public Object create(int tokenType, String text) {
119: Token fromToken = createToken(tokenType, text);
120: Tree t = (Tree) create(fromToken);
121: return t;
122: }
123:
124: public int getType(Object t) {
125: ((Tree) t).getType();
126: return 0;
127: }
128:
129: public void setType(Object t, int type) {
130: throw new NoSuchMethodError("don't know enough about Tree node");
131: }
132:
133: public String getText(Object t) {
134: return ((Tree) t).getText();
135: }
136:
137: public void setText(Object t, String text) {
138: throw new NoSuchMethodError("don't know enough about Tree node");
139: }
140:
141: public Object getChild(Object t, int i) {
142: return ((Tree) t).getChild(i);
143: }
144:
145: public int getChildCount(Object t) {
146: return ((Tree) t).getChildCount();
147: }
148:
149: public int getUniqueID(Object node) {
150: if (treeToUniqueIDMap == null) {
151: treeToUniqueIDMap = new HashMap();
152: }
153: Integer prevID = (Integer) treeToUniqueIDMap.get(node);
154: if (prevID != null) {
155: return prevID.intValue();
156: }
157: int ID = uniqueNodeID;
158: treeToUniqueIDMap.put(node, new Integer(ID));
159: uniqueNodeID++;
160: return ID;
161: // GC makes these nonunique:
162: // return System.identityHashCode(node);
163: }
164:
165: /** Tell me how to create a token for use with imaginary token nodes.
166: * For example, there is probably no input symbol associated with imaginary
167: * token DECL, but you need to create it as a payload or whatever for
168: * the DECL node as in ^(DECL type ID).
169: *
170: * If you care what the token payload objects' type is, you should
171: * override this method and any other createToken variant.
172: */
173: public abstract Token createToken(int tokenType, String text);
174:
175: /** Tell me how to create a token for use with imaginary token nodes.
176: * For example, there is probably no input symbol associated with imaginary
177: * token DECL, but you need to create it as a payload or whatever for
178: * the DECL node as in ^(DECL type ID).
179: *
180: * This is a variant of createToken where the new token is derived from
181: * an actual real input token. Typically this is for converting '{'
182: * tokens to BLOCK etc... You'll see
183: *
184: * r : lc='{' ID+ '}' -> ^(BLOCK[$lc] ID+) ;
185: *
186: * If you care what the token payload objects' type is, you should
187: * override this method and any other createToken variant.
188: */
189: public abstract Token createToken(Token fromToken);
190: }
|