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-2012 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) 617*16467b97STreehugger Robot and isinstance(args[1], Token)): 618*16467b97STreehugger Robot # Object create(int tokenType, Token fromToken); 619*16467b97STreehugger Robot## warnings.warn( 620*16467b97STreehugger Robot## "Using create() is deprecated, use createFromToken()", 621*16467b97STreehugger Robot## DeprecationWarning, 622*16467b97STreehugger Robot## stacklevel=2 623*16467b97STreehugger Robot## ) 624*16467b97STreehugger Robot return self.createFromToken(args[0], args[1]) 625*16467b97STreehugger Robot 626*16467b97STreehugger Robot if (len(args) == 3 627*16467b97STreehugger Robot and isinstance(args[0], int) 628*16467b97STreehugger Robot and isinstance(args[1], Token) 629*16467b97STreehugger Robot and isinstance(args[2], str)): 630*16467b97STreehugger Robot # Object create(int tokenType, Token fromToken, String text); 631*16467b97STreehugger Robot## warnings.warn( 632*16467b97STreehugger Robot## "Using create() is deprecated, use createFromToken()", 633*16467b97STreehugger Robot## DeprecationWarning, 634*16467b97STreehugger Robot## stacklevel=2 635*16467b97STreehugger Robot## ) 636*16467b97STreehugger Robot return self.createFromToken(args[0], args[1], args[2]) 637*16467b97STreehugger Robot 638*16467b97STreehugger Robot if (len(args) == 2 639*16467b97STreehugger Robot and isinstance(args[0], int) 640*16467b97STreehugger Robot and isinstance(args[1], str)): 641*16467b97STreehugger Robot # Object create(int tokenType, String text); 642*16467b97STreehugger Robot## warnings.warn( 643*16467b97STreehugger Robot## "Using create() is deprecated, use createFromType()", 644*16467b97STreehugger Robot## DeprecationWarning, 645*16467b97STreehugger Robot## stacklevel=2 646*16467b97STreehugger Robot## ) 647*16467b97STreehugger Robot return self.createFromType(args[0], args[1]) 648*16467b97STreehugger Robot 649*16467b97STreehugger Robot raise TypeError( 650*16467b97STreehugger Robot "No create method with this signature found: {}" 651*16467b97STreehugger Robot .format(', '.join(type(v).__name__ for v in args))) 652*16467b97STreehugger Robot 653*16467b97STreehugger Robot 654*16467b97STreehugger Robot############################################################################ 655*16467b97STreehugger Robot# 656*16467b97STreehugger Robot# base implementation of Tree and TreeAdaptor 657*16467b97STreehugger Robot# 658*16467b97STreehugger Robot# Tree 659*16467b97STreehugger Robot# \- BaseTree 660*16467b97STreehugger Robot# 661*16467b97STreehugger Robot# TreeAdaptor 662*16467b97STreehugger Robot# \- BaseTreeAdaptor 663*16467b97STreehugger Robot# 664*16467b97STreehugger Robot############################################################################ 665*16467b97STreehugger Robot 666*16467b97STreehugger Robot 667*16467b97STreehugger Robotclass BaseTree(Tree): 668*16467b97STreehugger Robot """ 669*16467b97STreehugger Robot @brief A generic tree implementation with no payload. 670*16467b97STreehugger Robot 671*16467b97STreehugger Robot You must subclass to 672*16467b97STreehugger Robot actually have any user data. ANTLR v3 uses a list of children approach 673*16467b97STreehugger Robot instead of the child-sibling approach in v2. A flat tree (a list) is 674*16467b97STreehugger Robot an empty node whose children represent the list. An empty, but 675*16467b97STreehugger Robot non-null node is called "nil". 676*16467b97STreehugger Robot """ 677*16467b97STreehugger Robot 678*16467b97STreehugger Robot # BaseTree is abstract, no need to complain about not implemented abstract 679*16467b97STreehugger Robot # methods 680*16467b97STreehugger Robot # pylint: disable-msg=W0223 681*16467b97STreehugger Robot 682*16467b97STreehugger Robot def __init__(self, node=None): 683*16467b97STreehugger Robot """ 684*16467b97STreehugger Robot Create a new node from an existing node does nothing for BaseTree 685*16467b97STreehugger Robot as there are no fields other than the children list, which cannot 686*16467b97STreehugger Robot be copied as the children are not considered part of this node. 687*16467b97STreehugger Robot """ 688*16467b97STreehugger Robot 689*16467b97STreehugger Robot super().__init__() 690*16467b97STreehugger Robot self.children = [] 691*16467b97STreehugger Robot self.parent = None 692*16467b97STreehugger Robot self.childIndex = 0 693*16467b97STreehugger Robot 694*16467b97STreehugger Robot 695*16467b97STreehugger Robot def getChild(self, i): 696*16467b97STreehugger Robot try: 697*16467b97STreehugger Robot return self.children[i] 698*16467b97STreehugger Robot except IndexError: 699*16467b97STreehugger Robot return None 700*16467b97STreehugger Robot 701*16467b97STreehugger Robot 702*16467b97STreehugger Robot def getChildren(self): 703*16467b97STreehugger Robot """@brief Get the children internal List 704*16467b97STreehugger Robot 705*16467b97STreehugger Robot Note that if you directly mess with 706*16467b97STreehugger Robot the list, do so at your own risk. 707*16467b97STreehugger Robot """ 708*16467b97STreehugger Robot 709*16467b97STreehugger Robot # FIXME: mark as deprecated 710*16467b97STreehugger Robot return self.children 711*16467b97STreehugger Robot 712*16467b97STreehugger Robot 713*16467b97STreehugger Robot def getFirstChildWithType(self, treeType): 714*16467b97STreehugger Robot for child in self.children: 715*16467b97STreehugger Robot if child.getType() == treeType: 716*16467b97STreehugger Robot return child 717*16467b97STreehugger Robot 718*16467b97STreehugger Robot return None 719*16467b97STreehugger Robot 720*16467b97STreehugger Robot 721*16467b97STreehugger Robot def getChildCount(self): 722*16467b97STreehugger Robot return len(self.children) 723*16467b97STreehugger Robot 724*16467b97STreehugger Robot 725*16467b97STreehugger Robot def addChild(self, childTree): 726*16467b97STreehugger Robot """Add t as child of this node. 727*16467b97STreehugger Robot 728*16467b97STreehugger Robot Warning: if t has no children, but child does 729*16467b97STreehugger Robot and child isNil then this routine moves children to t via 730*16467b97STreehugger Robot t.children = child.children; i.e., without copying the array. 731*16467b97STreehugger Robot """ 732*16467b97STreehugger Robot 733*16467b97STreehugger Robot # this implementation is much simpler and probably less efficient 734*16467b97STreehugger Robot # than the mumbo-jumbo that Ter did for the Java runtime. 735*16467b97STreehugger Robot 736*16467b97STreehugger Robot if childTree is None: 737*16467b97STreehugger Robot return 738*16467b97STreehugger Robot 739*16467b97STreehugger Robot if childTree.isNil(): 740*16467b97STreehugger Robot # t is an empty node possibly with children 741*16467b97STreehugger Robot 742*16467b97STreehugger Robot if self.children is childTree.children: 743*16467b97STreehugger Robot raise ValueError("attempt to add child list to itself") 744*16467b97STreehugger Robot 745*16467b97STreehugger Robot # fix parent pointer and childIndex for new children 746*16467b97STreehugger Robot for idx, child in enumerate(childTree.children): 747*16467b97STreehugger Robot child.parent = self 748*16467b97STreehugger Robot child.childIndex = len(self.children) + idx 749*16467b97STreehugger Robot 750*16467b97STreehugger Robot self.children += childTree.children 751*16467b97STreehugger Robot 752*16467b97STreehugger Robot else: 753*16467b97STreehugger Robot # child is not nil (don't care about children) 754*16467b97STreehugger Robot self.children.append(childTree) 755*16467b97STreehugger Robot childTree.parent = self 756*16467b97STreehugger Robot childTree.childIndex = len(self.children) - 1 757*16467b97STreehugger Robot 758*16467b97STreehugger Robot 759*16467b97STreehugger Robot def addChildren(self, children): 760*16467b97STreehugger Robot """Add all elements of kids list as children of this node""" 761*16467b97STreehugger Robot 762*16467b97STreehugger Robot self.children += children 763*16467b97STreehugger Robot 764*16467b97STreehugger Robot 765*16467b97STreehugger Robot def setChild(self, i, t): 766*16467b97STreehugger Robot if t is None: 767*16467b97STreehugger Robot return 768*16467b97STreehugger Robot 769*16467b97STreehugger Robot if t.isNil(): 770*16467b97STreehugger Robot raise ValueError("Can't set single child to a list") 771*16467b97STreehugger Robot 772*16467b97STreehugger Robot self.children[i] = t 773*16467b97STreehugger Robot t.parent = self 774*16467b97STreehugger Robot t.childIndex = i 775*16467b97STreehugger Robot 776*16467b97STreehugger Robot 777*16467b97STreehugger Robot def deleteChild(self, i): 778*16467b97STreehugger Robot killed = self.children[i] 779*16467b97STreehugger Robot 780*16467b97STreehugger Robot del self.children[i] 781*16467b97STreehugger Robot 782*16467b97STreehugger Robot # walk rest and decrement their child indexes 783*16467b97STreehugger Robot for idx, child in enumerate(self.children[i:]): 784*16467b97STreehugger Robot child.childIndex = i + idx 785*16467b97STreehugger Robot 786*16467b97STreehugger Robot return killed 787*16467b97STreehugger Robot 788*16467b97STreehugger Robot 789*16467b97STreehugger Robot def replaceChildren(self, startChildIndex, stopChildIndex, newTree): 790*16467b97STreehugger Robot """ 791*16467b97STreehugger Robot Delete children from start to stop and replace with t even if t is 792*16467b97STreehugger Robot a list (nil-root tree). num of children can increase or decrease. 793*16467b97STreehugger Robot For huge child lists, inserting children can force walking rest of 794*16467b97STreehugger Robot children to set their childindex; could be slow. 795*16467b97STreehugger Robot """ 796*16467b97STreehugger Robot 797*16467b97STreehugger Robot if (startChildIndex >= len(self.children) 798*16467b97STreehugger Robot or stopChildIndex >= len(self.children)): 799*16467b97STreehugger Robot raise IndexError("indexes invalid") 800*16467b97STreehugger Robot 801*16467b97STreehugger Robot replacingHowMany = stopChildIndex - startChildIndex + 1 802*16467b97STreehugger Robot 803*16467b97STreehugger Robot # normalize to a list of children to add: newChildren 804*16467b97STreehugger Robot if newTree.isNil(): 805*16467b97STreehugger Robot newChildren = newTree.children 806*16467b97STreehugger Robot 807*16467b97STreehugger Robot else: 808*16467b97STreehugger Robot newChildren = [newTree] 809*16467b97STreehugger Robot 810*16467b97STreehugger Robot replacingWithHowMany = len(newChildren) 811*16467b97STreehugger Robot delta = replacingHowMany - replacingWithHowMany 812*16467b97STreehugger Robot 813*16467b97STreehugger Robot 814*16467b97STreehugger Robot if delta == 0: 815*16467b97STreehugger Robot # if same number of nodes, do direct replace 816*16467b97STreehugger Robot for idx, child in enumerate(newChildren): 817*16467b97STreehugger Robot self.children[idx + startChildIndex] = child 818*16467b97STreehugger Robot child.parent = self 819*16467b97STreehugger Robot child.childIndex = idx + startChildIndex 820*16467b97STreehugger Robot 821*16467b97STreehugger Robot else: 822*16467b97STreehugger Robot # length of children changes... 823*16467b97STreehugger Robot 824*16467b97STreehugger Robot # ...delete replaced segment... 825*16467b97STreehugger Robot del self.children[startChildIndex:stopChildIndex+1] 826*16467b97STreehugger Robot 827*16467b97STreehugger Robot # ...insert new segment... 828*16467b97STreehugger Robot self.children[startChildIndex:startChildIndex] = newChildren 829*16467b97STreehugger Robot 830*16467b97STreehugger Robot # ...and fix indeces 831*16467b97STreehugger Robot self.freshenParentAndChildIndexes(startChildIndex) 832*16467b97STreehugger Robot 833*16467b97STreehugger Robot 834*16467b97STreehugger Robot def isNil(self): 835*16467b97STreehugger Robot return False 836*16467b97STreehugger Robot 837*16467b97STreehugger Robot 838*16467b97STreehugger Robot def freshenParentAndChildIndexes(self, offset=0): 839*16467b97STreehugger Robot for idx, child in enumerate(self.children[offset:]): 840*16467b97STreehugger Robot child.childIndex = idx + offset 841*16467b97STreehugger Robot child.parent = self 842*16467b97STreehugger Robot 843*16467b97STreehugger Robot 844*16467b97STreehugger Robot def sanityCheckParentAndChildIndexes(self, parent=None, i=-1): 845*16467b97STreehugger Robot if parent != self.parent: 846*16467b97STreehugger Robot raise ValueError( 847*16467b97STreehugger Robot "parents don't match; expected {!r} found {!r}" 848*16467b97STreehugger Robot .format(parent, self.parent)) 849*16467b97STreehugger Robot 850*16467b97STreehugger Robot if i != self.childIndex: 851*16467b97STreehugger Robot raise ValueError( 852*16467b97STreehugger Robot "child indexes don't match; expected {} found {}" 853*16467b97STreehugger Robot .format(i, self.childIndex)) 854*16467b97STreehugger Robot 855*16467b97STreehugger Robot for idx, child in enumerate(self.children): 856*16467b97STreehugger Robot child.sanityCheckParentAndChildIndexes(self, idx) 857*16467b97STreehugger Robot 858*16467b97STreehugger Robot 859*16467b97STreehugger Robot def getChildIndex(self): 860*16467b97STreehugger Robot """BaseTree doesn't track child indexes.""" 861*16467b97STreehugger Robot 862*16467b97STreehugger Robot return 0 863*16467b97STreehugger Robot 864*16467b97STreehugger Robot 865*16467b97STreehugger Robot def setChildIndex(self, index): 866*16467b97STreehugger Robot """BaseTree doesn't track child indexes.""" 867*16467b97STreehugger Robot 868*16467b97STreehugger Robot pass 869*16467b97STreehugger Robot 870*16467b97STreehugger Robot 871*16467b97STreehugger Robot def getParent(self): 872*16467b97STreehugger Robot """BaseTree doesn't track parent pointers.""" 873*16467b97STreehugger Robot 874*16467b97STreehugger Robot return None 875*16467b97STreehugger Robot 876*16467b97STreehugger Robot def setParent(self, t): 877*16467b97STreehugger Robot """BaseTree doesn't track parent pointers.""" 878*16467b97STreehugger Robot 879*16467b97STreehugger Robot pass 880*16467b97STreehugger Robot 881*16467b97STreehugger Robot 882*16467b97STreehugger Robot def hasAncestor(self, ttype): 883*16467b97STreehugger Robot """Walk upwards looking for ancestor with this token type.""" 884*16467b97STreehugger Robot return self.getAncestor(ttype) is not None 885*16467b97STreehugger Robot 886*16467b97STreehugger Robot def getAncestor(self, ttype): 887*16467b97STreehugger Robot """Walk upwards and get first ancestor with this token type.""" 888*16467b97STreehugger Robot t = self.getParent() 889*16467b97STreehugger Robot while t is not None: 890*16467b97STreehugger Robot if t.getType() == ttype: 891*16467b97STreehugger Robot return t 892*16467b97STreehugger Robot t = t.getParent() 893*16467b97STreehugger Robot 894*16467b97STreehugger Robot return None 895*16467b97STreehugger Robot 896*16467b97STreehugger Robot def getAncestors(self): 897*16467b97STreehugger Robot """Return a list of all ancestors of this node. 898*16467b97STreehugger Robot 899*16467b97STreehugger Robot The first node of list is the root and the last is the parent of 900*16467b97STreehugger Robot this node. 901*16467b97STreehugger Robot """ 902*16467b97STreehugger Robot if self.getParent() is None: 903*16467b97STreehugger Robot return None 904*16467b97STreehugger Robot 905*16467b97STreehugger Robot ancestors = [] 906*16467b97STreehugger Robot t = self.getParent() 907*16467b97STreehugger Robot while t is not None: 908*16467b97STreehugger Robot ancestors.insert(0, t) # insert at start 909*16467b97STreehugger Robot t = t.getParent() 910*16467b97STreehugger Robot 911*16467b97STreehugger Robot return ancestors 912*16467b97STreehugger Robot 913*16467b97STreehugger Robot 914*16467b97STreehugger Robot def toStringTree(self): 915*16467b97STreehugger Robot """Print out a whole tree not just a node""" 916*16467b97STreehugger Robot 917*16467b97STreehugger Robot if len(self.children) == 0: 918*16467b97STreehugger Robot return self.toString() 919*16467b97STreehugger Robot 920*16467b97STreehugger Robot buf = [] 921*16467b97STreehugger Robot if not self.isNil(): 922*16467b97STreehugger Robot buf.append('(') 923*16467b97STreehugger Robot buf.append(self.toString()) 924*16467b97STreehugger Robot buf.append(' ') 925*16467b97STreehugger Robot 926*16467b97STreehugger Robot for i, child in enumerate(self.children): 927*16467b97STreehugger Robot if i > 0: 928*16467b97STreehugger Robot buf.append(' ') 929*16467b97STreehugger Robot buf.append(child.toStringTree()) 930*16467b97STreehugger Robot 931*16467b97STreehugger Robot if not self.isNil(): 932*16467b97STreehugger Robot buf.append(')') 933*16467b97STreehugger Robot 934*16467b97STreehugger Robot return ''.join(buf) 935*16467b97STreehugger Robot 936*16467b97STreehugger Robot 937*16467b97STreehugger Robot def getLine(self): 938*16467b97STreehugger Robot return 0 939*16467b97STreehugger Robot 940*16467b97STreehugger Robot 941*16467b97STreehugger Robot def getCharPositionInLine(self): 942*16467b97STreehugger Robot return 0 943*16467b97STreehugger Robot 944*16467b97STreehugger Robot 945*16467b97STreehugger Robot def toString(self): 946*16467b97STreehugger Robot """Override to say how a node (not a tree) should look as text""" 947*16467b97STreehugger Robot 948*16467b97STreehugger Robot raise NotImplementedError 949*16467b97STreehugger Robot 950*16467b97STreehugger Robot 951*16467b97STreehugger Robot 952*16467b97STreehugger Robotclass BaseTreeAdaptor(TreeAdaptor): 953*16467b97STreehugger Robot """ 954*16467b97STreehugger Robot @brief A TreeAdaptor that works with any Tree implementation. 955*16467b97STreehugger Robot """ 956*16467b97STreehugger Robot 957*16467b97STreehugger Robot # BaseTreeAdaptor is abstract, no need to complain about not implemented 958*16467b97STreehugger Robot # abstract methods 959*16467b97STreehugger Robot # pylint: disable-msg=W0223 960*16467b97STreehugger Robot 961*16467b97STreehugger Robot def nil(self): 962*16467b97STreehugger Robot return self.createWithPayload(None) 963*16467b97STreehugger Robot 964*16467b97STreehugger Robot 965*16467b97STreehugger Robot def errorNode(self, input, start, stop, exc): 966*16467b97STreehugger Robot """ 967*16467b97STreehugger Robot create tree node that holds the start and stop tokens associated 968*16467b97STreehugger Robot with an error. 969*16467b97STreehugger Robot 970*16467b97STreehugger Robot If you specify your own kind of tree nodes, you will likely have to 971*16467b97STreehugger Robot override this method. CommonTree returns Token.INVALID_TOKEN_TYPE 972*16467b97STreehugger Robot if no token payload but you might have to set token type for diff 973*16467b97STreehugger Robot node type. 974*16467b97STreehugger Robot 975*16467b97STreehugger Robot You don't have to subclass CommonErrorNode; you will likely need to 976*16467b97STreehugger Robot subclass your own tree node class to avoid class cast exception. 977*16467b97STreehugger Robot """ 978*16467b97STreehugger Robot 979*16467b97STreehugger Robot return CommonErrorNode(input, start, stop, exc) 980*16467b97STreehugger Robot 981*16467b97STreehugger Robot 982*16467b97STreehugger Robot def isNil(self, tree): 983*16467b97STreehugger Robot return tree.isNil() 984*16467b97STreehugger Robot 985*16467b97STreehugger Robot 986*16467b97STreehugger Robot def dupTree(self, t, parent=None): 987*16467b97STreehugger Robot """ 988*16467b97STreehugger Robot This is generic in the sense that it will work with any kind of 989*16467b97STreehugger Robot tree (not just Tree interface). It invokes the adaptor routines 990*16467b97STreehugger Robot not the tree node routines to do the construction. 991*16467b97STreehugger Robot """ 992*16467b97STreehugger Robot 993*16467b97STreehugger Robot if t is None: 994*16467b97STreehugger Robot return None 995*16467b97STreehugger Robot 996*16467b97STreehugger Robot newTree = self.dupNode(t) 997*16467b97STreehugger Robot 998*16467b97STreehugger Robot # ensure new subtree root has parent/child index set 999*16467b97STreehugger Robot 1000*16467b97STreehugger Robot # same index in new tree 1001*16467b97STreehugger Robot self.setChildIndex(newTree, self.getChildIndex(t)) 1002*16467b97STreehugger Robot 1003*16467b97STreehugger Robot self.setParent(newTree, parent) 1004*16467b97STreehugger Robot 1005*16467b97STreehugger Robot for i in range(self.getChildCount(t)): 1006*16467b97STreehugger Robot child = self.getChild(t, i) 1007*16467b97STreehugger Robot newSubTree = self.dupTree(child, t) 1008*16467b97STreehugger Robot self.addChild(newTree, newSubTree) 1009*16467b97STreehugger Robot 1010*16467b97STreehugger Robot return newTree 1011*16467b97STreehugger Robot 1012*16467b97STreehugger Robot 1013*16467b97STreehugger Robot def addChild(self, tree, child): 1014*16467b97STreehugger Robot """ 1015*16467b97STreehugger Robot Add a child to the tree t. If child is a flat tree (a list), make all 1016*16467b97STreehugger Robot in list children of t. Warning: if t has no children, but child does 1017*16467b97STreehugger Robot and child isNil then you can decide it is ok to move children to t via 1018*16467b97STreehugger Robot t.children = child.children; i.e., without copying the array. Just 1019*16467b97STreehugger Robot make sure that this is consistent with have the user will build 1020*16467b97STreehugger Robot ASTs. 1021*16467b97STreehugger Robot """ 1022*16467b97STreehugger Robot 1023*16467b97STreehugger Robot #if isinstance(child, Token): 1024*16467b97STreehugger Robot # child = self.createWithPayload(child) 1025*16467b97STreehugger Robot 1026*16467b97STreehugger Robot if tree is not None and child is not None: 1027*16467b97STreehugger Robot tree.addChild(child) 1028*16467b97STreehugger Robot 1029*16467b97STreehugger Robot 1030*16467b97STreehugger Robot def becomeRoot(self, newRoot, oldRoot): 1031*16467b97STreehugger Robot """ 1032*16467b97STreehugger Robot If oldRoot is a nil root, just copy or move the children to newRoot. 1033*16467b97STreehugger Robot If not a nil root, make oldRoot a child of newRoot. 1034*16467b97STreehugger Robot 1035*16467b97STreehugger Robot old=^(nil a b c), new=r yields ^(r a b c) 1036*16467b97STreehugger Robot old=^(a b c), new=r yields ^(r ^(a b c)) 1037*16467b97STreehugger Robot 1038*16467b97STreehugger Robot If newRoot is a nil-rooted single child tree, use the single 1039*16467b97STreehugger Robot child as the new root node. 1040*16467b97STreehugger Robot 1041*16467b97STreehugger Robot old=^(nil a b c), new=^(nil r) yields ^(r a b c) 1042*16467b97STreehugger Robot old=^(a b c), new=^(nil r) yields ^(r ^(a b c)) 1043*16467b97STreehugger Robot 1044*16467b97STreehugger Robot If oldRoot was null, it's ok, just return newRoot (even if isNil). 1045*16467b97STreehugger Robot 1046*16467b97STreehugger Robot old=null, new=r yields r 1047*16467b97STreehugger Robot old=null, new=^(nil r) yields ^(nil r) 1048*16467b97STreehugger Robot 1049*16467b97STreehugger Robot Return newRoot. Throw an exception if newRoot is not a 1050*16467b97STreehugger Robot simple node or nil root with a single child node--it must be a root 1051*16467b97STreehugger Robot node. If newRoot is ^(nil x) return x as newRoot. 1052*16467b97STreehugger Robot 1053*16467b97STreehugger Robot Be advised that it's ok for newRoot to point at oldRoot's 1054*16467b97STreehugger Robot children; i.e., you don't have to copy the list. We are 1055*16467b97STreehugger Robot constructing these nodes so we should have this control for 1056*16467b97STreehugger Robot efficiency. 1057*16467b97STreehugger Robot """ 1058*16467b97STreehugger Robot 1059*16467b97STreehugger Robot if isinstance(newRoot, Token): 1060*16467b97STreehugger Robot newRoot = self.create(newRoot) 1061*16467b97STreehugger Robot 1062*16467b97STreehugger Robot if oldRoot is None: 1063*16467b97STreehugger Robot return newRoot 1064*16467b97STreehugger Robot 1065*16467b97STreehugger Robot if not isinstance(newRoot, CommonTree): 1066*16467b97STreehugger Robot newRoot = self.createWithPayload(newRoot) 1067*16467b97STreehugger Robot 1068*16467b97STreehugger Robot # handle ^(nil real-node) 1069*16467b97STreehugger Robot if newRoot.isNil(): 1070*16467b97STreehugger Robot nc = newRoot.getChildCount() 1071*16467b97STreehugger Robot if nc == 1: 1072*16467b97STreehugger Robot newRoot = newRoot.getChild(0) 1073*16467b97STreehugger Robot 1074*16467b97STreehugger Robot elif nc > 1: 1075*16467b97STreehugger Robot # TODO: make tree run time exceptions hierarchy 1076*16467b97STreehugger Robot raise RuntimeError("more than one node as root") 1077*16467b97STreehugger Robot 1078*16467b97STreehugger Robot # add oldRoot to newRoot; addChild takes care of case where oldRoot 1079*16467b97STreehugger Robot # is a flat list (i.e., nil-rooted tree). All children of oldRoot 1080*16467b97STreehugger Robot # are added to newRoot. 1081*16467b97STreehugger Robot newRoot.addChild(oldRoot) 1082*16467b97STreehugger Robot return newRoot 1083*16467b97STreehugger Robot 1084*16467b97STreehugger Robot 1085*16467b97STreehugger Robot def rulePostProcessing(self, root): 1086*16467b97STreehugger Robot """Transform ^(nil x) to x and nil to null""" 1087*16467b97STreehugger Robot 1088*16467b97STreehugger Robot if root is not None and root.isNil(): 1089*16467b97STreehugger Robot if root.getChildCount() == 0: 1090*16467b97STreehugger Robot root = None 1091*16467b97STreehugger Robot 1092*16467b97STreehugger Robot elif root.getChildCount() == 1: 1093*16467b97STreehugger Robot root = root.getChild(0) 1094*16467b97STreehugger Robot # whoever invokes rule will set parent and child index 1095*16467b97STreehugger Robot root.setParent(None) 1096*16467b97STreehugger Robot root.setChildIndex(-1) 1097*16467b97STreehugger Robot 1098*16467b97STreehugger Robot return root 1099*16467b97STreehugger Robot 1100*16467b97STreehugger Robot 1101*16467b97STreehugger Robot def createFromToken(self, tokenType, fromToken, text=None): 1102*16467b97STreehugger Robot if fromToken is None: 1103*16467b97STreehugger Robot return self.createFromType(tokenType, text) 1104*16467b97STreehugger Robot 1105*16467b97STreehugger Robot assert isinstance(tokenType, int), type(tokenType).__name__ 1106*16467b97STreehugger Robot assert isinstance(fromToken, Token), type(fromToken).__name__ 1107*16467b97STreehugger Robot assert text is None or isinstance(text, str), type(text).__name__ 1108*16467b97STreehugger Robot 1109*16467b97STreehugger Robot fromToken = self.createToken(fromToken) 1110*16467b97STreehugger Robot fromToken.type = tokenType 1111*16467b97STreehugger Robot if text is not None: 1112*16467b97STreehugger Robot fromToken.text = text 1113*16467b97STreehugger Robot t = self.createWithPayload(fromToken) 1114*16467b97STreehugger Robot return t 1115*16467b97STreehugger Robot 1116*16467b97STreehugger Robot 1117*16467b97STreehugger Robot def createFromType(self, tokenType, text): 1118*16467b97STreehugger Robot assert isinstance(tokenType, int), type(tokenType).__name__ 1119*16467b97STreehugger Robot assert isinstance(text, str) or text is None, type(text).__name__ 1120*16467b97STreehugger Robot 1121*16467b97STreehugger Robot fromToken = self.createToken(tokenType=tokenType, text=text) 1122*16467b97STreehugger Robot t = self.createWithPayload(fromToken) 1123*16467b97STreehugger Robot return t 1124*16467b97STreehugger Robot 1125*16467b97STreehugger Robot 1126*16467b97STreehugger Robot def getType(self, t): 1127*16467b97STreehugger Robot return t.getType() 1128*16467b97STreehugger Robot 1129*16467b97STreehugger Robot 1130*16467b97STreehugger Robot def setType(self, t, type): 1131*16467b97STreehugger Robot raise RuntimeError("don't know enough about Tree node") 1132*16467b97STreehugger Robot 1133*16467b97STreehugger Robot 1134*16467b97STreehugger Robot def getText(self, t): 1135*16467b97STreehugger Robot return t.getText() 1136*16467b97STreehugger Robot 1137*16467b97STreehugger Robot 1138*16467b97STreehugger Robot def setText(self, t, text): 1139*16467b97STreehugger Robot raise RuntimeError("don't know enough about Tree node") 1140*16467b97STreehugger Robot 1141*16467b97STreehugger Robot 1142*16467b97STreehugger Robot def getChild(self, t, i): 1143*16467b97STreehugger Robot return t.getChild(i) 1144*16467b97STreehugger Robot 1145*16467b97STreehugger Robot 1146*16467b97STreehugger Robot def setChild(self, t, i, child): 1147*16467b97STreehugger Robot t.setChild(i, child) 1148*16467b97STreehugger Robot 1149*16467b97STreehugger Robot 1150*16467b97STreehugger Robot def deleteChild(self, t, i): 1151*16467b97STreehugger Robot return t.deleteChild(i) 1152*16467b97STreehugger Robot 1153*16467b97STreehugger Robot 1154*16467b97STreehugger Robot def getChildCount(self, t): 1155*16467b97STreehugger Robot return t.getChildCount() 1156*16467b97STreehugger Robot 1157*16467b97STreehugger Robot 1158*16467b97STreehugger Robot def getUniqueID(self, node): 1159*16467b97STreehugger Robot return hash(node) 1160*16467b97STreehugger Robot 1161*16467b97STreehugger Robot 1162*16467b97STreehugger Robot def createToken(self, fromToken=None, tokenType=None, text=None): 1163*16467b97STreehugger Robot """ 1164*16467b97STreehugger Robot Tell me how to create a token for use with imaginary token nodes. 1165*16467b97STreehugger Robot For example, there is probably no input symbol associated with imaginary 1166*16467b97STreehugger Robot token DECL, but you need to create it as a payload or whatever for 1167*16467b97STreehugger Robot the DECL node as in ^(DECL type ID). 1168*16467b97STreehugger Robot 1169*16467b97STreehugger Robot If you care what the token payload objects' type is, you should 1170*16467b97STreehugger Robot override this method and any other createToken variant. 1171*16467b97STreehugger Robot """ 1172*16467b97STreehugger Robot 1173*16467b97STreehugger Robot raise NotImplementedError 1174*16467b97STreehugger Robot 1175*16467b97STreehugger Robot 1176*16467b97STreehugger Robot############################################################################ 1177*16467b97STreehugger Robot# 1178*16467b97STreehugger Robot# common tree implementation 1179*16467b97STreehugger Robot# 1180*16467b97STreehugger Robot# Tree 1181*16467b97STreehugger Robot# \- BaseTree 1182*16467b97STreehugger Robot# \- CommonTree 1183*16467b97STreehugger Robot# \- CommonErrorNode 1184*16467b97STreehugger Robot# 1185*16467b97STreehugger Robot# TreeAdaptor 1186*16467b97STreehugger Robot# \- BaseTreeAdaptor 1187*16467b97STreehugger Robot# \- CommonTreeAdaptor 1188*16467b97STreehugger Robot# 1189*16467b97STreehugger Robot############################################################################ 1190*16467b97STreehugger Robot 1191*16467b97STreehugger Robot 1192*16467b97STreehugger Robotclass CommonTree(BaseTree): 1193*16467b97STreehugger Robot """@brief A tree node that is wrapper for a Token object. 1194*16467b97STreehugger Robot 1195*16467b97STreehugger Robot After 3.0 release 1196*16467b97STreehugger Robot while building tree rewrite stuff, it became clear that computing 1197*16467b97STreehugger Robot parent and child index is very difficult and cumbersome. Better to 1198*16467b97STreehugger Robot spend the space in every tree node. If you don't want these extra 1199*16467b97STreehugger Robot fields, it's easy to cut them out in your own BaseTree subclass. 1200*16467b97STreehugger Robot 1201*16467b97STreehugger Robot """ 1202*16467b97STreehugger Robot 1203*16467b97STreehugger Robot def __init__(self, payload): 1204*16467b97STreehugger Robot BaseTree.__init__(self) 1205*16467b97STreehugger Robot 1206*16467b97STreehugger Robot # What token indexes bracket all tokens associated with this node 1207*16467b97STreehugger Robot # and below? 1208*16467b97STreehugger Robot self.startIndex = -1 1209*16467b97STreehugger Robot self.stopIndex = -1 1210*16467b97STreehugger Robot 1211*16467b97STreehugger Robot # Who is the parent node of this node; if null, implies node is root 1212*16467b97STreehugger Robot self.parent = None 1213*16467b97STreehugger Robot 1214*16467b97STreehugger Robot # What index is this node in the child list? Range: 0..n-1 1215*16467b97STreehugger Robot self.childIndex = -1 1216*16467b97STreehugger Robot 1217*16467b97STreehugger Robot # A single token is the payload 1218*16467b97STreehugger Robot if payload is None: 1219*16467b97STreehugger Robot self.token = None 1220*16467b97STreehugger Robot 1221*16467b97STreehugger Robot elif isinstance(payload, CommonTree): 1222*16467b97STreehugger Robot self.token = payload.token 1223*16467b97STreehugger Robot self.startIndex = payload.startIndex 1224*16467b97STreehugger Robot self.stopIndex = payload.stopIndex 1225*16467b97STreehugger Robot 1226*16467b97STreehugger Robot elif payload is None or isinstance(payload, Token): 1227*16467b97STreehugger Robot self.token = payload 1228*16467b97STreehugger Robot 1229*16467b97STreehugger Robot else: 1230*16467b97STreehugger Robot raise TypeError(type(payload).__name__) 1231*16467b97STreehugger Robot 1232*16467b97STreehugger Robot 1233*16467b97STreehugger Robot 1234*16467b97STreehugger Robot def getToken(self): 1235*16467b97STreehugger Robot return self.token 1236*16467b97STreehugger Robot 1237*16467b97STreehugger Robot 1238*16467b97STreehugger Robot def dupNode(self): 1239*16467b97STreehugger Robot return CommonTree(self) 1240*16467b97STreehugger Robot 1241*16467b97STreehugger Robot 1242*16467b97STreehugger Robot def isNil(self): 1243*16467b97STreehugger Robot return self.token is None 1244*16467b97STreehugger Robot 1245*16467b97STreehugger Robot 1246*16467b97STreehugger Robot def getType(self): 1247*16467b97STreehugger Robot if self.token is None: 1248*16467b97STreehugger Robot return INVALID_TOKEN_TYPE 1249*16467b97STreehugger Robot 1250*16467b97STreehugger Robot return self.token.type 1251*16467b97STreehugger Robot 1252*16467b97STreehugger Robot type = property(getType) 1253*16467b97STreehugger Robot 1254*16467b97STreehugger Robot 1255*16467b97STreehugger Robot def getText(self): 1256*16467b97STreehugger Robot if self.token is None: 1257*16467b97STreehugger Robot return None 1258*16467b97STreehugger Robot 1259*16467b97STreehugger Robot return self.token.text 1260*16467b97STreehugger Robot 1261*16467b97STreehugger Robot text = property(getText) 1262*16467b97STreehugger Robot 1263*16467b97STreehugger Robot 1264*16467b97STreehugger Robot def getLine(self): 1265*16467b97STreehugger Robot if self.token is None or self.token.line == 0: 1266*16467b97STreehugger Robot if self.getChildCount(): 1267*16467b97STreehugger Robot return self.getChild(0).getLine() 1268*16467b97STreehugger Robot else: 1269*16467b97STreehugger Robot return 0 1270*16467b97STreehugger Robot 1271*16467b97STreehugger Robot return self.token.line 1272*16467b97STreehugger Robot 1273*16467b97STreehugger Robot line = property(getLine) 1274*16467b97STreehugger Robot 1275*16467b97STreehugger Robot 1276*16467b97STreehugger Robot def getCharPositionInLine(self): 1277*16467b97STreehugger Robot if self.token is None or self.token.charPositionInLine == -1: 1278*16467b97STreehugger Robot if self.getChildCount(): 1279*16467b97STreehugger Robot return self.getChild(0).getCharPositionInLine() 1280*16467b97STreehugger Robot else: 1281*16467b97STreehugger Robot return 0 1282*16467b97STreehugger Robot 1283*16467b97STreehugger Robot else: 1284*16467b97STreehugger Robot return self.token.charPositionInLine 1285*16467b97STreehugger Robot 1286*16467b97STreehugger Robot charPositionInLine = property(getCharPositionInLine) 1287*16467b97STreehugger Robot 1288*16467b97STreehugger Robot 1289*16467b97STreehugger Robot def getTokenStartIndex(self): 1290*16467b97STreehugger Robot if self.startIndex == -1 and self.token: 1291*16467b97STreehugger Robot return self.token.index 1292*16467b97STreehugger Robot 1293*16467b97STreehugger Robot return self.startIndex 1294*16467b97STreehugger Robot 1295*16467b97STreehugger Robot def setTokenStartIndex(self, index): 1296*16467b97STreehugger Robot self.startIndex = index 1297*16467b97STreehugger Robot 1298*16467b97STreehugger Robot tokenStartIndex = property(getTokenStartIndex, setTokenStartIndex) 1299*16467b97STreehugger Robot 1300*16467b97STreehugger Robot 1301*16467b97STreehugger Robot def getTokenStopIndex(self): 1302*16467b97STreehugger Robot if self.stopIndex == -1 and self.token: 1303*16467b97STreehugger Robot return self.token.index 1304*16467b97STreehugger Robot 1305*16467b97STreehugger Robot return self.stopIndex 1306*16467b97STreehugger Robot 1307*16467b97STreehugger Robot def setTokenStopIndex(self, index): 1308*16467b97STreehugger Robot self.stopIndex = index 1309*16467b97STreehugger Robot 1310*16467b97STreehugger Robot tokenStopIndex = property(getTokenStopIndex, setTokenStopIndex) 1311*16467b97STreehugger Robot 1312*16467b97STreehugger Robot 1313*16467b97STreehugger Robot def setUnknownTokenBoundaries(self): 1314*16467b97STreehugger Robot """For every node in this subtree, make sure it's start/stop token's 1315*16467b97STreehugger Robot are set. Walk depth first, visit bottom up. Only updates nodes 1316*16467b97STreehugger Robot with at least one token index < 0. 1317*16467b97STreehugger Robot """ 1318*16467b97STreehugger Robot 1319*16467b97STreehugger Robot if self.children is None: 1320*16467b97STreehugger Robot if self.startIndex < 0 or self.stopIndex < 0: 1321*16467b97STreehugger Robot self.startIndex = self.stopIndex = self.token.index 1322*16467b97STreehugger Robot 1323*16467b97STreehugger Robot return 1324*16467b97STreehugger Robot 1325*16467b97STreehugger Robot for child in self.children: 1326*16467b97STreehugger Robot child.setUnknownTokenBoundaries() 1327*16467b97STreehugger Robot 1328*16467b97STreehugger Robot if self.startIndex >= 0 and self.stopIndex >= 0: 1329*16467b97STreehugger Robot # already set 1330*16467b97STreehugger Robot return 1331*16467b97STreehugger Robot 1332*16467b97STreehugger Robot if self.children: 1333*16467b97STreehugger Robot firstChild = self.children[0] 1334*16467b97STreehugger Robot lastChild = self.children[-1] 1335*16467b97STreehugger Robot self.startIndex = firstChild.getTokenStartIndex() 1336*16467b97STreehugger Robot self.stopIndex = lastChild.getTokenStopIndex() 1337*16467b97STreehugger Robot 1338*16467b97STreehugger Robot 1339*16467b97STreehugger Robot def getChildIndex(self): 1340*16467b97STreehugger Robot #FIXME: mark as deprecated 1341*16467b97STreehugger Robot return self.childIndex 1342*16467b97STreehugger Robot 1343*16467b97STreehugger Robot 1344*16467b97STreehugger Robot def setChildIndex(self, idx): 1345*16467b97STreehugger Robot #FIXME: mark as deprecated 1346*16467b97STreehugger Robot self.childIndex = idx 1347*16467b97STreehugger Robot 1348*16467b97STreehugger Robot 1349*16467b97STreehugger Robot def getParent(self): 1350*16467b97STreehugger Robot #FIXME: mark as deprecated 1351*16467b97STreehugger Robot return self.parent 1352*16467b97STreehugger Robot 1353*16467b97STreehugger Robot 1354*16467b97STreehugger Robot def setParent(self, t): 1355*16467b97STreehugger Robot #FIXME: mark as deprecated 1356*16467b97STreehugger Robot self.parent = t 1357*16467b97STreehugger Robot 1358*16467b97STreehugger Robot 1359*16467b97STreehugger Robot def toString(self): 1360*16467b97STreehugger Robot if self.isNil(): 1361*16467b97STreehugger Robot return "nil" 1362*16467b97STreehugger Robot 1363*16467b97STreehugger Robot if self.getType() == INVALID_TOKEN_TYPE: 1364*16467b97STreehugger Robot return "<errornode>" 1365*16467b97STreehugger Robot 1366*16467b97STreehugger Robot return self.token.text 1367*16467b97STreehugger Robot 1368*16467b97STreehugger Robot __str__ = toString 1369*16467b97STreehugger Robot 1370*16467b97STreehugger Robot 1371*16467b97STreehugger Robot 1372*16467b97STreehugger Robot def toStringTree(self): 1373*16467b97STreehugger Robot if not self.children: 1374*16467b97STreehugger Robot return self.toString() 1375*16467b97STreehugger Robot 1376*16467b97STreehugger Robot ret = '' 1377*16467b97STreehugger Robot if not self.isNil(): 1378*16467b97STreehugger Robot ret += '({!s} '.format(self) 1379*16467b97STreehugger Robot 1380*16467b97STreehugger Robot ret += ' '.join([child.toStringTree() for child in self.children]) 1381*16467b97STreehugger Robot 1382*16467b97STreehugger Robot if not self.isNil(): 1383*16467b97STreehugger Robot ret += ')' 1384*16467b97STreehugger Robot 1385*16467b97STreehugger Robot return ret 1386*16467b97STreehugger Robot 1387*16467b97STreehugger Robot 1388*16467b97STreehugger RobotINVALID_NODE = CommonTree(INVALID_TOKEN) 1389*16467b97STreehugger Robot 1390*16467b97STreehugger Robot 1391*16467b97STreehugger Robotclass CommonErrorNode(CommonTree): 1392*16467b97STreehugger Robot """A node representing erroneous token range in token stream""" 1393*16467b97STreehugger Robot 1394*16467b97STreehugger Robot def __init__(self, input, start, stop, exc): 1395*16467b97STreehugger Robot CommonTree.__init__(self, None) 1396*16467b97STreehugger Robot 1397*16467b97STreehugger Robot if (stop is None or (stop.index < start.index and stop.type != EOF)): 1398*16467b97STreehugger Robot # sometimes resync does not consume a token (when LT(1) is 1399*16467b97STreehugger Robot # in follow set. So, stop will be 1 to left to start. adjust. 1400*16467b97STreehugger Robot # Also handle case where start is the first token and no token 1401*16467b97STreehugger Robot # is consumed during recovery; LT(-1) will return null. 1402*16467b97STreehugger Robot stop = start 1403*16467b97STreehugger Robot 1404*16467b97STreehugger Robot self.input = input 1405*16467b97STreehugger Robot self.start = start 1406*16467b97STreehugger Robot self.stop = stop 1407*16467b97STreehugger Robot self.trappedException = exc 1408*16467b97STreehugger Robot 1409*16467b97STreehugger Robot 1410*16467b97STreehugger Robot def isNil(self): 1411*16467b97STreehugger Robot return False 1412*16467b97STreehugger Robot 1413*16467b97STreehugger Robot 1414*16467b97STreehugger Robot def getType(self): 1415*16467b97STreehugger Robot return INVALID_TOKEN_TYPE 1416*16467b97STreehugger Robot 1417*16467b97STreehugger Robot 1418*16467b97STreehugger Robot def getText(self): 1419*16467b97STreehugger Robot if isinstance(self.start, Token): 1420*16467b97STreehugger Robot i = self.start.index 1421*16467b97STreehugger Robot j = self.stop.index 1422*16467b97STreehugger Robot if self.stop.type == EOF: 1423*16467b97STreehugger Robot j = self.input.size() 1424*16467b97STreehugger Robot 1425*16467b97STreehugger Robot badText = self.input.toString(i, j) 1426*16467b97STreehugger Robot 1427*16467b97STreehugger Robot elif isinstance(self.start, Tree): 1428*16467b97STreehugger Robot badText = self.input.toString(self.start, self.stop) 1429*16467b97STreehugger Robot 1430*16467b97STreehugger Robot else: 1431*16467b97STreehugger Robot # people should subclass if they alter the tree type so this 1432*16467b97STreehugger Robot # next one is for sure correct. 1433*16467b97STreehugger Robot badText = "<unknown>" 1434*16467b97STreehugger Robot 1435*16467b97STreehugger Robot return badText 1436*16467b97STreehugger Robot 1437*16467b97STreehugger Robot 1438*16467b97STreehugger Robot def toString(self): 1439*16467b97STreehugger Robot if isinstance(self.trappedException, MissingTokenException): 1440*16467b97STreehugger Robot return ("<missing type: " 1441*16467b97STreehugger Robot + str(self.trappedException.getMissingType()) 1442*16467b97STreehugger Robot + ">") 1443*16467b97STreehugger Robot 1444*16467b97STreehugger Robot elif isinstance(self.trappedException, UnwantedTokenException): 1445*16467b97STreehugger Robot return ("<extraneous: " 1446*16467b97STreehugger Robot + str(self.trappedException.getUnexpectedToken()) 1447*16467b97STreehugger Robot + ", resync=" + self.getText() + ">") 1448*16467b97STreehugger Robot 1449*16467b97STreehugger Robot elif isinstance(self.trappedException, MismatchedTokenException): 1450*16467b97STreehugger Robot return ("<mismatched token: " 1451*16467b97STreehugger Robot + str(self.trappedException.token) 1452*16467b97STreehugger Robot + ", resync=" + self.getText() + ">") 1453*16467b97STreehugger Robot 1454*16467b97STreehugger Robot elif isinstance(self.trappedException, NoViableAltException): 1455*16467b97STreehugger Robot return ("<unexpected: " 1456*16467b97STreehugger Robot + str(self.trappedException.token) 1457*16467b97STreehugger Robot + ", resync=" + self.getText() + ">") 1458*16467b97STreehugger Robot 1459*16467b97STreehugger Robot return "<error: "+self.getText()+">" 1460*16467b97STreehugger Robot 1461*16467b97STreehugger Robot __str__ = toString 1462*16467b97STreehugger Robot 1463*16467b97STreehugger Robot 1464*16467b97STreehugger Robotclass CommonTreeAdaptor(BaseTreeAdaptor): 1465*16467b97STreehugger Robot """ 1466*16467b97STreehugger Robot @brief A TreeAdaptor that works with any Tree implementation. 1467*16467b97STreehugger Robot 1468*16467b97STreehugger Robot It provides 1469*16467b97STreehugger Robot really just factory methods; all the work is done by BaseTreeAdaptor. 1470*16467b97STreehugger Robot If you would like to have different tokens created than ClassicToken 1471*16467b97STreehugger Robot objects, you need to override this and then set the parser tree adaptor to 1472*16467b97STreehugger Robot use your subclass. 1473*16467b97STreehugger Robot 1474*16467b97STreehugger Robot To get your parser to build nodes of a different type, override 1475*16467b97STreehugger Robot create(Token), errorNode(), and to be safe, YourTreeClass.dupNode(). 1476*16467b97STreehugger Robot dupNode is called to duplicate nodes during rewrite operations. 1477*16467b97STreehugger Robot """ 1478*16467b97STreehugger Robot 1479*16467b97STreehugger Robot def dupNode(self, treeNode): 1480*16467b97STreehugger Robot """ 1481*16467b97STreehugger Robot Duplicate a node. This is part of the factory; 1482*16467b97STreehugger Robot override if you want another kind of node to be built. 1483*16467b97STreehugger Robot 1484*16467b97STreehugger Robot I could use reflection to prevent having to override this 1485*16467b97STreehugger Robot but reflection is slow. 1486*16467b97STreehugger Robot """ 1487*16467b97STreehugger Robot 1488*16467b97STreehugger Robot if treeNode is None: 1489*16467b97STreehugger Robot return None 1490*16467b97STreehugger Robot 1491*16467b97STreehugger Robot return treeNode.dupNode() 1492*16467b97STreehugger Robot 1493*16467b97STreehugger Robot 1494*16467b97STreehugger Robot def createWithPayload(self, payload): 1495*16467b97STreehugger Robot return CommonTree(payload) 1496*16467b97STreehugger Robot 1497*16467b97STreehugger Robot 1498*16467b97STreehugger Robot def createToken(self, fromToken=None, tokenType=None, text=None): 1499*16467b97STreehugger Robot """ 1500*16467b97STreehugger Robot Tell me how to create a token for use with imaginary token nodes. 1501*16467b97STreehugger Robot For example, there is probably no input symbol associated with imaginary 1502*16467b97STreehugger Robot token DECL, but you need to create it as a payload or whatever for 1503*16467b97STreehugger Robot the DECL node as in ^(DECL type ID). 1504*16467b97STreehugger Robot 1505*16467b97STreehugger Robot If you care what the token payload objects' type is, you should 1506*16467b97STreehugger Robot override this method and any other createToken variant. 1507*16467b97STreehugger Robot """ 1508*16467b97STreehugger Robot 1509*16467b97STreehugger Robot if fromToken is not None: 1510*16467b97STreehugger Robot return CommonToken(oldToken=fromToken) 1511*16467b97STreehugger Robot 1512*16467b97STreehugger Robot return CommonToken(type=tokenType, text=text) 1513*16467b97STreehugger Robot 1514*16467b97STreehugger Robot 1515*16467b97STreehugger Robot def setTokenBoundaries(self, t, startToken, stopToken): 1516*16467b97STreehugger Robot """ 1517*16467b97STreehugger Robot Track start/stop token for subtree root created for a rule. 1518*16467b97STreehugger Robot Only works with Tree nodes. For rules that match nothing, 1519*16467b97STreehugger Robot seems like this will yield start=i and stop=i-1 in a nil node. 1520*16467b97STreehugger Robot Might be useful info so I'll not force to be i..i. 1521*16467b97STreehugger Robot """ 1522*16467b97STreehugger Robot 1523*16467b97STreehugger Robot if t is None: 1524*16467b97STreehugger Robot return 1525*16467b97STreehugger Robot 1526*16467b97STreehugger Robot start = 0 1527*16467b97STreehugger Robot stop = 0 1528*16467b97STreehugger Robot 1529*16467b97STreehugger Robot if startToken is not None: 1530*16467b97STreehugger Robot start = startToken.index 1531*16467b97STreehugger Robot 1532*16467b97STreehugger Robot if stopToken is not None: 1533*16467b97STreehugger Robot stop = stopToken.index 1534*16467b97STreehugger Robot 1535*16467b97STreehugger Robot t.setTokenStartIndex(start) 1536*16467b97STreehugger Robot t.setTokenStopIndex(stop) 1537*16467b97STreehugger Robot 1538*16467b97STreehugger Robot 1539*16467b97STreehugger Robot def getTokenStartIndex(self, t): 1540*16467b97STreehugger Robot if t is None: 1541*16467b97STreehugger Robot return -1 1542*16467b97STreehugger Robot return t.getTokenStartIndex() 1543*16467b97STreehugger Robot 1544*16467b97STreehugger Robot 1545*16467b97STreehugger Robot def getTokenStopIndex(self, t): 1546*16467b97STreehugger Robot if t is None: 1547*16467b97STreehugger Robot return -1 1548*16467b97STreehugger Robot return t.getTokenStopIndex() 1549*16467b97STreehugger Robot 1550*16467b97STreehugger Robot 1551*16467b97STreehugger Robot def getText(self, t): 1552*16467b97STreehugger Robot if t is None: 1553*16467b97STreehugger Robot return None 1554*16467b97STreehugger Robot return t.text 1555*16467b97STreehugger Robot 1556*16467b97STreehugger Robot 1557*16467b97STreehugger Robot def getType(self, t): 1558*16467b97STreehugger Robot if t is None: 1559*16467b97STreehugger Robot return INVALID_TOKEN_TYPE 1560*16467b97STreehugger Robot 1561*16467b97STreehugger Robot return t.type 1562*16467b97STreehugger Robot 1563*16467b97STreehugger Robot 1564*16467b97STreehugger Robot def getToken(self, t): 1565*16467b97STreehugger Robot """ 1566*16467b97STreehugger Robot What is the Token associated with this node? If 1567*16467b97STreehugger Robot you are not using CommonTree, then you must 1568*16467b97STreehugger Robot override this in your own adaptor. 1569*16467b97STreehugger Robot """ 1570*16467b97STreehugger Robot 1571*16467b97STreehugger Robot if isinstance(t, CommonTree): 1572*16467b97STreehugger Robot return t.getToken() 1573*16467b97STreehugger Robot 1574*16467b97STreehugger Robot return None # no idea what to do 1575*16467b97STreehugger Robot 1576*16467b97STreehugger Robot 1577*16467b97STreehugger Robot def getChild(self, t, i): 1578*16467b97STreehugger Robot if t is None: 1579*16467b97STreehugger Robot return None 1580*16467b97STreehugger Robot return t.getChild(i) 1581*16467b97STreehugger Robot 1582*16467b97STreehugger Robot 1583*16467b97STreehugger Robot def getChildCount(self, t): 1584*16467b97STreehugger Robot if t is None: 1585*16467b97STreehugger Robot return 0 1586*16467b97STreehugger Robot return t.getChildCount() 1587*16467b97STreehugger Robot 1588*16467b97STreehugger Robot 1589*16467b97STreehugger Robot def getParent(self, t): 1590*16467b97STreehugger Robot return t.getParent() 1591*16467b97STreehugger Robot 1592*16467b97STreehugger Robot 1593*16467b97STreehugger Robot def setParent(self, t, parent): 1594*16467b97STreehugger Robot t.setParent(parent) 1595*16467b97STreehugger Robot 1596*16467b97STreehugger Robot 1597*16467b97STreehugger Robot def getChildIndex(self, t): 1598*16467b97STreehugger Robot if t is None: 1599*16467b97STreehugger Robot return 0 1600*16467b97STreehugger Robot return t.getChildIndex() 1601*16467b97STreehugger Robot 1602*16467b97STreehugger Robot 1603*16467b97STreehugger Robot def setChildIndex(self, t, index): 1604*16467b97STreehugger Robot t.setChildIndex(index) 1605*16467b97STreehugger Robot 1606*16467b97STreehugger Robot 1607*16467b97STreehugger Robot def replaceChildren(self, parent, startChildIndex, stopChildIndex, t): 1608*16467b97STreehugger Robot if parent is not None: 1609*16467b97STreehugger Robot parent.replaceChildren(startChildIndex, stopChildIndex, t) 1610*16467b97STreehugger Robot 1611*16467b97STreehugger Robot 1612*16467b97STreehugger Robot############################################################################ 1613*16467b97STreehugger Robot# 1614*16467b97STreehugger Robot# streams 1615*16467b97STreehugger Robot# 1616*16467b97STreehugger Robot# TreeNodeStream 1617*16467b97STreehugger Robot# \- BaseTree 1618*16467b97STreehugger Robot# \- CommonTree 1619*16467b97STreehugger Robot# 1620*16467b97STreehugger Robot# TreeAdaptor 1621*16467b97STreehugger Robot# \- BaseTreeAdaptor 1622*16467b97STreehugger Robot# \- CommonTreeAdaptor 1623*16467b97STreehugger Robot# 1624*16467b97STreehugger Robot############################################################################ 1625*16467b97STreehugger Robot 1626*16467b97STreehugger Robot 1627*16467b97STreehugger Robot 1628*16467b97STreehugger Robotclass TreeNodeStream(IntStream): 1629*16467b97STreehugger Robot """@brief A stream of tree nodes 1630*16467b97STreehugger Robot 1631*16467b97STreehugger Robot It accessing nodes from a tree of some kind. 1632*16467b97STreehugger Robot """ 1633*16467b97STreehugger Robot 1634*16467b97STreehugger Robot # TreeNodeStream is abstract, no need to complain about not implemented 1635*16467b97STreehugger Robot # abstract methods 1636*16467b97STreehugger Robot # pylint: disable-msg=W0223 1637*16467b97STreehugger Robot 1638*16467b97STreehugger Robot def get(self, i): 1639*16467b97STreehugger Robot """Get a tree node at an absolute index i; 0..n-1. 1640*16467b97STreehugger Robot If you don't want to buffer up nodes, then this method makes no 1641*16467b97STreehugger Robot sense for you. 1642*16467b97STreehugger Robot """ 1643*16467b97STreehugger Robot 1644*16467b97STreehugger Robot raise NotImplementedError 1645*16467b97STreehugger Robot 1646*16467b97STreehugger Robot 1647*16467b97STreehugger Robot def LT(self, k): 1648*16467b97STreehugger Robot """ 1649*16467b97STreehugger Robot Get tree node at current input pointer + i ahead where i=1 is next node. 1650*16467b97STreehugger Robot i<0 indicates nodes in the past. So LT(-1) is previous node, but 1651*16467b97STreehugger Robot implementations are not required to provide results for k < -1. 1652*16467b97STreehugger Robot LT(0) is undefined. For i>=n, return null. 1653*16467b97STreehugger Robot Return null for LT(0) and any index that results in an absolute address 1654*16467b97STreehugger Robot that is negative. 1655*16467b97STreehugger Robot 1656*16467b97STreehugger Robot This is analogus to the LT() method of the TokenStream, but this 1657*16467b97STreehugger Robot returns a tree node instead of a token. Makes code gen identical 1658*16467b97STreehugger Robot for both parser and tree grammars. :) 1659*16467b97STreehugger Robot """ 1660*16467b97STreehugger Robot 1661*16467b97STreehugger Robot raise NotImplementedError 1662*16467b97STreehugger Robot 1663*16467b97STreehugger Robot 1664*16467b97STreehugger Robot def getTreeSource(self): 1665*16467b97STreehugger Robot """ 1666*16467b97STreehugger Robot Where is this stream pulling nodes from? This is not the name, but 1667*16467b97STreehugger Robot the object that provides node objects. 1668*16467b97STreehugger Robot """ 1669*16467b97STreehugger Robot 1670*16467b97STreehugger Robot raise NotImplementedError 1671*16467b97STreehugger Robot 1672*16467b97STreehugger Robot 1673*16467b97STreehugger Robot def getTokenStream(self): 1674*16467b97STreehugger Robot """ 1675*16467b97STreehugger Robot If the tree associated with this stream was created from a TokenStream, 1676*16467b97STreehugger Robot you can specify it here. Used to do rule $text attribute in tree 1677*16467b97STreehugger Robot parser. Optional unless you use tree parser rule text attribute 1678*16467b97STreehugger Robot or output=template and rewrite=true options. 1679*16467b97STreehugger Robot """ 1680*16467b97STreehugger Robot 1681*16467b97STreehugger Robot raise NotImplementedError 1682*16467b97STreehugger Robot 1683*16467b97STreehugger Robot 1684*16467b97STreehugger Robot def getTreeAdaptor(self): 1685*16467b97STreehugger Robot """ 1686*16467b97STreehugger Robot What adaptor can tell me how to interpret/navigate nodes and 1687*16467b97STreehugger Robot trees. E.g., get text of a node. 1688*16467b97STreehugger Robot """ 1689*16467b97STreehugger Robot 1690*16467b97STreehugger Robot raise NotImplementedError 1691*16467b97STreehugger Robot 1692*16467b97STreehugger Robot 1693*16467b97STreehugger Robot def setUniqueNavigationNodes(self, uniqueNavigationNodes): 1694*16467b97STreehugger Robot """ 1695*16467b97STreehugger Robot As we flatten the tree, we use UP, DOWN nodes to represent 1696*16467b97STreehugger Robot the tree structure. When debugging we need unique nodes 1697*16467b97STreehugger Robot so we have to instantiate new ones. When doing normal tree 1698*16467b97STreehugger Robot parsing, it's slow and a waste of memory to create unique 1699*16467b97STreehugger Robot navigation nodes. Default should be false; 1700*16467b97STreehugger Robot """ 1701*16467b97STreehugger Robot 1702*16467b97STreehugger Robot raise NotImplementedError 1703*16467b97STreehugger Robot 1704*16467b97STreehugger Robot 1705*16467b97STreehugger Robot def reset(self): 1706*16467b97STreehugger Robot """ 1707*16467b97STreehugger Robot Reset the tree node stream in such a way that it acts like 1708*16467b97STreehugger Robot a freshly constructed stream. 1709*16467b97STreehugger Robot """ 1710*16467b97STreehugger Robot 1711*16467b97STreehugger Robot raise NotImplementedError 1712*16467b97STreehugger Robot 1713*16467b97STreehugger Robot 1714*16467b97STreehugger Robot def toString(self, start, stop): 1715*16467b97STreehugger Robot """ 1716*16467b97STreehugger Robot Return the text of all nodes from start to stop, inclusive. 1717*16467b97STreehugger Robot If the stream does not buffer all the nodes then it can still 1718*16467b97STreehugger Robot walk recursively from start until stop. You can always return 1719*16467b97STreehugger Robot null or "" too, but users should not access $ruleLabel.text in 1720*16467b97STreehugger Robot an action of course in that case. 1721*16467b97STreehugger Robot """ 1722*16467b97STreehugger Robot 1723*16467b97STreehugger Robot raise NotImplementedError 1724*16467b97STreehugger Robot 1725*16467b97STreehugger Robot 1726*16467b97STreehugger Robot # REWRITING TREES (used by tree parser) 1727*16467b97STreehugger Robot def replaceChildren(self, parent, startChildIndex, stopChildIndex, t): 1728*16467b97STreehugger Robot """ 1729*16467b97STreehugger Robot Replace from start to stop child index of parent with t, which might 1730*16467b97STreehugger Robot be a list. Number of children may be different 1731*16467b97STreehugger Robot after this call. The stream is notified because it is walking the 1732*16467b97STreehugger Robot tree and might need to know you are monkeying with the underlying 1733*16467b97STreehugger Robot tree. Also, it might be able to modify the node stream to avoid 1734*16467b97STreehugger Robot restreaming for future phases. 1735*16467b97STreehugger Robot 1736*16467b97STreehugger Robot If parent is null, don't do anything; must be at root of overall tree. 1737*16467b97STreehugger Robot Can't replace whatever points to the parent externally. Do nothing. 1738*16467b97STreehugger Robot """ 1739*16467b97STreehugger Robot 1740*16467b97STreehugger Robot raise NotImplementedError 1741*16467b97STreehugger Robot 1742*16467b97STreehugger Robot 1743*16467b97STreehugger Robotclass CommonTreeNodeStream(TreeNodeStream): 1744*16467b97STreehugger Robot """@brief A buffered stream of tree nodes. 1745*16467b97STreehugger Robot 1746*16467b97STreehugger Robot Nodes can be from a tree of ANY kind. 1747*16467b97STreehugger Robot 1748*16467b97STreehugger Robot This node stream sucks all nodes out of the tree specified in 1749*16467b97STreehugger Robot the constructor during construction and makes pointers into 1750*16467b97STreehugger Robot the tree using an array of Object pointers. The stream necessarily 1751*16467b97STreehugger Robot includes pointers to DOWN and UP and EOF nodes. 1752*16467b97STreehugger Robot 1753*16467b97STreehugger Robot This stream knows how to mark/release for backtracking. 1754*16467b97STreehugger Robot 1755*16467b97STreehugger Robot This stream is most suitable for tree interpreters that need to 1756*16467b97STreehugger Robot jump around a lot or for tree parsers requiring speed (at cost of memory). 1757*16467b97STreehugger Robot There is some duplicated functionality here with UnBufferedTreeNodeStream 1758*16467b97STreehugger Robot but just in bookkeeping, not tree walking etc... 1759*16467b97STreehugger Robot 1760*16467b97STreehugger Robot @see UnBufferedTreeNodeStream 1761*16467b97STreehugger Robot """ 1762*16467b97STreehugger Robot 1763*16467b97STreehugger Robot def __init__(self, *args): 1764*16467b97STreehugger Robot TreeNodeStream.__init__(self) 1765*16467b97STreehugger Robot 1766*16467b97STreehugger Robot if len(args) == 1: 1767*16467b97STreehugger Robot adaptor = CommonTreeAdaptor() 1768*16467b97STreehugger Robot tree = args[0] 1769*16467b97STreehugger Robot 1770*16467b97STreehugger Robot nodes = None 1771*16467b97STreehugger Robot down = None 1772*16467b97STreehugger Robot up = None 1773*16467b97STreehugger Robot eof = None 1774*16467b97STreehugger Robot 1775*16467b97STreehugger Robot elif len(args) == 2: 1776*16467b97STreehugger Robot adaptor = args[0] 1777*16467b97STreehugger Robot tree = args[1] 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) == 3: 1785*16467b97STreehugger Robot parent = args[0] 1786*16467b97STreehugger Robot start = args[1] 1787*16467b97STreehugger Robot stop = args[2] 1788*16467b97STreehugger Robot 1789*16467b97STreehugger Robot adaptor = parent.adaptor 1790*16467b97STreehugger Robot tree = parent.root 1791*16467b97STreehugger Robot 1792*16467b97STreehugger Robot nodes = parent.nodes[start:stop] 1793*16467b97STreehugger Robot down = parent.down 1794*16467b97STreehugger Robot up = parent.up 1795*16467b97STreehugger Robot eof = parent.eof 1796*16467b97STreehugger Robot 1797*16467b97STreehugger Robot else: 1798*16467b97STreehugger Robot raise TypeError("Invalid arguments") 1799*16467b97STreehugger Robot 1800*16467b97STreehugger Robot # all these navigation nodes are shared and hence they 1801*16467b97STreehugger Robot # cannot contain any line/column info 1802*16467b97STreehugger Robot if down is not None: 1803*16467b97STreehugger Robot self.down = down 1804*16467b97STreehugger Robot else: 1805*16467b97STreehugger Robot self.down = adaptor.createFromType(DOWN, "DOWN") 1806*16467b97STreehugger Robot 1807*16467b97STreehugger Robot if up is not None: 1808*16467b97STreehugger Robot self.up = up 1809*16467b97STreehugger Robot else: 1810*16467b97STreehugger Robot self.up = adaptor.createFromType(UP, "UP") 1811*16467b97STreehugger Robot 1812*16467b97STreehugger Robot if eof is not None: 1813*16467b97STreehugger Robot self.eof = eof 1814*16467b97STreehugger Robot else: 1815*16467b97STreehugger Robot self.eof = adaptor.createFromType(EOF, "EOF") 1816*16467b97STreehugger Robot 1817*16467b97STreehugger Robot # The complete mapping from stream index to tree node. 1818*16467b97STreehugger Robot # This buffer includes pointers to DOWN, UP, and EOF nodes. 1819*16467b97STreehugger Robot # It is built upon ctor invocation. The elements are type 1820*16467b97STreehugger Robot # Object as we don't what the trees look like. 1821*16467b97STreehugger Robot 1822*16467b97STreehugger Robot # Load upon first need of the buffer so we can set token types 1823*16467b97STreehugger Robot # of interest for reverseIndexing. Slows us down a wee bit to 1824*16467b97STreehugger Robot # do all of the if p==-1 testing everywhere though. 1825*16467b97STreehugger Robot if nodes is not None: 1826*16467b97STreehugger Robot self.nodes = nodes 1827*16467b97STreehugger Robot else: 1828*16467b97STreehugger Robot self.nodes = [] 1829*16467b97STreehugger Robot 1830*16467b97STreehugger Robot # Pull nodes from which tree? 1831*16467b97STreehugger Robot self.root = tree 1832*16467b97STreehugger Robot 1833*16467b97STreehugger Robot # IF this tree (root) was created from a token stream, track it. 1834*16467b97STreehugger Robot self.tokens = None 1835*16467b97STreehugger Robot 1836*16467b97STreehugger Robot # What tree adaptor was used to build these trees 1837*16467b97STreehugger Robot self.adaptor = adaptor 1838*16467b97STreehugger Robot 1839*16467b97STreehugger Robot # Reuse same DOWN, UP navigation nodes unless this is true 1840*16467b97STreehugger Robot self.uniqueNavigationNodes = False 1841*16467b97STreehugger Robot 1842*16467b97STreehugger Robot # The index into the nodes list of the current node (next node 1843*16467b97STreehugger Robot # to consume). If -1, nodes array not filled yet. 1844*16467b97STreehugger Robot self.p = -1 1845*16467b97STreehugger Robot 1846*16467b97STreehugger Robot # Track the last mark() call result value for use in rewind(). 1847*16467b97STreehugger Robot self.lastMarker = None 1848*16467b97STreehugger Robot 1849*16467b97STreehugger Robot # Stack of indexes used for push/pop calls 1850*16467b97STreehugger Robot self.calls = [] 1851*16467b97STreehugger Robot 1852*16467b97STreehugger Robot 1853*16467b97STreehugger Robot def fillBuffer(self): 1854*16467b97STreehugger Robot """Walk tree with depth-first-search and fill nodes buffer. 1855*16467b97STreehugger Robot Don't do DOWN, UP nodes if its a list (t is isNil). 1856*16467b97STreehugger Robot """ 1857*16467b97STreehugger Robot 1858*16467b97STreehugger Robot self._fillBuffer(self.root) 1859*16467b97STreehugger Robot self.p = 0 # buffer of nodes intialized now 1860*16467b97STreehugger Robot 1861*16467b97STreehugger Robot 1862*16467b97STreehugger Robot def _fillBuffer(self, t): 1863*16467b97STreehugger Robot nil = self.adaptor.isNil(t) 1864*16467b97STreehugger Robot 1865*16467b97STreehugger Robot if not nil: 1866*16467b97STreehugger Robot self.nodes.append(t) # add this node 1867*16467b97STreehugger Robot 1868*16467b97STreehugger Robot # add DOWN node if t has children 1869*16467b97STreehugger Robot n = self.adaptor.getChildCount(t) 1870*16467b97STreehugger Robot if not nil and n > 0: 1871*16467b97STreehugger Robot self.addNavigationNode(DOWN) 1872*16467b97STreehugger Robot 1873*16467b97STreehugger Robot # and now add all its children 1874*16467b97STreehugger Robot for c in range(n): 1875*16467b97STreehugger Robot self._fillBuffer(self.adaptor.getChild(t, c)) 1876*16467b97STreehugger Robot 1877*16467b97STreehugger Robot # add UP node if t has children 1878*16467b97STreehugger Robot if not nil and n > 0: 1879*16467b97STreehugger Robot self.addNavigationNode(UP) 1880*16467b97STreehugger Robot 1881*16467b97STreehugger Robot 1882*16467b97STreehugger Robot def getNodeIndex(self, node): 1883*16467b97STreehugger Robot """What is the stream index for node? 0..n-1 1884*16467b97STreehugger Robot Return -1 if node not found. 1885*16467b97STreehugger Robot """ 1886*16467b97STreehugger Robot 1887*16467b97STreehugger Robot if self.p == -1: 1888*16467b97STreehugger Robot self.fillBuffer() 1889*16467b97STreehugger Robot 1890*16467b97STreehugger Robot for i, t in enumerate(self.nodes): 1891*16467b97STreehugger Robot if t == node: 1892*16467b97STreehugger Robot return i 1893*16467b97STreehugger Robot 1894*16467b97STreehugger Robot return -1 1895*16467b97STreehugger Robot 1896*16467b97STreehugger Robot 1897*16467b97STreehugger Robot def addNavigationNode(self, ttype): 1898*16467b97STreehugger Robot """ 1899*16467b97STreehugger Robot As we flatten the tree, we use UP, DOWN nodes to represent 1900*16467b97STreehugger Robot the tree structure. When debugging we need unique nodes 1901*16467b97STreehugger Robot so instantiate new ones when uniqueNavigationNodes is true. 1902*16467b97STreehugger Robot """ 1903*16467b97STreehugger Robot 1904*16467b97STreehugger Robot navNode = None 1905*16467b97STreehugger Robot 1906*16467b97STreehugger Robot if ttype == DOWN: 1907*16467b97STreehugger Robot if self.hasUniqueNavigationNodes(): 1908*16467b97STreehugger Robot navNode = self.adaptor.createFromType(DOWN, "DOWN") 1909*16467b97STreehugger Robot 1910*16467b97STreehugger Robot else: 1911*16467b97STreehugger Robot navNode = self.down 1912*16467b97STreehugger Robot 1913*16467b97STreehugger Robot else: 1914*16467b97STreehugger Robot if self.hasUniqueNavigationNodes(): 1915*16467b97STreehugger Robot navNode = self.adaptor.createFromType(UP, "UP") 1916*16467b97STreehugger Robot 1917*16467b97STreehugger Robot else: 1918*16467b97STreehugger Robot navNode = self.up 1919*16467b97STreehugger Robot 1920*16467b97STreehugger Robot self.nodes.append(navNode) 1921*16467b97STreehugger Robot 1922*16467b97STreehugger Robot 1923*16467b97STreehugger Robot def get(self, i): 1924*16467b97STreehugger Robot if self.p == -1: 1925*16467b97STreehugger Robot self.fillBuffer() 1926*16467b97STreehugger Robot 1927*16467b97STreehugger Robot return self.nodes[i] 1928*16467b97STreehugger Robot 1929*16467b97STreehugger Robot 1930*16467b97STreehugger Robot def LT(self, k): 1931*16467b97STreehugger Robot if self.p == -1: 1932*16467b97STreehugger Robot self.fillBuffer() 1933*16467b97STreehugger Robot 1934*16467b97STreehugger Robot if k == 0: 1935*16467b97STreehugger Robot return None 1936*16467b97STreehugger Robot 1937*16467b97STreehugger Robot if k < 0: 1938*16467b97STreehugger Robot return self.LB(-k) 1939*16467b97STreehugger Robot 1940*16467b97STreehugger Robot if self.p + k - 1 >= len(self.nodes): 1941*16467b97STreehugger Robot return self.eof 1942*16467b97STreehugger Robot 1943*16467b97STreehugger Robot return self.nodes[self.p + k - 1] 1944*16467b97STreehugger Robot 1945*16467b97STreehugger Robot 1946*16467b97STreehugger Robot def getCurrentSymbol(self): 1947*16467b97STreehugger Robot return self.LT(1) 1948*16467b97STreehugger Robot 1949*16467b97STreehugger Robot 1950*16467b97STreehugger Robot def LB(self, k): 1951*16467b97STreehugger Robot """Look backwards k nodes""" 1952*16467b97STreehugger Robot 1953*16467b97STreehugger Robot if k == 0: 1954*16467b97STreehugger Robot return None 1955*16467b97STreehugger Robot 1956*16467b97STreehugger Robot if self.p - k < 0: 1957*16467b97STreehugger Robot return None 1958*16467b97STreehugger Robot 1959*16467b97STreehugger Robot return self.nodes[self.p - k] 1960*16467b97STreehugger Robot 1961*16467b97STreehugger Robot 1962*16467b97STreehugger Robot def isEOF(self, obj): 1963*16467b97STreehugger Robot return self.adaptor.getType(obj) == EOF 1964*16467b97STreehugger Robot 1965*16467b97STreehugger Robot 1966*16467b97STreehugger Robot def getTreeSource(self): 1967*16467b97STreehugger Robot return self.root 1968*16467b97STreehugger Robot 1969*16467b97STreehugger Robot 1970*16467b97STreehugger Robot def getSourceName(self): 1971*16467b97STreehugger Robot return self.getTokenStream().getSourceName() 1972*16467b97STreehugger Robot 1973*16467b97STreehugger Robot 1974*16467b97STreehugger Robot def getTokenStream(self): 1975*16467b97STreehugger Robot return self.tokens 1976*16467b97STreehugger Robot 1977*16467b97STreehugger Robot 1978*16467b97STreehugger Robot def setTokenStream(self, tokens): 1979*16467b97STreehugger Robot self.tokens = tokens 1980*16467b97STreehugger Robot 1981*16467b97STreehugger Robot 1982*16467b97STreehugger Robot def getTreeAdaptor(self): 1983*16467b97STreehugger Robot return self.adaptor 1984*16467b97STreehugger Robot 1985*16467b97STreehugger Robot 1986*16467b97STreehugger Robot def hasUniqueNavigationNodes(self): 1987*16467b97STreehugger Robot return self.uniqueNavigationNodes 1988*16467b97STreehugger Robot 1989*16467b97STreehugger Robot 1990*16467b97STreehugger Robot def setUniqueNavigationNodes(self, uniqueNavigationNodes): 1991*16467b97STreehugger Robot self.uniqueNavigationNodes = uniqueNavigationNodes 1992*16467b97STreehugger Robot 1993*16467b97STreehugger Robot 1994*16467b97STreehugger Robot def consume(self): 1995*16467b97STreehugger Robot if self.p == -1: 1996*16467b97STreehugger Robot self.fillBuffer() 1997*16467b97STreehugger Robot 1998*16467b97STreehugger Robot self.p += 1 1999*16467b97STreehugger Robot 2000*16467b97STreehugger Robot 2001*16467b97STreehugger Robot def LA(self, i): 2002*16467b97STreehugger Robot return self.adaptor.getType(self.LT(i)) 2003*16467b97STreehugger Robot 2004*16467b97STreehugger Robot 2005*16467b97STreehugger Robot def mark(self): 2006*16467b97STreehugger Robot if self.p == -1: 2007*16467b97STreehugger Robot self.fillBuffer() 2008*16467b97STreehugger Robot 2009*16467b97STreehugger Robot 2010*16467b97STreehugger Robot self.lastMarker = self.index() 2011*16467b97STreehugger Robot return self.lastMarker 2012*16467b97STreehugger Robot 2013*16467b97STreehugger Robot 2014*16467b97STreehugger Robot def release(self, marker=None): 2015*16467b97STreehugger Robot # no resources to release 2016*16467b97STreehugger Robot 2017*16467b97STreehugger Robot pass 2018*16467b97STreehugger Robot 2019*16467b97STreehugger Robot 2020*16467b97STreehugger Robot def index(self): 2021*16467b97STreehugger Robot return self.p 2022*16467b97STreehugger Robot 2023*16467b97STreehugger Robot 2024*16467b97STreehugger Robot def rewind(self, marker=None): 2025*16467b97STreehugger Robot if marker is None: 2026*16467b97STreehugger Robot marker = self.lastMarker 2027*16467b97STreehugger Robot 2028*16467b97STreehugger Robot self.seek(marker) 2029*16467b97STreehugger Robot 2030*16467b97STreehugger Robot 2031*16467b97STreehugger Robot def seek(self, index): 2032*16467b97STreehugger Robot if self.p == -1: 2033*16467b97STreehugger Robot self.fillBuffer() 2034*16467b97STreehugger Robot 2035*16467b97STreehugger Robot self.p = index 2036*16467b97STreehugger Robot 2037*16467b97STreehugger Robot 2038*16467b97STreehugger Robot def push(self, index): 2039*16467b97STreehugger Robot """ 2040*16467b97STreehugger Robot Make stream jump to a new location, saving old location. 2041*16467b97STreehugger Robot Switch back with pop(). 2042*16467b97STreehugger Robot """ 2043*16467b97STreehugger Robot 2044*16467b97STreehugger Robot self.calls.append(self.p) # save current index 2045*16467b97STreehugger Robot self.seek(index) 2046*16467b97STreehugger Robot 2047*16467b97STreehugger Robot 2048*16467b97STreehugger Robot def pop(self): 2049*16467b97STreehugger Robot """ 2050*16467b97STreehugger Robot Seek back to previous index saved during last push() call. 2051*16467b97STreehugger Robot Return top of stack (return index). 2052*16467b97STreehugger Robot """ 2053*16467b97STreehugger Robot 2054*16467b97STreehugger Robot ret = self.calls.pop(-1) 2055*16467b97STreehugger Robot self.seek(ret) 2056*16467b97STreehugger Robot return ret 2057*16467b97STreehugger Robot 2058*16467b97STreehugger Robot 2059*16467b97STreehugger Robot def reset(self): 2060*16467b97STreehugger Robot self.p = 0 2061*16467b97STreehugger Robot self.lastMarker = 0 2062*16467b97STreehugger Robot self.calls = [] 2063*16467b97STreehugger Robot 2064*16467b97STreehugger Robot 2065*16467b97STreehugger Robot def size(self): 2066*16467b97STreehugger Robot if self.p == -1: 2067*16467b97STreehugger Robot self.fillBuffer() 2068*16467b97STreehugger Robot 2069*16467b97STreehugger Robot return len(self.nodes) 2070*16467b97STreehugger Robot 2071*16467b97STreehugger Robot 2072*16467b97STreehugger Robot # TREE REWRITE INTERFACE 2073*16467b97STreehugger Robot 2074*16467b97STreehugger Robot def replaceChildren(self, parent, startChildIndex, stopChildIndex, t): 2075*16467b97STreehugger Robot if parent is not None: 2076*16467b97STreehugger Robot self.adaptor.replaceChildren( 2077*16467b97STreehugger Robot parent, startChildIndex, stopChildIndex, t 2078*16467b97STreehugger Robot ) 2079*16467b97STreehugger Robot 2080*16467b97STreehugger Robot 2081*16467b97STreehugger Robot def __str__(self): 2082*16467b97STreehugger Robot """Used for testing, just return the token type stream""" 2083*16467b97STreehugger Robot 2084*16467b97STreehugger Robot if self.p == -1: 2085*16467b97STreehugger Robot self.fillBuffer() 2086*16467b97STreehugger Robot 2087*16467b97STreehugger Robot return ' '.join([str(self.adaptor.getType(node)) 2088*16467b97STreehugger Robot for node in self.nodes 2089*16467b97STreehugger Robot ]) 2090*16467b97STreehugger Robot 2091*16467b97STreehugger Robot 2092*16467b97STreehugger Robot def toString(self, start, stop): 2093*16467b97STreehugger Robot if start is None or stop is None: 2094*16467b97STreehugger Robot return None 2095*16467b97STreehugger Robot 2096*16467b97STreehugger Robot if self.p == -1: 2097*16467b97STreehugger Robot self.fillBuffer() 2098*16467b97STreehugger Robot 2099*16467b97STreehugger Robot #System.out.println("stop: "+stop); 2100*16467b97STreehugger Robot #if ( start instanceof CommonTree ) 2101*16467b97STreehugger Robot # System.out.print("toString: "+((CommonTree)start).getToken()+", "); 2102*16467b97STreehugger Robot #else 2103*16467b97STreehugger Robot # System.out.println(start); 2104*16467b97STreehugger Robot #if ( stop instanceof CommonTree ) 2105*16467b97STreehugger Robot # System.out.println(((CommonTree)stop).getToken()); 2106*16467b97STreehugger Robot #else 2107*16467b97STreehugger Robot # System.out.println(stop); 2108*16467b97STreehugger Robot 2109*16467b97STreehugger Robot # if we have the token stream, use that to dump text in order 2110*16467b97STreehugger Robot if self.tokens is not None: 2111*16467b97STreehugger Robot beginTokenIndex = self.adaptor.getTokenStartIndex(start) 2112*16467b97STreehugger Robot endTokenIndex = self.adaptor.getTokenStopIndex(stop) 2113*16467b97STreehugger Robot 2114*16467b97STreehugger Robot # if it's a tree, use start/stop index from start node 2115*16467b97STreehugger Robot # else use token range from start/stop nodes 2116*16467b97STreehugger Robot if self.adaptor.getType(stop) == UP: 2117*16467b97STreehugger Robot endTokenIndex = self.adaptor.getTokenStopIndex(start) 2118*16467b97STreehugger Robot 2119*16467b97STreehugger Robot elif self.adaptor.getType(stop) == EOF: 2120*16467b97STreehugger Robot endTokenIndex = self.size() -2 # don't use EOF 2121*16467b97STreehugger Robot 2122*16467b97STreehugger Robot return self.tokens.toString(beginTokenIndex, endTokenIndex) 2123*16467b97STreehugger Robot 2124*16467b97STreehugger Robot # walk nodes looking for start 2125*16467b97STreehugger Robot i, t = 0, None 2126*16467b97STreehugger Robot for i, t in enumerate(self.nodes): 2127*16467b97STreehugger Robot if t == start: 2128*16467b97STreehugger Robot break 2129*16467b97STreehugger Robot 2130*16467b97STreehugger Robot # now walk until we see stop, filling string buffer with text 2131*16467b97STreehugger Robot buf = [] 2132*16467b97STreehugger Robot t = self.nodes[i] 2133*16467b97STreehugger Robot while t != stop: 2134*16467b97STreehugger Robot text = self.adaptor.getText(t) 2135*16467b97STreehugger Robot if text is None: 2136*16467b97STreehugger Robot text = " " + self.adaptor.getType(t) 2137*16467b97STreehugger Robot 2138*16467b97STreehugger Robot buf.append(text) 2139*16467b97STreehugger Robot i += 1 2140*16467b97STreehugger Robot t = self.nodes[i] 2141*16467b97STreehugger Robot 2142*16467b97STreehugger Robot # include stop node too 2143*16467b97STreehugger Robot text = self.adaptor.getText(stop) 2144*16467b97STreehugger Robot if text is None: 2145*16467b97STreehugger Robot text = " " +self.adaptor.getType(stop) 2146*16467b97STreehugger Robot 2147*16467b97STreehugger Robot buf.append(text) 2148*16467b97STreehugger Robot 2149*16467b97STreehugger Robot return ''.join(buf) 2150*16467b97STreehugger Robot 2151*16467b97STreehugger Robot 2152*16467b97STreehugger Robot ## iterator interface 2153*16467b97STreehugger Robot def __iter__(self): 2154*16467b97STreehugger Robot if self.p == -1: 2155*16467b97STreehugger Robot self.fillBuffer() 2156*16467b97STreehugger Robot 2157*16467b97STreehugger Robot for node in self.nodes: 2158*16467b97STreehugger Robot yield node 2159*16467b97STreehugger Robot 2160*16467b97STreehugger Robot 2161*16467b97STreehugger Robot############################################################################# 2162*16467b97STreehugger Robot# 2163*16467b97STreehugger Robot# tree parser 2164*16467b97STreehugger Robot# 2165*16467b97STreehugger Robot############################################################################# 2166*16467b97STreehugger Robot 2167*16467b97STreehugger Robotclass TreeParser(BaseRecognizer): 2168*16467b97STreehugger Robot """@brief Baseclass for generated tree parsers. 2169*16467b97STreehugger Robot 2170*16467b97STreehugger Robot A parser for a stream of tree nodes. "tree grammars" result in a subclass 2171*16467b97STreehugger Robot of this. All the error reporting and recovery is shared with Parser via 2172*16467b97STreehugger Robot the BaseRecognizer superclass. 2173*16467b97STreehugger Robot """ 2174*16467b97STreehugger Robot 2175*16467b97STreehugger Robot def __init__(self, input, state=None): 2176*16467b97STreehugger Robot BaseRecognizer.__init__(self, state) 2177*16467b97STreehugger Robot 2178*16467b97STreehugger Robot self.input = None 2179*16467b97STreehugger Robot self.setTreeNodeStream(input) 2180*16467b97STreehugger Robot 2181*16467b97STreehugger Robot 2182*16467b97STreehugger Robot def reset(self): 2183*16467b97STreehugger Robot BaseRecognizer.reset(self) # reset all recognizer state variables 2184*16467b97STreehugger Robot if self.input is not None: 2185*16467b97STreehugger Robot self.input.seek(0) # rewind the input 2186*16467b97STreehugger Robot 2187*16467b97STreehugger Robot 2188*16467b97STreehugger Robot def setTreeNodeStream(self, input): 2189*16467b97STreehugger Robot """Set the input stream""" 2190*16467b97STreehugger Robot 2191*16467b97STreehugger Robot self.input = input 2192*16467b97STreehugger Robot 2193*16467b97STreehugger Robot 2194*16467b97STreehugger Robot def getTreeNodeStream(self): 2195*16467b97STreehugger Robot return self.input 2196*16467b97STreehugger Robot 2197*16467b97STreehugger Robot 2198*16467b97STreehugger Robot def getSourceName(self): 2199*16467b97STreehugger Robot return self.input.getSourceName() 2200*16467b97STreehugger Robot 2201*16467b97STreehugger Robot 2202*16467b97STreehugger Robot def getCurrentInputSymbol(self, input): 2203*16467b97STreehugger Robot return input.LT(1) 2204*16467b97STreehugger Robot 2205*16467b97STreehugger Robot 2206*16467b97STreehugger Robot def getMissingSymbol(self, input, e, expectedTokenType, follow): 2207*16467b97STreehugger Robot tokenText = "<missing " + self.tokenNames[expectedTokenType] + ">" 2208*16467b97STreehugger Robot adaptor = input.adaptor 2209*16467b97STreehugger Robot return adaptor.createToken( 2210*16467b97STreehugger Robot CommonToken(type=expectedTokenType, text=tokenText)) 2211*16467b97STreehugger Robot 2212*16467b97STreehugger Robot 2213*16467b97STreehugger Robot # precompiled regex used by inContext 2214*16467b97STreehugger Robot dotdot = ".*[^.]\\.\\.[^.].*" 2215*16467b97STreehugger Robot doubleEtc = ".*\\.\\.\\.\\s+\\.\\.\\..*" 2216*16467b97STreehugger Robot dotdotPattern = re.compile(dotdot) 2217*16467b97STreehugger Robot doubleEtcPattern = re.compile(doubleEtc) 2218*16467b97STreehugger Robot 2219*16467b97STreehugger Robot def inContext(self, context, adaptor=None, tokenName=None, t=None): 2220*16467b97STreehugger Robot """Check if current node in input has a context. 2221*16467b97STreehugger Robot 2222*16467b97STreehugger Robot Context means sequence of nodes towards root of tree. For example, 2223*16467b97STreehugger Robot you might say context is "MULT" which means my parent must be MULT. 2224*16467b97STreehugger Robot "CLASS VARDEF" says current node must be child of a VARDEF and whose 2225*16467b97STreehugger Robot parent is a CLASS node. You can use "..." to mean zero-or-more nodes. 2226*16467b97STreehugger Robot "METHOD ... VARDEF" means my parent is VARDEF and somewhere above 2227*16467b97STreehugger Robot that is a METHOD node. The first node in the context is not 2228*16467b97STreehugger Robot necessarily the root. The context matcher stops matching and returns 2229*16467b97STreehugger Robot true when it runs out of context. There is no way to force the first 2230*16467b97STreehugger Robot node to be the root. 2231*16467b97STreehugger Robot """ 2232*16467b97STreehugger Robot 2233*16467b97STreehugger Robot return self._inContext( 2234*16467b97STreehugger Robot self.input.getTreeAdaptor(), self.tokenNames, 2235*16467b97STreehugger Robot self.input.LT(1), context) 2236*16467b97STreehugger Robot 2237*16467b97STreehugger Robot @classmethod 2238*16467b97STreehugger Robot def _inContext(cls, adaptor, tokenNames, t, context): 2239*16467b97STreehugger Robot """The worker for inContext. 2240*16467b97STreehugger Robot 2241*16467b97STreehugger Robot It's static and full of parameters for testing purposes. 2242*16467b97STreehugger Robot """ 2243*16467b97STreehugger Robot 2244*16467b97STreehugger Robot if cls.dotdotPattern.match(context): 2245*16467b97STreehugger Robot # don't allow "..", must be "..." 2246*16467b97STreehugger Robot raise ValueError("invalid syntax: ..") 2247*16467b97STreehugger Robot 2248*16467b97STreehugger Robot if cls.doubleEtcPattern.match(context): 2249*16467b97STreehugger Robot # don't allow double "..." 2250*16467b97STreehugger Robot raise ValueError("invalid syntax: ... ...") 2251*16467b97STreehugger Robot 2252*16467b97STreehugger Robot # ensure spaces around ... 2253*16467b97STreehugger Robot context = context.replace("...", " ... ") 2254*16467b97STreehugger Robot context = context.strip() 2255*16467b97STreehugger Robot nodes = context.split() 2256*16467b97STreehugger Robot 2257*16467b97STreehugger Robot ni = len(nodes) - 1 2258*16467b97STreehugger Robot t = adaptor.getParent(t) 2259*16467b97STreehugger Robot while ni >= 0 and t is not None: 2260*16467b97STreehugger Robot if nodes[ni] == "...": 2261*16467b97STreehugger Robot # walk upwards until we see nodes[ni-1] then continue walking 2262*16467b97STreehugger Robot if ni == 0: 2263*16467b97STreehugger Robot # ... at start is no-op 2264*16467b97STreehugger Robot return True 2265*16467b97STreehugger Robot goal = nodes[ni-1] 2266*16467b97STreehugger Robot ancestor = cls._getAncestor(adaptor, tokenNames, t, goal) 2267*16467b97STreehugger Robot if ancestor is None: 2268*16467b97STreehugger Robot return False 2269*16467b97STreehugger Robot t = ancestor 2270*16467b97STreehugger Robot ni -= 1 2271*16467b97STreehugger Robot 2272*16467b97STreehugger Robot name = tokenNames[adaptor.getType(t)] 2273*16467b97STreehugger Robot if name != nodes[ni]: 2274*16467b97STreehugger Robot return False 2275*16467b97STreehugger Robot 2276*16467b97STreehugger Robot # advance to parent and to previous element in context node list 2277*16467b97STreehugger Robot ni -= 1 2278*16467b97STreehugger Robot t = adaptor.getParent(t) 2279*16467b97STreehugger Robot 2280*16467b97STreehugger Robot # at root but more nodes to match 2281*16467b97STreehugger Robot if t is None and ni >= 0: 2282*16467b97STreehugger Robot return False 2283*16467b97STreehugger Robot 2284*16467b97STreehugger Robot return True 2285*16467b97STreehugger Robot 2286*16467b97STreehugger Robot @staticmethod 2287*16467b97STreehugger Robot def _getAncestor(adaptor, tokenNames, t, goal): 2288*16467b97STreehugger Robot """Helper for static inContext.""" 2289*16467b97STreehugger Robot while t is not None: 2290*16467b97STreehugger Robot name = tokenNames[adaptor.getType(t)] 2291*16467b97STreehugger Robot if name == goal: 2292*16467b97STreehugger Robot return t 2293*16467b97STreehugger Robot t = adaptor.getParent(t) 2294*16467b97STreehugger Robot 2295*16467b97STreehugger Robot return None 2296*16467b97STreehugger Robot 2297*16467b97STreehugger Robot 2298*16467b97STreehugger Robot def matchAny(self): 2299*16467b97STreehugger Robot """ 2300*16467b97STreehugger Robot Match '.' in tree parser has special meaning. Skip node or 2301*16467b97STreehugger Robot entire tree if node has children. If children, scan until 2302*16467b97STreehugger Robot corresponding UP node. 2303*16467b97STreehugger Robot """ 2304*16467b97STreehugger Robot 2305*16467b97STreehugger Robot self._state.errorRecovery = False 2306*16467b97STreehugger Robot 2307*16467b97STreehugger Robot look = self.input.LT(1) 2308*16467b97STreehugger Robot if self.input.getTreeAdaptor().getChildCount(look) == 0: 2309*16467b97STreehugger Robot self.input.consume() # not subtree, consume 1 node and return 2310*16467b97STreehugger Robot return 2311*16467b97STreehugger Robot 2312*16467b97STreehugger Robot # current node is a subtree, skip to corresponding UP. 2313*16467b97STreehugger Robot # must count nesting level to get right UP 2314*16467b97STreehugger Robot level = 0 2315*16467b97STreehugger Robot tokenType = self.input.getTreeAdaptor().getType(look) 2316*16467b97STreehugger Robot while tokenType != EOF and not (tokenType == UP and level==0): 2317*16467b97STreehugger Robot self.input.consume() 2318*16467b97STreehugger Robot look = self.input.LT(1) 2319*16467b97STreehugger Robot tokenType = self.input.getTreeAdaptor().getType(look) 2320*16467b97STreehugger Robot if tokenType == DOWN: 2321*16467b97STreehugger Robot level += 1 2322*16467b97STreehugger Robot 2323*16467b97STreehugger Robot elif tokenType == UP: 2324*16467b97STreehugger Robot level -= 1 2325*16467b97STreehugger Robot 2326*16467b97STreehugger Robot self.input.consume() # consume UP 2327*16467b97STreehugger Robot 2328*16467b97STreehugger Robot 2329*16467b97STreehugger Robot def mismatch(self, input, ttype, follow): 2330*16467b97STreehugger Robot """ 2331*16467b97STreehugger Robot We have DOWN/UP nodes in the stream that have no line info; override. 2332*16467b97STreehugger Robot plus we want to alter the exception type. Don't try to recover 2333*16467b97STreehugger Robot from tree parser errors inline... 2334*16467b97STreehugger Robot """ 2335*16467b97STreehugger Robot 2336*16467b97STreehugger Robot raise MismatchedTreeNodeException(ttype, input) 2337*16467b97STreehugger Robot 2338*16467b97STreehugger Robot 2339*16467b97STreehugger Robot def getErrorHeader(self, e): 2340*16467b97STreehugger Robot """ 2341*16467b97STreehugger Robot Prefix error message with the grammar name because message is 2342*16467b97STreehugger Robot always intended for the programmer because the parser built 2343*16467b97STreehugger Robot the input tree not the user. 2344*16467b97STreehugger Robot """ 2345*16467b97STreehugger Robot 2346*16467b97STreehugger Robot return (self.getGrammarFileName() + 2347*16467b97STreehugger Robot ": node from {}line {}:{}".format( 2348*16467b97STreehugger Robot "after " if e.approximateLineInfo else '', 2349*16467b97STreehugger Robot e.line, 2350*16467b97STreehugger Robot e.charPositionInLine)) 2351*16467b97STreehugger Robot 2352*16467b97STreehugger Robot def getErrorMessage(self, e): 2353*16467b97STreehugger Robot """ 2354*16467b97STreehugger Robot Tree parsers parse nodes they usually have a token object as 2355*16467b97STreehugger Robot payload. Set the exception token and do the default behavior. 2356*16467b97STreehugger Robot """ 2357*16467b97STreehugger Robot 2358*16467b97STreehugger Robot if isinstance(self, TreeParser): 2359*16467b97STreehugger Robot adaptor = e.input.getTreeAdaptor() 2360*16467b97STreehugger Robot e.token = adaptor.getToken(e.node) 2361*16467b97STreehugger Robot if e.token is not None: # could be an UP/DOWN node 2362*16467b97STreehugger Robot e.token = CommonToken( 2363*16467b97STreehugger Robot type=adaptor.getType(e.node), 2364*16467b97STreehugger Robot text=adaptor.getText(e.node) 2365*16467b97STreehugger Robot ) 2366*16467b97STreehugger Robot 2367*16467b97STreehugger Robot return BaseRecognizer.getErrorMessage(self, e) 2368*16467b97STreehugger Robot 2369*16467b97STreehugger Robot 2370*16467b97STreehugger Robot def traceIn(self, ruleName, ruleIndex): 2371*16467b97STreehugger Robot BaseRecognizer.traceIn(self, ruleName, ruleIndex, self.input.LT(1)) 2372*16467b97STreehugger Robot 2373*16467b97STreehugger Robot 2374*16467b97STreehugger Robot def traceOut(self, ruleName, ruleIndex): 2375*16467b97STreehugger Robot BaseRecognizer.traceOut(self, ruleName, ruleIndex, self.input.LT(1)) 2376*16467b97STreehugger Robot 2377*16467b97STreehugger Robot 2378*16467b97STreehugger Robot############################################################################# 2379*16467b97STreehugger Robot# 2380*16467b97STreehugger Robot# tree visitor 2381*16467b97STreehugger Robot# 2382*16467b97STreehugger Robot############################################################################# 2383*16467b97STreehugger Robot 2384*16467b97STreehugger Robotclass TreeVisitor(object): 2385*16467b97STreehugger Robot """Do a depth first walk of a tree, applying pre() and post() actions 2386*16467b97STreehugger Robot we go. 2387*16467b97STreehugger Robot """ 2388*16467b97STreehugger Robot 2389*16467b97STreehugger Robot def __init__(self, adaptor=None): 2390*16467b97STreehugger Robot if adaptor is not None: 2391*16467b97STreehugger Robot self.adaptor = adaptor 2392*16467b97STreehugger Robot else: 2393*16467b97STreehugger Robot self.adaptor = CommonTreeAdaptor() 2394*16467b97STreehugger Robot 2395*16467b97STreehugger Robot def visit(self, t, pre_action=None, post_action=None): 2396*16467b97STreehugger Robot """Visit every node in tree t and trigger an action for each node 2397*16467b97STreehugger Robot before/after having visited all of its children. Bottom up walk. 2398*16467b97STreehugger Robot Execute both actions even if t has no children. Ignore return 2399*16467b97STreehugger Robot results from transforming children since they will have altered 2400*16467b97STreehugger Robot the child list of this node (their parent). Return result of 2401*16467b97STreehugger Robot applying post action to this node. 2402*16467b97STreehugger Robot 2403*16467b97STreehugger Robot The Python version differs from the Java version by taking two 2404*16467b97STreehugger Robot callables 'pre_action' and 'post_action' instead of a class instance 2405*16467b97STreehugger Robot that wraps those methods. Those callables must accept a TreeNode as 2406*16467b97STreehugger Robot their single argument and return the (potentially transformed or 2407*16467b97STreehugger Robot replaced) TreeNode. 2408*16467b97STreehugger Robot """ 2409*16467b97STreehugger Robot 2410*16467b97STreehugger Robot isNil = self.adaptor.isNil(t) 2411*16467b97STreehugger Robot if pre_action is not None and not isNil: 2412*16467b97STreehugger Robot # if rewritten, walk children of new t 2413*16467b97STreehugger Robot t = pre_action(t) 2414*16467b97STreehugger Robot 2415*16467b97STreehugger Robot idx = 0 2416*16467b97STreehugger Robot while idx < self.adaptor.getChildCount(t): 2417*16467b97STreehugger Robot child = self.adaptor.getChild(t, idx) 2418*16467b97STreehugger Robot self.visit(child, pre_action, post_action) 2419*16467b97STreehugger Robot idx += 1 2420*16467b97STreehugger Robot 2421*16467b97STreehugger Robot if post_action is not None and not isNil: 2422*16467b97STreehugger Robot t = post_action(t) 2423*16467b97STreehugger Robot 2424*16467b97STreehugger Robot return t 2425*16467b97STreehugger Robot 2426*16467b97STreehugger Robot############################################################################# 2427*16467b97STreehugger Robot# 2428*16467b97STreehugger Robot# tree iterator 2429*16467b97STreehugger Robot# 2430*16467b97STreehugger Robot############################################################################# 2431*16467b97STreehugger Robot 2432*16467b97STreehugger Robotclass TreeIterator(object): 2433*16467b97STreehugger Robot """ 2434*16467b97STreehugger Robot Return a node stream from a doubly-linked tree whose nodes 2435*16467b97STreehugger Robot know what child index they are. 2436*16467b97STreehugger Robot 2437*16467b97STreehugger Robot Emit navigation nodes (DOWN, UP, and EOF) to let show tree structure. 2438*16467b97STreehugger Robot """ 2439*16467b97STreehugger Robot 2440*16467b97STreehugger Robot def __init__(self, tree, adaptor=None): 2441*16467b97STreehugger Robot if adaptor is None: 2442*16467b97STreehugger Robot adaptor = CommonTreeAdaptor() 2443*16467b97STreehugger Robot 2444*16467b97STreehugger Robot self.root = tree 2445*16467b97STreehugger Robot self.adaptor = adaptor 2446*16467b97STreehugger Robot 2447*16467b97STreehugger Robot self.first_time = True 2448*16467b97STreehugger Robot self.tree = tree 2449*16467b97STreehugger Robot 2450*16467b97STreehugger Robot # If we emit UP/DOWN nodes, we need to spit out multiple nodes per 2451*16467b97STreehugger Robot # next() call. 2452*16467b97STreehugger Robot self.nodes = [] 2453*16467b97STreehugger Robot 2454*16467b97STreehugger Robot # navigation nodes to return during walk and at end 2455*16467b97STreehugger Robot self.down = adaptor.createFromType(DOWN, "DOWN") 2456*16467b97STreehugger Robot self.up = adaptor.createFromType(UP, "UP") 2457*16467b97STreehugger Robot self.eof = adaptor.createFromType(EOF, "EOF") 2458*16467b97STreehugger Robot 2459*16467b97STreehugger Robot 2460*16467b97STreehugger Robot def reset(self): 2461*16467b97STreehugger Robot self.first_time = True 2462*16467b97STreehugger Robot self.tree = self.root 2463*16467b97STreehugger Robot self.nodes = [] 2464*16467b97STreehugger Robot 2465*16467b97STreehugger Robot 2466*16467b97STreehugger Robot def __iter__(self): 2467*16467b97STreehugger Robot return self 2468*16467b97STreehugger Robot 2469*16467b97STreehugger Robot 2470*16467b97STreehugger Robot def has_next(self): 2471*16467b97STreehugger Robot if self.first_time: 2472*16467b97STreehugger Robot return self.root is not None 2473*16467b97STreehugger Robot 2474*16467b97STreehugger Robot if len(self.nodes) > 0: 2475*16467b97STreehugger Robot return True 2476*16467b97STreehugger Robot 2477*16467b97STreehugger Robot if self.tree is None: 2478*16467b97STreehugger Robot return False 2479*16467b97STreehugger Robot 2480*16467b97STreehugger Robot if self.adaptor.getChildCount(self.tree) > 0: 2481*16467b97STreehugger Robot return True 2482*16467b97STreehugger Robot 2483*16467b97STreehugger Robot # back at root? 2484*16467b97STreehugger Robot return self.adaptor.getParent(self.tree) is not None 2485*16467b97STreehugger Robot 2486*16467b97STreehugger Robot 2487*16467b97STreehugger Robot def __next__(self): 2488*16467b97STreehugger Robot if not self.has_next(): 2489*16467b97STreehugger Robot raise StopIteration 2490*16467b97STreehugger Robot 2491*16467b97STreehugger Robot if self.first_time: 2492*16467b97STreehugger Robot # initial condition 2493*16467b97STreehugger Robot self.first_time = False 2494*16467b97STreehugger Robot if self.adaptor.getChildCount(self.tree) == 0: 2495*16467b97STreehugger Robot # single node tree (special) 2496*16467b97STreehugger Robot self.nodes.append(self.eof) 2497*16467b97STreehugger Robot return self.tree 2498*16467b97STreehugger Robot 2499*16467b97STreehugger Robot return self.tree 2500*16467b97STreehugger Robot 2501*16467b97STreehugger Robot # if any queued up, use those first 2502*16467b97STreehugger Robot if len(self.nodes) > 0: 2503*16467b97STreehugger Robot return self.nodes.pop(0) 2504*16467b97STreehugger Robot 2505*16467b97STreehugger Robot # no nodes left? 2506*16467b97STreehugger Robot if self.tree is None: 2507*16467b97STreehugger Robot return self.eof 2508*16467b97STreehugger Robot 2509*16467b97STreehugger Robot # next node will be child 0 if any children 2510*16467b97STreehugger Robot if self.adaptor.getChildCount(self.tree) > 0: 2511*16467b97STreehugger Robot self.tree = self.adaptor.getChild(self.tree, 0) 2512*16467b97STreehugger Robot # real node is next after DOWN 2513*16467b97STreehugger Robot self.nodes.append(self.tree) 2514*16467b97STreehugger Robot return self.down 2515*16467b97STreehugger Robot 2516*16467b97STreehugger Robot # if no children, look for next sibling of tree or ancestor 2517*16467b97STreehugger Robot parent = self.adaptor.getParent(self.tree) 2518*16467b97STreehugger Robot # while we're out of siblings, keep popping back up towards root 2519*16467b97STreehugger Robot while (parent is not None 2520*16467b97STreehugger Robot and self.adaptor.getChildIndex(self.tree)+1 >= self.adaptor.getChildCount(parent)): 2521*16467b97STreehugger Robot # we're moving back up 2522*16467b97STreehugger Robot self.nodes.append(self.up) 2523*16467b97STreehugger Robot self.tree = parent 2524*16467b97STreehugger Robot parent = self.adaptor.getParent(self.tree) 2525*16467b97STreehugger Robot 2526*16467b97STreehugger Robot # no nodes left? 2527*16467b97STreehugger Robot if parent is None: 2528*16467b97STreehugger Robot self.tree = None # back at root? nothing left then 2529*16467b97STreehugger Robot self.nodes.append(self.eof) # add to queue, might have UP nodes in there 2530*16467b97STreehugger Robot return self.nodes.pop(0) 2531*16467b97STreehugger Robot 2532*16467b97STreehugger Robot # must have found a node with an unvisited sibling 2533*16467b97STreehugger Robot # move to it and return it 2534*16467b97STreehugger Robot nextSiblingIndex = self.adaptor.getChildIndex(self.tree) + 1 2535*16467b97STreehugger Robot self.tree = self.adaptor.getChild(parent, nextSiblingIndex) 2536*16467b97STreehugger Robot self.nodes.append(self.tree) # add to queue, might have UP nodes in there 2537*16467b97STreehugger Robot return self.nodes.pop(0) 2538*16467b97STreehugger Robot 2539*16467b97STreehugger Robot 2540*16467b97STreehugger Robot 2541*16467b97STreehugger Robot############################################################################# 2542*16467b97STreehugger Robot# 2543*16467b97STreehugger Robot# streams for rule rewriting 2544*16467b97STreehugger Robot# 2545*16467b97STreehugger Robot############################################################################# 2546*16467b97STreehugger Robot 2547*16467b97STreehugger Robotclass RewriteRuleElementStream(object): 2548*16467b97STreehugger Robot """@brief Internal helper class. 2549*16467b97STreehugger Robot 2550*16467b97STreehugger Robot A generic list of elements tracked in an alternative to be used in 2551*16467b97STreehugger Robot a -> rewrite rule. We need to subclass to fill in the next() method, 2552*16467b97STreehugger Robot which returns either an AST node wrapped around a token payload or 2553*16467b97STreehugger Robot an existing subtree. 2554*16467b97STreehugger Robot 2555*16467b97STreehugger Robot Once you start next()ing, do not try to add more elements. It will 2556*16467b97STreehugger Robot break the cursor tracking I believe. 2557*16467b97STreehugger Robot 2558*16467b97STreehugger Robot @see org.antlr.runtime.tree.RewriteRuleSubtreeStream 2559*16467b97STreehugger Robot @see org.antlr.runtime.tree.RewriteRuleTokenStream 2560*16467b97STreehugger Robot 2561*16467b97STreehugger Robot TODO: add mechanism to detect/puke on modification after reading from 2562*16467b97STreehugger Robot stream 2563*16467b97STreehugger Robot """ 2564*16467b97STreehugger Robot 2565*16467b97STreehugger Robot def __init__(self, adaptor, elementDescription, elements=None): 2566*16467b97STreehugger Robot # Cursor 0..n-1. If singleElement!=null, cursor is 0 until you next(), 2567*16467b97STreehugger Robot # which bumps it to 1 meaning no more elements. 2568*16467b97STreehugger Robot self.cursor = 0 2569*16467b97STreehugger Robot 2570*16467b97STreehugger Robot # Track single elements w/o creating a list. Upon 2nd add, alloc list 2571*16467b97STreehugger Robot self.singleElement = None 2572*16467b97STreehugger Robot 2573*16467b97STreehugger Robot # The list of tokens or subtrees we are tracking 2574*16467b97STreehugger Robot self.elements = None 2575*16467b97STreehugger Robot 2576*16467b97STreehugger Robot # Once a node / subtree has been used in a stream, it must be dup'd 2577*16467b97STreehugger Robot # from then on. Streams are reset after subrules so that the streams 2578*16467b97STreehugger Robot # can be reused in future subrules. So, reset must set a dirty bit. 2579*16467b97STreehugger Robot # If dirty, then next() always returns a dup. 2580*16467b97STreehugger Robot self.dirty = False 2581*16467b97STreehugger Robot 2582*16467b97STreehugger Robot # The element or stream description; usually has name of the token or 2583*16467b97STreehugger Robot # rule reference that this list tracks. Can include rulename too, but 2584*16467b97STreehugger Robot # the exception would track that info. 2585*16467b97STreehugger Robot self.elementDescription = elementDescription 2586*16467b97STreehugger Robot 2587*16467b97STreehugger Robot self.adaptor = adaptor 2588*16467b97STreehugger Robot 2589*16467b97STreehugger Robot if isinstance(elements, (list, tuple)): 2590*16467b97STreehugger Robot # Create a stream, but feed off an existing list 2591*16467b97STreehugger Robot self.singleElement = None 2592*16467b97STreehugger Robot self.elements = elements 2593*16467b97STreehugger Robot 2594*16467b97STreehugger Robot else: 2595*16467b97STreehugger Robot # Create a stream with one element 2596*16467b97STreehugger Robot self.add(elements) 2597*16467b97STreehugger Robot 2598*16467b97STreehugger Robot 2599*16467b97STreehugger Robot def reset(self): 2600*16467b97STreehugger Robot """ 2601*16467b97STreehugger Robot Reset the condition of this stream so that it appears we have 2602*16467b97STreehugger Robot not consumed any of its elements. Elements themselves are untouched. 2603*16467b97STreehugger Robot Once we reset the stream, any future use will need duplicates. Set 2604*16467b97STreehugger Robot the dirty bit. 2605*16467b97STreehugger Robot """ 2606*16467b97STreehugger Robot 2607*16467b97STreehugger Robot self.cursor = 0 2608*16467b97STreehugger Robot self.dirty = True 2609*16467b97STreehugger Robot 2610*16467b97STreehugger Robot 2611*16467b97STreehugger Robot def add(self, el): 2612*16467b97STreehugger Robot if el is None: 2613*16467b97STreehugger Robot return 2614*16467b97STreehugger Robot 2615*16467b97STreehugger Robot if self.elements is not None: # if in list, just add 2616*16467b97STreehugger Robot self.elements.append(el) 2617*16467b97STreehugger Robot return 2618*16467b97STreehugger Robot 2619*16467b97STreehugger Robot if self.singleElement is None: # no elements yet, track w/o list 2620*16467b97STreehugger Robot self.singleElement = el 2621*16467b97STreehugger Robot return 2622*16467b97STreehugger Robot 2623*16467b97STreehugger Robot # adding 2nd element, move to list 2624*16467b97STreehugger Robot self.elements = [] 2625*16467b97STreehugger Robot self.elements.append(self.singleElement) 2626*16467b97STreehugger Robot self.singleElement = None 2627*16467b97STreehugger Robot self.elements.append(el) 2628*16467b97STreehugger Robot 2629*16467b97STreehugger Robot 2630*16467b97STreehugger Robot def nextTree(self): 2631*16467b97STreehugger Robot """ 2632*16467b97STreehugger Robot Return the next element in the stream. If out of elements, throw 2633*16467b97STreehugger Robot an exception unless size()==1. If size is 1, then return elements[0]. 2634*16467b97STreehugger Robot 2635*16467b97STreehugger Robot Return a duplicate node/subtree if stream is out of elements and 2636*16467b97STreehugger Robot size==1. If we've already used the element, dup (dirty bit set). 2637*16467b97STreehugger Robot """ 2638*16467b97STreehugger Robot 2639*16467b97STreehugger Robot if (self.dirty 2640*16467b97STreehugger Robot or (self.cursor >= len(self) and len(self) == 1) 2641*16467b97STreehugger Robot ): 2642*16467b97STreehugger Robot # if out of elements and size is 1, dup 2643*16467b97STreehugger Robot el = self._next() 2644*16467b97STreehugger Robot return self.dup(el) 2645*16467b97STreehugger Robot 2646*16467b97STreehugger Robot # test size above then fetch 2647*16467b97STreehugger Robot el = self._next() 2648*16467b97STreehugger Robot return el 2649*16467b97STreehugger Robot 2650*16467b97STreehugger Robot 2651*16467b97STreehugger Robot def _next(self): 2652*16467b97STreehugger Robot """ 2653*16467b97STreehugger Robot do the work of getting the next element, making sure that it's 2654*16467b97STreehugger Robot a tree node or subtree. Deal with the optimization of single- 2655*16467b97STreehugger Robot element list versus list of size > 1. Throw an exception 2656*16467b97STreehugger Robot if the stream is empty or we're out of elements and size>1. 2657*16467b97STreehugger Robot protected so you can override in a subclass if necessary. 2658*16467b97STreehugger Robot """ 2659*16467b97STreehugger Robot 2660*16467b97STreehugger Robot if len(self) == 0: 2661*16467b97STreehugger Robot raise RewriteEmptyStreamException(self.elementDescription) 2662*16467b97STreehugger Robot 2663*16467b97STreehugger Robot if self.cursor >= len(self): # out of elements? 2664*16467b97STreehugger Robot if len(self) == 1: # if size is 1, it's ok; return and we'll dup 2665*16467b97STreehugger Robot return self.toTree(self.singleElement) 2666*16467b97STreehugger Robot 2667*16467b97STreehugger Robot # out of elements and size was not 1, so we can't dup 2668*16467b97STreehugger Robot raise RewriteCardinalityException(self.elementDescription) 2669*16467b97STreehugger Robot 2670*16467b97STreehugger Robot # we have elements 2671*16467b97STreehugger Robot if self.singleElement is not None: 2672*16467b97STreehugger Robot self.cursor += 1 # move cursor even for single element list 2673*16467b97STreehugger Robot return self.toTree(self.singleElement) 2674*16467b97STreehugger Robot 2675*16467b97STreehugger Robot # must have more than one in list, pull from elements 2676*16467b97STreehugger Robot o = self.toTree(self.elements[self.cursor]) 2677*16467b97STreehugger Robot self.cursor += 1 2678*16467b97STreehugger Robot return o 2679*16467b97STreehugger Robot 2680*16467b97STreehugger Robot 2681*16467b97STreehugger Robot def dup(self, el): 2682*16467b97STreehugger Robot """ 2683*16467b97STreehugger Robot When constructing trees, sometimes we need to dup a token or AST 2684*16467b97STreehugger Robot subtree. Dup'ing a token means just creating another AST node 2685*16467b97STreehugger Robot around it. For trees, you must call the adaptor.dupTree() unless 2686*16467b97STreehugger Robot the element is for a tree root; then it must be a node dup. 2687*16467b97STreehugger Robot """ 2688*16467b97STreehugger Robot 2689*16467b97STreehugger Robot raise NotImplementedError 2690*16467b97STreehugger Robot 2691*16467b97STreehugger Robot 2692*16467b97STreehugger Robot def toTree(self, el): 2693*16467b97STreehugger Robot """ 2694*16467b97STreehugger Robot Ensure stream emits trees; tokens must be converted to AST nodes. 2695*16467b97STreehugger Robot AST nodes can be passed through unmolested. 2696*16467b97STreehugger Robot """ 2697*16467b97STreehugger Robot 2698*16467b97STreehugger Robot return el 2699*16467b97STreehugger Robot 2700*16467b97STreehugger Robot 2701*16467b97STreehugger Robot def hasNext(self): 2702*16467b97STreehugger Robot return ( (self.singleElement is not None and self.cursor < 1) 2703*16467b97STreehugger Robot or (self.elements is not None 2704*16467b97STreehugger Robot and self.cursor < len(self.elements) 2705*16467b97STreehugger Robot ) 2706*16467b97STreehugger Robot ) 2707*16467b97STreehugger Robot 2708*16467b97STreehugger Robot 2709*16467b97STreehugger Robot def size(self): 2710*16467b97STreehugger Robot if self.singleElement is not None: 2711*16467b97STreehugger Robot return 1 2712*16467b97STreehugger Robot 2713*16467b97STreehugger Robot if self.elements is not None: 2714*16467b97STreehugger Robot return len(self.elements) 2715*16467b97STreehugger Robot 2716*16467b97STreehugger Robot return 0 2717*16467b97STreehugger Robot 2718*16467b97STreehugger Robot __len__ = size 2719*16467b97STreehugger Robot 2720*16467b97STreehugger Robot 2721*16467b97STreehugger Robot def getDescription(self): 2722*16467b97STreehugger Robot """Deprecated. Directly access elementDescription attribute""" 2723*16467b97STreehugger Robot 2724*16467b97STreehugger Robot return self.elementDescription 2725*16467b97STreehugger Robot 2726*16467b97STreehugger Robot 2727*16467b97STreehugger Robotclass RewriteRuleTokenStream(RewriteRuleElementStream): 2728*16467b97STreehugger Robot """@brief Internal helper class.""" 2729*16467b97STreehugger Robot 2730*16467b97STreehugger Robot def toTree(self, el): 2731*16467b97STreehugger Robot # Don't convert to a tree unless they explicitly call nextTree. 2732*16467b97STreehugger Robot # This way we can do hetero tree nodes in rewrite. 2733*16467b97STreehugger Robot return el 2734*16467b97STreehugger Robot 2735*16467b97STreehugger Robot 2736*16467b97STreehugger Robot def nextNode(self): 2737*16467b97STreehugger Robot t = self._next() 2738*16467b97STreehugger Robot return self.adaptor.createWithPayload(t) 2739*16467b97STreehugger Robot 2740*16467b97STreehugger Robot 2741*16467b97STreehugger Robot def nextToken(self): 2742*16467b97STreehugger Robot return self._next() 2743*16467b97STreehugger Robot 2744*16467b97STreehugger Robot 2745*16467b97STreehugger Robot def dup(self, el): 2746*16467b97STreehugger Robot raise TypeError("dup can't be called for a token stream.") 2747*16467b97STreehugger Robot 2748*16467b97STreehugger Robot 2749*16467b97STreehugger Robotclass RewriteRuleSubtreeStream(RewriteRuleElementStream): 2750*16467b97STreehugger Robot """@brief Internal helper class.""" 2751*16467b97STreehugger Robot 2752*16467b97STreehugger Robot def nextNode(self): 2753*16467b97STreehugger Robot """ 2754*16467b97STreehugger Robot Treat next element as a single node even if it's a subtree. 2755*16467b97STreehugger Robot This is used instead of next() when the result has to be a 2756*16467b97STreehugger Robot tree root node. Also prevents us from duplicating recently-added 2757*16467b97STreehugger Robot children; e.g., ^(type ID)+ adds ID to type and then 2nd iteration 2758*16467b97STreehugger Robot must dup the type node, but ID has been added. 2759*16467b97STreehugger Robot 2760*16467b97STreehugger Robot Referencing a rule result twice is ok; dup entire tree as 2761*16467b97STreehugger Robot we can't be adding trees as root; e.g., expr expr. 2762*16467b97STreehugger Robot 2763*16467b97STreehugger Robot Hideous code duplication here with super.next(). Can't think of 2764*16467b97STreehugger Robot a proper way to refactor. This needs to always call dup node 2765*16467b97STreehugger Robot and super.next() doesn't know which to call: dup node or dup tree. 2766*16467b97STreehugger Robot """ 2767*16467b97STreehugger Robot 2768*16467b97STreehugger Robot if (self.dirty 2769*16467b97STreehugger Robot or (self.cursor >= len(self) and len(self) == 1) 2770*16467b97STreehugger Robot ): 2771*16467b97STreehugger Robot # if out of elements and size is 1, dup (at most a single node 2772*16467b97STreehugger Robot # since this is for making root nodes). 2773*16467b97STreehugger Robot el = self._next() 2774*16467b97STreehugger Robot return self.adaptor.dupNode(el) 2775*16467b97STreehugger Robot 2776*16467b97STreehugger Robot # test size above then fetch 2777*16467b97STreehugger Robot el = self._next() 2778*16467b97STreehugger Robot while self.adaptor.isNil(el) and self.adaptor.getChildCount(el) == 1: 2779*16467b97STreehugger Robot el = self.adaptor.getChild(el, 0) 2780*16467b97STreehugger Robot 2781*16467b97STreehugger Robot # dup just the root (want node here) 2782*16467b97STreehugger Robot return self.adaptor.dupNode(el) 2783*16467b97STreehugger Robot 2784*16467b97STreehugger Robot 2785*16467b97STreehugger Robot def dup(self, el): 2786*16467b97STreehugger Robot return self.adaptor.dupTree(el) 2787*16467b97STreehugger Robot 2788*16467b97STreehugger Robot 2789*16467b97STreehugger Robot 2790*16467b97STreehugger Robotclass RewriteRuleNodeStream(RewriteRuleElementStream): 2791*16467b97STreehugger Robot """ 2792*16467b97STreehugger Robot Queues up nodes matched on left side of -> in a tree parser. This is 2793*16467b97STreehugger Robot the analog of RewriteRuleTokenStream for normal parsers. 2794*16467b97STreehugger Robot """ 2795*16467b97STreehugger Robot 2796*16467b97STreehugger Robot def nextNode(self): 2797*16467b97STreehugger Robot return self._next() 2798*16467b97STreehugger Robot 2799*16467b97STreehugger Robot 2800*16467b97STreehugger Robot def toTree(self, el): 2801*16467b97STreehugger Robot return self.adaptor.dupNode(el) 2802*16467b97STreehugger Robot 2803*16467b97STreehugger Robot 2804*16467b97STreehugger Robot def dup(self, el): 2805*16467b97STreehugger Robot # we dup every node, so don't have to worry about calling dup; short- 2806*16467b97STreehugger Robot #circuited next() so it doesn't call. 2807*16467b97STreehugger Robot raise TypeError("dup can't be called for a node stream.") 2808*16467b97STreehugger Robot 2809*16467b97STreehugger Robot 2810*16467b97STreehugger Robotclass TreeRuleReturnScope(RuleReturnScope): 2811*16467b97STreehugger Robot """ 2812*16467b97STreehugger Robot This is identical to the ParserRuleReturnScope except that 2813*16467b97STreehugger Robot the start property is a tree nodes not Token object 2814*16467b97STreehugger Robot when you are parsing trees. To be generic the tree node types 2815*16467b97STreehugger Robot have to be Object. 2816*16467b97STreehugger Robot """ 2817*16467b97STreehugger Robot 2818*16467b97STreehugger Robot def __init__(self): 2819*16467b97STreehugger Robot super().__init__() 2820*16467b97STreehugger Robot self.start = None 2821*16467b97STreehugger Robot self.tree = None 2822*16467b97STreehugger Robot 2823*16467b97STreehugger Robot 2824*16467b97STreehugger Robot def getStart(self): 2825*16467b97STreehugger Robot return self.start 2826*16467b97STreehugger Robot 2827*16467b97STreehugger Robot 2828*16467b97STreehugger Robot def getTree(self): 2829*16467b97STreehugger Robot return self.tree 2830