1package org.antlr.runtime.tree { 2 3 import flash.utils.Dictionary; 4 5 import mx.utils.ObjectUtil; 6 7 import org.antlr.runtime.*; 8 9 /** A TreeAdaptor that works with any Tree implementation. */ 10 public class BaseTreeAdaptor implements TreeAdaptor { 11 /** System.identityHashCode() is not always unique; we have to 12 * track ourselves. That's ok, it's only for debugging, though it's 13 * expensive: we have to create a hashtable with all tree nodes in it. 14 */ 15 protected var treeToUniqueIDMap:Dictionary; 16 protected var uniqueNodeID:int = 1; 17 18 public function nil():Object { 19 return createWithPayload(null); 20 } 21 22 /** create tree node that holds the start and stop tokens associated 23 * with an error. 24 * 25 * If you specify your own kind of tree nodes, you will likely have to 26 * override this method. CommonTree returns Token.INVALID_TOKEN_TYPE 27 * if no token payload but you might have to set token type for diff 28 * node type. 29 * 30 * You don't have to subclass CommonErrorNode; you will likely need to 31 * subclass your own tree node class to avoid class cast exception. 32 */ 33 public function errorNode(input:TokenStream, start:Token, stop:Token, 34 e:RecognitionException):Object { 35 var t:CommonErrorNode = new CommonErrorNode(input, start, stop, e); 36 //System.out.println("returning error node '"+t+"' @index="+input.index()); 37 return t; 38 } 39 40 public function isNil(tree:Object):Boolean { 41 return Tree(tree).isNil; 42 } 43 44 public function dupTree(tree:Object):Object { 45 return dupTreeWithParent(tree, null); 46 } 47 48 /** This is generic in the sense that it will work with any kind of 49 * tree (not just Tree interface). It invokes the adaptor routines 50 * not the tree node routines to do the construction. 51 */ 52 public function dupTreeWithParent(t:Object, parent:Object):Object { 53 if ( t==null ) { 54 return null; 55 } 56 var newTree:Object = dupNode(t); 57 // ensure new subtree root has parent/child index set 58 setChildIndex(newTree, getChildIndex(t)); // same index in new tree 59 setParent(newTree, parent); 60 var n:int = getChildCount(t); 61 for (var i:int = 0; i < n; i++) { 62 var child:Object = getChild(t, i); 63 var newSubTree:Object = dupTreeWithParent(child, t); 64 addChild(newTree, newSubTree); 65 } 66 return newTree; 67 } 68 69 /** Add a child to the tree t. If child is a flat tree (a list), make all 70 * in list children of t. Warning: if t has no children, but child does 71 * and child isNil then you can decide it is ok to move children to t via 72 * t.children = child.children; i.e., without copying the array. Just 73 * make sure that this is consistent with have the user will build 74 * ASTs. 75 */ 76 public function addChild(t:Object, child:Object):void { 77 if ( t!=null && child!=null ) { 78 Tree(t).addChild(Tree(child)); 79 } 80 } 81 82 /** If oldRoot is a nil root, just copy or move the children to newRoot. 83 * If not a nil root, make oldRoot a child of newRoot. 84 * 85 * old=^(nil a b c), new=r yields ^(r a b c) 86 * old=^(a b c), new=r yields ^(r ^(a b c)) 87 * 88 * If newRoot is a nil-rooted single child tree, use the single 89 * child as the new root node. 90 * 91 * old=^(nil a b c), new=^(nil r) yields ^(r a b c) 92 * old=^(a b c), new=^(nil r) yields ^(r ^(a b c)) 93 * 94 * If oldRoot was null, it's ok, just return newRoot (even if isNil). 95 * 96 * old=null, new=r yields r 97 * old=null, new=^(nil r) yields ^(nil r) 98 * 99 * Return newRoot. Throw an exception if newRoot is not a 100 * simple node or nil root with a single child node--it must be a root 101 * node. If newRoot is ^(nil x) return x as newRoot. 102 * 103 * Be advised that it's ok for newRoot to point at oldRoot's 104 * children; i.e., you don't have to copy the list. We are 105 * constructing these nodes so we should have this control for 106 * efficiency. 107 */ 108 public function becomeRoot(newRoot:Object, oldRoot:Object):Object { 109 // If new Root is token, then create a Tree. 110 if (newRoot is Token) { 111 newRoot = createWithPayload(Token(newRoot)); 112 } 113 114 var newRootTree:Tree = Tree(newRoot); 115 var oldRootTree:Tree = Tree(oldRoot); 116 if ( oldRoot==null ) { 117 return newRoot; 118 } 119 // handle ^(nil real-node) 120 if ( newRootTree.isNil ) { 121 var nc:int = newRootTree.childCount; 122 if ( nc==1 ) newRootTree = Tree(newRootTree.getChild(0)); 123 else if ( nc >1 ) { 124 // TODO: make tree run time exceptions hierarchy 125 throw new Error("more than one node as root (TODO: make exception hierarchy)"); 126 } 127 } 128 // add oldRoot to newRoot; addChild takes care of case where oldRoot 129 // is a flat list (i.e., nil-rooted tree). All children of oldRoot 130 // are added to newRoot. 131 newRootTree.addChild(oldRootTree); 132 return newRootTree; 133 } 134 135 /** Transform ^(nil x) to x and nil to null */ 136 public function rulePostProcessing(root:Object):Object { 137 var r:Tree = Tree(root); 138 if ( r!=null && r.isNil ) { 139 if ( r.childCount==0 ) { 140 r = null; 141 } 142 else if ( r.childCount==1 ) { 143 r = Tree(r.getChild(0)); 144 // whoever invokes rule will set parent and child index 145 r.parent = null; 146 r.childIndex = -1; 147 } 148 } 149 return r; 150 } 151 152 public function createFromToken(tokenType:int, fromToken:Token, text:String = null):Object { 153 fromToken = createToken(fromToken); 154 fromToken.type = tokenType; 155 if (text != null) { 156 fromToken.text = text; 157 } 158 return createWithPayload(fromToken); 159 } 160 161 public function createFromType(tokenType:int, text:String):Object { 162 var fromToken:Token = createTokenFromType(tokenType, text); 163 return createWithPayload(fromToken); 164 } 165 166 public function getType(t:Object):int { 167 return Tree(t).type; 168 } 169 170 public function setType(t:Object, type:int):void { 171 throw new Error("don't know enough about Tree node"); 172 } 173 174 public function getText(t:Object):String { 175 return Tree(t).text; 176 } 177 178 public function setText(t:Object, text:String):void { 179 throw new Error("don't know enough about Tree node"); 180 } 181 182 public function getChild(t:Object, i:int):Object { 183 return Tree(t).getChild(i); 184 } 185 186 public function setChild(t:Object, i:int, child:Object):void { 187 Tree(t).setChild(i, Tree(child)); 188 } 189 190 public function deleteChild(t:Object, i:int):Object { 191 return Tree(t).deleteChild(i); 192 } 193 194 public function getChildCount(t:Object):int { 195 return Tree(t).childCount; 196 } 197 198 public function getUniqueID(node:Object):int { 199 if ( treeToUniqueIDMap==null ) { 200 treeToUniqueIDMap = new Dictionary(); 201 } 202 if (treeToUniqueIDMap.hasOwnProperty(node)) { 203 return treeToUniqueIDMap[node]; 204 } 205 206 var ID:int = uniqueNodeID; 207 treeToUniqueIDMap[node] = ID; 208 uniqueNodeID++; 209 return ID; 210 211 } 212 213 /** Tell me how to create a token for use with imaginary token nodes. 214 * For example, there is probably no input symbol associated with imaginary 215 * token DECL, but you need to create it as a payload or whatever for 216 * the DECL node as in ^(DECL type ID). 217 * 218 * If you care what the token payload objects' type is, you should 219 * override this method and any other createToken variant. 220 */ 221 public function createTokenFromType(tokenType:int, text:String):Token { 222 throw new Error("Not implemented - abstract function"); 223 } 224 225 /** Tell me how to create a token for use with imaginary token nodes. 226 * For example, there is probably no input symbol associated with imaginary 227 * token DECL, but you need to create it as a payload or whatever for 228 * the DECL node as in ^(DECL type ID). 229 * 230 * This is a variant of createToken where the new token is derived from 231 * an actual real input token. Typically this is for converting '{' 232 * tokens to BLOCK etc... You'll see 233 * 234 * r : lc='{' ID+ '}' -> ^(BLOCK[$lc] ID+) ; 235 * 236 * If you care what the token payload objects' type is, you should 237 * override this method and any other createToken variant. 238 * 239 */ 240 public function createToken(fromToken:Token):Token { 241 throw new Error("Not implemented - abstract function"); 242 } 243 244 public function createWithPayload(payload:Token):Object { 245 throw new Error("Not implemented - abstract function"); 246 } 247 248 public function dupNode(t:Object):Object { 249 throw new Error("Not implemented - abstract function"); 250 } 251 252 public function getToken(t:Object):Token { 253 throw new Error("Not implemented - abstract function"); 254 } 255 256 public function setTokenBoundaries(t:Object, startToken:Token, stopToken:Token):void { 257 throw new Error("Not implemented - abstract function"); 258 } 259 260 public function getTokenStartIndex(t:Object):int { 261 throw new Error("Not implemented - abstract function"); 262 } 263 264 public function getTokenStopIndex(t:Object):int { 265 throw new Error("Not implemented - abstract function"); 266 } 267 268 public function getParent(t:Object):Object { 269 throw new Error("Not implemented - abstract function"); 270 } 271 272 public function setParent(t:Object, parent:Object):void { 273 throw new Error("Not implemented - abstract function"); 274 } 275 276 public function getChildIndex(t:Object):int { 277 throw new Error("Not implemented - abstract function"); 278 } 279 280 public function setChildIndex(t:Object, index:int):void { 281 throw new Error("Not implemented - abstract function"); 282 } 283 284 public function replaceChildren(parent:Object, startChildIndex:int, stopChildIndex:int, t:Object):void { 285 throw new Error("Not implemented - abstract function"); 286 } 287 288 public function create(... args):Object { 289 if (args.length == 1 && args[0] is Token) { 290 return createWithPayload(args[0]); 291 } 292 else if (args.length == 2 && 293 args[0] is int && 294 args[1] is Token) { 295 return createFromToken(args[0], args[1]); 296 } 297 else if (args.length == 3 && 298 args[0] is int && 299 args[1] is Token && 300 args[2] is String) { 301 return createFromToken(args[0], args[1], args[2]); 302 } 303 else if (args.length == 2 && 304 args[0] is int && 305 args[1] is String) { 306 return createFromType(args[0], args[1]); 307 } 308 throw new Error("No methods signature for arguments : " + ObjectUtil.toString(args)); 309 } 310 } 311 312 313}