1*16467b97STreehugger Robot""" @package antlr3.tree 2*16467b97STreehugger Robot@brief ANTLR3 runtime package, tree module 3*16467b97STreehugger Robot 4*16467b97STreehugger RobotThis module contains all support classes for AST construction and tree parsers. 5*16467b97STreehugger Robot 6*16467b97STreehugger Robot""" 7*16467b97STreehugger Robot 8*16467b97STreehugger Robot# begin[licence] 9*16467b97STreehugger Robot# 10*16467b97STreehugger Robot# [The "BSD licence"] 11*16467b97STreehugger Robot# Copyright (c) 2005-2008 Terence Parr 12*16467b97STreehugger Robot# All rights reserved. 13*16467b97STreehugger Robot# 14*16467b97STreehugger Robot# Redistribution and use in source and binary forms, with or without 15*16467b97STreehugger Robot# modification, are permitted provided that the following conditions 16*16467b97STreehugger Robot# are met: 17*16467b97STreehugger Robot# 1. Redistributions of source code must retain the above copyright 18*16467b97STreehugger Robot# notice, this list of conditions and the following disclaimer. 19*16467b97STreehugger Robot# 2. Redistributions in binary form must reproduce the above copyright 20*16467b97STreehugger Robot# notice, this list of conditions and the following disclaimer in the 21*16467b97STreehugger Robot# documentation and/or other materials provided with the distribution. 22*16467b97STreehugger Robot# 3. The name of the author may not be used to endorse or promote products 23*16467b97STreehugger Robot# derived from this software without specific prior written permission. 24*16467b97STreehugger Robot# 25*16467b97STreehugger Robot# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 26*16467b97STreehugger Robot# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27*16467b97STreehugger Robot# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28*16467b97STreehugger Robot# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 29*16467b97STreehugger Robot# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 30*16467b97STreehugger Robot# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31*16467b97STreehugger Robot# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32*16467b97STreehugger Robot# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33*16467b97STreehugger Robot# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34*16467b97STreehugger Robot# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35*16467b97STreehugger Robot# 36*16467b97STreehugger Robot# end[licence] 37*16467b97STreehugger Robot 38*16467b97STreehugger Robot# lot's of docstrings are missing, don't complain for now... 39*16467b97STreehugger Robot# pylint: disable-msg=C0111 40*16467b97STreehugger Robot 41*16467b97STreehugger Robotimport re 42*16467b97STreehugger Robot 43*16467b97STreehugger Robotfrom antlr3.constants import UP, DOWN, EOF, INVALID_TOKEN_TYPE 44*16467b97STreehugger Robotfrom antlr3.recognizers import BaseRecognizer, RuleReturnScope 45*16467b97STreehugger Robotfrom antlr3.streams import IntStream 46*16467b97STreehugger Robotfrom antlr3.tokens import CommonToken, Token, INVALID_TOKEN 47*16467b97STreehugger Robotfrom antlr3.exceptions import MismatchedTreeNodeException, \ 48*16467b97STreehugger Robot MissingTokenException, UnwantedTokenException, MismatchedTokenException, \ 49*16467b97STreehugger Robot NoViableAltException 50*16467b97STreehugger Robot 51*16467b97STreehugger Robot 52*16467b97STreehugger Robot############################################################################ 53*16467b97STreehugger Robot# 54*16467b97STreehugger Robot# tree related exceptions 55*16467b97STreehugger Robot# 56*16467b97STreehugger Robot############################################################################ 57*16467b97STreehugger Robot 58*16467b97STreehugger Robot 59*16467b97STreehugger Robotclass RewriteCardinalityException(RuntimeError): 60*16467b97STreehugger Robot """ 61*16467b97STreehugger Robot @brief Base class for all exceptions thrown during AST rewrite construction. 62*16467b97STreehugger Robot 63*16467b97STreehugger Robot This signifies a case where the cardinality of two or more elements 64*16467b97STreehugger Robot in a subrule are different: (ID INT)+ where |ID|!=|INT| 65*16467b97STreehugger Robot """ 66*16467b97STreehugger Robot 67*16467b97STreehugger Robot def __init__(self, elementDescription): 68*16467b97STreehugger Robot RuntimeError.__init__(self, elementDescription) 69*16467b97STreehugger Robot 70*16467b97STreehugger Robot self.elementDescription = elementDescription 71*16467b97STreehugger Robot 72*16467b97STreehugger Robot 73*16467b97STreehugger Robot def getMessage(self): 74*16467b97STreehugger Robot return self.elementDescription 75*16467b97STreehugger Robot 76*16467b97STreehugger Robot 77*16467b97STreehugger Robotclass RewriteEarlyExitException(RewriteCardinalityException): 78*16467b97STreehugger Robot """@brief No elements within a (...)+ in a rewrite rule""" 79*16467b97STreehugger Robot 80*16467b97STreehugger Robot def __init__(self, elementDescription=None): 81*16467b97STreehugger Robot RewriteCardinalityException.__init__(self, elementDescription) 82*16467b97STreehugger Robot 83*16467b97STreehugger Robot 84*16467b97STreehugger Robotclass RewriteEmptyStreamException(RewriteCardinalityException): 85*16467b97STreehugger Robot """ 86*16467b97STreehugger Robot @brief Ref to ID or expr but no tokens in ID stream or subtrees in expr stream 87*16467b97STreehugger Robot """ 88*16467b97STreehugger Robot 89*16467b97STreehugger Robot pass 90*16467b97STreehugger Robot 91*16467b97STreehugger Robot 92*16467b97STreehugger Robot############################################################################ 93*16467b97STreehugger Robot# 94*16467b97STreehugger Robot# basic Tree and TreeAdaptor interfaces 95*16467b97STreehugger Robot# 96*16467b97STreehugger Robot############################################################################ 97*16467b97STreehugger Robot 98*16467b97STreehugger Robotclass Tree(object): 99*16467b97STreehugger Robot """ 100*16467b97STreehugger Robot @brief Abstract baseclass for tree nodes. 101*16467b97STreehugger Robot 102*16467b97STreehugger Robot What does a tree look like? ANTLR has a number of support classes 103*16467b97STreehugger Robot such as CommonTreeNodeStream that work on these kinds of trees. You 104*16467b97STreehugger Robot don't have to make your trees implement this interface, but if you do, 105*16467b97STreehugger Robot you'll be able to use more support code. 106*16467b97STreehugger Robot 107*16467b97STreehugger Robot NOTE: When constructing trees, ANTLR can build any kind of tree; it can 108*16467b97STreehugger Robot even use Token objects as trees if you add a child list to your tokens. 109*16467b97STreehugger Robot 110*16467b97STreehugger Robot This is a tree node without any payload; just navigation and factory stuff. 111*16467b97STreehugger Robot """ 112*16467b97STreehugger Robot 113*16467b97STreehugger Robot 114*16467b97STreehugger Robot def getChild(self, i): 115*16467b97STreehugger Robot raise NotImplementedError 116*16467b97STreehugger Robot 117*16467b97STreehugger Robot 118*16467b97STreehugger Robot def getChildCount(self): 119*16467b97STreehugger Robot raise NotImplementedError 120*16467b97STreehugger Robot 121*16467b97STreehugger Robot 122*16467b97STreehugger Robot def getParent(self): 123*16467b97STreehugger Robot """Tree tracks parent and child index now > 3.0""" 124*16467b97STreehugger Robot 125*16467b97STreehugger Robot raise NotImplementedError 126*16467b97STreehugger Robot 127*16467b97STreehugger Robot def setParent(self, t): 128*16467b97STreehugger Robot """Tree tracks parent and child index now > 3.0""" 129*16467b97STreehugger Robot 130*16467b97STreehugger Robot raise NotImplementedError 131*16467b97STreehugger Robot 132*16467b97STreehugger Robot 133*16467b97STreehugger Robot def hasAncestor(self, ttype): 134*16467b97STreehugger Robot """Walk upwards looking for ancestor with this token type.""" 135*16467b97STreehugger Robot 136*16467b97STreehugger Robot raise NotImplementedError 137*16467b97STreehugger Robot 138*16467b97STreehugger Robot def getAncestor(self, ttype): 139*16467b97STreehugger Robot """Walk upwards and get first ancestor with this token type.""" 140*16467b97STreehugger Robot 141*16467b97STreehugger Robot raise NotImplementedError 142*16467b97STreehugger Robot 143*16467b97STreehugger Robot def getAncestors(self): 144*16467b97STreehugger Robot """Return a list of all ancestors of this node. 145*16467b97STreehugger Robot 146*16467b97STreehugger Robot The first node of list is the root and the last is the parent of 147*16467b97STreehugger Robot this node. 148*16467b97STreehugger Robot """ 149*16467b97STreehugger Robot 150*16467b97STreehugger Robot raise NotImplementedError 151*16467b97STreehugger Robot 152*16467b97STreehugger Robot 153*16467b97STreehugger Robot def getChildIndex(self): 154*16467b97STreehugger Robot """This node is what child index? 0..n-1""" 155*16467b97STreehugger Robot 156*16467b97STreehugger Robot raise NotImplementedError 157*16467b97STreehugger Robot 158*16467b97STreehugger Robot def setChildIndex(self, index): 159*16467b97STreehugger Robot """This node is what child index? 0..n-1""" 160*16467b97STreehugger Robot 161*16467b97STreehugger Robot raise NotImplementedError 162*16467b97STreehugger Robot 163*16467b97STreehugger Robot 164*16467b97STreehugger Robot def freshenParentAndChildIndexes(self): 165*16467b97STreehugger Robot """Set the parent and child index values for all children""" 166*16467b97STreehugger Robot 167*16467b97STreehugger Robot raise NotImplementedError 168*16467b97STreehugger Robot 169*16467b97STreehugger Robot 170*16467b97STreehugger Robot def addChild(self, t): 171*16467b97STreehugger Robot """ 172*16467b97STreehugger Robot Add t as a child to this node. If t is null, do nothing. If t 173*16467b97STreehugger Robot is nil, add all children of t to this' children. 174*16467b97STreehugger Robot """ 175*16467b97STreehugger Robot 176*16467b97STreehugger Robot raise NotImplementedError 177*16467b97STreehugger Robot 178*16467b97STreehugger Robot 179*16467b97STreehugger Robot def setChild(self, i, t): 180*16467b97STreehugger Robot """Set ith child (0..n-1) to t; t must be non-null and non-nil node""" 181*16467b97STreehugger Robot 182*16467b97STreehugger Robot raise NotImplementedError 183*16467b97STreehugger Robot 184*16467b97STreehugger Robot 185*16467b97STreehugger Robot def deleteChild(self, i): 186*16467b97STreehugger Robot raise NotImplementedError 187*16467b97STreehugger Robot 188*16467b97STreehugger Robot 189*16467b97STreehugger Robot def replaceChildren(self, startChildIndex, stopChildIndex, t): 190*16467b97STreehugger Robot """ 191*16467b97STreehugger Robot Delete children from start to stop and replace with t even if t is 192*16467b97STreehugger Robot a list (nil-root tree). num of children can increase or decrease. 193*16467b97STreehugger Robot For huge child lists, inserting children can force walking rest of 194*16467b97STreehugger Robot children to set their childindex; could be slow. 195*16467b97STreehugger Robot """ 196*16467b97STreehugger Robot 197*16467b97STreehugger Robot raise NotImplementedError 198*16467b97STreehugger Robot 199*16467b97STreehugger Robot 200*16467b97STreehugger Robot def isNil(self): 201*16467b97STreehugger Robot """ 202*16467b97STreehugger Robot Indicates the node is a nil node but may still have children, meaning 203*16467b97STreehugger Robot the tree is a flat list. 204*16467b97STreehugger Robot """ 205*16467b97STreehugger Robot 206*16467b97STreehugger Robot raise NotImplementedError 207*16467b97STreehugger Robot 208*16467b97STreehugger Robot 209*16467b97STreehugger Robot def getTokenStartIndex(self): 210*16467b97STreehugger Robot """ 211*16467b97STreehugger Robot What is the smallest token index (indexing from 0) for this node 212*16467b97STreehugger Robot and its children? 213*16467b97STreehugger Robot """ 214*16467b97STreehugger Robot 215*16467b97STreehugger Robot raise NotImplementedError 216*16467b97STreehugger Robot 217*16467b97STreehugger Robot 218*16467b97STreehugger Robot def setTokenStartIndex(self, index): 219*16467b97STreehugger Robot raise NotImplementedError 220*16467b97STreehugger Robot 221*16467b97STreehugger Robot 222*16467b97STreehugger Robot def getTokenStopIndex(self): 223*16467b97STreehugger Robot """ 224*16467b97STreehugger Robot What is the largest token index (indexing from 0) for this node 225*16467b97STreehugger Robot and its children? 226*16467b97STreehugger Robot """ 227*16467b97STreehugger Robot 228*16467b97STreehugger Robot raise NotImplementedError 229*16467b97STreehugger Robot 230*16467b97STreehugger Robot 231*16467b97STreehugger Robot def setTokenStopIndex(self, index): 232*16467b97STreehugger Robot raise NotImplementedError 233*16467b97STreehugger Robot 234*16467b97STreehugger Robot 235*16467b97STreehugger Robot def dupNode(self): 236*16467b97STreehugger Robot raise NotImplementedError 237*16467b97STreehugger Robot 238*16467b97STreehugger Robot 239*16467b97STreehugger Robot def getType(self): 240*16467b97STreehugger Robot """Return a token type; needed for tree parsing.""" 241*16467b97STreehugger Robot 242*16467b97STreehugger Robot raise NotImplementedError 243*16467b97STreehugger Robot 244*16467b97STreehugger Robot 245*16467b97STreehugger Robot def getText(self): 246*16467b97STreehugger Robot raise NotImplementedError 247*16467b97STreehugger Robot 248*16467b97STreehugger Robot 249*16467b97STreehugger Robot def getLine(self): 250*16467b97STreehugger Robot """ 251*16467b97STreehugger Robot In case we don't have a token payload, what is the line for errors? 252*16467b97STreehugger Robot """ 253*16467b97STreehugger Robot 254*16467b97STreehugger Robot raise NotImplementedError 255*16467b97STreehugger Robot 256*16467b97STreehugger Robot 257*16467b97STreehugger Robot def getCharPositionInLine(self): 258*16467b97STreehugger Robot raise NotImplementedError 259*16467b97STreehugger Robot 260*16467b97STreehugger Robot 261*16467b97STreehugger Robot def toStringTree(self): 262*16467b97STreehugger Robot raise NotImplementedError 263*16467b97STreehugger Robot 264*16467b97STreehugger Robot 265*16467b97STreehugger Robot def toString(self): 266*16467b97STreehugger Robot raise NotImplementedError 267*16467b97STreehugger Robot 268*16467b97STreehugger Robot 269*16467b97STreehugger Robot 270*16467b97STreehugger Robotclass TreeAdaptor(object): 271*16467b97STreehugger Robot """ 272*16467b97STreehugger Robot @brief Abstract baseclass for tree adaptors. 273*16467b97STreehugger Robot 274*16467b97STreehugger Robot How to create and navigate trees. Rather than have a separate factory 275*16467b97STreehugger Robot and adaptor, I've merged them. Makes sense to encapsulate. 276*16467b97STreehugger Robot 277*16467b97STreehugger Robot This takes the place of the tree construction code generated in the 278*16467b97STreehugger Robot generated code in 2.x and the ASTFactory. 279*16467b97STreehugger Robot 280*16467b97STreehugger Robot I do not need to know the type of a tree at all so they are all 281*16467b97STreehugger Robot generic Objects. This may increase the amount of typecasting needed. :( 282*16467b97STreehugger Robot """ 283*16467b97STreehugger Robot 284*16467b97STreehugger Robot # C o n s t r u c t i o n 285*16467b97STreehugger Robot 286*16467b97STreehugger Robot def createWithPayload(self, payload): 287*16467b97STreehugger Robot """ 288*16467b97STreehugger Robot Create a tree node from Token object; for CommonTree type trees, 289*16467b97STreehugger Robot then the token just becomes the payload. This is the most 290*16467b97STreehugger Robot common create call. 291*16467b97STreehugger Robot 292*16467b97STreehugger Robot Override if you want another kind of node to be built. 293*16467b97STreehugger Robot """ 294*16467b97STreehugger Robot 295*16467b97STreehugger Robot raise NotImplementedError 296*16467b97STreehugger Robot 297*16467b97STreehugger Robot 298*16467b97STreehugger Robot def dupNode(self, treeNode): 299*16467b97STreehugger Robot """Duplicate a single tree node. 300*16467b97STreehugger Robot 301*16467b97STreehugger Robot Override if you want another kind of node to be built.""" 302*16467b97STreehugger Robot 303*16467b97STreehugger Robot raise NotImplementedError 304*16467b97STreehugger Robot 305*16467b97STreehugger Robot 306*16467b97STreehugger Robot def dupTree(self, tree): 307*16467b97STreehugger Robot """Duplicate tree recursively, using dupNode() for each node""" 308*16467b97STreehugger Robot 309*16467b97STreehugger Robot raise NotImplementedError 310*16467b97STreehugger Robot 311*16467b97STreehugger Robot 312*16467b97STreehugger Robot def nil(self): 313*16467b97STreehugger Robot """ 314*16467b97STreehugger Robot Return a nil node (an empty but non-null node) that can hold 315*16467b97STreehugger Robot a list of element as the children. If you want a flat tree (a list) 316*16467b97STreehugger Robot use "t=adaptor.nil(); t.addChild(x); t.addChild(y);" 317*16467b97STreehugger Robot """ 318*16467b97STreehugger Robot 319*16467b97STreehugger Robot raise NotImplementedError 320*16467b97STreehugger Robot 321*16467b97STreehugger Robot 322*16467b97STreehugger Robot def errorNode(self, input, start, stop, exc): 323*16467b97STreehugger Robot """ 324*16467b97STreehugger Robot Return a tree node representing an error. This node records the 325*16467b97STreehugger Robot tokens consumed during error recovery. The start token indicates the 326*16467b97STreehugger Robot input symbol at which the error was detected. The stop token indicates 327*16467b97STreehugger Robot the last symbol consumed during recovery. 328*16467b97STreehugger Robot 329*16467b97STreehugger Robot You must specify the input stream so that the erroneous text can 330*16467b97STreehugger Robot be packaged up in the error node. The exception could be useful 331*16467b97STreehugger Robot to some applications; default implementation stores ptr to it in 332*16467b97STreehugger Robot the CommonErrorNode. 333*16467b97STreehugger Robot 334*16467b97STreehugger Robot This only makes sense during token parsing, not tree parsing. 335*16467b97STreehugger Robot Tree parsing should happen only when parsing and tree construction 336*16467b97STreehugger Robot succeed. 337*16467b97STreehugger Robot """ 338*16467b97STreehugger Robot 339*16467b97STreehugger Robot raise NotImplementedError 340*16467b97STreehugger Robot 341*16467b97STreehugger Robot 342*16467b97STreehugger Robot def isNil(self, tree): 343*16467b97STreehugger Robot """Is tree considered a nil node used to make lists of child nodes?""" 344*16467b97STreehugger Robot 345*16467b97STreehugger Robot raise NotImplementedError 346*16467b97STreehugger Robot 347*16467b97STreehugger Robot 348*16467b97STreehugger Robot def addChild(self, t, child): 349*16467b97STreehugger Robot """ 350*16467b97STreehugger Robot Add a child to the tree t. If child is a flat tree (a list), make all 351*16467b97STreehugger Robot in list children of t. Warning: if t has no children, but child does 352*16467b97STreehugger Robot and child isNil then you can decide it is ok to move children to t via 353*16467b97STreehugger Robot t.children = child.children; i.e., without copying the array. Just 354*16467b97STreehugger Robot make sure that this is consistent with have the user will build 355*16467b97STreehugger Robot ASTs. Do nothing if t or child is null. 356*16467b97STreehugger Robot """ 357*16467b97STreehugger Robot 358*16467b97STreehugger Robot raise NotImplementedError 359*16467b97STreehugger Robot 360*16467b97STreehugger Robot 361*16467b97STreehugger Robot def becomeRoot(self, newRoot, oldRoot): 362*16467b97STreehugger Robot """ 363*16467b97STreehugger Robot If oldRoot is a nil root, just copy or move the children to newRoot. 364*16467b97STreehugger Robot If not a nil root, make oldRoot a child of newRoot. 365*16467b97STreehugger Robot 366*16467b97STreehugger Robot old=^(nil a b c), new=r yields ^(r a b c) 367*16467b97STreehugger Robot old=^(a b c), new=r yields ^(r ^(a b c)) 368*16467b97STreehugger Robot 369*16467b97STreehugger Robot If newRoot is a nil-rooted single child tree, use the single 370*16467b97STreehugger Robot child as the new root node. 371*16467b97STreehugger Robot 372*16467b97STreehugger Robot old=^(nil a b c), new=^(nil r) yields ^(r a b c) 373*16467b97STreehugger Robot old=^(a b c), new=^(nil r) yields ^(r ^(a b c)) 374*16467b97STreehugger Robot 375*16467b97STreehugger Robot If oldRoot was null, it's ok, just return newRoot (even if isNil). 376*16467b97STreehugger Robot 377*16467b97STreehugger Robot old=null, new=r yields r 378*16467b97STreehugger Robot old=null, new=^(nil r) yields ^(nil r) 379*16467b97STreehugger Robot 380*16467b97STreehugger Robot Return newRoot. Throw an exception if newRoot is not a 381*16467b97STreehugger Robot simple node or nil root with a single child node--it must be a root 382*16467b97STreehugger Robot node. If newRoot is ^(nil x) return x as newRoot. 383*16467b97STreehugger Robot 384*16467b97STreehugger Robot Be advised that it's ok for newRoot to point at oldRoot's 385*16467b97STreehugger Robot children; i.e., you don't have to copy the list. We are 386*16467b97STreehugger Robot constructing these nodes so we should have this control for 387*16467b97STreehugger Robot efficiency. 388*16467b97STreehugger Robot """ 389*16467b97STreehugger Robot 390*16467b97STreehugger Robot raise NotImplementedError 391*16467b97STreehugger Robot 392*16467b97STreehugger Robot 393*16467b97STreehugger Robot def rulePostProcessing(self, root): 394*16467b97STreehugger Robot """ 395*16467b97STreehugger Robot Given the root of the subtree created for this rule, post process 396*16467b97STreehugger Robot it to do any simplifications or whatever you want. A required 397*16467b97STreehugger Robot behavior is to convert ^(nil singleSubtree) to singleSubtree 398*16467b97STreehugger Robot as the setting of start/stop indexes relies on a single non-nil root 399*16467b97STreehugger Robot for non-flat trees. 400*16467b97STreehugger Robot 401*16467b97STreehugger Robot Flat trees such as for lists like "idlist : ID+ ;" are left alone 402*16467b97STreehugger Robot unless there is only one ID. For a list, the start/stop indexes 403*16467b97STreehugger Robot are set in the nil node. 404*16467b97STreehugger Robot 405*16467b97STreehugger Robot This method is executed after all rule tree construction and right 406*16467b97STreehugger Robot before setTokenBoundaries(). 407*16467b97STreehugger Robot """ 408*16467b97STreehugger Robot 409*16467b97STreehugger Robot raise NotImplementedError 410*16467b97STreehugger Robot 411*16467b97STreehugger Robot 412*16467b97STreehugger Robot def getUniqueID(self, node): 413*16467b97STreehugger Robot """For identifying trees. 414*16467b97STreehugger Robot 415*16467b97STreehugger Robot How to identify nodes so we can say "add node to a prior node"? 416*16467b97STreehugger Robot Even becomeRoot is an issue. Use System.identityHashCode(node) 417*16467b97STreehugger Robot usually. 418*16467b97STreehugger Robot """ 419*16467b97STreehugger Robot 420*16467b97STreehugger Robot raise NotImplementedError 421*16467b97STreehugger Robot 422*16467b97STreehugger Robot 423*16467b97STreehugger Robot # R e w r i t e R u l e s 424*16467b97STreehugger Robot 425*16467b97STreehugger Robot def createFromToken(self, tokenType, fromToken, text=None): 426*16467b97STreehugger Robot """ 427*16467b97STreehugger Robot Create a new node derived from a token, with a new token type and 428*16467b97STreehugger Robot (optionally) new text. 429*16467b97STreehugger Robot 430*16467b97STreehugger Robot This is invoked from an imaginary node ref on right side of a 431*16467b97STreehugger Robot rewrite rule as IMAG[$tokenLabel] or IMAG[$tokenLabel "IMAG"]. 432*16467b97STreehugger Robot 433*16467b97STreehugger Robot This should invoke createToken(Token). 434*16467b97STreehugger Robot """ 435*16467b97STreehugger Robot 436*16467b97STreehugger Robot raise NotImplementedError 437*16467b97STreehugger Robot 438*16467b97STreehugger Robot 439*16467b97STreehugger Robot def createFromType(self, tokenType, text): 440*16467b97STreehugger Robot """Create a new node derived from a token, with a new token type. 441*16467b97STreehugger Robot 442*16467b97STreehugger Robot This is invoked from an imaginary node ref on right side of a 443*16467b97STreehugger Robot rewrite rule as IMAG["IMAG"]. 444*16467b97STreehugger Robot 445*16467b97STreehugger Robot This should invoke createToken(int,String). 446*16467b97STreehugger Robot """ 447*16467b97STreehugger Robot 448*16467b97STreehugger Robot raise NotImplementedError 449*16467b97STreehugger Robot 450*16467b97STreehugger Robot 451*16467b97STreehugger Robot # C o n t e n t 452*16467b97STreehugger Robot 453*16467b97STreehugger Robot def getType(self, t): 454*16467b97STreehugger Robot """For tree parsing, I need to know the token type of a node""" 455*16467b97STreehugger Robot 456*16467b97STreehugger Robot raise NotImplementedError 457*16467b97STreehugger Robot 458*16467b97STreehugger Robot 459*16467b97STreehugger Robot def setType(self, t, type): 460*16467b97STreehugger Robot """Node constructors can set the type of a node""" 461*16467b97STreehugger Robot 462*16467b97STreehugger Robot raise NotImplementedError 463*16467b97STreehugger Robot 464*16467b97STreehugger Robot 465*16467b97STreehugger Robot def getText(self, t): 466*16467b97STreehugger Robot raise NotImplementedError 467*16467b97STreehugger Robot 468*16467b97STreehugger Robot def setText(self, t, text): 469*16467b97STreehugger Robot """Node constructors can set the text of a node""" 470*16467b97STreehugger Robot 471*16467b97STreehugger Robot raise NotImplementedError 472*16467b97STreehugger Robot 473*16467b97STreehugger Robot 474*16467b97STreehugger Robot def getToken(self, t): 475*16467b97STreehugger Robot """Return the token object from which this node was created. 476*16467b97STreehugger Robot 477*16467b97STreehugger Robot Currently used only for printing an error message. 478*16467b97STreehugger Robot The error display routine in BaseRecognizer needs to 479*16467b97STreehugger Robot display where the input the error occurred. If your 480*16467b97STreehugger Robot tree of limitation does not store information that can 481*16467b97STreehugger Robot lead you to the token, you can create a token filled with 482*16467b97STreehugger Robot the appropriate information and pass that back. See 483*16467b97STreehugger Robot BaseRecognizer.getErrorMessage(). 484*16467b97STreehugger Robot """ 485*16467b97STreehugger Robot 486*16467b97STreehugger Robot raise NotImplementedError 487*16467b97STreehugger Robot 488*16467b97STreehugger Robot 489*16467b97STreehugger Robot def setTokenBoundaries(self, t, startToken, stopToken): 490*16467b97STreehugger Robot """ 491*16467b97STreehugger Robot Where are the bounds in the input token stream for this node and 492*16467b97STreehugger Robot all children? Each rule that creates AST nodes will call this 493*16467b97STreehugger Robot method right before returning. Flat trees (i.e., lists) will 494*16467b97STreehugger Robot still usually have a nil root node just to hold the children list. 495*16467b97STreehugger Robot That node would contain the start/stop indexes then. 496*16467b97STreehugger Robot """ 497*16467b97STreehugger Robot 498*16467b97STreehugger Robot raise NotImplementedError 499*16467b97STreehugger Robot 500*16467b97STreehugger Robot 501*16467b97STreehugger Robot def getTokenStartIndex(self, t): 502*16467b97STreehugger Robot """ 503*16467b97STreehugger Robot Get the token start index for this subtree; return -1 if no such index 504*16467b97STreehugger Robot """ 505*16467b97STreehugger Robot 506*16467b97STreehugger Robot raise NotImplementedError 507*16467b97STreehugger Robot 508*16467b97STreehugger Robot 509*16467b97STreehugger Robot def getTokenStopIndex(self, t): 510*16467b97STreehugger Robot """ 511*16467b97STreehugger Robot Get the token stop index for this subtree; return -1 if no such index 512*16467b97STreehugger Robot """ 513*16467b97STreehugger Robot 514*16467b97STreehugger Robot raise NotImplementedError 515*16467b97STreehugger Robot 516*16467b97STreehugger Robot 517*16467b97STreehugger Robot # N a v i g a t i o n / T r e e P a r s i n g 518*16467b97STreehugger Robot 519*16467b97STreehugger Robot def getChild(self, t, i): 520*16467b97STreehugger Robot """Get a child 0..n-1 node""" 521*16467b97STreehugger Robot 522*16467b97STreehugger Robot raise NotImplementedError 523*16467b97STreehugger Robot 524*16467b97STreehugger Robot 525*16467b97STreehugger Robot def setChild(self, t, i, child): 526*16467b97STreehugger Robot """Set ith child (0..n-1) to t; t must be non-null and non-nil node""" 527*16467b97STreehugger Robot 528*16467b97STreehugger Robot raise NotImplementedError 529*16467b97STreehugger Robot 530*16467b97STreehugger Robot 531*16467b97STreehugger Robot def deleteChild(self, t, i): 532*16467b97STreehugger Robot """Remove ith child and shift children down from right.""" 533*16467b97STreehugger Robot 534*16467b97STreehugger Robot raise NotImplementedError 535*16467b97STreehugger Robot 536*16467b97STreehugger Robot 537*16467b97STreehugger Robot def getChildCount(self, t): 538*16467b97STreehugger Robot """How many children? If 0, then this is a leaf node""" 539*16467b97STreehugger Robot 540*16467b97STreehugger Robot raise NotImplementedError 541*16467b97STreehugger Robot 542*16467b97STreehugger Robot 543*16467b97STreehugger Robot def getParent(self, t): 544*16467b97STreehugger Robot """ 545*16467b97STreehugger Robot Who is the parent node of this node; if null, implies node is root. 546*16467b97STreehugger Robot If your node type doesn't handle this, it's ok but the tree rewrites 547*16467b97STreehugger Robot in tree parsers need this functionality. 548*16467b97STreehugger Robot """ 549*16467b97STreehugger Robot 550*16467b97STreehugger Robot raise NotImplementedError 551*16467b97STreehugger Robot 552*16467b97STreehugger Robot 553*16467b97STreehugger Robot def setParent(self, t, parent): 554*16467b97STreehugger Robot """ 555*16467b97STreehugger Robot Who is the parent node of this node; if null, implies node is root. 556*16467b97STreehugger Robot If your node type doesn't handle this, it's ok but the tree rewrites 557*16467b97STreehugger Robot in tree parsers need this functionality. 558*16467b97STreehugger Robot """ 559*16467b97STreehugger Robot 560*16467b97STreehugger Robot raise NotImplementedError 561*16467b97STreehugger Robot 562*16467b97STreehugger Robot 563*16467b97STreehugger Robot def getChildIndex(self, t): 564*16467b97STreehugger Robot """ 565*16467b97STreehugger Robot What index is this node in the child list? Range: 0..n-1 566*16467b97STreehugger Robot If your node type doesn't handle this, it's ok but the tree rewrites 567*16467b97STreehugger Robot in tree parsers need this functionality. 568*16467b97STreehugger Robot """ 569*16467b97STreehugger Robot 570*16467b97STreehugger Robot raise NotImplementedError 571*16467b97STreehugger Robot 572*16467b97STreehugger Robot 573*16467b97STreehugger Robot def setChildIndex(self, t, index): 574*16467b97STreehugger Robot """ 575*16467b97STreehugger Robot What index is this node in the child list? Range: 0..n-1 576*16467b97STreehugger Robot If your node type doesn't handle this, it's ok but the tree rewrites 577*16467b97STreehugger Robot in tree parsers need this functionality. 578*16467b97STreehugger Robot """ 579*16467b97STreehugger Robot 580*16467b97STreehugger Robot raise NotImplementedError 581*16467b97STreehugger Robot 582*16467b97STreehugger Robot 583*16467b97STreehugger Robot def replaceChildren(self, parent, startChildIndex, stopChildIndex, t): 584*16467b97STreehugger Robot """ 585*16467b97STreehugger Robot Replace from start to stop child index of parent with t, which might 586*16467b97STreehugger Robot be a list. Number of children may be different 587*16467b97STreehugger Robot after this call. 588*16467b97STreehugger Robot 589*16467b97STreehugger Robot If parent is null, don't do anything; must be at root of overall tree. 590*16467b97STreehugger Robot Can't replace whatever points to the parent externally. Do nothing. 591*16467b97STreehugger Robot """ 592*16467b97STreehugger Robot 593*16467b97STreehugger Robot raise NotImplementedError 594*16467b97STreehugger Robot 595*16467b97STreehugger Robot 596*16467b97STreehugger Robot # Misc 597*16467b97STreehugger Robot 598*16467b97STreehugger Robot def create(self, *args): 599*16467b97STreehugger Robot """ 600*16467b97STreehugger Robot Deprecated, use createWithPayload, createFromToken or createFromType. 601*16467b97STreehugger Robot 602*16467b97STreehugger Robot This method only exists to mimic the Java interface of TreeAdaptor. 603*16467b97STreehugger Robot 604*16467b97STreehugger Robot """ 605*16467b97STreehugger Robot 606*16467b97STreehugger Robot if len(args) == 1 and isinstance(args[0], Token): 607*16467b97STreehugger Robot # Object create(Token payload); 608*16467b97STreehugger Robot## warnings.warn( 609*16467b97STreehugger Robot## "Using create() is deprecated, use createWithPayload()", 610*16467b97STreehugger Robot## DeprecationWarning, 611*16467b97STreehugger Robot## stacklevel=2 612*16467b97STreehugger Robot## ) 613*16467b97STreehugger Robot return self.createWithPayload(args[0]) 614*16467b97STreehugger Robot 615*16467b97STreehugger Robot if (len(args) == 2 616*16467b97STreehugger Robot and isinstance(args[0], (int, long)) 617*16467b97STreehugger Robot and isinstance(args[1], Token) 618*16467b97STreehugger Robot ): 619*16467b97STreehugger Robot # Object create(int tokenType, Token fromToken); 620*16467b97STreehugger Robot## warnings.warn( 621*16467b97STreehugger Robot## "Using create() is deprecated, use createFromToken()", 622*16467b97STreehugger Robot## DeprecationWarning, 623*16467b97STreehugger Robot## stacklevel=2 624*16467b97STreehugger Robot## ) 625*16467b97STreehugger Robot return self.createFromToken(args[0], args[1]) 626*16467b97STreehugger Robot 627*16467b97STreehugger Robot if (len(args) == 3 628*16467b97STreehugger Robot and isinstance(args[0], (int, long)) 629*16467b97STreehugger Robot and isinstance(args[1], Token) 630*16467b97STreehugger Robot and isinstance(args[2], basestring) 631*16467b97STreehugger Robot ): 632*16467b97STreehugger Robot # Object create(int tokenType, Token fromToken, String text); 633*16467b97STreehugger Robot## warnings.warn( 634*16467b97STreehugger Robot## "Using create() is deprecated, use createFromToken()", 635*16467b97STreehugger Robot## DeprecationWarning, 636*16467b97STreehugger Robot## stacklevel=2 637*16467b97STreehugger Robot## ) 638*16467b97STreehugger Robot return self.createFromToken(args[0], args[1], args[2]) 639*16467b97STreehugger Robot 640*16467b97STreehugger Robot if (len(args) == 2 641*16467b97STreehugger Robot and isinstance(args[0], (int, long)) 642*16467b97STreehugger Robot and isinstance(args[1], basestring) 643*16467b97STreehugger Robot ): 644*16467b97STreehugger Robot # Object create(int tokenType, String text); 645*16467b97STreehugger Robot## warnings.warn( 646*16467b97STreehugger Robot## "Using create() is deprecated, use createFromType()", 647*16467b97STreehugger Robot## DeprecationWarning, 648*16467b97STreehugger Robot## stacklevel=2 649*16467b97STreehugger Robot## ) 650*16467b97STreehugger Robot return self.createFromType(args[0], args[1]) 651*16467b97STreehugger Robot 652*16467b97STreehugger Robot raise TypeError( 653*16467b97STreehugger Robot "No create method with this signature found: %s" 654*16467b97STreehugger Robot % (', '.join(type(v).__name__ for v in args)) 655*16467b97STreehugger Robot ) 656*16467b97STreehugger Robot 657*16467b97STreehugger Robot 658*16467b97STreehugger Robot############################################################################ 659*16467b97STreehugger Robot# 660*16467b97STreehugger Robot# base implementation of Tree and TreeAdaptor 661*16467b97STreehugger Robot# 662*16467b97STreehugger Robot# Tree 663*16467b97STreehugger Robot# \- BaseTree 664*16467b97STreehugger Robot# 665*16467b97STreehugger Robot# TreeAdaptor 666*16467b97STreehugger Robot# \- BaseTreeAdaptor 667*16467b97STreehugger Robot# 668*16467b97STreehugger Robot############################################################################ 669*16467b97STreehugger Robot 670*16467b97STreehugger Robot 671*16467b97STreehugger Robotclass BaseTree(Tree): 672*16467b97STreehugger Robot """ 673*16467b97STreehugger Robot @brief A generic tree implementation with no payload. 674*16467b97STreehugger Robot 675*16467b97STreehugger Robot You must subclass to 676*16467b97STreehugger Robot actually have any user data. ANTLR v3 uses a list of children approach 677*16467b97STreehugger Robot instead of the child-sibling approach in v2. A flat tree (a list) is 678*16467b97STreehugger Robot an empty node whose children represent the list. An empty, but 679*16467b97STreehugger Robot non-null node is called "nil". 680*16467b97STreehugger Robot """ 681*16467b97STreehugger Robot 682*16467b97STreehugger Robot # BaseTree is abstract, no need to complain about not implemented abstract 683*16467b97STreehugger Robot # methods 684*16467b97STreehugger Robot # pylint: disable-msg=W0223 685*16467b97STreehugger Robot 686*16467b97STreehugger Robot def __init__(self, node=None): 687*16467b97STreehugger Robot """ 688*16467b97STreehugger Robot Create a new node from an existing node does nothing for BaseTree 689*16467b97STreehugger Robot as there are no fields other than the children list, which cannot 690*16467b97STreehugger Robot be copied as the children are not considered part of this node. 691*16467b97STreehugger Robot """ 692*16467b97STreehugger Robot 693*16467b97STreehugger Robot Tree.__init__(self) 694*16467b97STreehugger Robot self.children = [] 695*16467b97STreehugger Robot self.parent = None 696*16467b97STreehugger Robot self.childIndex = 0 697*16467b97STreehugger Robot 698*16467b97STreehugger Robot 699*16467b97STreehugger Robot def getChild(self, i): 700*16467b97STreehugger Robot try: 701*16467b97STreehugger Robot return self.children[i] 702*16467b97STreehugger Robot except IndexError: 703*16467b97STreehugger Robot return None 704*16467b97STreehugger Robot 705*16467b97STreehugger Robot 706*16467b97STreehugger Robot def getChildren(self): 707*16467b97STreehugger Robot """@brief Get the children internal List 708*16467b97STreehugger Robot 709*16467b97STreehugger Robot Note that if you directly mess with 710*16467b97STreehugger Robot the list, do so at your own risk. 711*16467b97STreehugger Robot """ 712*16467b97STreehugger Robot 713*16467b97STreehugger Robot # FIXME: mark as deprecated 714*16467b97STreehugger Robot return self.children 715*16467b97STreehugger Robot 716*16467b97STreehugger Robot 717*16467b97STreehugger Robot def getFirstChildWithType(self, treeType): 718*16467b97STreehugger Robot for child in self.children: 719*16467b97STreehugger Robot if child.getType() == treeType: 720*16467b97STreehugger Robot return child 721*16467b97STreehugger Robot 722*16467b97STreehugger Robot return None 723*16467b97STreehugger Robot 724*16467b97STreehugger Robot 725*16467b97STreehugger Robot def getChildCount(self): 726*16467b97STreehugger Robot return len(self.children) 727*16467b97STreehugger Robot 728*16467b97STreehugger Robot 729*16467b97STreehugger Robot def addChild(self, childTree): 730*16467b97STreehugger Robot """Add t as child of this node. 731*16467b97STreehugger Robot 732*16467b97STreehugger Robot Warning: if t has no children, but child does 733*16467b97STreehugger Robot and child isNil then this routine moves children to t via 734*16467b97STreehugger Robot t.children = child.children; i.e., without copying the array. 735*16467b97STreehugger Robot """ 736*16467b97STreehugger Robot 737*16467b97STreehugger Robot # this implementation is much simpler and probably less efficient 738*16467b97STreehugger Robot # than the mumbo-jumbo that Ter did for the Java runtime. 739*16467b97STreehugger Robot 740*16467b97STreehugger Robot if childTree is None: 741*16467b97STreehugger Robot return 742*16467b97STreehugger Robot 743*16467b97STreehugger Robot if childTree.isNil(): 744*16467b97STreehugger Robot # t is an empty node possibly with children 745*16467b97STreehugger Robot 746*16467b97STreehugger Robot if self.children is childTree.children: 747*16467b97STreehugger Robot raise ValueError("attempt to add child list to itself") 748*16467b97STreehugger Robot 749*16467b97STreehugger Robot # fix parent pointer and childIndex for new children 750*16467b97STreehugger Robot for idx, child in enumerate(childTree.children): 751*16467b97STreehugger Robot child.parent = self 752*16467b97STreehugger Robot child.childIndex = len(self.children) + idx 753*16467b97STreehugger Robot 754*16467b97STreehugger Robot self.children += childTree.children 755*16467b97STreehugger Robot 756*16467b97STreehugger Robot else: 757*16467b97STreehugger Robot # child is not nil (don't care about children) 758*16467b97STreehugger Robot self.children.append(childTree) 759*16467b97STreehugger Robot childTree.parent = self 760*16467b97STreehugger Robot childTree.childIndex = len(self.children) - 1 761*16467b97STreehugger Robot 762*16467b97STreehugger Robot 763*16467b97STreehugger Robot def addChildren(self, children): 764*16467b97STreehugger Robot """Add all elements of kids list as children of this node""" 765*16467b97STreehugger Robot 766*16467b97STreehugger Robot self.children += children 767*16467b97STreehugger Robot 768*16467b97STreehugger Robot 769*16467b97STreehugger Robot def setChild(self, i, t): 770*16467b97STreehugger Robot if t is None: 771*16467b97STreehugger Robot return 772*16467b97STreehugger Robot 773*16467b97STreehugger Robot if t.isNil(): 774*16467b97STreehugger Robot raise ValueError("Can't set single child to a list") 775*16467b97STreehugger Robot 776*16467b97STreehugger Robot self.children[i] = t 777*16467b97STreehugger Robot t.parent = self 778*16467b97STreehugger Robot t.childIndex = i 779*16467b97STreehugger Robot 780*16467b97STreehugger Robot 781*16467b97STreehugger Robot def deleteChild(self, i): 782*16467b97STreehugger Robot killed = self.children[i] 783*16467b97STreehugger Robot 784*16467b97STreehugger Robot del self.children[i] 785*16467b97STreehugger Robot 786*16467b97STreehugger Robot # walk rest and decrement their child indexes 787*16467b97STreehugger Robot for idx, child in enumerate(self.children[i:]): 788*16467b97STreehugger Robot child.childIndex = i + idx 789*16467b97STreehugger Robot 790*16467b97STreehugger Robot return killed 791*16467b97STreehugger Robot 792*16467b97STreehugger Robot 793*16467b97STreehugger Robot def replaceChildren(self, startChildIndex, stopChildIndex, newTree): 794*16467b97STreehugger Robot """ 795*16467b97STreehugger Robot Delete children from start to stop and replace with t even if t is 796*16467b97STreehugger Robot a list (nil-root tree). num of children can increase or decrease. 797*16467b97STreehugger Robot For huge child lists, inserting children can force walking rest of 798*16467b97STreehugger Robot children to set their childindex; could be slow. 799*16467b97STreehugger Robot """ 800*16467b97STreehugger Robot 801*16467b97STreehugger Robot if (startChildIndex >= len(self.children) 802*16467b97STreehugger Robot or stopChildIndex >= len(self.children) 803*16467b97STreehugger Robot ): 804*16467b97STreehugger Robot raise IndexError("indexes invalid") 805*16467b97STreehugger Robot 806*16467b97STreehugger Robot replacingHowMany = stopChildIndex - startChildIndex + 1 807*16467b97STreehugger Robot 808*16467b97STreehugger Robot # normalize to a list of children to add: newChildren 809*16467b97STreehugger Robot if newTree.isNil(): 810*16467b97STreehugger Robot newChildren = newTree.children 811*16467b97STreehugger Robot 812*16467b97STreehugger Robot else: 813*16467b97STreehugger Robot newChildren = [newTree] 814*16467b97STreehugger Robot 815*16467b97STreehugger Robot replacingWithHowMany = len(newChildren) 816*16467b97STreehugger Robot delta = replacingHowMany - replacingWithHowMany 817*16467b97STreehugger Robot 818*16467b97STreehugger Robot 819*16467b97STreehugger Robot if delta == 0: 820*16467b97STreehugger Robot # if same number of nodes, do direct replace 821*16467b97STreehugger Robot for idx, child in enumerate(newChildren): 822*16467b97STreehugger Robot self.children[idx + startChildIndex] = child 823*16467b97STreehugger Robot child.parent = self 824*16467b97STreehugger Robot child.childIndex = idx + startChildIndex 825*16467b97STreehugger Robot 826*16467b97STreehugger Robot else: 827*16467b97STreehugger Robot # length of children changes... 828*16467b97STreehugger Robot 829*16467b97STreehugger Robot # ...delete replaced segment... 830*16467b97STreehugger Robot del self.children[startChildIndex:stopChildIndex+1] 831*16467b97STreehugger Robot 832*16467b97STreehugger Robot # ...insert new segment... 833*16467b97STreehugger Robot self.children[startChildIndex:startChildIndex] = newChildren 834*16467b97STreehugger Robot 835*16467b97STreehugger Robot # ...and fix indeces 836*16467b97STreehugger Robot self.freshenParentAndChildIndexes(startChildIndex) 837*16467b97STreehugger Robot 838*16467b97STreehugger Robot 839*16467b97STreehugger Robot def isNil(self): 840*16467b97STreehugger Robot return False 841*16467b97STreehugger Robot 842*16467b97STreehugger Robot 843*16467b97STreehugger Robot def freshenParentAndChildIndexes(self, offset=0): 844*16467b97STreehugger Robot for idx, child in enumerate(self.children[offset:]): 845*16467b97STreehugger Robot child.childIndex = idx + offset 846*16467b97STreehugger Robot child.parent = self 847*16467b97STreehugger Robot 848*16467b97STreehugger Robot 849*16467b97STreehugger Robot def sanityCheckParentAndChildIndexes(self, parent=None, i=-1): 850*16467b97STreehugger Robot if parent != self.parent: 851*16467b97STreehugger Robot raise ValueError( 852*16467b97STreehugger Robot "parents don't match; expected %r found %r" 853*16467b97STreehugger Robot % (parent, self.parent) 854*16467b97STreehugger Robot ) 855*16467b97STreehugger Robot 856*16467b97STreehugger Robot if i != self.childIndex: 857*16467b97STreehugger Robot raise ValueError( 858*16467b97STreehugger Robot "child indexes don't match; expected %d found %d" 859*16467b97STreehugger Robot % (i, self.childIndex) 860*16467b97STreehugger Robot ) 861*16467b97STreehugger Robot 862*16467b97STreehugger Robot for idx, child in enumerate(self.children): 863*16467b97STreehugger Robot child.sanityCheckParentAndChildIndexes(self, idx) 864*16467b97STreehugger Robot 865*16467b97STreehugger Robot 866*16467b97STreehugger Robot def getChildIndex(self): 867*16467b97STreehugger Robot """BaseTree doesn't track child indexes.""" 868*16467b97STreehugger Robot 869*16467b97STreehugger Robot return 0 870*16467b97STreehugger Robot 871*16467b97STreehugger Robot 872*16467b97STreehugger Robot def setChildIndex(self, index): 873*16467b97STreehugger Robot """BaseTree doesn't track child indexes.""" 874*16467b97STreehugger Robot 875*16467b97STreehugger Robot pass 876*16467b97STreehugger Robot 877*16467b97STreehugger Robot 878*16467b97STreehugger Robot def getParent(self): 879*16467b97STreehugger Robot """BaseTree doesn't track parent pointers.""" 880*16467b97STreehugger Robot 881*16467b97STreehugger Robot return None 882*16467b97STreehugger Robot 883*16467b97STreehugger Robot def setParent(self, t): 884*16467b97STreehugger Robot """BaseTree doesn't track parent pointers.""" 885*16467b97STreehugger Robot 886*16467b97STreehugger Robot pass 887*16467b97STreehugger Robot 888*16467b97STreehugger Robot 889*16467b97STreehugger Robot def hasAncestor(self, ttype): 890*16467b97STreehugger Robot """Walk upwards looking for ancestor with this token type.""" 891*16467b97STreehugger Robot return self.getAncestor(ttype) is not None 892*16467b97STreehugger Robot 893*16467b97STreehugger Robot def getAncestor(self, ttype): 894*16467b97STreehugger Robot """Walk upwards and get first ancestor with this token type.""" 895*16467b97STreehugger Robot t = self.getParent() 896*16467b97STreehugger Robot while t is not None: 897*16467b97STreehugger Robot if t.getType() == ttype: 898*16467b97STreehugger Robot return t 899*16467b97STreehugger Robot t = t.getParent() 900*16467b97STreehugger Robot 901*16467b97STreehugger Robot return None 902*16467b97STreehugger Robot 903*16467b97STreehugger Robot def getAncestors(self): 904*16467b97STreehugger Robot """Return a list of all ancestors of this node. 905*16467b97STreehugger Robot 906*16467b97STreehugger Robot The first node of list is the root and the last is the parent of 907*16467b97STreehugger Robot this node. 908*16467b97STreehugger Robot """ 909*16467b97STreehugger Robot if selfgetParent() is None: 910*16467b97STreehugger Robot return None 911*16467b97STreehugger Robot 912*16467b97STreehugger Robot ancestors = [] 913*16467b97STreehugger Robot t = self.getParent() 914*16467b97STreehugger Robot while t is not None: 915*16467b97STreehugger Robot ancestors.insert(0, t) # insert at start 916*16467b97STreehugger Robot t = t.getParent() 917*16467b97STreehugger Robot 918*16467b97STreehugger Robot return ancestors 919*16467b97STreehugger Robot 920*16467b97STreehugger Robot 921*16467b97STreehugger Robot def toStringTree(self): 922*16467b97STreehugger Robot """Print out a whole tree not just a node""" 923*16467b97STreehugger Robot 924*16467b97STreehugger Robot if len(self.children) == 0: 925*16467b97STreehugger Robot return self.toString() 926*16467b97STreehugger Robot 927*16467b97STreehugger Robot buf = [] 928*16467b97STreehugger Robot if not self.isNil(): 929*16467b97STreehugger Robot buf.append('(') 930*16467b97STreehugger Robot buf.append(self.toString()) 931*16467b97STreehugger Robot buf.append(' ') 932*16467b97STreehugger Robot 933*16467b97STreehugger Robot for i, child in enumerate(self.children): 934*16467b97STreehugger Robot if i > 0: 935*16467b97STreehugger Robot buf.append(' ') 936*16467b97STreehugger Robot buf.append(child.toStringTree()) 937*16467b97STreehugger Robot 938*16467b97STreehugger Robot if not self.isNil(): 939*16467b97STreehugger Robot buf.append(')') 940*16467b97STreehugger Robot 941*16467b97STreehugger Robot return ''.join(buf) 942*16467b97STreehugger Robot 943*16467b97STreehugger Robot 944*16467b97STreehugger Robot def getLine(self): 945*16467b97STreehugger Robot return 0 946*16467b97STreehugger Robot 947*16467b97STreehugger Robot 948*16467b97STreehugger Robot def getCharPositionInLine(self): 949*16467b97STreehugger Robot return 0 950*16467b97STreehugger Robot 951*16467b97STreehugger Robot 952*16467b97STreehugger Robot def toString(self): 953*16467b97STreehugger Robot """Override to say how a node (not a tree) should look as text""" 954*16467b97STreehugger Robot 955*16467b97STreehugger Robot raise NotImplementedError 956*16467b97STreehugger Robot 957*16467b97STreehugger Robot 958*16467b97STreehugger Robot 959*16467b97STreehugger Robotclass BaseTreeAdaptor(TreeAdaptor): 960*16467b97STreehugger Robot """ 961*16467b97STreehugger Robot @brief A TreeAdaptor that works with any Tree implementation. 962*16467b97STreehugger Robot """ 963*16467b97STreehugger Robot 964*16467b97STreehugger Robot # BaseTreeAdaptor is abstract, no need to complain about not implemented 965*16467b97STreehugger Robot # abstract methods 966*16467b97STreehugger Robot # pylint: disable-msg=W0223 967*16467b97STreehugger Robot 968*16467b97STreehugger Robot def nil(self): 969*16467b97STreehugger Robot return self.createWithPayload(None) 970*16467b97STreehugger Robot 971*16467b97STreehugger Robot 972*16467b97STreehugger Robot def errorNode(self, input, start, stop, exc): 973*16467b97STreehugger Robot """ 974*16467b97STreehugger Robot create tree node that holds the start and stop tokens associated 975*16467b97STreehugger Robot with an error. 976*16467b97STreehugger Robot 977*16467b97STreehugger Robot If you specify your own kind of tree nodes, you will likely have to 978*16467b97STreehugger Robot override this method. CommonTree returns Token.INVALID_TOKEN_TYPE 979*16467b97STreehugger Robot if no token payload but you might have to set token type for diff 980*16467b97STreehugger Robot node type. 981*16467b97STreehugger Robot 982*16467b97STreehugger Robot You don't have to subclass CommonErrorNode; you will likely need to 983*16467b97STreehugger Robot subclass your own tree node class to avoid class cast exception. 984*16467b97STreehugger Robot """ 985*16467b97STreehugger Robot 986*16467b97STreehugger Robot return CommonErrorNode(input, start, stop, exc) 987*16467b97STreehugger Robot 988*16467b97STreehugger Robot 989*16467b97STreehugger Robot def isNil(self, tree): 990*16467b97STreehugger Robot return tree.isNil() 991*16467b97STreehugger Robot 992*16467b97STreehugger Robot 993*16467b97STreehugger Robot def dupTree(self, t, parent=None): 994*16467b97STreehugger Robot """ 995*16467b97STreehugger Robot This is generic in the sense that it will work with any kind of 996*16467b97STreehugger Robot tree (not just Tree interface). It invokes the adaptor routines 997*16467b97STreehugger Robot not the tree node routines to do the construction. 998*16467b97STreehugger Robot """ 999*16467b97STreehugger Robot 1000*16467b97STreehugger Robot if t is None: 1001*16467b97STreehugger Robot return None 1002*16467b97STreehugger Robot 1003*16467b97STreehugger Robot newTree = self.dupNode(t) 1004*16467b97STreehugger Robot 1005*16467b97STreehugger Robot # ensure new subtree root has parent/child index set 1006*16467b97STreehugger Robot 1007*16467b97STreehugger Robot # same index in new tree 1008*16467b97STreehugger Robot self.setChildIndex(newTree, self.getChildIndex(t)) 1009*16467b97STreehugger Robot 1010*16467b97STreehugger Robot self.setParent(newTree, parent) 1011*16467b97STreehugger Robot 1012*16467b97STreehugger Robot for i in range(self.getChildCount(t)): 1013*16467b97STreehugger Robot child = self.getChild(t, i) 1014*16467b97STreehugger Robot newSubTree = self.dupTree(child, t) 1015*16467b97STreehugger Robot self.addChild(newTree, newSubTree) 1016*16467b97STreehugger Robot 1017*16467b97STreehugger Robot return newTree 1018*16467b97STreehugger Robot 1019*16467b97STreehugger Robot 1020*16467b97STreehugger Robot def addChild(self, tree, child): 1021*16467b97STreehugger Robot """ 1022*16467b97STreehugger Robot Add a child to the tree t. If child is a flat tree (a list), make all 1023*16467b97STreehugger Robot in list children of t. Warning: if t has no children, but child does 1024*16467b97STreehugger Robot and child isNil then you can decide it is ok to move children to t via 1025*16467b97STreehugger Robot t.children = child.children; i.e., without copying the array. Just 1026*16467b97STreehugger Robot make sure that this is consistent with have the user will build 1027*16467b97STreehugger Robot ASTs. 1028*16467b97STreehugger Robot """ 1029*16467b97STreehugger Robot 1030*16467b97STreehugger Robot #if isinstance(child, Token): 1031*16467b97STreehugger Robot # child = self.createWithPayload(child) 1032*16467b97STreehugger Robot 1033*16467b97STreehugger Robot if tree is not None and child is not None: 1034*16467b97STreehugger Robot tree.addChild(child) 1035*16467b97STreehugger Robot 1036*16467b97STreehugger Robot 1037*16467b97STreehugger Robot def becomeRoot(self, newRoot, oldRoot): 1038*16467b97STreehugger Robot """ 1039*16467b97STreehugger Robot If oldRoot is a nil root, just copy or move the children to newRoot. 1040*16467b97STreehugger Robot If not a nil root, make oldRoot a child of newRoot. 1041*16467b97STreehugger Robot 1042*16467b97STreehugger Robot old=^(nil a b c), new=r yields ^(r a b c) 1043*16467b97STreehugger Robot old=^(a b c), new=r yields ^(r ^(a b c)) 1044*16467b97STreehugger Robot 1045*16467b97STreehugger Robot If newRoot is a nil-rooted single child tree, use the single 1046*16467b97STreehugger Robot child as the new root node. 1047*16467b97STreehugger Robot 1048*16467b97STreehugger Robot old=^(nil a b c), new=^(nil r) yields ^(r a b c) 1049*16467b97STreehugger Robot old=^(a b c), new=^(nil r) yields ^(r ^(a b c)) 1050*16467b97STreehugger Robot 1051*16467b97STreehugger Robot If oldRoot was null, it's ok, just return newRoot (even if isNil). 1052*16467b97STreehugger Robot 1053*16467b97STreehugger Robot old=null, new=r yields r 1054*16467b97STreehugger Robot old=null, new=^(nil r) yields ^(nil r) 1055*16467b97STreehugger Robot 1056*16467b97STreehugger Robot Return newRoot. Throw an exception if newRoot is not a 1057*16467b97STreehugger Robot simple node or nil root with a single child node--it must be a root 1058*16467b97STreehugger Robot node. If newRoot is ^(nil x) return x as newRoot. 1059*16467b97STreehugger Robot 1060*16467b97STreehugger Robot Be advised that it's ok for newRoot to point at oldRoot's 1061*16467b97STreehugger Robot children; i.e., you don't have to copy the list. We are 1062*16467b97STreehugger Robot constructing these nodes so we should have this control for 1063*16467b97STreehugger Robot efficiency. 1064*16467b97STreehugger Robot """ 1065*16467b97STreehugger Robot 1066*16467b97STreehugger Robot if isinstance(newRoot, Token): 1067*16467b97STreehugger Robot newRoot = self.create(newRoot) 1068*16467b97STreehugger Robot 1069*16467b97STreehugger Robot if oldRoot is None: 1070*16467b97STreehugger Robot return newRoot 1071*16467b97STreehugger Robot 1072*16467b97STreehugger Robot if not isinstance(newRoot, CommonTree): 1073*16467b97STreehugger Robot newRoot = self.createWithPayload(newRoot) 1074*16467b97STreehugger Robot 1075*16467b97STreehugger Robot # handle ^(nil real-node) 1076*16467b97STreehugger Robot if newRoot.isNil(): 1077*16467b97STreehugger Robot nc = newRoot.getChildCount() 1078*16467b97STreehugger Robot if nc == 1: 1079*16467b97STreehugger Robot newRoot = newRoot.getChild(0) 1080*16467b97STreehugger Robot 1081*16467b97STreehugger Robot elif nc > 1: 1082*16467b97STreehugger Robot # TODO: make tree run time exceptions hierarchy 1083*16467b97STreehugger Robot raise RuntimeError("more than one node as root") 1084*16467b97STreehugger Robot 1085*16467b97STreehugger Robot # add oldRoot to newRoot; addChild takes care of case where oldRoot 1086*16467b97STreehugger Robot # is a flat list (i.e., nil-rooted tree). All children of oldRoot 1087*16467b97STreehugger Robot # are added to newRoot. 1088*16467b97STreehugger Robot newRoot.addChild(oldRoot) 1089*16467b97STreehugger Robot return newRoot 1090*16467b97STreehugger Robot 1091*16467b97STreehugger Robot 1092*16467b97STreehugger Robot def rulePostProcessing(self, root): 1093*16467b97STreehugger Robot """Transform ^(nil x) to x and nil to null""" 1094*16467b97STreehugger Robot 1095*16467b97STreehugger Robot if root is not None and root.isNil(): 1096*16467b97STreehugger Robot if root.getChildCount() == 0: 1097*16467b97STreehugger Robot root = None 1098*16467b97STreehugger Robot 1099*16467b97STreehugger Robot elif root.getChildCount() == 1: 1100*16467b97STreehugger Robot root = root.getChild(0) 1101*16467b97STreehugger Robot # whoever invokes rule will set parent and child index 1102*16467b97STreehugger Robot root.setParent(None) 1103*16467b97STreehugger Robot root.setChildIndex(-1) 1104*16467b97STreehugger Robot 1105*16467b97STreehugger Robot return root 1106*16467b97STreehugger Robot 1107*16467b97STreehugger Robot 1108*16467b97STreehugger Robot def createFromToken(self, tokenType, fromToken, text=None): 1109*16467b97STreehugger Robot if fromToken is None: 1110*16467b97STreehugger Robot return self.createFromType(tokenType, text) 1111*16467b97STreehugger Robot 1112*16467b97STreehugger Robot assert isinstance(tokenType, (int, long)), type(tokenType).__name__ 1113*16467b97STreehugger Robot assert isinstance(fromToken, Token), type(fromToken).__name__ 1114*16467b97STreehugger Robot assert text is None or isinstance(text, basestring), type(text).__name__ 1115*16467b97STreehugger Robot 1116*16467b97STreehugger Robot fromToken = self.createToken(fromToken) 1117*16467b97STreehugger Robot fromToken.type = tokenType 1118*16467b97STreehugger Robot if text is not None: 1119*16467b97STreehugger Robot fromToken.text = text 1120*16467b97STreehugger Robot t = self.createWithPayload(fromToken) 1121*16467b97STreehugger Robot return t 1122*16467b97STreehugger Robot 1123*16467b97STreehugger Robot 1124*16467b97STreehugger Robot def createFromType(self, tokenType, text): 1125*16467b97STreehugger Robot assert isinstance(tokenType, (int, long)), type(tokenType).__name__ 1126*16467b97STreehugger Robot assert isinstance(text, basestring) or text is None, type(text).__name__ 1127*16467b97STreehugger Robot 1128*16467b97STreehugger Robot fromToken = self.createToken(tokenType=tokenType, text=text) 1129*16467b97STreehugger Robot t = self.createWithPayload(fromToken) 1130*16467b97STreehugger Robot return t 1131*16467b97STreehugger Robot 1132*16467b97STreehugger Robot 1133*16467b97STreehugger Robot def getType(self, t): 1134*16467b97STreehugger Robot return t.getType() 1135*16467b97STreehugger Robot 1136*16467b97STreehugger Robot 1137*16467b97STreehugger Robot def setType(self, t, type): 1138*16467b97STreehugger Robot raise RuntimeError("don't know enough about Tree node") 1139*16467b97STreehugger Robot 1140*16467b97STreehugger Robot 1141*16467b97STreehugger Robot def getText(self, t): 1142*16467b97STreehugger Robot return t.getText() 1143*16467b97STreehugger Robot 1144*16467b97STreehugger Robot 1145*16467b97STreehugger Robot def setText(self, t, text): 1146*16467b97STreehugger Robot raise RuntimeError("don't know enough about Tree node") 1147*16467b97STreehugger Robot 1148*16467b97STreehugger Robot 1149*16467b97STreehugger Robot def getChild(self, t, i): 1150*16467b97STreehugger Robot return t.getChild(i) 1151*16467b97STreehugger Robot 1152*16467b97STreehugger Robot 1153*16467b97STreehugger Robot def setChild(self, t, i, child): 1154*16467b97STreehugger Robot t.setChild(i, child) 1155*16467b97STreehugger Robot 1156*16467b97STreehugger Robot 1157*16467b97STreehugger Robot def deleteChild(self, t, i): 1158*16467b97STreehugger Robot return t.deleteChild(i) 1159*16467b97STreehugger Robot 1160*16467b97STreehugger Robot 1161*16467b97STreehugger Robot def getChildCount(self, t): 1162*16467b97STreehugger Robot return t.getChildCount() 1163*16467b97STreehugger Robot 1164*16467b97STreehugger Robot 1165*16467b97STreehugger Robot def getUniqueID(self, node): 1166*16467b97STreehugger Robot return hash(node) 1167*16467b97STreehugger Robot 1168*16467b97STreehugger Robot 1169*16467b97STreehugger Robot def createToken(self, fromToken=None, tokenType=None, text=None): 1170*16467b97STreehugger Robot """ 1171*16467b97STreehugger Robot Tell me how to create a token for use with imaginary token nodes. 1172*16467b97STreehugger Robot For example, there is probably no input symbol associated with imaginary 1173*16467b97STreehugger Robot token DECL, but you need to create it as a payload or whatever for 1174*16467b97STreehugger Robot the DECL node as in ^(DECL type ID). 1175*16467b97STreehugger Robot 1176*16467b97STreehugger Robot If you care what the token payload objects' type is, you should 1177*16467b97STreehugger Robot override this method and any other createToken variant. 1178*16467b97STreehugger Robot """ 1179*16467b97STreehugger Robot 1180*16467b97STreehugger Robot raise NotImplementedError 1181*16467b97STreehugger Robot 1182*16467b97STreehugger Robot 1183*16467b97STreehugger Robot############################################################################ 1184*16467b97STreehugger Robot# 1185*16467b97STreehugger Robot# common tree implementation 1186*16467b97STreehugger Robot# 1187*16467b97STreehugger Robot# Tree 1188*16467b97STreehugger Robot# \- BaseTree 1189*16467b97STreehugger Robot# \- CommonTree 1190*16467b97STreehugger Robot# \- CommonErrorNode 1191*16467b97STreehugger Robot# 1192*16467b97STreehugger Robot# TreeAdaptor 1193*16467b97STreehugger Robot# \- BaseTreeAdaptor 1194*16467b97STreehugger Robot# \- CommonTreeAdaptor 1195*16467b97STreehugger Robot# 1196*16467b97STreehugger Robot############################################################################ 1197*16467b97STreehugger Robot 1198*16467b97STreehugger Robot 1199*16467b97STreehugger Robotclass CommonTree(BaseTree): 1200*16467b97STreehugger Robot """@brief A tree node that is wrapper for a Token object. 1201*16467b97STreehugger Robot 1202*16467b97STreehugger Robot After 3.0 release 1203*16467b97STreehugger Robot while building tree rewrite stuff, it became clear that computing 1204*16467b97STreehugger Robot parent and child index is very difficult and cumbersome. Better to 1205*16467b97STreehugger Robot spend the space in every tree node. If you don't want these extra 1206*16467b97STreehugger Robot fields, it's easy to cut them out in your own BaseTree subclass. 1207*16467b97STreehugger Robot 1208*16467b97STreehugger Robot """ 1209*16467b97STreehugger Robot 1210*16467b97STreehugger Robot def __init__(self, payload): 1211*16467b97STreehugger Robot BaseTree.__init__(self) 1212*16467b97STreehugger Robot 1213*16467b97STreehugger Robot # What token indexes bracket all tokens associated with this node 1214*16467b97STreehugger Robot # and below? 1215*16467b97STreehugger Robot self.startIndex = -1 1216*16467b97STreehugger Robot self.stopIndex = -1 1217*16467b97STreehugger Robot 1218*16467b97STreehugger Robot # Who is the parent node of this node; if null, implies node is root 1219*16467b97STreehugger Robot self.parent = None 1220*16467b97STreehugger Robot 1221*16467b97STreehugger Robot # What index is this node in the child list? Range: 0..n-1 1222*16467b97STreehugger Robot self.childIndex = -1 1223*16467b97STreehugger Robot 1224*16467b97STreehugger Robot # A single token is the payload 1225*16467b97STreehugger Robot if payload is None: 1226*16467b97STreehugger Robot self.token = None 1227*16467b97STreehugger Robot 1228*16467b97STreehugger Robot elif isinstance(payload, CommonTree): 1229*16467b97STreehugger Robot self.token = payload.token 1230*16467b97STreehugger Robot self.startIndex = payload.startIndex 1231*16467b97STreehugger Robot self.stopIndex = payload.stopIndex 1232*16467b97STreehugger Robot 1233*16467b97STreehugger Robot elif payload is None or isinstance(payload, Token): 1234*16467b97STreehugger Robot self.token = payload 1235*16467b97STreehugger Robot 1236*16467b97STreehugger Robot else: 1237*16467b97STreehugger Robot raise TypeError(type(payload).__name__) 1238*16467b97STreehugger Robot 1239*16467b97STreehugger Robot 1240*16467b97STreehugger Robot 1241*16467b97STreehugger Robot def getToken(self): 1242*16467b97STreehugger Robot return self.token 1243*16467b97STreehugger Robot 1244*16467b97STreehugger Robot 1245*16467b97STreehugger Robot def dupNode(self): 1246*16467b97STreehugger Robot return CommonTree(self) 1247*16467b97STreehugger Robot 1248*16467b97STreehugger Robot 1249*16467b97STreehugger Robot def isNil(self): 1250*16467b97STreehugger Robot return self.token is None 1251*16467b97STreehugger Robot 1252*16467b97STreehugger Robot 1253*16467b97STreehugger Robot def getType(self): 1254*16467b97STreehugger Robot if self.token is None: 1255*16467b97STreehugger Robot return INVALID_TOKEN_TYPE 1256*16467b97STreehugger Robot 1257*16467b97STreehugger Robot return self.token.getType() 1258*16467b97STreehugger Robot 1259*16467b97STreehugger Robot type = property(getType) 1260*16467b97STreehugger Robot 1261*16467b97STreehugger Robot 1262*16467b97STreehugger Robot def getText(self): 1263*16467b97STreehugger Robot if self.token is None: 1264*16467b97STreehugger Robot return None 1265*16467b97STreehugger Robot 1266*16467b97STreehugger Robot return self.token.text 1267*16467b97STreehugger Robot 1268*16467b97STreehugger Robot text = property(getText) 1269*16467b97STreehugger Robot 1270*16467b97STreehugger Robot 1271*16467b97STreehugger Robot def getLine(self): 1272*16467b97STreehugger Robot if self.token is None or self.token.getLine() == 0: 1273*16467b97STreehugger Robot if self.getChildCount(): 1274*16467b97STreehugger Robot return self.getChild(0).getLine() 1275*16467b97STreehugger Robot else: 1276*16467b97STreehugger Robot return 0 1277*16467b97STreehugger Robot 1278*16467b97STreehugger Robot return self.token.getLine() 1279*16467b97STreehugger Robot 1280*16467b97STreehugger Robot line = property(getLine) 1281*16467b97STreehugger Robot 1282*16467b97STreehugger Robot 1283*16467b97STreehugger Robot def getCharPositionInLine(self): 1284*16467b97STreehugger Robot if self.token is None or self.token.getCharPositionInLine() == -1: 1285*16467b97STreehugger Robot if self.getChildCount(): 1286*16467b97STreehugger Robot return self.getChild(0).getCharPositionInLine() 1287*16467b97STreehugger Robot else: 1288*16467b97STreehugger Robot return 0 1289*16467b97STreehugger Robot 1290*16467b97STreehugger Robot else: 1291*16467b97STreehugger Robot return self.token.getCharPositionInLine() 1292*16467b97STreehugger Robot 1293*16467b97STreehugger Robot charPositionInLine = property(getCharPositionInLine) 1294*16467b97STreehugger Robot 1295*16467b97STreehugger Robot 1296*16467b97STreehugger Robot def getTokenStartIndex(self): 1297*16467b97STreehugger Robot if self.startIndex == -1 and self.token is not None: 1298*16467b97STreehugger Robot return self.token.getTokenIndex() 1299*16467b97STreehugger Robot 1300*16467b97STreehugger Robot return self.startIndex 1301*16467b97STreehugger Robot 1302*16467b97STreehugger Robot def setTokenStartIndex(self, index): 1303*16467b97STreehugger Robot self.startIndex = index 1304*16467b97STreehugger Robot 1305*16467b97STreehugger Robot tokenStartIndex = property(getTokenStartIndex, setTokenStartIndex) 1306*16467b97STreehugger Robot 1307*16467b97STreehugger Robot 1308*16467b97STreehugger Robot def getTokenStopIndex(self): 1309*16467b97STreehugger Robot if self.stopIndex == -1 and self.token is not None: 1310*16467b97STreehugger Robot return self.token.getTokenIndex() 1311*16467b97STreehugger Robot 1312*16467b97STreehugger Robot return self.stopIndex 1313*16467b97STreehugger Robot 1314*16467b97STreehugger Robot def setTokenStopIndex(self, index): 1315*16467b97STreehugger Robot self.stopIndex = index 1316*16467b97STreehugger Robot 1317*16467b97STreehugger Robot tokenStopIndex = property(getTokenStopIndex, setTokenStopIndex) 1318*16467b97STreehugger Robot 1319*16467b97STreehugger Robot 1320*16467b97STreehugger Robot def setUnknownTokenBoundaries(self): 1321*16467b97STreehugger Robot """For every node in this subtree, make sure it's start/stop token's 1322*16467b97STreehugger Robot are set. Walk depth first, visit bottom up. Only updates nodes 1323*16467b97STreehugger Robot with at least one token index < 0. 1324*16467b97STreehugger Robot """ 1325*16467b97STreehugger Robot 1326*16467b97STreehugger Robot if self.children is None: 1327*16467b97STreehugger Robot if self.startIndex < 0 or self.stopIndex < 0: 1328*16467b97STreehugger Robot self.startIndex = self.stopIndex = self.token.getTokenIndex() 1329*16467b97STreehugger Robot 1330*16467b97STreehugger Robot return 1331*16467b97STreehugger Robot 1332*16467b97STreehugger Robot for child in self.children: 1333*16467b97STreehugger Robot child.setUnknownTokenBoundaries() 1334*16467b97STreehugger Robot 1335*16467b97STreehugger Robot if self.startIndex >= 0 and self.stopIndex >= 0: 1336*16467b97STreehugger Robot # already set 1337*16467b97STreehugger Robot return 1338*16467b97STreehugger Robot 1339*16467b97STreehugger Robot if self.children: 1340*16467b97STreehugger Robot firstChild = self.children[0] 1341*16467b97STreehugger Robot lastChild = self.children[-1] 1342*16467b97STreehugger Robot self.startIndex = firstChild.getTokenStartIndex() 1343*16467b97STreehugger Robot self.stopIndex = lastChild.getTokenStopIndex() 1344*16467b97STreehugger Robot 1345*16467b97STreehugger Robot 1346*16467b97STreehugger Robot def getChildIndex(self): 1347*16467b97STreehugger Robot #FIXME: mark as deprecated 1348*16467b97STreehugger Robot return self.childIndex 1349*16467b97STreehugger Robot 1350*16467b97STreehugger Robot 1351*16467b97STreehugger Robot def setChildIndex(self, idx): 1352*16467b97STreehugger Robot #FIXME: mark as deprecated 1353*16467b97STreehugger Robot self.childIndex = idx 1354*16467b97STreehugger Robot 1355*16467b97STreehugger Robot 1356*16467b97STreehugger Robot def getParent(self): 1357*16467b97STreehugger Robot #FIXME: mark as deprecated 1358*16467b97STreehugger Robot return self.parent 1359*16467b97STreehugger Robot 1360*16467b97STreehugger Robot 1361*16467b97STreehugger Robot def setParent(self, t): 1362*16467b97STreehugger Robot #FIXME: mark as deprecated 1363*16467b97STreehugger Robot self.parent = t 1364*16467b97STreehugger Robot 1365*16467b97STreehugger Robot 1366*16467b97STreehugger Robot def toString(self): 1367*16467b97STreehugger Robot if self.isNil(): 1368*16467b97STreehugger Robot return "nil" 1369*16467b97STreehugger Robot 1370*16467b97STreehugger Robot if self.getType() == INVALID_TOKEN_TYPE: 1371*16467b97STreehugger Robot return "<errornode>" 1372*16467b97STreehugger Robot 1373*16467b97STreehugger Robot return self.token.text 1374*16467b97STreehugger Robot 1375*16467b97STreehugger Robot __str__ = toString 1376*16467b97STreehugger Robot 1377*16467b97STreehugger Robot 1378*16467b97STreehugger Robot 1379*16467b97STreehugger Robot def toStringTree(self): 1380*16467b97STreehugger Robot if not self.children: 1381*16467b97STreehugger Robot return self.toString() 1382*16467b97STreehugger Robot 1383*16467b97STreehugger Robot ret = '' 1384*16467b97STreehugger Robot if not self.isNil(): 1385*16467b97STreehugger Robot ret += '(%s ' % (self.toString()) 1386*16467b97STreehugger Robot 1387*16467b97STreehugger Robot ret += ' '.join([child.toStringTree() for child in self.children]) 1388*16467b97STreehugger Robot 1389*16467b97STreehugger Robot if not self.isNil(): 1390*16467b97STreehugger Robot ret += ')' 1391*16467b97STreehugger Robot 1392*16467b97STreehugger Robot return ret 1393*16467b97STreehugger Robot 1394*16467b97STreehugger Robot 1395*16467b97STreehugger RobotINVALID_NODE = CommonTree(INVALID_TOKEN) 1396*16467b97STreehugger Robot 1397*16467b97STreehugger Robot 1398*16467b97STreehugger Robotclass CommonErrorNode(CommonTree): 1399*16467b97STreehugger Robot """A node representing erroneous token range in token stream""" 1400*16467b97STreehugger Robot 1401*16467b97STreehugger Robot def __init__(self, input, start, stop, exc): 1402*16467b97STreehugger Robot CommonTree.__init__(self, None) 1403*16467b97STreehugger Robot 1404*16467b97STreehugger Robot if (stop is None or 1405*16467b97STreehugger Robot (stop.getTokenIndex() < start.getTokenIndex() and 1406*16467b97STreehugger Robot stop.getType() != EOF 1407*16467b97STreehugger Robot ) 1408*16467b97STreehugger Robot ): 1409*16467b97STreehugger Robot # sometimes resync does not consume a token (when LT(1) is 1410*16467b97STreehugger Robot # in follow set. So, stop will be 1 to left to start. adjust. 1411*16467b97STreehugger Robot # Also handle case where start is the first token and no token 1412*16467b97STreehugger Robot # is consumed during recovery; LT(-1) will return null. 1413*16467b97STreehugger Robot stop = start 1414*16467b97STreehugger Robot 1415*16467b97STreehugger Robot self.input = input 1416*16467b97STreehugger Robot self.start = start 1417*16467b97STreehugger Robot self.stop = stop 1418*16467b97STreehugger Robot self.trappedException = exc 1419*16467b97STreehugger Robot 1420*16467b97STreehugger Robot 1421*16467b97STreehugger Robot def isNil(self): 1422*16467b97STreehugger Robot return False 1423*16467b97STreehugger Robot 1424*16467b97STreehugger Robot 1425*16467b97STreehugger Robot def getType(self): 1426*16467b97STreehugger Robot return INVALID_TOKEN_TYPE 1427*16467b97STreehugger Robot 1428*16467b97STreehugger Robot 1429*16467b97STreehugger Robot def getText(self): 1430*16467b97STreehugger Robot if isinstance(self.start, Token): 1431*16467b97STreehugger Robot i = self.start.getTokenIndex() 1432*16467b97STreehugger Robot j = self.stop.getTokenIndex() 1433*16467b97STreehugger Robot if self.stop.getType() == EOF: 1434*16467b97STreehugger Robot j = self.input.size() 1435*16467b97STreehugger Robot 1436*16467b97STreehugger Robot badText = self.input.toString(i, j) 1437*16467b97STreehugger Robot 1438*16467b97STreehugger Robot elif isinstance(self.start, Tree): 1439*16467b97STreehugger Robot badText = self.input.toString(self.start, self.stop) 1440*16467b97STreehugger Robot 1441*16467b97STreehugger Robot else: 1442*16467b97STreehugger Robot # people should subclass if they alter the tree type so this 1443*16467b97STreehugger Robot # next one is for sure correct. 1444*16467b97STreehugger Robot badText = "<unknown>" 1445*16467b97STreehugger Robot 1446*16467b97STreehugger Robot return badText 1447*16467b97STreehugger Robot 1448*16467b97STreehugger Robot 1449*16467b97STreehugger Robot def toString(self): 1450*16467b97STreehugger Robot if isinstance(self.trappedException, MissingTokenException): 1451*16467b97STreehugger Robot return ("<missing type: " 1452*16467b97STreehugger Robot + str(self.trappedException.getMissingType()) 1453*16467b97STreehugger Robot + ">") 1454*16467b97STreehugger Robot 1455*16467b97STreehugger Robot elif isinstance(self.trappedException, UnwantedTokenException): 1456*16467b97STreehugger Robot return ("<extraneous: " 1457*16467b97STreehugger Robot + str(self.trappedException.getUnexpectedToken()) 1458*16467b97STreehugger Robot + ", resync=" + self.getText() + ">") 1459*16467b97STreehugger Robot 1460*16467b97STreehugger Robot elif isinstance(self.trappedException, MismatchedTokenException): 1461*16467b97STreehugger Robot return ("<mismatched token: " 1462*16467b97STreehugger Robot + str(self.trappedException.token) 1463*16467b97STreehugger Robot + ", resync=" + self.getText() + ">") 1464*16467b97STreehugger Robot 1465*16467b97STreehugger Robot elif isinstance(self.trappedException, NoViableAltException): 1466*16467b97STreehugger Robot return ("<unexpected: " 1467*16467b97STreehugger Robot + str(self.trappedException.token) 1468*16467b97STreehugger Robot + ", resync=" + self.getText() + ">") 1469*16467b97STreehugger Robot 1470*16467b97STreehugger Robot return "<error: "+self.getText()+">" 1471*16467b97STreehugger Robot 1472*16467b97STreehugger Robot 1473*16467b97STreehugger Robotclass CommonTreeAdaptor(BaseTreeAdaptor): 1474*16467b97STreehugger Robot """ 1475*16467b97STreehugger Robot @brief A TreeAdaptor that works with any Tree implementation. 1476*16467b97STreehugger Robot 1477*16467b97STreehugger Robot It provides 1478*16467b97STreehugger Robot really just factory methods; all the work is done by BaseTreeAdaptor. 1479*16467b97STreehugger Robot If you would like to have different tokens created than ClassicToken 1480*16467b97STreehugger Robot objects, you need to override this and then set the parser tree adaptor to 1481*16467b97STreehugger Robot use your subclass. 1482*16467b97STreehugger Robot 1483*16467b97STreehugger Robot To get your parser to build nodes of a different type, override 1484*16467b97STreehugger Robot create(Token), errorNode(), and to be safe, YourTreeClass.dupNode(). 1485*16467b97STreehugger Robot dupNode is called to duplicate nodes during rewrite operations. 1486*16467b97STreehugger Robot """ 1487*16467b97STreehugger Robot 1488*16467b97STreehugger Robot def dupNode(self, treeNode): 1489*16467b97STreehugger Robot """ 1490*16467b97STreehugger Robot Duplicate a node. This is part of the factory; 1491*16467b97STreehugger Robot override if you want another kind of node to be built. 1492*16467b97STreehugger Robot 1493*16467b97STreehugger Robot I could use reflection to prevent having to override this 1494*16467b97STreehugger Robot but reflection is slow. 1495*16467b97STreehugger Robot """ 1496*16467b97STreehugger Robot 1497*16467b97STreehugger Robot if treeNode is None: 1498*16467b97STreehugger Robot return None 1499*16467b97STreehugger Robot 1500*16467b97STreehugger Robot return treeNode.dupNode() 1501*16467b97STreehugger Robot 1502*16467b97STreehugger Robot 1503*16467b97STreehugger Robot def createWithPayload(self, payload): 1504*16467b97STreehugger Robot return CommonTree(payload) 1505*16467b97STreehugger Robot 1506*16467b97STreehugger Robot 1507*16467b97STreehugger Robot def createToken(self, fromToken=None, tokenType=None, text=None): 1508*16467b97STreehugger Robot """ 1509*16467b97STreehugger Robot Tell me how to create a token for use with imaginary token nodes. 1510*16467b97STreehugger Robot For example, there is probably no input symbol associated with imaginary 1511*16467b97STreehugger Robot token DECL, but you need to create it as a payload or whatever for 1512*16467b97STreehugger Robot the DECL node as in ^(DECL type ID). 1513*16467b97STreehugger Robot 1514*16467b97STreehugger Robot If you care what the token payload objects' type is, you should 1515*16467b97STreehugger Robot override this method and any other createToken variant. 1516*16467b97STreehugger Robot """ 1517*16467b97STreehugger Robot 1518*16467b97STreehugger Robot if fromToken is not None: 1519*16467b97STreehugger Robot return CommonToken(oldToken=fromToken) 1520*16467b97STreehugger Robot 1521*16467b97STreehugger Robot return CommonToken(type=tokenType, text=text) 1522*16467b97STreehugger Robot 1523*16467b97STreehugger Robot 1524*16467b97STreehugger Robot def setTokenBoundaries(self, t, startToken, stopToken): 1525*16467b97STreehugger Robot """ 1526*16467b97STreehugger Robot Track start/stop token for subtree root created for a rule. 1527*16467b97STreehugger Robot Only works with Tree nodes. For rules that match nothing, 1528*16467b97STreehugger Robot seems like this will yield start=i and stop=i-1 in a nil node. 1529*16467b97STreehugger Robot Might be useful info so I'll not force to be i..i. 1530*16467b97STreehugger Robot """ 1531*16467b97STreehugger Robot 1532*16467b97STreehugger Robot if t is None: 1533*16467b97STreehugger Robot return 1534*16467b97STreehugger Robot 1535*16467b97STreehugger Robot start = 0 1536*16467b97STreehugger Robot stop = 0 1537*16467b97STreehugger Robot 1538*16467b97STreehugger Robot if startToken is not None: 1539*16467b97STreehugger Robot start = startToken.index 1540*16467b97STreehugger Robot 1541*16467b97STreehugger Robot if stopToken is not None: 1542*16467b97STreehugger Robot stop = stopToken.index 1543*16467b97STreehugger Robot 1544*16467b97STreehugger Robot t.setTokenStartIndex(start) 1545*16467b97STreehugger Robot t.setTokenStopIndex(stop) 1546*16467b97STreehugger Robot 1547*16467b97STreehugger Robot 1548*16467b97STreehugger Robot def getTokenStartIndex(self, t): 1549*16467b97STreehugger Robot if t is None: 1550*16467b97STreehugger Robot return -1 1551*16467b97STreehugger Robot return t.getTokenStartIndex() 1552*16467b97STreehugger Robot 1553*16467b97STreehugger Robot 1554*16467b97STreehugger Robot def getTokenStopIndex(self, t): 1555*16467b97STreehugger Robot if t is None: 1556*16467b97STreehugger Robot return -1 1557*16467b97STreehugger Robot return t.getTokenStopIndex() 1558*16467b97STreehugger Robot 1559*16467b97STreehugger Robot 1560*16467b97STreehugger Robot def getText(self, t): 1561*16467b97STreehugger Robot if t is None: 1562*16467b97STreehugger Robot return None 1563*16467b97STreehugger Robot return t.getText() 1564*16467b97STreehugger Robot 1565*16467b97STreehugger Robot 1566*16467b97STreehugger Robot def getType(self, t): 1567*16467b97STreehugger Robot if t is None: 1568*16467b97STreehugger Robot return INVALID_TOKEN_TYPE 1569*16467b97STreehugger Robot 1570*16467b97STreehugger Robot return t.getType() 1571*16467b97STreehugger Robot 1572*16467b97STreehugger Robot 1573*16467b97STreehugger Robot def getToken(self, t): 1574*16467b97STreehugger Robot """ 1575*16467b97STreehugger Robot What is the Token associated with this node? If 1576*16467b97STreehugger Robot you are not using CommonTree, then you must 1577*16467b97STreehugger Robot override this in your own adaptor. 1578*16467b97STreehugger Robot """ 1579*16467b97STreehugger Robot 1580*16467b97STreehugger Robot if isinstance(t, CommonTree): 1581*16467b97STreehugger Robot return t.getToken() 1582*16467b97STreehugger Robot 1583*16467b97STreehugger Robot return None # no idea what to do 1584*16467b97STreehugger Robot 1585*16467b97STreehugger Robot 1586*16467b97STreehugger Robot def getChild(self, t, i): 1587*16467b97STreehugger Robot if t is None: 1588*16467b97STreehugger Robot return None 1589*16467b97STreehugger Robot return t.getChild(i) 1590*16467b97STreehugger Robot 1591*16467b97STreehugger Robot 1592*16467b97STreehugger Robot def getChildCount(self, t): 1593*16467b97STreehugger Robot if t is None: 1594*16467b97STreehugger Robot return 0 1595*16467b97STreehugger Robot return t.getChildCount() 1596*16467b97STreehugger Robot 1597*16467b97STreehugger Robot 1598*16467b97STreehugger Robot def getParent(self, t): 1599*16467b97STreehugger Robot return t.getParent() 1600*16467b97STreehugger Robot 1601*16467b97STreehugger Robot 1602*16467b97STreehugger Robot def setParent(self, t, parent): 1603*16467b97STreehugger Robot t.setParent(parent) 1604*16467b97STreehugger Robot 1605*16467b97STreehugger Robot 1606*16467b97STreehugger Robot def getChildIndex(self, t): 1607*16467b97STreehugger Robot if t is None: 1608*16467b97STreehugger Robot return 0 1609*16467b97STreehugger Robot return t.getChildIndex() 1610*16467b97STreehugger Robot 1611*16467b97STreehugger Robot 1612*16467b97STreehugger Robot def setChildIndex(self, t, index): 1613*16467b97STreehugger Robot t.setChildIndex(index) 1614*16467b97STreehugger Robot 1615*16467b97STreehugger Robot 1616*16467b97STreehugger Robot def replaceChildren(self, parent, startChildIndex, stopChildIndex, t): 1617*16467b97STreehugger Robot if parent is not None: 1618*16467b97STreehugger Robot parent.replaceChildren(startChildIndex, stopChildIndex, t) 1619*16467b97STreehugger Robot 1620*16467b97STreehugger Robot 1621*16467b97STreehugger Robot############################################################################ 1622*16467b97STreehugger Robot# 1623*16467b97STreehugger Robot# streams 1624*16467b97STreehugger Robot# 1625*16467b97STreehugger Robot# TreeNodeStream 1626*16467b97STreehugger Robot# \- BaseTree 1627*16467b97STreehugger Robot# \- CommonTree 1628*16467b97STreehugger Robot# 1629*16467b97STreehugger Robot# TreeAdaptor 1630*16467b97STreehugger Robot# \- BaseTreeAdaptor 1631*16467b97STreehugger Robot# \- CommonTreeAdaptor 1632*16467b97STreehugger Robot# 1633*16467b97STreehugger Robot############################################################################ 1634*16467b97STreehugger Robot 1635*16467b97STreehugger Robot 1636*16467b97STreehugger Robot 1637*16467b97STreehugger Robotclass TreeNodeStream(IntStream): 1638*16467b97STreehugger Robot """@brief A stream of tree nodes 1639*16467b97STreehugger Robot 1640*16467b97STreehugger Robot It accessing nodes from a tree of some kind. 1641*16467b97STreehugger Robot """ 1642*16467b97STreehugger Robot 1643*16467b97STreehugger Robot # TreeNodeStream is abstract, no need to complain about not implemented 1644*16467b97STreehugger Robot # abstract methods 1645*16467b97STreehugger Robot # pylint: disable-msg=W0223 1646*16467b97STreehugger Robot 1647*16467b97STreehugger Robot def get(self, i): 1648*16467b97STreehugger Robot """Get a tree node at an absolute index i; 0..n-1. 1649*16467b97STreehugger Robot If you don't want to buffer up nodes, then this method makes no 1650*16467b97STreehugger Robot sense for you. 1651*16467b97STreehugger Robot """ 1652*16467b97STreehugger Robot 1653*16467b97STreehugger Robot raise NotImplementedError 1654*16467b97STreehugger Robot 1655*16467b97STreehugger Robot 1656*16467b97STreehugger Robot def LT(self, k): 1657*16467b97STreehugger Robot """ 1658*16467b97STreehugger Robot Get tree node at current input pointer + i ahead where i=1 is next node. 1659*16467b97STreehugger Robot i<0 indicates nodes in the past. So LT(-1) is previous node, but 1660*16467b97STreehugger Robot implementations are not required to provide results for k < -1. 1661*16467b97STreehugger Robot LT(0) is undefined. For i>=n, return null. 1662*16467b97STreehugger Robot Return null for LT(0) and any index that results in an absolute address 1663*16467b97STreehugger Robot that is negative. 1664*16467b97STreehugger Robot 1665*16467b97STreehugger Robot This is analogus to the LT() method of the TokenStream, but this 1666*16467b97STreehugger Robot returns a tree node instead of a token. Makes code gen identical 1667*16467b97STreehugger Robot for both parser and tree grammars. :) 1668*16467b97STreehugger Robot """ 1669*16467b97STreehugger Robot 1670*16467b97STreehugger Robot raise NotImplementedError 1671*16467b97STreehugger Robot 1672*16467b97STreehugger Robot 1673*16467b97STreehugger Robot def getTreeSource(self): 1674*16467b97STreehugger Robot """ 1675*16467b97STreehugger Robot Where is this stream pulling nodes from? This is not the name, but 1676*16467b97STreehugger Robot the object that provides node objects. 1677*16467b97STreehugger Robot """ 1678*16467b97STreehugger Robot 1679*16467b97STreehugger Robot raise NotImplementedError 1680*16467b97STreehugger Robot 1681*16467b97STreehugger Robot 1682*16467b97STreehugger Robot def getTokenStream(self): 1683*16467b97STreehugger Robot """ 1684*16467b97STreehugger Robot If the tree associated with this stream was created from a TokenStream, 1685*16467b97STreehugger Robot you can specify it here. Used to do rule $text attribute in tree 1686*16467b97STreehugger Robot parser. Optional unless you use tree parser rule text attribute 1687*16467b97STreehugger Robot or output=template and rewrite=true options. 1688*16467b97STreehugger Robot """ 1689*16467b97STreehugger Robot 1690*16467b97STreehugger Robot raise NotImplementedError 1691*16467b97STreehugger Robot 1692*16467b97STreehugger Robot 1693*16467b97STreehugger Robot def getTreeAdaptor(self): 1694*16467b97STreehugger Robot """ 1695*16467b97STreehugger Robot What adaptor can tell me how to interpret/navigate nodes and 1696*16467b97STreehugger Robot trees. E.g., get text of a node. 1697*16467b97STreehugger Robot """ 1698*16467b97STreehugger Robot 1699*16467b97STreehugger Robot raise NotImplementedError 1700*16467b97STreehugger Robot 1701*16467b97STreehugger Robot 1702*16467b97STreehugger Robot def setUniqueNavigationNodes(self, uniqueNavigationNodes): 1703*16467b97STreehugger Robot """ 1704*16467b97STreehugger Robot As we flatten the tree, we use UP, DOWN nodes to represent 1705*16467b97STreehugger Robot the tree structure. When debugging we need unique nodes 1706*16467b97STreehugger Robot so we have to instantiate new ones. When doing normal tree 1707*16467b97STreehugger Robot parsing, it's slow and a waste of memory to create unique 1708*16467b97STreehugger Robot navigation nodes. Default should be false; 1709*16467b97STreehugger Robot """ 1710*16467b97STreehugger Robot 1711*16467b97STreehugger Robot raise NotImplementedError 1712*16467b97STreehugger Robot 1713*16467b97STreehugger Robot 1714*16467b97STreehugger Robot def reset(self): 1715*16467b97STreehugger Robot """ 1716*16467b97STreehugger Robot Reset the tree node stream in such a way that it acts like 1717*16467b97STreehugger Robot a freshly constructed stream. 1718*16467b97STreehugger Robot """ 1719*16467b97STreehugger Robot 1720*16467b97STreehugger Robot raise NotImplementedError 1721*16467b97STreehugger Robot 1722*16467b97STreehugger Robot 1723*16467b97STreehugger Robot def toString(self, start, stop): 1724*16467b97STreehugger Robot """ 1725*16467b97STreehugger Robot Return the text of all nodes from start to stop, inclusive. 1726*16467b97STreehugger Robot If the stream does not buffer all the nodes then it can still 1727*16467b97STreehugger Robot walk recursively from start until stop. You can always return 1728*16467b97STreehugger Robot null or "" too, but users should not access $ruleLabel.text in 1729*16467b97STreehugger Robot an action of course in that case. 1730*16467b97STreehugger Robot """ 1731*16467b97STreehugger Robot 1732*16467b97STreehugger Robot raise NotImplementedError 1733*16467b97STreehugger Robot 1734*16467b97STreehugger Robot 1735*16467b97STreehugger Robot # REWRITING TREES (used by tree parser) 1736*16467b97STreehugger Robot def replaceChildren(self, parent, startChildIndex, stopChildIndex, t): 1737*16467b97STreehugger Robot """ 1738*16467b97STreehugger Robot Replace from start to stop child index of parent with t, which might 1739*16467b97STreehugger Robot be a list. Number of children may be different 1740*16467b97STreehugger Robot after this call. The stream is notified because it is walking the 1741*16467b97STreehugger Robot tree and might need to know you are monkeying with the underlying 1742*16467b97STreehugger Robot tree. Also, it might be able to modify the node stream to avoid 1743*16467b97STreehugger Robot restreaming for future phases. 1744*16467b97STreehugger Robot 1745*16467b97STreehugger Robot If parent is null, don't do anything; must be at root of overall tree. 1746*16467b97STreehugger Robot Can't replace whatever points to the parent externally. Do nothing. 1747*16467b97STreehugger Robot """ 1748*16467b97STreehugger Robot 1749*16467b97STreehugger Robot raise NotImplementedError 1750*16467b97STreehugger Robot 1751*16467b97STreehugger Robot 1752*16467b97STreehugger Robotclass CommonTreeNodeStream(TreeNodeStream): 1753*16467b97STreehugger Robot """@brief A buffered stream of tree nodes. 1754*16467b97STreehugger Robot 1755*16467b97STreehugger Robot Nodes can be from a tree of ANY kind. 1756*16467b97STreehugger Robot 1757*16467b97STreehugger Robot This node stream sucks all nodes out of the tree specified in 1758*16467b97STreehugger Robot the constructor during construction and makes pointers into 1759*16467b97STreehugger Robot the tree using an array of Object pointers. The stream necessarily 1760*16467b97STreehugger Robot includes pointers to DOWN and UP and EOF nodes. 1761*16467b97STreehugger Robot 1762*16467b97STreehugger Robot This stream knows how to mark/release for backtracking. 1763*16467b97STreehugger Robot 1764*16467b97STreehugger Robot This stream is most suitable for tree interpreters that need to 1765*16467b97STreehugger Robot jump around a lot or for tree parsers requiring speed (at cost of memory). 1766*16467b97STreehugger Robot There is some duplicated functionality here with UnBufferedTreeNodeStream 1767*16467b97STreehugger Robot but just in bookkeeping, not tree walking etc... 1768*16467b97STreehugger Robot 1769*16467b97STreehugger Robot @see UnBufferedTreeNodeStream 1770*16467b97STreehugger Robot """ 1771*16467b97STreehugger Robot 1772*16467b97STreehugger Robot def __init__(self, *args): 1773*16467b97STreehugger Robot TreeNodeStream.__init__(self) 1774*16467b97STreehugger Robot 1775*16467b97STreehugger Robot if len(args) == 1: 1776*16467b97STreehugger Robot adaptor = CommonTreeAdaptor() 1777*16467b97STreehugger Robot tree = args[0] 1778*16467b97STreehugger Robot 1779*16467b97STreehugger Robot nodes = None 1780*16467b97STreehugger Robot down = None 1781*16467b97STreehugger Robot up = None 1782*16467b97STreehugger Robot eof = None 1783*16467b97STreehugger Robot 1784*16467b97STreehugger Robot elif len(args) == 2: 1785*16467b97STreehugger Robot adaptor = args[0] 1786*16467b97STreehugger Robot tree = args[1] 1787*16467b97STreehugger Robot 1788*16467b97STreehugger Robot nodes = None 1789*16467b97STreehugger Robot down = None 1790*16467b97STreehugger Robot up = None 1791*16467b97STreehugger Robot eof = None 1792*16467b97STreehugger Robot 1793*16467b97STreehugger Robot elif len(args) == 3: 1794*16467b97STreehugger Robot parent = args[0] 1795*16467b97STreehugger Robot start = args[1] 1796*16467b97STreehugger Robot stop = args[2] 1797*16467b97STreehugger Robot 1798*16467b97STreehugger Robot adaptor = parent.adaptor 1799*16467b97STreehugger Robot tree = parent.root 1800*16467b97STreehugger Robot 1801*16467b97STreehugger Robot nodes = parent.nodes[start:stop] 1802*16467b97STreehugger Robot down = parent.down 1803*16467b97STreehugger Robot up = parent.up 1804*16467b97STreehugger Robot eof = parent.eof 1805*16467b97STreehugger Robot 1806*16467b97STreehugger Robot else: 1807*16467b97STreehugger Robot raise TypeError("Invalid arguments") 1808*16467b97STreehugger Robot 1809*16467b97STreehugger Robot # all these navigation nodes are shared and hence they 1810*16467b97STreehugger Robot # cannot contain any line/column info 1811*16467b97STreehugger Robot if down is not None: 1812*16467b97STreehugger Robot self.down = down 1813*16467b97STreehugger Robot else: 1814*16467b97STreehugger Robot self.down = adaptor.createFromType(DOWN, "DOWN") 1815*16467b97STreehugger Robot 1816*16467b97STreehugger Robot if up is not None: 1817*16467b97STreehugger Robot self.up = up 1818*16467b97STreehugger Robot else: 1819*16467b97STreehugger Robot self.up = adaptor.createFromType(UP, "UP") 1820*16467b97STreehugger Robot 1821*16467b97STreehugger Robot if eof is not None: 1822*16467b97STreehugger Robot self.eof = eof 1823*16467b97STreehugger Robot else: 1824*16467b97STreehugger Robot self.eof = adaptor.createFromType(EOF, "EOF") 1825*16467b97STreehugger Robot 1826*16467b97STreehugger Robot # The complete mapping from stream index to tree node. 1827*16467b97STreehugger Robot # This buffer includes pointers to DOWN, UP, and EOF nodes. 1828*16467b97STreehugger Robot # It is built upon ctor invocation. The elements are type 1829*16467b97STreehugger Robot # Object as we don't what the trees look like. 1830*16467b97STreehugger Robot 1831*16467b97STreehugger Robot # Load upon first need of the buffer so we can set token types 1832*16467b97STreehugger Robot # of interest for reverseIndexing. Slows us down a wee bit to 1833*16467b97STreehugger Robot # do all of the if p==-1 testing everywhere though. 1834*16467b97STreehugger Robot if nodes is not None: 1835*16467b97STreehugger Robot self.nodes = nodes 1836*16467b97STreehugger Robot else: 1837*16467b97STreehugger Robot self.nodes = [] 1838*16467b97STreehugger Robot 1839*16467b97STreehugger Robot # Pull nodes from which tree? 1840*16467b97STreehugger Robot self.root = tree 1841*16467b97STreehugger Robot 1842*16467b97STreehugger Robot # IF this tree (root) was created from a token stream, track it. 1843*16467b97STreehugger Robot self.tokens = None 1844*16467b97STreehugger Robot 1845*16467b97STreehugger Robot # What tree adaptor was used to build these trees 1846*16467b97STreehugger Robot self.adaptor = adaptor 1847*16467b97STreehugger Robot 1848*16467b97STreehugger Robot # Reuse same DOWN, UP navigation nodes unless this is true 1849*16467b97STreehugger Robot self.uniqueNavigationNodes = False 1850*16467b97STreehugger Robot 1851*16467b97STreehugger Robot # The index into the nodes list of the current node (next node 1852*16467b97STreehugger Robot # to consume). If -1, nodes array not filled yet. 1853*16467b97STreehugger Robot self.p = -1 1854*16467b97STreehugger Robot 1855*16467b97STreehugger Robot # Track the last mark() call result value for use in rewind(). 1856*16467b97STreehugger Robot self.lastMarker = None 1857*16467b97STreehugger Robot 1858*16467b97STreehugger Robot # Stack of indexes used for push/pop calls 1859*16467b97STreehugger Robot self.calls = [] 1860*16467b97STreehugger Robot 1861*16467b97STreehugger Robot 1862*16467b97STreehugger Robot def __iter__(self): 1863*16467b97STreehugger Robot return TreeIterator(self.root, self.adaptor) 1864*16467b97STreehugger Robot 1865*16467b97STreehugger Robot 1866*16467b97STreehugger Robot def fillBuffer(self): 1867*16467b97STreehugger Robot """Walk tree with depth-first-search and fill nodes buffer. 1868*16467b97STreehugger Robot Don't do DOWN, UP nodes if its a list (t is isNil). 1869*16467b97STreehugger Robot """ 1870*16467b97STreehugger Robot 1871*16467b97STreehugger Robot self._fillBuffer(self.root) 1872*16467b97STreehugger Robot self.p = 0 # buffer of nodes intialized now 1873*16467b97STreehugger Robot 1874*16467b97STreehugger Robot 1875*16467b97STreehugger Robot def _fillBuffer(self, t): 1876*16467b97STreehugger Robot nil = self.adaptor.isNil(t) 1877*16467b97STreehugger Robot 1878*16467b97STreehugger Robot if not nil: 1879*16467b97STreehugger Robot self.nodes.append(t) # add this node 1880*16467b97STreehugger Robot 1881*16467b97STreehugger Robot # add DOWN node if t has children 1882*16467b97STreehugger Robot n = self.adaptor.getChildCount(t) 1883*16467b97STreehugger Robot if not nil and n > 0: 1884*16467b97STreehugger Robot self.addNavigationNode(DOWN) 1885*16467b97STreehugger Robot 1886*16467b97STreehugger Robot # and now add all its children 1887*16467b97STreehugger Robot for c in range(n): 1888*16467b97STreehugger Robot self._fillBuffer(self.adaptor.getChild(t, c)) 1889*16467b97STreehugger Robot 1890*16467b97STreehugger Robot # add UP node if t has children 1891*16467b97STreehugger Robot if not nil and n > 0: 1892*16467b97STreehugger Robot self.addNavigationNode(UP) 1893*16467b97STreehugger Robot 1894*16467b97STreehugger Robot 1895*16467b97STreehugger Robot def getNodeIndex(self, node): 1896*16467b97STreehugger Robot """What is the stream index for node? 0..n-1 1897*16467b97STreehugger Robot Return -1 if node not found. 1898*16467b97STreehugger Robot """ 1899*16467b97STreehugger Robot 1900*16467b97STreehugger Robot if self.p == -1: 1901*16467b97STreehugger Robot self.fillBuffer() 1902*16467b97STreehugger Robot 1903*16467b97STreehugger Robot for i, t in enumerate(self.nodes): 1904*16467b97STreehugger Robot if t == node: 1905*16467b97STreehugger Robot return i 1906*16467b97STreehugger Robot 1907*16467b97STreehugger Robot return -1 1908*16467b97STreehugger Robot 1909*16467b97STreehugger Robot 1910*16467b97STreehugger Robot def addNavigationNode(self, ttype): 1911*16467b97STreehugger Robot """ 1912*16467b97STreehugger Robot As we flatten the tree, we use UP, DOWN nodes to represent 1913*16467b97STreehugger Robot the tree structure. When debugging we need unique nodes 1914*16467b97STreehugger Robot so instantiate new ones when uniqueNavigationNodes is true. 1915*16467b97STreehugger Robot """ 1916*16467b97STreehugger Robot 1917*16467b97STreehugger Robot navNode = None 1918*16467b97STreehugger Robot 1919*16467b97STreehugger Robot if ttype == DOWN: 1920*16467b97STreehugger Robot if self.hasUniqueNavigationNodes(): 1921*16467b97STreehugger Robot navNode = self.adaptor.createFromType(DOWN, "DOWN") 1922*16467b97STreehugger Robot 1923*16467b97STreehugger Robot else: 1924*16467b97STreehugger Robot navNode = self.down 1925*16467b97STreehugger Robot 1926*16467b97STreehugger Robot else: 1927*16467b97STreehugger Robot if self.hasUniqueNavigationNodes(): 1928*16467b97STreehugger Robot navNode = self.adaptor.createFromType(UP, "UP") 1929*16467b97STreehugger Robot 1930*16467b97STreehugger Robot else: 1931*16467b97STreehugger Robot navNode = self.up 1932*16467b97STreehugger Robot 1933*16467b97STreehugger Robot self.nodes.append(navNode) 1934*16467b97STreehugger Robot 1935*16467b97STreehugger Robot 1936*16467b97STreehugger Robot def get(self, i): 1937*16467b97STreehugger Robot if self.p == -1: 1938*16467b97STreehugger Robot self.fillBuffer() 1939*16467b97STreehugger Robot 1940*16467b97STreehugger Robot return self.nodes[i] 1941*16467b97STreehugger Robot 1942*16467b97STreehugger Robot 1943*16467b97STreehugger Robot def LT(self, k): 1944*16467b97STreehugger Robot if self.p == -1: 1945*16467b97STreehugger Robot self.fillBuffer() 1946*16467b97STreehugger Robot 1947*16467b97STreehugger Robot if k == 0: 1948*16467b97STreehugger Robot return None 1949*16467b97STreehugger Robot 1950*16467b97STreehugger Robot if k < 0: 1951*16467b97STreehugger Robot return self.LB(-k) 1952*16467b97STreehugger Robot 1953*16467b97STreehugger Robot if self.p + k - 1 >= len(self.nodes): 1954*16467b97STreehugger Robot return self.eof 1955*16467b97STreehugger Robot 1956*16467b97STreehugger Robot return self.nodes[self.p + k - 1] 1957*16467b97STreehugger Robot 1958*16467b97STreehugger Robot 1959*16467b97STreehugger Robot def getCurrentSymbol(self): 1960*16467b97STreehugger Robot return self.LT(1) 1961*16467b97STreehugger Robot 1962*16467b97STreehugger Robot 1963*16467b97STreehugger Robot def LB(self, k): 1964*16467b97STreehugger Robot """Look backwards k nodes""" 1965*16467b97STreehugger Robot 1966*16467b97STreehugger Robot if k == 0: 1967*16467b97STreehugger Robot return None 1968*16467b97STreehugger Robot 1969*16467b97STreehugger Robot if self.p - k < 0: 1970*16467b97STreehugger Robot return None 1971*16467b97STreehugger Robot 1972*16467b97STreehugger Robot return self.nodes[self.p - k] 1973*16467b97STreehugger Robot 1974*16467b97STreehugger Robot 1975*16467b97STreehugger Robot def isEOF(self, obj): 1976*16467b97STreehugger Robot return self.adaptor.getType(obj) == EOF 1977*16467b97STreehugger Robot 1978*16467b97STreehugger Robot 1979*16467b97STreehugger Robot def getTreeSource(self): 1980*16467b97STreehugger Robot return self.root 1981*16467b97STreehugger Robot 1982*16467b97STreehugger Robot 1983*16467b97STreehugger Robot def getSourceName(self): 1984*16467b97STreehugger Robot return self.getTokenStream().getSourceName() 1985*16467b97STreehugger Robot 1986*16467b97STreehugger Robot 1987*16467b97STreehugger Robot def getTokenStream(self): 1988*16467b97STreehugger Robot return self.tokens 1989*16467b97STreehugger Robot 1990*16467b97STreehugger Robot 1991*16467b97STreehugger Robot def setTokenStream(self, tokens): 1992*16467b97STreehugger Robot self.tokens = tokens 1993*16467b97STreehugger Robot 1994*16467b97STreehugger Robot 1995*16467b97STreehugger Robot def getTreeAdaptor(self): 1996*16467b97STreehugger Robot return self.adaptor 1997*16467b97STreehugger Robot 1998*16467b97STreehugger Robot 1999*16467b97STreehugger Robot def hasUniqueNavigationNodes(self): 2000*16467b97STreehugger Robot return self.uniqueNavigationNodes 2001*16467b97STreehugger Robot 2002*16467b97STreehugger Robot 2003*16467b97STreehugger Robot def setUniqueNavigationNodes(self, uniqueNavigationNodes): 2004*16467b97STreehugger Robot self.uniqueNavigationNodes = uniqueNavigationNodes 2005*16467b97STreehugger Robot 2006*16467b97STreehugger Robot 2007*16467b97STreehugger Robot def consume(self): 2008*16467b97STreehugger Robot if self.p == -1: 2009*16467b97STreehugger Robot self.fillBuffer() 2010*16467b97STreehugger Robot 2011*16467b97STreehugger Robot self.p += 1 2012*16467b97STreehugger Robot 2013*16467b97STreehugger Robot 2014*16467b97STreehugger Robot def LA(self, i): 2015*16467b97STreehugger Robot return self.adaptor.getType(self.LT(i)) 2016*16467b97STreehugger Robot 2017*16467b97STreehugger Robot 2018*16467b97STreehugger Robot def mark(self): 2019*16467b97STreehugger Robot if self.p == -1: 2020*16467b97STreehugger Robot self.fillBuffer() 2021*16467b97STreehugger Robot 2022*16467b97STreehugger Robot 2023*16467b97STreehugger Robot self.lastMarker = self.index() 2024*16467b97STreehugger Robot return self.lastMarker 2025*16467b97STreehugger Robot 2026*16467b97STreehugger Robot 2027*16467b97STreehugger Robot def release(self, marker=None): 2028*16467b97STreehugger Robot # no resources to release 2029*16467b97STreehugger Robot 2030*16467b97STreehugger Robot pass 2031*16467b97STreehugger Robot 2032*16467b97STreehugger Robot 2033*16467b97STreehugger Robot def index(self): 2034*16467b97STreehugger Robot return self.p 2035*16467b97STreehugger Robot 2036*16467b97STreehugger Robot 2037*16467b97STreehugger Robot def rewind(self, marker=None): 2038*16467b97STreehugger Robot if marker is None: 2039*16467b97STreehugger Robot marker = self.lastMarker 2040*16467b97STreehugger Robot 2041*16467b97STreehugger Robot self.seek(marker) 2042*16467b97STreehugger Robot 2043*16467b97STreehugger Robot 2044*16467b97STreehugger Robot def seek(self, index): 2045*16467b97STreehugger Robot if self.p == -1: 2046*16467b97STreehugger Robot self.fillBuffer() 2047*16467b97STreehugger Robot 2048*16467b97STreehugger Robot self.p = index 2049*16467b97STreehugger Robot 2050*16467b97STreehugger Robot 2051*16467b97STreehugger Robot def push(self, index): 2052*16467b97STreehugger Robot """ 2053*16467b97STreehugger Robot Make stream jump to a new location, saving old location. 2054*16467b97STreehugger Robot Switch back with pop(). 2055*16467b97STreehugger Robot """ 2056*16467b97STreehugger Robot 2057*16467b97STreehugger Robot self.calls.append(self.p) # save current index 2058*16467b97STreehugger Robot self.seek(index) 2059*16467b97STreehugger Robot 2060*16467b97STreehugger Robot 2061*16467b97STreehugger Robot def pop(self): 2062*16467b97STreehugger Robot """ 2063*16467b97STreehugger Robot Seek back to previous index saved during last push() call. 2064*16467b97STreehugger Robot Return top of stack (return index). 2065*16467b97STreehugger Robot """ 2066*16467b97STreehugger Robot 2067*16467b97STreehugger Robot ret = self.calls.pop(-1) 2068*16467b97STreehugger Robot self.seek(ret) 2069*16467b97STreehugger Robot return ret 2070*16467b97STreehugger Robot 2071*16467b97STreehugger Robot 2072*16467b97STreehugger Robot def reset(self): 2073*16467b97STreehugger Robot self.p = 0 2074*16467b97STreehugger Robot self.lastMarker = 0 2075*16467b97STreehugger Robot self.calls = [] 2076*16467b97STreehugger Robot 2077*16467b97STreehugger Robot 2078*16467b97STreehugger Robot def size(self): 2079*16467b97STreehugger Robot if self.p == -1: 2080*16467b97STreehugger Robot self.fillBuffer() 2081*16467b97STreehugger Robot 2082*16467b97STreehugger Robot return len(self.nodes) 2083*16467b97STreehugger Robot 2084*16467b97STreehugger Robot 2085*16467b97STreehugger Robot # TREE REWRITE INTERFACE 2086*16467b97STreehugger Robot 2087*16467b97STreehugger Robot def replaceChildren(self, parent, startChildIndex, stopChildIndex, t): 2088*16467b97STreehugger Robot if parent is not None: 2089*16467b97STreehugger Robot self.adaptor.replaceChildren( 2090*16467b97STreehugger Robot parent, startChildIndex, stopChildIndex, t 2091*16467b97STreehugger Robot ) 2092*16467b97STreehugger Robot 2093*16467b97STreehugger Robot 2094*16467b97STreehugger Robot def __str__(self): 2095*16467b97STreehugger Robot """Used for testing, just return the token type stream""" 2096*16467b97STreehugger Robot 2097*16467b97STreehugger Robot if self.p == -1: 2098*16467b97STreehugger Robot self.fillBuffer() 2099*16467b97STreehugger Robot 2100*16467b97STreehugger Robot return ' '.join([str(self.adaptor.getType(node)) 2101*16467b97STreehugger Robot for node in self.nodes 2102*16467b97STreehugger Robot ]) 2103*16467b97STreehugger Robot 2104*16467b97STreehugger Robot 2105*16467b97STreehugger Robot def toString(self, start, stop): 2106*16467b97STreehugger Robot if start is None or stop is None: 2107*16467b97STreehugger Robot return None 2108*16467b97STreehugger Robot 2109*16467b97STreehugger Robot if self.p == -1: 2110*16467b97STreehugger Robot self.fillBuffer() 2111*16467b97STreehugger Robot 2112*16467b97STreehugger Robot #System.out.println("stop: "+stop); 2113*16467b97STreehugger Robot #if ( start instanceof CommonTree ) 2114*16467b97STreehugger Robot # System.out.print("toString: "+((CommonTree)start).getToken()+", "); 2115*16467b97STreehugger Robot #else 2116*16467b97STreehugger Robot # System.out.println(start); 2117*16467b97STreehugger Robot #if ( stop instanceof CommonTree ) 2118*16467b97STreehugger Robot # System.out.println(((CommonTree)stop).getToken()); 2119*16467b97STreehugger Robot #else 2120*16467b97STreehugger Robot # System.out.println(stop); 2121*16467b97STreehugger Robot 2122*16467b97STreehugger Robot # if we have the token stream, use that to dump text in order 2123*16467b97STreehugger Robot if self.tokens is not None: 2124*16467b97STreehugger Robot beginTokenIndex = self.adaptor.getTokenStartIndex(start) 2125*16467b97STreehugger Robot endTokenIndex = self.adaptor.getTokenStopIndex(stop) 2126*16467b97STreehugger Robot 2127*16467b97STreehugger Robot # if it's a tree, use start/stop index from start node 2128*16467b97STreehugger Robot # else use token range from start/stop nodes 2129*16467b97STreehugger Robot if self.adaptor.getType(stop) == UP: 2130*16467b97STreehugger Robot endTokenIndex = self.adaptor.getTokenStopIndex(start) 2131*16467b97STreehugger Robot 2132*16467b97STreehugger Robot elif self.adaptor.getType(stop) == EOF: 2133*16467b97STreehugger Robot endTokenIndex = self.size() -2 # don't use EOF 2134*16467b97STreehugger Robot 2135*16467b97STreehugger Robot return self.tokens.toString(beginTokenIndex, endTokenIndex) 2136*16467b97STreehugger Robot 2137*16467b97STreehugger Robot # walk nodes looking for start 2138*16467b97STreehugger Robot i, t = 0, None 2139*16467b97STreehugger Robot for i, t in enumerate(self.nodes): 2140*16467b97STreehugger Robot if t == start: 2141*16467b97STreehugger Robot break 2142*16467b97STreehugger Robot 2143*16467b97STreehugger Robot # now walk until we see stop, filling string buffer with text 2144*16467b97STreehugger Robot buf = [] 2145*16467b97STreehugger Robot t = self.nodes[i] 2146*16467b97STreehugger Robot while t != stop: 2147*16467b97STreehugger Robot text = self.adaptor.getText(t) 2148*16467b97STreehugger Robot if text is None: 2149*16467b97STreehugger Robot text = " " + self.adaptor.getType(t) 2150*16467b97STreehugger Robot 2151*16467b97STreehugger Robot buf.append(text) 2152*16467b97STreehugger Robot i += 1 2153*16467b97STreehugger Robot t = self.nodes[i] 2154*16467b97STreehugger Robot 2155*16467b97STreehugger Robot # include stop node too 2156*16467b97STreehugger Robot text = self.adaptor.getText(stop) 2157*16467b97STreehugger Robot if text is None: 2158*16467b97STreehugger Robot text = " " +self.adaptor.getType(stop) 2159*16467b97STreehugger Robot 2160*16467b97STreehugger Robot buf.append(text) 2161*16467b97STreehugger Robot 2162*16467b97STreehugger Robot return ''.join(buf) 2163*16467b97STreehugger Robot 2164*16467b97STreehugger Robot 2165*16467b97STreehugger Robot ## iterator interface 2166*16467b97STreehugger Robot def __iter__(self): 2167*16467b97STreehugger Robot if self.p == -1: 2168*16467b97STreehugger Robot self.fillBuffer() 2169*16467b97STreehugger Robot 2170*16467b97STreehugger Robot for node in self.nodes: 2171*16467b97STreehugger Robot yield node 2172*16467b97STreehugger Robot 2173*16467b97STreehugger Robot 2174*16467b97STreehugger Robot############################################################################# 2175*16467b97STreehugger Robot# 2176*16467b97STreehugger Robot# tree parser 2177*16467b97STreehugger Robot# 2178*16467b97STreehugger Robot############################################################################# 2179*16467b97STreehugger Robot 2180*16467b97STreehugger Robotclass TreeParser(BaseRecognizer): 2181*16467b97STreehugger Robot """@brief Baseclass for generated tree parsers. 2182*16467b97STreehugger Robot 2183*16467b97STreehugger Robot A parser for a stream of tree nodes. "tree grammars" result in a subclass 2184*16467b97STreehugger Robot of this. All the error reporting and recovery is shared with Parser via 2185*16467b97STreehugger Robot the BaseRecognizer superclass. 2186*16467b97STreehugger Robot """ 2187*16467b97STreehugger Robot 2188*16467b97STreehugger Robot def __init__(self, input, state=None): 2189*16467b97STreehugger Robot BaseRecognizer.__init__(self, state) 2190*16467b97STreehugger Robot 2191*16467b97STreehugger Robot self.input = None 2192*16467b97STreehugger Robot self.setTreeNodeStream(input) 2193*16467b97STreehugger Robot 2194*16467b97STreehugger Robot 2195*16467b97STreehugger Robot def reset(self): 2196*16467b97STreehugger Robot BaseRecognizer.reset(self) # reset all recognizer state variables 2197*16467b97STreehugger Robot if self.input is not None: 2198*16467b97STreehugger Robot self.input.seek(0) # rewind the input 2199*16467b97STreehugger Robot 2200*16467b97STreehugger Robot 2201*16467b97STreehugger Robot def setTreeNodeStream(self, input): 2202*16467b97STreehugger Robot """Set the input stream""" 2203*16467b97STreehugger Robot 2204*16467b97STreehugger Robot self.input = input 2205*16467b97STreehugger Robot 2206*16467b97STreehugger Robot 2207*16467b97STreehugger Robot def getTreeNodeStream(self): 2208*16467b97STreehugger Robot return self.input 2209*16467b97STreehugger Robot 2210*16467b97STreehugger Robot 2211*16467b97STreehugger Robot def getSourceName(self): 2212*16467b97STreehugger Robot return self.input.getSourceName() 2213*16467b97STreehugger Robot 2214*16467b97STreehugger Robot 2215*16467b97STreehugger Robot def getCurrentInputSymbol(self, input): 2216*16467b97STreehugger Robot return input.LT(1) 2217*16467b97STreehugger Robot 2218*16467b97STreehugger Robot 2219*16467b97STreehugger Robot def getMissingSymbol(self, input, e, expectedTokenType, follow): 2220*16467b97STreehugger Robot tokenText = "<missing " + self.tokenNames[expectedTokenType] + ">" 2221*16467b97STreehugger Robot adaptor = input.adaptor 2222*16467b97STreehugger Robot return adaptor.createToken( 2223*16467b97STreehugger Robot CommonToken(type=expectedTokenType, text=tokenText)) 2224*16467b97STreehugger Robot 2225*16467b97STreehugger Robot 2226*16467b97STreehugger Robot # precompiled regex used by inContext 2227*16467b97STreehugger Robot dotdot = ".*[^.]\\.\\.[^.].*" 2228*16467b97STreehugger Robot doubleEtc = ".*\\.\\.\\.\\s+\\.\\.\\..*" 2229*16467b97STreehugger Robot dotdotPattern = re.compile(dotdot) 2230*16467b97STreehugger Robot doubleEtcPattern = re.compile(doubleEtc) 2231*16467b97STreehugger Robot 2232*16467b97STreehugger Robot def inContext(self, context, adaptor=None, tokenName=None, t=None): 2233*16467b97STreehugger Robot """Check if current node in input has a context. 2234*16467b97STreehugger Robot 2235*16467b97STreehugger Robot Context means sequence of nodes towards root of tree. For example, 2236*16467b97STreehugger Robot you might say context is "MULT" which means my parent must be MULT. 2237*16467b97STreehugger Robot "CLASS VARDEF" says current node must be child of a VARDEF and whose 2238*16467b97STreehugger Robot parent is a CLASS node. You can use "..." to mean zero-or-more nodes. 2239*16467b97STreehugger Robot "METHOD ... VARDEF" means my parent is VARDEF and somewhere above 2240*16467b97STreehugger Robot that is a METHOD node. The first node in the context is not 2241*16467b97STreehugger Robot necessarily the root. The context matcher stops matching and returns 2242*16467b97STreehugger Robot true when it runs out of context. There is no way to force the first 2243*16467b97STreehugger Robot node to be the root. 2244*16467b97STreehugger Robot """ 2245*16467b97STreehugger Robot 2246*16467b97STreehugger Robot return _inContext( 2247*16467b97STreehugger Robot self.input.getTreeAdaptor(), self.getTokenNames(), 2248*16467b97STreehugger Robot self.input.LT(1), context) 2249*16467b97STreehugger Robot 2250*16467b97STreehugger Robot @classmethod 2251*16467b97STreehugger Robot def _inContext(cls, adaptor, tokenNames, t, context): 2252*16467b97STreehugger Robot """The worker for inContext. 2253*16467b97STreehugger Robot 2254*16467b97STreehugger Robot It's static and full of parameters for testing purposes. 2255*16467b97STreehugger Robot """ 2256*16467b97STreehugger Robot 2257*16467b97STreehugger Robot if cls.dotdotPattern.match(context): 2258*16467b97STreehugger Robot # don't allow "..", must be "..." 2259*16467b97STreehugger Robot raise ValueError("invalid syntax: ..") 2260*16467b97STreehugger Robot 2261*16467b97STreehugger Robot if cls.doubleEtcPattern.match(context): 2262*16467b97STreehugger Robot # don't allow double "..." 2263*16467b97STreehugger Robot raise ValueError("invalid syntax: ... ...") 2264*16467b97STreehugger Robot 2265*16467b97STreehugger Robot # ensure spaces around ... 2266*16467b97STreehugger Robot context = context.replace("...", " ... ") 2267*16467b97STreehugger Robot context = context.strip() 2268*16467b97STreehugger Robot nodes = context.split() 2269*16467b97STreehugger Robot 2270*16467b97STreehugger Robot ni = len(nodes) - 1 2271*16467b97STreehugger Robot t = adaptor.getParent(t) 2272*16467b97STreehugger Robot while ni >= 0 and t is not None: 2273*16467b97STreehugger Robot if nodes[ni] == "...": 2274*16467b97STreehugger Robot # walk upwards until we see nodes[ni-1] then continue walking 2275*16467b97STreehugger Robot if ni == 0: 2276*16467b97STreehugger Robot # ... at start is no-op 2277*16467b97STreehugger Robot return True 2278*16467b97STreehugger Robot goal = nodes[ni-1] 2279*16467b97STreehugger Robot ancestor = cls._getAncestor(adaptor, tokenNames, t, goal) 2280*16467b97STreehugger Robot if ancestor is None: 2281*16467b97STreehugger Robot return False 2282*16467b97STreehugger Robot t = ancestor 2283*16467b97STreehugger Robot ni -= 1 2284*16467b97STreehugger Robot 2285*16467b97STreehugger Robot name = tokenNames[adaptor.getType(t)] 2286*16467b97STreehugger Robot if name != nodes[ni]: 2287*16467b97STreehugger Robot return False 2288*16467b97STreehugger Robot 2289*16467b97STreehugger Robot # advance to parent and to previous element in context node list 2290*16467b97STreehugger Robot ni -= 1 2291*16467b97STreehugger Robot t = adaptor.getParent(t) 2292*16467b97STreehugger Robot 2293*16467b97STreehugger Robot # at root but more nodes to match 2294*16467b97STreehugger Robot if t is None and ni >= 0: 2295*16467b97STreehugger Robot return False 2296*16467b97STreehugger Robot 2297*16467b97STreehugger Robot return True 2298*16467b97STreehugger Robot 2299*16467b97STreehugger Robot @staticmethod 2300*16467b97STreehugger Robot def _getAncestor(adaptor, tokenNames, t, goal): 2301*16467b97STreehugger Robot """Helper for static inContext.""" 2302*16467b97STreehugger Robot while t is not None: 2303*16467b97STreehugger Robot name = tokenNames[adaptor.getType(t)] 2304*16467b97STreehugger Robot if name == goal: 2305*16467b97STreehugger Robot return t 2306*16467b97STreehugger Robot t = adaptor.getParent(t) 2307*16467b97STreehugger Robot 2308*16467b97STreehugger Robot return None 2309*16467b97STreehugger Robot 2310*16467b97STreehugger Robot 2311*16467b97STreehugger Robot def matchAny(self, ignore): # ignore stream, copy of this.input 2312*16467b97STreehugger Robot """ 2313*16467b97STreehugger Robot Match '.' in tree parser has special meaning. Skip node or 2314*16467b97STreehugger Robot entire tree if node has children. If children, scan until 2315*16467b97STreehugger Robot corresponding UP node. 2316*16467b97STreehugger Robot """ 2317*16467b97STreehugger Robot 2318*16467b97STreehugger Robot self._state.errorRecovery = False 2319*16467b97STreehugger Robot 2320*16467b97STreehugger Robot look = self.input.LT(1) 2321*16467b97STreehugger Robot if self.input.getTreeAdaptor().getChildCount(look) == 0: 2322*16467b97STreehugger Robot self.input.consume() # not subtree, consume 1 node and return 2323*16467b97STreehugger Robot return 2324*16467b97STreehugger Robot 2325*16467b97STreehugger Robot # current node is a subtree, skip to corresponding UP. 2326*16467b97STreehugger Robot # must count nesting level to get right UP 2327*16467b97STreehugger Robot level = 0 2328*16467b97STreehugger Robot tokenType = self.input.getTreeAdaptor().getType(look) 2329*16467b97STreehugger Robot while tokenType != EOF and not (tokenType == UP and level==0): 2330*16467b97STreehugger Robot self.input.consume() 2331*16467b97STreehugger Robot look = self.input.LT(1) 2332*16467b97STreehugger Robot tokenType = self.input.getTreeAdaptor().getType(look) 2333*16467b97STreehugger Robot if tokenType == DOWN: 2334*16467b97STreehugger Robot level += 1 2335*16467b97STreehugger Robot 2336*16467b97STreehugger Robot elif tokenType == UP: 2337*16467b97STreehugger Robot level -= 1 2338*16467b97STreehugger Robot 2339*16467b97STreehugger Robot self.input.consume() # consume UP 2340*16467b97STreehugger Robot 2341*16467b97STreehugger Robot 2342*16467b97STreehugger Robot def mismatch(self, input, ttype, follow): 2343*16467b97STreehugger Robot """ 2344*16467b97STreehugger Robot We have DOWN/UP nodes in the stream that have no line info; override. 2345*16467b97STreehugger Robot plus we want to alter the exception type. Don't try to recover 2346*16467b97STreehugger Robot from tree parser errors inline... 2347*16467b97STreehugger Robot """ 2348*16467b97STreehugger Robot 2349*16467b97STreehugger Robot raise MismatchedTreeNodeException(ttype, input) 2350*16467b97STreehugger Robot 2351*16467b97STreehugger Robot 2352*16467b97STreehugger Robot def getErrorHeader(self, e): 2353*16467b97STreehugger Robot """ 2354*16467b97STreehugger Robot Prefix error message with the grammar name because message is 2355*16467b97STreehugger Robot always intended for the programmer because the parser built 2356*16467b97STreehugger Robot the input tree not the user. 2357*16467b97STreehugger Robot """ 2358*16467b97STreehugger Robot 2359*16467b97STreehugger Robot return (self.getGrammarFileName() + 2360*16467b97STreehugger Robot ": node from %sline %s:%s" 2361*16467b97STreehugger Robot % (['', "after "][e.approximateLineInfo], 2362*16467b97STreehugger Robot e.line, 2363*16467b97STreehugger Robot e.charPositionInLine 2364*16467b97STreehugger Robot ) 2365*16467b97STreehugger Robot ) 2366*16467b97STreehugger Robot 2367*16467b97STreehugger Robot def getErrorMessage(self, e, tokenNames): 2368*16467b97STreehugger Robot """ 2369*16467b97STreehugger Robot Tree parsers parse nodes they usually have a token object as 2370*16467b97STreehugger Robot payload. Set the exception token and do the default behavior. 2371*16467b97STreehugger Robot """ 2372*16467b97STreehugger Robot 2373*16467b97STreehugger Robot if isinstance(self, TreeParser): 2374*16467b97STreehugger Robot adaptor = e.input.getTreeAdaptor() 2375*16467b97STreehugger Robot e.token = adaptor.getToken(e.node) 2376*16467b97STreehugger Robot if e.token is not None: # could be an UP/DOWN node 2377*16467b97STreehugger Robot e.token = CommonToken( 2378*16467b97STreehugger Robot type=adaptor.getType(e.node), 2379*16467b97STreehugger Robot text=adaptor.getText(e.node) 2380*16467b97STreehugger Robot ) 2381*16467b97STreehugger Robot 2382*16467b97STreehugger Robot return BaseRecognizer.getErrorMessage(self, e, tokenNames) 2383*16467b97STreehugger Robot 2384*16467b97STreehugger Robot 2385*16467b97STreehugger Robot def traceIn(self, ruleName, ruleIndex): 2386*16467b97STreehugger Robot BaseRecognizer.traceIn(self, ruleName, ruleIndex, self.input.LT(1)) 2387*16467b97STreehugger Robot 2388*16467b97STreehugger Robot 2389*16467b97STreehugger Robot def traceOut(self, ruleName, ruleIndex): 2390*16467b97STreehugger Robot BaseRecognizer.traceOut(self, ruleName, ruleIndex, self.input.LT(1)) 2391*16467b97STreehugger Robot 2392*16467b97STreehugger Robot 2393*16467b97STreehugger Robot############################################################################# 2394*16467b97STreehugger Robot# 2395*16467b97STreehugger Robot# tree visitor 2396*16467b97STreehugger Robot# 2397*16467b97STreehugger Robot############################################################################# 2398*16467b97STreehugger Robot 2399*16467b97STreehugger Robotclass TreeVisitor(object): 2400*16467b97STreehugger Robot """Do a depth first walk of a tree, applying pre() and post() actions 2401*16467b97STreehugger Robot we go. 2402*16467b97STreehugger Robot """ 2403*16467b97STreehugger Robot 2404*16467b97STreehugger Robot def __init__(self, adaptor=None): 2405*16467b97STreehugger Robot if adaptor is not None: 2406*16467b97STreehugger Robot self.adaptor = adaptor 2407*16467b97STreehugger Robot else: 2408*16467b97STreehugger Robot self.adaptor = CommonTreeAdaptor() 2409*16467b97STreehugger Robot 2410*16467b97STreehugger Robot def visit(self, t, pre_action=None, post_action=None): 2411*16467b97STreehugger Robot """Visit every node in tree t and trigger an action for each node 2412*16467b97STreehugger Robot before/after having visited all of its children. Bottom up walk. 2413*16467b97STreehugger Robot Execute both actions even if t has no children. Ignore return 2414*16467b97STreehugger Robot results from transforming children since they will have altered 2415*16467b97STreehugger Robot the child list of this node (their parent). Return result of 2416*16467b97STreehugger Robot applying post action to this node. 2417*16467b97STreehugger Robot 2418*16467b97STreehugger Robot The Python version differs from the Java version by taking two 2419*16467b97STreehugger Robot callables 'pre_action' and 'post_action' instead of a class instance 2420*16467b97STreehugger Robot that wraps those methods. Those callables must accept a TreeNode as 2421*16467b97STreehugger Robot their single argument and return the (potentially transformed or 2422*16467b97STreehugger Robot replaced) TreeNode. 2423*16467b97STreehugger Robot """ 2424*16467b97STreehugger Robot 2425*16467b97STreehugger Robot isNil = self.adaptor.isNil(t) 2426*16467b97STreehugger Robot if pre_action is not None and not isNil: 2427*16467b97STreehugger Robot # if rewritten, walk children of new t 2428*16467b97STreehugger Robot t = pre_action(t) 2429*16467b97STreehugger Robot 2430*16467b97STreehugger Robot idx = 0 2431*16467b97STreehugger Robot while idx < self.adaptor.getChildCount(t): 2432*16467b97STreehugger Robot child = self.adaptor.getChild(t, idx) 2433*16467b97STreehugger Robot self.visit(child, pre_action, post_action) 2434*16467b97STreehugger Robot idx += 1 2435*16467b97STreehugger Robot 2436*16467b97STreehugger Robot if post_action is not None and not isNil: 2437*16467b97STreehugger Robot t = post_action(t) 2438*16467b97STreehugger Robot 2439*16467b97STreehugger Robot return t 2440*16467b97STreehugger Robot 2441*16467b97STreehugger Robot############################################################################# 2442*16467b97STreehugger Robot# 2443*16467b97STreehugger Robot# tree iterator 2444*16467b97STreehugger Robot# 2445*16467b97STreehugger Robot############################################################################# 2446*16467b97STreehugger Robot 2447*16467b97STreehugger Robotclass TreeIterator(object): 2448*16467b97STreehugger Robot """ 2449*16467b97STreehugger Robot Return a node stream from a doubly-linked tree whose nodes 2450*16467b97STreehugger Robot know what child index they are. 2451*16467b97STreehugger Robot 2452*16467b97STreehugger Robot Emit navigation nodes (DOWN, UP, and EOF) to let show tree structure. 2453*16467b97STreehugger Robot """ 2454*16467b97STreehugger Robot 2455*16467b97STreehugger Robot def __init__(self, tree, adaptor=None): 2456*16467b97STreehugger Robot if adaptor is None: 2457*16467b97STreehugger Robot adaptor = CommonTreeAdaptor() 2458*16467b97STreehugger Robot 2459*16467b97STreehugger Robot self.root = tree 2460*16467b97STreehugger Robot self.adaptor = adaptor 2461*16467b97STreehugger Robot 2462*16467b97STreehugger Robot self.first_time = True 2463*16467b97STreehugger Robot self.tree = tree 2464*16467b97STreehugger Robot 2465*16467b97STreehugger Robot # If we emit UP/DOWN nodes, we need to spit out multiple nodes per 2466*16467b97STreehugger Robot # next() call. 2467*16467b97STreehugger Robot self.nodes = [] 2468*16467b97STreehugger Robot 2469*16467b97STreehugger Robot # navigation nodes to return during walk and at end 2470*16467b97STreehugger Robot self.down = adaptor.createFromType(DOWN, "DOWN") 2471*16467b97STreehugger Robot self.up = adaptor.createFromType(UP, "UP") 2472*16467b97STreehugger Robot self.eof = adaptor.createFromType(EOF, "EOF") 2473*16467b97STreehugger Robot 2474*16467b97STreehugger Robot 2475*16467b97STreehugger Robot def reset(self): 2476*16467b97STreehugger Robot self.first_time = True 2477*16467b97STreehugger Robot self.tree = self.root 2478*16467b97STreehugger Robot self.nodes = [] 2479*16467b97STreehugger Robot 2480*16467b97STreehugger Robot 2481*16467b97STreehugger Robot def __iter__(self): 2482*16467b97STreehugger Robot return self 2483*16467b97STreehugger Robot 2484*16467b97STreehugger Robot 2485*16467b97STreehugger Robot def has_next(self): 2486*16467b97STreehugger Robot if self.first_time: 2487*16467b97STreehugger Robot return self.root is not None 2488*16467b97STreehugger Robot 2489*16467b97STreehugger Robot if len(self.nodes) > 0: 2490*16467b97STreehugger Robot return True 2491*16467b97STreehugger Robot 2492*16467b97STreehugger Robot if self.tree is None: 2493*16467b97STreehugger Robot return False 2494*16467b97STreehugger Robot 2495*16467b97STreehugger Robot if self.adaptor.getChildCount(self.tree) > 0: 2496*16467b97STreehugger Robot return True 2497*16467b97STreehugger Robot 2498*16467b97STreehugger Robot # back at root? 2499*16467b97STreehugger Robot return self.adaptor.getParent(self.tree) is not None 2500*16467b97STreehugger Robot 2501*16467b97STreehugger Robot 2502*16467b97STreehugger Robot def next(self): 2503*16467b97STreehugger Robot if not self.has_next(): 2504*16467b97STreehugger Robot raise StopIteration 2505*16467b97STreehugger Robot 2506*16467b97STreehugger Robot if self.first_time: 2507*16467b97STreehugger Robot # initial condition 2508*16467b97STreehugger Robot self.first_time = False 2509*16467b97STreehugger Robot if self.adaptor.getChildCount(self.tree) == 0: 2510*16467b97STreehugger Robot # single node tree (special) 2511*16467b97STreehugger Robot self.nodes.append(self.eof) 2512*16467b97STreehugger Robot return self.tree 2513*16467b97STreehugger Robot 2514*16467b97STreehugger Robot return self.tree 2515*16467b97STreehugger Robot 2516*16467b97STreehugger Robot # if any queued up, use those first 2517*16467b97STreehugger Robot if len(self.nodes) > 0: 2518*16467b97STreehugger Robot return self.nodes.pop(0) 2519*16467b97STreehugger Robot 2520*16467b97STreehugger Robot # no nodes left? 2521*16467b97STreehugger Robot if self.tree is None: 2522*16467b97STreehugger Robot return self.eof 2523*16467b97STreehugger Robot 2524*16467b97STreehugger Robot # next node will be child 0 if any children 2525*16467b97STreehugger Robot if self.adaptor.getChildCount(self.tree) > 0: 2526*16467b97STreehugger Robot self.tree = self.adaptor.getChild(self.tree, 0) 2527*16467b97STreehugger Robot # real node is next after DOWN 2528*16467b97STreehugger Robot self.nodes.append(self.tree) 2529*16467b97STreehugger Robot return self.down 2530*16467b97STreehugger Robot 2531*16467b97STreehugger Robot # if no children, look for next sibling of tree or ancestor 2532*16467b97STreehugger Robot parent = self.adaptor.getParent(self.tree) 2533*16467b97STreehugger Robot # while we're out of siblings, keep popping back up towards root 2534*16467b97STreehugger Robot while (parent is not None 2535*16467b97STreehugger Robot and self.adaptor.getChildIndex(self.tree)+1 >= self.adaptor.getChildCount(parent)): 2536*16467b97STreehugger Robot # we're moving back up 2537*16467b97STreehugger Robot self.nodes.append(self.up) 2538*16467b97STreehugger Robot self.tree = parent 2539*16467b97STreehugger Robot parent = self.adaptor.getParent(self.tree) 2540*16467b97STreehugger Robot 2541*16467b97STreehugger Robot # no nodes left? 2542*16467b97STreehugger Robot if parent is None: 2543*16467b97STreehugger Robot self.tree = None # back at root? nothing left then 2544*16467b97STreehugger Robot self.nodes.append(self.eof) # add to queue, might have UP nodes in there 2545*16467b97STreehugger Robot return self.nodes.pop(0) 2546*16467b97STreehugger Robot 2547*16467b97STreehugger Robot # must have found a node with an unvisited sibling 2548*16467b97STreehugger Robot # move to it and return it 2549*16467b97STreehugger Robot nextSiblingIndex = self.adaptor.getChildIndex(self.tree) + 1 2550*16467b97STreehugger Robot self.tree = self.adaptor.getChild(parent, nextSiblingIndex) 2551*16467b97STreehugger Robot self.nodes.append(self.tree) # add to queue, might have UP nodes in there 2552*16467b97STreehugger Robot return self.nodes.pop(0) 2553*16467b97STreehugger Robot 2554*16467b97STreehugger Robot 2555*16467b97STreehugger Robot 2556*16467b97STreehugger Robot############################################################################# 2557*16467b97STreehugger Robot# 2558*16467b97STreehugger Robot# streams for rule rewriting 2559*16467b97STreehugger Robot# 2560*16467b97STreehugger Robot############################################################################# 2561*16467b97STreehugger Robot 2562*16467b97STreehugger Robotclass RewriteRuleElementStream(object): 2563*16467b97STreehugger Robot """@brief Internal helper class. 2564*16467b97STreehugger Robot 2565*16467b97STreehugger Robot A generic list of elements tracked in an alternative to be used in 2566*16467b97STreehugger Robot a -> rewrite rule. We need to subclass to fill in the next() method, 2567*16467b97STreehugger Robot which returns either an AST node wrapped around a token payload or 2568*16467b97STreehugger Robot an existing subtree. 2569*16467b97STreehugger Robot 2570*16467b97STreehugger Robot Once you start next()ing, do not try to add more elements. It will 2571*16467b97STreehugger Robot break the cursor tracking I believe. 2572*16467b97STreehugger Robot 2573*16467b97STreehugger Robot @see org.antlr.runtime.tree.RewriteRuleSubtreeStream 2574*16467b97STreehugger Robot @see org.antlr.runtime.tree.RewriteRuleTokenStream 2575*16467b97STreehugger Robot 2576*16467b97STreehugger Robot TODO: add mechanism to detect/puke on modification after reading from 2577*16467b97STreehugger Robot stream 2578*16467b97STreehugger Robot """ 2579*16467b97STreehugger Robot 2580*16467b97STreehugger Robot def __init__(self, adaptor, elementDescription, elements=None): 2581*16467b97STreehugger Robot # Cursor 0..n-1. If singleElement!=null, cursor is 0 until you next(), 2582*16467b97STreehugger Robot # which bumps it to 1 meaning no more elements. 2583*16467b97STreehugger Robot self.cursor = 0 2584*16467b97STreehugger Robot 2585*16467b97STreehugger Robot # Track single elements w/o creating a list. Upon 2nd add, alloc list 2586*16467b97STreehugger Robot self.singleElement = None 2587*16467b97STreehugger Robot 2588*16467b97STreehugger Robot # The list of tokens or subtrees we are tracking 2589*16467b97STreehugger Robot self.elements = None 2590*16467b97STreehugger Robot 2591*16467b97STreehugger Robot # Once a node / subtree has been used in a stream, it must be dup'd 2592*16467b97STreehugger Robot # from then on. Streams are reset after subrules so that the streams 2593*16467b97STreehugger Robot # can be reused in future subrules. So, reset must set a dirty bit. 2594*16467b97STreehugger Robot # If dirty, then next() always returns a dup. 2595*16467b97STreehugger Robot self.dirty = False 2596*16467b97STreehugger Robot 2597*16467b97STreehugger Robot # The element or stream description; usually has name of the token or 2598*16467b97STreehugger Robot # rule reference that this list tracks. Can include rulename too, but 2599*16467b97STreehugger Robot # the exception would track that info. 2600*16467b97STreehugger Robot self.elementDescription = elementDescription 2601*16467b97STreehugger Robot 2602*16467b97STreehugger Robot self.adaptor = adaptor 2603*16467b97STreehugger Robot 2604*16467b97STreehugger Robot if isinstance(elements, (list, tuple)): 2605*16467b97STreehugger Robot # Create a stream, but feed off an existing list 2606*16467b97STreehugger Robot self.singleElement = None 2607*16467b97STreehugger Robot self.elements = elements 2608*16467b97STreehugger Robot 2609*16467b97STreehugger Robot else: 2610*16467b97STreehugger Robot # Create a stream with one element 2611*16467b97STreehugger Robot self.add(elements) 2612*16467b97STreehugger Robot 2613*16467b97STreehugger Robot 2614*16467b97STreehugger Robot def reset(self): 2615*16467b97STreehugger Robot """ 2616*16467b97STreehugger Robot Reset the condition of this stream so that it appears we have 2617*16467b97STreehugger Robot not consumed any of its elements. Elements themselves are untouched. 2618*16467b97STreehugger Robot Once we reset the stream, any future use will need duplicates. Set 2619*16467b97STreehugger Robot the dirty bit. 2620*16467b97STreehugger Robot """ 2621*16467b97STreehugger Robot 2622*16467b97STreehugger Robot self.cursor = 0 2623*16467b97STreehugger Robot self.dirty = True 2624*16467b97STreehugger Robot 2625*16467b97STreehugger Robot 2626*16467b97STreehugger Robot def add(self, el): 2627*16467b97STreehugger Robot if el is None: 2628*16467b97STreehugger Robot return 2629*16467b97STreehugger Robot 2630*16467b97STreehugger Robot if self.elements is not None: # if in list, just add 2631*16467b97STreehugger Robot self.elements.append(el) 2632*16467b97STreehugger Robot return 2633*16467b97STreehugger Robot 2634*16467b97STreehugger Robot if self.singleElement is None: # no elements yet, track w/o list 2635*16467b97STreehugger Robot self.singleElement = el 2636*16467b97STreehugger Robot return 2637*16467b97STreehugger Robot 2638*16467b97STreehugger Robot # adding 2nd element, move to list 2639*16467b97STreehugger Robot self.elements = [] 2640*16467b97STreehugger Robot self.elements.append(self.singleElement) 2641*16467b97STreehugger Robot self.singleElement = None 2642*16467b97STreehugger Robot self.elements.append(el) 2643*16467b97STreehugger Robot 2644*16467b97STreehugger Robot 2645*16467b97STreehugger Robot def nextTree(self): 2646*16467b97STreehugger Robot """ 2647*16467b97STreehugger Robot Return the next element in the stream. If out of elements, throw 2648*16467b97STreehugger Robot an exception unless size()==1. If size is 1, then return elements[0]. 2649*16467b97STreehugger Robot 2650*16467b97STreehugger Robot Return a duplicate node/subtree if stream is out of elements and 2651*16467b97STreehugger Robot size==1. If we've already used the element, dup (dirty bit set). 2652*16467b97STreehugger Robot """ 2653*16467b97STreehugger Robot 2654*16467b97STreehugger Robot if (self.dirty 2655*16467b97STreehugger Robot or (self.cursor >= len(self) and len(self) == 1) 2656*16467b97STreehugger Robot ): 2657*16467b97STreehugger Robot # if out of elements and size is 1, dup 2658*16467b97STreehugger Robot el = self._next() 2659*16467b97STreehugger Robot return self.dup(el) 2660*16467b97STreehugger Robot 2661*16467b97STreehugger Robot # test size above then fetch 2662*16467b97STreehugger Robot el = self._next() 2663*16467b97STreehugger Robot return el 2664*16467b97STreehugger Robot 2665*16467b97STreehugger Robot 2666*16467b97STreehugger Robot def _next(self): 2667*16467b97STreehugger Robot """ 2668*16467b97STreehugger Robot do the work of getting the next element, making sure that it's 2669*16467b97STreehugger Robot a tree node or subtree. Deal with the optimization of single- 2670*16467b97STreehugger Robot element list versus list of size > 1. Throw an exception 2671*16467b97STreehugger Robot if the stream is empty or we're out of elements and size>1. 2672*16467b97STreehugger Robot protected so you can override in a subclass if necessary. 2673*16467b97STreehugger Robot """ 2674*16467b97STreehugger Robot 2675*16467b97STreehugger Robot if len(self) == 0: 2676*16467b97STreehugger Robot raise RewriteEmptyStreamException(self.elementDescription) 2677*16467b97STreehugger Robot 2678*16467b97STreehugger Robot if self.cursor >= len(self): # out of elements? 2679*16467b97STreehugger Robot if len(self) == 1: # if size is 1, it's ok; return and we'll dup 2680*16467b97STreehugger Robot return self.toTree(self.singleElement) 2681*16467b97STreehugger Robot 2682*16467b97STreehugger Robot # out of elements and size was not 1, so we can't dup 2683*16467b97STreehugger Robot raise RewriteCardinalityException(self.elementDescription) 2684*16467b97STreehugger Robot 2685*16467b97STreehugger Robot # we have elements 2686*16467b97STreehugger Robot if self.singleElement is not None: 2687*16467b97STreehugger Robot self.cursor += 1 # move cursor even for single element list 2688*16467b97STreehugger Robot return self.toTree(self.singleElement) 2689*16467b97STreehugger Robot 2690*16467b97STreehugger Robot # must have more than one in list, pull from elements 2691*16467b97STreehugger Robot o = self.toTree(self.elements[self.cursor]) 2692*16467b97STreehugger Robot self.cursor += 1 2693*16467b97STreehugger Robot return o 2694*16467b97STreehugger Robot 2695*16467b97STreehugger Robot 2696*16467b97STreehugger Robot def dup(self, el): 2697*16467b97STreehugger Robot """ 2698*16467b97STreehugger Robot When constructing trees, sometimes we need to dup a token or AST 2699*16467b97STreehugger Robot subtree. Dup'ing a token means just creating another AST node 2700*16467b97STreehugger Robot around it. For trees, you must call the adaptor.dupTree() unless 2701*16467b97STreehugger Robot the element is for a tree root; then it must be a node dup. 2702*16467b97STreehugger Robot """ 2703*16467b97STreehugger Robot 2704*16467b97STreehugger Robot raise NotImplementedError 2705*16467b97STreehugger Robot 2706*16467b97STreehugger Robot 2707*16467b97STreehugger Robot def toTree(self, el): 2708*16467b97STreehugger Robot """ 2709*16467b97STreehugger Robot Ensure stream emits trees; tokens must be converted to AST nodes. 2710*16467b97STreehugger Robot AST nodes can be passed through unmolested. 2711*16467b97STreehugger Robot """ 2712*16467b97STreehugger Robot 2713*16467b97STreehugger Robot return el 2714*16467b97STreehugger Robot 2715*16467b97STreehugger Robot 2716*16467b97STreehugger Robot def hasNext(self): 2717*16467b97STreehugger Robot return ( (self.singleElement is not None and self.cursor < 1) 2718*16467b97STreehugger Robot or (self.elements is not None 2719*16467b97STreehugger Robot and self.cursor < len(self.elements) 2720*16467b97STreehugger Robot ) 2721*16467b97STreehugger Robot ) 2722*16467b97STreehugger Robot 2723*16467b97STreehugger Robot 2724*16467b97STreehugger Robot def size(self): 2725*16467b97STreehugger Robot if self.singleElement is not None: 2726*16467b97STreehugger Robot return 1 2727*16467b97STreehugger Robot 2728*16467b97STreehugger Robot if self.elements is not None: 2729*16467b97STreehugger Robot return len(self.elements) 2730*16467b97STreehugger Robot 2731*16467b97STreehugger Robot return 0 2732*16467b97STreehugger Robot 2733*16467b97STreehugger Robot __len__ = size 2734*16467b97STreehugger Robot 2735*16467b97STreehugger Robot 2736*16467b97STreehugger Robot def getDescription(self): 2737*16467b97STreehugger Robot """Deprecated. Directly access elementDescription attribute""" 2738*16467b97STreehugger Robot 2739*16467b97STreehugger Robot return self.elementDescription 2740*16467b97STreehugger Robot 2741*16467b97STreehugger Robot 2742*16467b97STreehugger Robotclass RewriteRuleTokenStream(RewriteRuleElementStream): 2743*16467b97STreehugger Robot """@brief Internal helper class.""" 2744*16467b97STreehugger Robot 2745*16467b97STreehugger Robot def toTree(self, el): 2746*16467b97STreehugger Robot # Don't convert to a tree unless they explicitly call nextTree. 2747*16467b97STreehugger Robot # This way we can do hetero tree nodes in rewrite. 2748*16467b97STreehugger Robot return el 2749*16467b97STreehugger Robot 2750*16467b97STreehugger Robot 2751*16467b97STreehugger Robot def nextNode(self): 2752*16467b97STreehugger Robot t = self._next() 2753*16467b97STreehugger Robot return self.adaptor.createWithPayload(t) 2754*16467b97STreehugger Robot 2755*16467b97STreehugger Robot 2756*16467b97STreehugger Robot def nextToken(self): 2757*16467b97STreehugger Robot return self._next() 2758*16467b97STreehugger Robot 2759*16467b97STreehugger Robot 2760*16467b97STreehugger Robot def dup(self, el): 2761*16467b97STreehugger Robot raise TypeError("dup can't be called for a token stream.") 2762*16467b97STreehugger Robot 2763*16467b97STreehugger Robot 2764*16467b97STreehugger Robotclass RewriteRuleSubtreeStream(RewriteRuleElementStream): 2765*16467b97STreehugger Robot """@brief Internal helper class.""" 2766*16467b97STreehugger Robot 2767*16467b97STreehugger Robot def nextNode(self): 2768*16467b97STreehugger Robot """ 2769*16467b97STreehugger Robot Treat next element as a single node even if it's a subtree. 2770*16467b97STreehugger Robot This is used instead of next() when the result has to be a 2771*16467b97STreehugger Robot tree root node. Also prevents us from duplicating recently-added 2772*16467b97STreehugger Robot children; e.g., ^(type ID)+ adds ID to type and then 2nd iteration 2773*16467b97STreehugger Robot must dup the type node, but ID has been added. 2774*16467b97STreehugger Robot 2775*16467b97STreehugger Robot Referencing a rule result twice is ok; dup entire tree as 2776*16467b97STreehugger Robot we can't be adding trees as root; e.g., expr expr. 2777*16467b97STreehugger Robot 2778*16467b97STreehugger Robot Hideous code duplication here with super.next(). Can't think of 2779*16467b97STreehugger Robot a proper way to refactor. This needs to always call dup node 2780*16467b97STreehugger Robot and super.next() doesn't know which to call: dup node or dup tree. 2781*16467b97STreehugger Robot """ 2782*16467b97STreehugger Robot 2783*16467b97STreehugger Robot if (self.dirty 2784*16467b97STreehugger Robot or (self.cursor >= len(self) and len(self) == 1) 2785*16467b97STreehugger Robot ): 2786*16467b97STreehugger Robot # if out of elements and size is 1, dup (at most a single node 2787*16467b97STreehugger Robot # since this is for making root nodes). 2788*16467b97STreehugger Robot el = self._next() 2789*16467b97STreehugger Robot return self.adaptor.dupNode(el) 2790*16467b97STreehugger Robot 2791*16467b97STreehugger Robot # test size above then fetch 2792*16467b97STreehugger Robot el = self._next() 2793*16467b97STreehugger Robot while self.adaptor.isNil(el) and self.adaptor.getChildCount(el) == 1: 2794*16467b97STreehugger Robot el = self.adaptor.getChild(el, 0) 2795*16467b97STreehugger Robot 2796*16467b97STreehugger Robot # dup just the root (want node here) 2797*16467b97STreehugger Robot return self.adaptor.dupNode(el) 2798*16467b97STreehugger Robot 2799*16467b97STreehugger Robot 2800*16467b97STreehugger Robot def dup(self, el): 2801*16467b97STreehugger Robot return self.adaptor.dupTree(el) 2802*16467b97STreehugger Robot 2803*16467b97STreehugger Robot 2804*16467b97STreehugger Robot 2805*16467b97STreehugger Robotclass RewriteRuleNodeStream(RewriteRuleElementStream): 2806*16467b97STreehugger Robot """ 2807*16467b97STreehugger Robot Queues up nodes matched on left side of -> in a tree parser. This is 2808*16467b97STreehugger Robot the analog of RewriteRuleTokenStream for normal parsers. 2809*16467b97STreehugger Robot """ 2810*16467b97STreehugger Robot 2811*16467b97STreehugger Robot def nextNode(self): 2812*16467b97STreehugger Robot return self._next() 2813*16467b97STreehugger Robot 2814*16467b97STreehugger Robot 2815*16467b97STreehugger Robot def toTree(self, el): 2816*16467b97STreehugger Robot return self.adaptor.dupNode(el) 2817*16467b97STreehugger Robot 2818*16467b97STreehugger Robot 2819*16467b97STreehugger Robot def dup(self, el): 2820*16467b97STreehugger Robot # we dup every node, so don't have to worry about calling dup; short- 2821*16467b97STreehugger Robot #circuited next() so it doesn't call. 2822*16467b97STreehugger Robot raise TypeError("dup can't be called for a node stream.") 2823*16467b97STreehugger Robot 2824*16467b97STreehugger Robot 2825*16467b97STreehugger Robotclass TreeRuleReturnScope(RuleReturnScope): 2826*16467b97STreehugger Robot """ 2827*16467b97STreehugger Robot This is identical to the ParserRuleReturnScope except that 2828*16467b97STreehugger Robot the start property is a tree nodes not Token object 2829*16467b97STreehugger Robot when you are parsing trees. To be generic the tree node types 2830*16467b97STreehugger Robot have to be Object. 2831*16467b97STreehugger Robot """ 2832*16467b97STreehugger Robot 2833*16467b97STreehugger Robot def __init__(self): 2834*16467b97STreehugger Robot self.start = None 2835*16467b97STreehugger Robot self.tree = None 2836*16467b97STreehugger Robot 2837*16467b97STreehugger Robot 2838*16467b97STreehugger Robot def getStart(self): 2839*16467b97STreehugger Robot return self.start 2840*16467b97STreehugger Robot 2841*16467b97STreehugger Robot 2842*16467b97STreehugger Robot def getTree(self): 2843*16467b97STreehugger Robot return self.tree 2844