tree.py
Go to the documentation of this file.
00001 """ @package antlr3.tree
00002 @brief ANTLR3 runtime package, tree module
00003 
00004 This module contains all support classes for AST construction and tree parsers.
00005 
00006 """
00007 
00008 # begin[licence]
00009 #
00010 # [The "BSD licence"]
00011 # Copyright (c) 2005-2008 Terence Parr
00012 # All rights reserved.
00013 #
00014 # Redistribution and use in source and binary forms, with or without
00015 # modification, are permitted provided that the following conditions
00016 # are met:
00017 # 1. Redistributions of source code must retain the above copyright
00018 #    notice, this list of conditions and the following disclaimer.
00019 # 2. Redistributions in binary form must reproduce the above copyright
00020 #    notice, this list of conditions and the following disclaimer in the
00021 #    documentation and/or other materials provided with the distribution.
00022 # 3. The name of the author may not be used to endorse or promote products
00023 #    derived from this software without specific prior written permission.
00024 #
00025 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00026 # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00027 # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00028 # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00029 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00030 # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00031 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00032 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00033 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00034 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00035 #
00036 # end[licence]
00037 
00038 # lot's of docstrings are missing, don't complain for now...
00039 # pylint: disable-msg=C0111
00040 
00041 import re
00042 
00043 from constants import UP, DOWN, EOF, INVALID_TOKEN_TYPE
00044 from recognizers import BaseRecognizer, RuleReturnScope
00045 from streams import IntStream
00046 from tokens import CommonToken, Token, INVALID_TOKEN
00047 from exceptions import MismatchedTreeNodeException, \
00048      MissingTokenException, UnwantedTokenException, MismatchedTokenException, \
00049      NoViableAltException
00050 
00051 
00052 ############################################################################
00053 #
00054 # tree related exceptions
00055 #
00056 ############################################################################
00057 
00058 
00059 class RewriteCardinalityException(RuntimeError):
00060     """
00061     @brief Base class for all exceptions thrown during AST rewrite construction.
00062 
00063     This signifies a case where the cardinality of two or more elements
00064     in a subrule are different: (ID INT)+ where |ID|!=|INT|
00065     """
00066 
00067     def __init__(self, elementDescription):
00068         RuntimeError.__init__(self, elementDescription)
00069 
00070         self.elementDescription = elementDescription
00071 
00072 
00073     def getMessage(self):
00074         return self.elementDescription
00075 
00076 
00077 class RewriteEarlyExitException(RewriteCardinalityException):
00078     """@brief No elements within a (...)+ in a rewrite rule"""
00079 
00080     def __init__(self, elementDescription=None):
00081         RewriteCardinalityException.__init__(self, elementDescription)
00082 
00083 
00084 class RewriteEmptyStreamException(RewriteCardinalityException):
00085     """
00086     @brief Ref to ID or expr but no tokens in ID stream or subtrees in expr stream
00087     """
00088 
00089     pass
00090 
00091 
00092 ############################################################################
00093 #
00094 # basic Tree and TreeAdaptor interfaces
00095 #
00096 ############################################################################
00097 
00098 class Tree(object):
00099     """
00100     @brief Abstract baseclass for tree nodes.
00101     
00102     What does a tree look like?  ANTLR has a number of support classes
00103     such as CommonTreeNodeStream that work on these kinds of trees.  You
00104     don't have to make your trees implement this interface, but if you do,
00105     you'll be able to use more support code.
00106 
00107     NOTE: When constructing trees, ANTLR can build any kind of tree; it can
00108     even use Token objects as trees if you add a child list to your tokens.
00109     
00110     This is a tree node without any payload; just navigation and factory stuff.
00111     """
00112 
00113 
00114     def getChild(self, i):
00115         raise NotImplementedError
00116     
00117 
00118     def getChildCount(self):
00119         raise NotImplementedError
00120     
00121 
00122     def getParent(self):
00123         """Tree tracks parent and child index now > 3.0"""
00124 
00125         raise NotImplementedError
00126     
00127     def setParent(self, t):
00128         """Tree tracks parent and child index now > 3.0"""
00129 
00130         raise NotImplementedError
00131     
00132 
00133     def hasAncestor(self, ttype):
00134         """Walk upwards looking for ancestor with this token type."""
00135 
00136         raise NotImplementedError
00137 
00138     def getAncestor(self, ttype):
00139         """Walk upwards and get first ancestor with this token type."""
00140 
00141         raise NotImplementedError
00142 
00143     def getAncestors(self):
00144         """Return a list of all ancestors of this node.
00145 
00146         The first node of list is the root and the last is the parent of
00147         this node.
00148         """
00149 
00150         raise NotImplementedError
00151 
00152 
00153     def getChildIndex(self):
00154         """This node is what child index? 0..n-1"""
00155 
00156         raise NotImplementedError
00157         
00158     def setChildIndex(self, index):
00159         """This node is what child index? 0..n-1"""
00160 
00161         raise NotImplementedError
00162         
00163 
00164     def freshenParentAndChildIndexes(self):
00165         """Set the parent and child index values for all children"""
00166         
00167         raise NotImplementedError
00168 
00169         
00170     def addChild(self, t):
00171         """
00172         Add t as a child to this node.  If t is null, do nothing.  If t
00173         is nil, add all children of t to this' children.
00174         """
00175 
00176         raise NotImplementedError
00177     
00178 
00179     def setChild(self, i, t):
00180         """Set ith child (0..n-1) to t; t must be non-null and non-nil node"""
00181 
00182         raise NotImplementedError
00183 
00184             
00185     def deleteChild(self, i):
00186         raise NotImplementedError
00187         
00188  
00189     def replaceChildren(self, startChildIndex, stopChildIndex, t):
00190         """
00191         Delete children from start to stop and replace with t even if t is
00192         a list (nil-root tree).  num of children can increase or decrease.
00193         For huge child lists, inserting children can force walking rest of
00194         children to set their childindex; could be slow.
00195         """
00196 
00197         raise NotImplementedError
00198 
00199 
00200     def isNil(self):
00201         """
00202         Indicates the node is a nil node but may still have children, meaning
00203         the tree is a flat list.
00204         """
00205 
00206         raise NotImplementedError
00207     
00208 
00209     def getTokenStartIndex(self):
00210         """
00211         What is the smallest token index (indexing from 0) for this node
00212            and its children?
00213         """
00214 
00215         raise NotImplementedError
00216 
00217 
00218     def setTokenStartIndex(self, index):
00219         raise NotImplementedError
00220 
00221 
00222     def getTokenStopIndex(self):
00223         """
00224         What is the largest token index (indexing from 0) for this node
00225         and its children?
00226         """
00227 
00228         raise NotImplementedError
00229 
00230 
00231     def setTokenStopIndex(self, index):
00232         raise NotImplementedError
00233 
00234 
00235     def dupNode(self):
00236         raise NotImplementedError
00237     
00238     
00239     def getType(self):
00240         """Return a token type; needed for tree parsing."""
00241 
00242         raise NotImplementedError
00243     
00244 
00245     def getText(self):
00246         raise NotImplementedError
00247     
00248 
00249     def getLine(self):
00250         """
00251         In case we don't have a token payload, what is the line for errors?
00252         """
00253 
00254         raise NotImplementedError
00255     
00256 
00257     def getCharPositionInLine(self):
00258         raise NotImplementedError
00259 
00260 
00261     def toStringTree(self):
00262         raise NotImplementedError
00263 
00264 
00265     def toString(self):
00266         raise NotImplementedError
00267 
00268 
00269 
00270 class TreeAdaptor(object):
00271     """
00272     @brief Abstract baseclass for tree adaptors.
00273     
00274     How to create and navigate trees.  Rather than have a separate factory
00275     and adaptor, I've merged them.  Makes sense to encapsulate.
00276 
00277     This takes the place of the tree construction code generated in the
00278     generated code in 2.x and the ASTFactory.
00279 
00280     I do not need to know the type of a tree at all so they are all
00281     generic Objects.  This may increase the amount of typecasting needed. :(
00282     """
00283     
00284     # C o n s t r u c t i o n
00285 
00286     def createWithPayload(self, payload):
00287         """
00288         Create a tree node from Token object; for CommonTree type trees,
00289         then the token just becomes the payload.  This is the most
00290         common create call.
00291 
00292         Override if you want another kind of node to be built.
00293         """
00294 
00295         raise NotImplementedError
00296     
00297 
00298     def dupNode(self, treeNode):
00299         """Duplicate a single tree node.
00300 
00301         Override if you want another kind of node to be built."""
00302 
00303         raise NotImplementedError
00304 
00305 
00306     def dupTree(self, tree):
00307         """Duplicate tree recursively, using dupNode() for each node"""
00308 
00309         raise NotImplementedError
00310 
00311 
00312     def nil(self):
00313         """
00314         Return a nil node (an empty but non-null node) that can hold
00315         a list of element as the children.  If you want a flat tree (a list)
00316         use "t=adaptor.nil(); t.addChild(x); t.addChild(y);"
00317         """
00318 
00319         raise NotImplementedError
00320 
00321 
00322     def errorNode(self, input, start, stop, exc):
00323         """
00324         Return a tree node representing an error.  This node records the
00325         tokens consumed during error recovery.  The start token indicates the
00326         input symbol at which the error was detected.  The stop token indicates
00327         the last symbol consumed during recovery.
00328 
00329         You must specify the input stream so that the erroneous text can
00330         be packaged up in the error node.  The exception could be useful
00331         to some applications; default implementation stores ptr to it in
00332         the CommonErrorNode.
00333 
00334         This only makes sense during token parsing, not tree parsing.
00335         Tree parsing should happen only when parsing and tree construction
00336         succeed.
00337         """
00338 
00339         raise NotImplementedError
00340 
00341 
00342     def isNil(self, tree):
00343         """Is tree considered a nil node used to make lists of child nodes?"""
00344 
00345         raise NotImplementedError
00346 
00347 
00348     def addChild(self, t, child):
00349         """
00350         Add a child to the tree t.  If child is a flat tree (a list), make all
00351         in list children of t.  Warning: if t has no children, but child does
00352         and child isNil then you can decide it is ok to move children to t via
00353         t.children = child.children; i.e., without copying the array.  Just
00354         make sure that this is consistent with have the user will build
00355         ASTs. Do nothing if t or child is null.
00356         """
00357 
00358         raise NotImplementedError
00359 
00360 
00361     def becomeRoot(self, newRoot, oldRoot):
00362         """
00363         If oldRoot is a nil root, just copy or move the children to newRoot.
00364         If not a nil root, make oldRoot a child of newRoot.
00365         
00366            old=^(nil a b c), new=r yields ^(r a b c)
00367            old=^(a b c), new=r yields ^(r ^(a b c))
00368 
00369         If newRoot is a nil-rooted single child tree, use the single
00370         child as the new root node.
00371 
00372            old=^(nil a b c), new=^(nil r) yields ^(r a b c)
00373            old=^(a b c), new=^(nil r) yields ^(r ^(a b c))
00374 
00375         If oldRoot was null, it's ok, just return newRoot (even if isNil).
00376 
00377            old=null, new=r yields r
00378            old=null, new=^(nil r) yields ^(nil r)
00379 
00380         Return newRoot.  Throw an exception if newRoot is not a
00381         simple node or nil root with a single child node--it must be a root
00382         node.  If newRoot is ^(nil x) return x as newRoot.
00383 
00384         Be advised that it's ok for newRoot to point at oldRoot's
00385         children; i.e., you don't have to copy the list.  We are
00386         constructing these nodes so we should have this control for
00387         efficiency.
00388         """
00389 
00390         raise NotImplementedError
00391 
00392 
00393     def rulePostProcessing(self, root):
00394         """
00395         Given the root of the subtree created for this rule, post process
00396         it to do any simplifications or whatever you want.  A required
00397         behavior is to convert ^(nil singleSubtree) to singleSubtree
00398         as the setting of start/stop indexes relies on a single non-nil root
00399         for non-flat trees.
00400 
00401         Flat trees such as for lists like "idlist : ID+ ;" are left alone
00402         unless there is only one ID.  For a list, the start/stop indexes
00403         are set in the nil node.
00404 
00405         This method is executed after all rule tree construction and right
00406         before setTokenBoundaries().
00407         """
00408 
00409         raise NotImplementedError
00410 
00411 
00412     def getUniqueID(self, node):
00413         """For identifying trees.
00414 
00415         How to identify nodes so we can say "add node to a prior node"?
00416         Even becomeRoot is an issue.  Use System.identityHashCode(node)
00417         usually.
00418         """
00419 
00420         raise NotImplementedError
00421 
00422 
00423     # R e w r i t e  R u l e s
00424 
00425     def createFromToken(self, tokenType, fromToken, text=None):
00426         """
00427         Create a new node derived from a token, with a new token type and
00428         (optionally) new text.
00429 
00430         This is invoked from an imaginary node ref on right side of a
00431         rewrite rule as IMAG[$tokenLabel] or IMAG[$tokenLabel "IMAG"].
00432 
00433         This should invoke createToken(Token).
00434         """
00435 
00436         raise NotImplementedError
00437 
00438 
00439     def createFromType(self, tokenType, text):
00440         """Create a new node derived from a token, with a new token type.
00441 
00442         This is invoked from an imaginary node ref on right side of a
00443         rewrite rule as IMAG["IMAG"].
00444 
00445         This should invoke createToken(int,String).
00446         """
00447 
00448         raise NotImplementedError
00449 
00450 
00451     # C o n t e n t
00452 
00453     def getType(self, t):
00454         """For tree parsing, I need to know the token type of a node"""
00455 
00456         raise NotImplementedError
00457 
00458 
00459     def setType(self, t, type):
00460         """Node constructors can set the type of a node"""
00461 
00462         raise NotImplementedError
00463 
00464 
00465     def getText(self, t):
00466         raise NotImplementedError
00467 
00468     def setText(self, t, text):
00469         """Node constructors can set the text of a node"""
00470 
00471         raise NotImplementedError
00472 
00473 
00474     def getToken(self, t):
00475         """Return the token object from which this node was created.
00476 
00477         Currently used only for printing an error message.
00478         The error display routine in BaseRecognizer needs to
00479         display where the input the error occurred. If your
00480         tree of limitation does not store information that can
00481         lead you to the token, you can create a token filled with
00482         the appropriate information and pass that back.  See
00483         BaseRecognizer.getErrorMessage().
00484         """
00485 
00486         raise NotImplementedError
00487 
00488 
00489     def setTokenBoundaries(self, t, startToken, stopToken):
00490         """
00491         Where are the bounds in the input token stream for this node and
00492         all children?  Each rule that creates AST nodes will call this
00493         method right before returning.  Flat trees (i.e., lists) will
00494         still usually have a nil root node just to hold the children list.
00495         That node would contain the start/stop indexes then.
00496         """
00497 
00498         raise NotImplementedError
00499 
00500 
00501     def getTokenStartIndex(self, t):
00502         """
00503         Get the token start index for this subtree; return -1 if no such index
00504         """
00505 
00506         raise NotImplementedError
00507 
00508         
00509     def getTokenStopIndex(self, t):
00510         """
00511         Get the token stop index for this subtree; return -1 if no such index
00512         """
00513 
00514         raise NotImplementedError
00515         
00516 
00517     # N a v i g a t i o n  /  T r e e  P a r s i n g
00518 
00519     def getChild(self, t, i):
00520         """Get a child 0..n-1 node"""
00521 
00522         raise NotImplementedError
00523 
00524 
00525     def setChild(self, t, i, child):
00526         """Set ith child (0..n-1) to t; t must be non-null and non-nil node"""
00527 
00528         raise NotImplementedError
00529 
00530 
00531     def deleteChild(self, t, i):
00532         """Remove ith child and shift children down from right."""
00533         
00534         raise NotImplementedError
00535 
00536 
00537     def getChildCount(self, t):
00538         """How many children?  If 0, then this is a leaf node"""
00539 
00540         raise NotImplementedError
00541 
00542 
00543     def getParent(self, t):
00544         """
00545         Who is the parent node of this node; if null, implies node is root.
00546         If your node type doesn't handle this, it's ok but the tree rewrites
00547         in tree parsers need this functionality.
00548         """
00549         
00550         raise NotImplementedError
00551 
00552 
00553     def setParent(self, t, parent):
00554         """
00555         Who is the parent node of this node; if null, implies node is root.
00556         If your node type doesn't handle this, it's ok but the tree rewrites
00557         in tree parsers need this functionality.
00558         """
00559 
00560         raise NotImplementedError
00561 
00562 
00563     def getChildIndex(self, t):
00564         """
00565         What index is this node in the child list? Range: 0..n-1
00566         If your node type doesn't handle this, it's ok but the tree rewrites
00567         in tree parsers need this functionality.
00568         """
00569 
00570         raise NotImplementedError
00571 
00572         
00573     def setChildIndex(self, t, index):
00574         """
00575         What index is this node in the child list? Range: 0..n-1
00576         If your node type doesn't handle this, it's ok but the tree rewrites
00577         in tree parsers need this functionality.
00578         """
00579 
00580         raise NotImplementedError
00581 
00582 
00583     def replaceChildren(self, parent, startChildIndex, stopChildIndex, t):
00584         """
00585         Replace from start to stop child index of parent with t, which might
00586         be a list.  Number of children may be different
00587         after this call.
00588 
00589         If parent is null, don't do anything; must be at root of overall tree.
00590         Can't replace whatever points to the parent externally.  Do nothing.
00591         """
00592 
00593         raise NotImplementedError
00594 
00595 
00596     # Misc
00597 
00598     def create(self, *args):
00599         """
00600         Deprecated, use createWithPayload, createFromToken or createFromType.
00601 
00602         This method only exists to mimic the Java interface of TreeAdaptor.
00603         
00604         """
00605 
00606         if len(args) == 1 and isinstance(args[0], Token):
00607             # Object create(Token payload);
00608 ##             warnings.warn(
00609 ##                 "Using create() is deprecated, use createWithPayload()",
00610 ##                 DeprecationWarning,
00611 ##                 stacklevel=2
00612 ##                 )
00613             return self.createWithPayload(args[0])
00614 
00615         if (len(args) == 2
00616             and isinstance(args[0], (int, long))
00617             and isinstance(args[1], Token)
00618             ):
00619             # Object create(int tokenType, Token fromToken);
00620 ##             warnings.warn(
00621 ##                 "Using create() is deprecated, use createFromToken()",
00622 ##                 DeprecationWarning,
00623 ##                 stacklevel=2
00624 ##                 )
00625             return self.createFromToken(args[0], args[1])
00626 
00627         if (len(args) == 3
00628             and isinstance(args[0], (int, long))
00629             and isinstance(args[1], Token)
00630             and isinstance(args[2], basestring)
00631             ):
00632             # Object create(int tokenType, Token fromToken, String text);
00633 ##             warnings.warn(
00634 ##                 "Using create() is deprecated, use createFromToken()",
00635 ##                 DeprecationWarning,
00636 ##                 stacklevel=2
00637 ##                 )
00638             return self.createFromToken(args[0], args[1], args[2])
00639 
00640         if (len(args) == 2
00641             and isinstance(args[0], (int, long))
00642             and isinstance(args[1], basestring)
00643             ):
00644             # Object create(int tokenType, String text);
00645 ##             warnings.warn(
00646 ##                 "Using create() is deprecated, use createFromType()",
00647 ##                 DeprecationWarning,
00648 ##                 stacklevel=2
00649 ##                 )
00650             return self.createFromType(args[0], args[1])
00651 
00652         raise TypeError(
00653             "No create method with this signature found: %s"
00654             % (', '.join(type(v).__name__ for v in args))
00655             )
00656     
00657 
00658 ############################################################################
00659 #
00660 # base implementation of Tree and TreeAdaptor
00661 #
00662 # Tree
00663 # \- BaseTree
00664 #
00665 # TreeAdaptor
00666 # \- BaseTreeAdaptor
00667 #
00668 ############################################################################
00669 
00670 
00671 class BaseTree(Tree):
00672     """
00673     @brief A generic tree implementation with no payload.
00674 
00675     You must subclass to
00676     actually have any user data.  ANTLR v3 uses a list of children approach
00677     instead of the child-sibling approach in v2.  A flat tree (a list) is
00678     an empty node whose children represent the list.  An empty, but
00679     non-null node is called "nil".
00680     """
00681 
00682     # BaseTree is abstract, no need to complain about not implemented abstract
00683     # methods
00684     # pylint: disable-msg=W0223
00685     
00686     def __init__(self, node=None):
00687         """
00688         Create a new node from an existing node does nothing for BaseTree
00689         as there are no fields other than the children list, which cannot
00690         be copied as the children are not considered part of this node. 
00691         """
00692         
00693         Tree.__init__(self)
00694         self.children = []
00695         self.parent = None
00696         self.childIndex = 0
00697         
00698 
00699     def getChild(self, i):
00700         try:
00701             return self.children[i]
00702         except IndexError:
00703             return None
00704 
00705 
00706     def getChildren(self):
00707         """@brief Get the children internal List
00708 
00709         Note that if you directly mess with
00710         the list, do so at your own risk.
00711         """
00712         
00713         # FIXME: mark as deprecated
00714         return self.children
00715 
00716 
00717     def getFirstChildWithType(self, treeType):
00718         for child in self.children:
00719             if child.getType() == treeType:
00720                 return child
00721 
00722         return None
00723 
00724 
00725     def getChildCount(self):
00726         return len(self.children)
00727 
00728 
00729     def addChild(self, childTree):
00730         """Add t as child of this node.
00731 
00732         Warning: if t has no children, but child does
00733         and child isNil then this routine moves children to t via
00734         t.children = child.children; i.e., without copying the array.
00735         """
00736 
00737         # this implementation is much simpler and probably less efficient
00738         # than the mumbo-jumbo that Ter did for the Java runtime.
00739         
00740         if childTree is None:
00741             return
00742 
00743         if childTree.isNil():
00744             # t is an empty node possibly with children
00745 
00746             if self.children is childTree.children:
00747                 raise ValueError("attempt to add child list to itself")
00748 
00749             # fix parent pointer and childIndex for new children
00750             for idx, child in enumerate(childTree.children):
00751                 child.parent = self
00752                 child.childIndex = len(self.children) + idx
00753                 
00754             self.children += childTree.children
00755 
00756         else:
00757             # child is not nil (don't care about children)
00758             self.children.append(childTree)
00759             childTree.parent = self
00760             childTree.childIndex = len(self.children) - 1
00761 
00762 
00763     def addChildren(self, children):
00764         """Add all elements of kids list as children of this node"""
00765 
00766         self.children += children
00767 
00768 
00769     def setChild(self, i, t):
00770         if t is None:
00771             return
00772 
00773         if t.isNil():
00774             raise ValueError("Can't set single child to a list")
00775         
00776         self.children[i] = t
00777         t.parent = self
00778         t.childIndex = i
00779         
00780 
00781     def deleteChild(self, i):
00782         killed = self.children[i]
00783         
00784         del self.children[i]
00785         
00786         # walk rest and decrement their child indexes
00787         for idx, child in enumerate(self.children[i:]):
00788             child.childIndex = i + idx
00789             
00790         return killed
00791 
00792     
00793     def replaceChildren(self, startChildIndex, stopChildIndex, newTree):
00794         """
00795         Delete children from start to stop and replace with t even if t is
00796         a list (nil-root tree).  num of children can increase or decrease.
00797         For huge child lists, inserting children can force walking rest of
00798         children to set their childindex; could be slow.
00799         """
00800 
00801         if (startChildIndex >= len(self.children)
00802             or stopChildIndex >= len(self.children)
00803             ):
00804             raise IndexError("indexes invalid")
00805 
00806         replacingHowMany = stopChildIndex - startChildIndex + 1
00807 
00808         # normalize to a list of children to add: newChildren
00809         if newTree.isNil():
00810             newChildren = newTree.children
00811 
00812         else:
00813             newChildren = [newTree]
00814 
00815         replacingWithHowMany = len(newChildren)
00816         delta = replacingHowMany - replacingWithHowMany
00817         
00818         
00819         if delta == 0:
00820             # if same number of nodes, do direct replace
00821             for idx, child in enumerate(newChildren):
00822                 self.children[idx + startChildIndex] = child
00823                 child.parent = self
00824                 child.childIndex = idx + startChildIndex
00825 
00826         else:
00827             # length of children changes...
00828 
00829             # ...delete replaced segment...
00830             del self.children[startChildIndex:stopChildIndex+1]
00831 
00832             # ...insert new segment...
00833             self.children[startChildIndex:startChildIndex] = newChildren
00834 
00835             # ...and fix indeces
00836             self.freshenParentAndChildIndexes(startChildIndex)
00837             
00838 
00839     def isNil(self):
00840         return False
00841 
00842 
00843     def freshenParentAndChildIndexes(self, offset=0):
00844         for idx, child in enumerate(self.children[offset:]):
00845             child.childIndex = idx + offset
00846             child.parent = self
00847 
00848 
00849     def sanityCheckParentAndChildIndexes(self, parent=None, i=-1):
00850         if parent != self.parent:
00851             raise ValueError(
00852                 "parents don't match; expected %r found %r"
00853                 % (parent, self.parent)
00854                 )
00855         
00856         if i != self.childIndex:
00857             raise ValueError(
00858                 "child indexes don't match; expected %d found %d"
00859                 % (i, self.childIndex)
00860                 )
00861 
00862         for idx, child in enumerate(self.children):
00863             child.sanityCheckParentAndChildIndexes(self, idx)
00864 
00865 
00866     def getChildIndex(self):
00867         """BaseTree doesn't track child indexes."""
00868         
00869         return 0
00870 
00871 
00872     def setChildIndex(self, index):
00873         """BaseTree doesn't track child indexes."""
00874 
00875         pass
00876     
00877 
00878     def getParent(self):
00879         """BaseTree doesn't track parent pointers."""
00880 
00881         return None
00882 
00883     def setParent(self, t):
00884         """BaseTree doesn't track parent pointers."""
00885 
00886         pass
00887 
00888 
00889     def hasAncestor(self, ttype):
00890         """Walk upwards looking for ancestor with this token type."""
00891         return self.getAncestor(ttype) is not None
00892 
00893     def getAncestor(self, ttype):
00894         """Walk upwards and get first ancestor with this token type."""
00895         t = self.getParent()
00896         while t is not None:
00897             if t.getType() == ttype:
00898                 return t
00899             t = t.getParent()
00900 
00901         return None
00902 
00903     def getAncestors(self):
00904         """Return a list of all ancestors of this node.
00905 
00906         The first node of list is the root and the last is the parent of
00907         this node.
00908         """
00909         if selfgetParent() is None:
00910             return None
00911 
00912         ancestors = []
00913         t = self.getParent()
00914         while t is not None:
00915             ancestors.insert(0, t) # insert at start
00916             t = t.getParent()
00917 
00918         return ancestors
00919 
00920 
00921     def toStringTree(self):
00922         """Print out a whole tree not just a node"""
00923 
00924         if len(self.children) == 0:
00925             return self.toString()
00926 
00927         buf = []
00928         if not self.isNil():
00929             buf.append('(')
00930             buf.append(self.toString())
00931             buf.append(' ')
00932 
00933         for i, child in enumerate(self.children):
00934             if i > 0:
00935                 buf.append(' ')
00936             buf.append(child.toStringTree())
00937 
00938         if not self.isNil():
00939             buf.append(')')
00940 
00941         return ''.join(buf)
00942 
00943 
00944     def getLine(self):
00945         return 0
00946 
00947 
00948     def getCharPositionInLine(self):
00949         return 0
00950 
00951 
00952     def toString(self):
00953         """Override to say how a node (not a tree) should look as text"""
00954 
00955         raise NotImplementedError
00956 
00957 
00958 
00959 class BaseTreeAdaptor(TreeAdaptor):
00960     """
00961     @brief A TreeAdaptor that works with any Tree implementation.
00962     """
00963     
00964     # BaseTreeAdaptor is abstract, no need to complain about not implemented
00965     # abstract methods
00966     # pylint: disable-msg=W0223
00967     
00968     def nil(self):
00969         return self.createWithPayload(None)
00970 
00971 
00972     def errorNode(self, input, start, stop, exc):
00973         """
00974         create tree node that holds the start and stop tokens associated
00975         with an error.
00976 
00977         If you specify your own kind of tree nodes, you will likely have to
00978         override this method. CommonTree returns Token.INVALID_TOKEN_TYPE
00979         if no token payload but you might have to set token type for diff
00980         node type.
00981 
00982         You don't have to subclass CommonErrorNode; you will likely need to
00983         subclass your own tree node class to avoid class cast exception.
00984         """
00985         
00986         return CommonErrorNode(input, start, stop, exc)
00987     
00988 
00989     def isNil(self, tree):
00990         return tree.isNil()
00991 
00992 
00993     def dupTree(self, t, parent=None):
00994         """
00995         This is generic in the sense that it will work with any kind of
00996         tree (not just Tree interface).  It invokes the adaptor routines
00997         not the tree node routines to do the construction.
00998         """
00999 
01000         if t is None:
01001             return None
01002 
01003         newTree = self.dupNode(t)
01004         
01005         # ensure new subtree root has parent/child index set
01006 
01007         # same index in new tree
01008         self.setChildIndex(newTree, self.getChildIndex(t))
01009         
01010         self.setParent(newTree, parent)
01011 
01012         for i in range(self.getChildCount(t)):
01013             child = self.getChild(t, i)
01014             newSubTree = self.dupTree(child, t)
01015             self.addChild(newTree, newSubTree)
01016 
01017         return newTree
01018 
01019 
01020     def addChild(self, tree, child):
01021         """
01022         Add a child to the tree t.  If child is a flat tree (a list), make all
01023         in list children of t.  Warning: if t has no children, but child does
01024         and child isNil then you can decide it is ok to move children to t via
01025         t.children = child.children; i.e., without copying the array.  Just
01026         make sure that this is consistent with have the user will build
01027         ASTs.
01028         """
01029 
01030         #if isinstance(child, Token):
01031         #    child = self.createWithPayload(child)
01032         
01033         if tree is not None and child is not None:
01034             tree.addChild(child)
01035 
01036 
01037     def becomeRoot(self, newRoot, oldRoot):
01038         """
01039         If oldRoot is a nil root, just copy or move the children to newRoot.
01040         If not a nil root, make oldRoot a child of newRoot.
01041 
01042           old=^(nil a b c), new=r yields ^(r a b c)
01043           old=^(a b c), new=r yields ^(r ^(a b c))
01044 
01045         If newRoot is a nil-rooted single child tree, use the single
01046         child as the new root node.
01047 
01048           old=^(nil a b c), new=^(nil r) yields ^(r a b c)
01049           old=^(a b c), new=^(nil r) yields ^(r ^(a b c))
01050 
01051         If oldRoot was null, it's ok, just return newRoot (even if isNil).
01052 
01053           old=null, new=r yields r
01054           old=null, new=^(nil r) yields ^(nil r)
01055 
01056         Return newRoot.  Throw an exception if newRoot is not a
01057         simple node or nil root with a single child node--it must be a root
01058         node.  If newRoot is ^(nil x) return x as newRoot.
01059 
01060         Be advised that it's ok for newRoot to point at oldRoot's
01061         children; i.e., you don't have to copy the list.  We are
01062         constructing these nodes so we should have this control for
01063         efficiency.
01064         """
01065 
01066         if isinstance(newRoot, Token):
01067             newRoot = self.create(newRoot)
01068 
01069         if oldRoot is None:
01070             return newRoot
01071         
01072         if not isinstance(newRoot, CommonTree):
01073             newRoot = self.createWithPayload(newRoot)
01074 
01075         # handle ^(nil real-node)
01076         if newRoot.isNil():
01077             nc = newRoot.getChildCount()
01078             if nc == 1:
01079                 newRoot = newRoot.getChild(0)
01080                 
01081             elif nc > 1:
01082                 # TODO: make tree run time exceptions hierarchy
01083                 raise RuntimeError("more than one node as root")
01084 
01085         # add oldRoot to newRoot; addChild takes care of case where oldRoot
01086         # is a flat list (i.e., nil-rooted tree).  All children of oldRoot
01087         # are added to newRoot.
01088         newRoot.addChild(oldRoot)
01089         return newRoot
01090 
01091 
01092     def rulePostProcessing(self, root):
01093         """Transform ^(nil x) to x and nil to null"""
01094         
01095         if root is not None and root.isNil():
01096             if root.getChildCount() == 0:
01097                 root = None
01098 
01099             elif root.getChildCount() == 1:
01100                 root = root.getChild(0)
01101                 # whoever invokes rule will set parent and child index
01102                 root.setParent(None)
01103                 root.setChildIndex(-1)
01104 
01105         return root
01106 
01107 
01108     def createFromToken(self, tokenType, fromToken, text=None):
01109         assert isinstance(tokenType, (int, long)), type(tokenType).__name__
01110         assert isinstance(fromToken, Token), type(fromToken).__name__
01111         assert text is None or isinstance(text, basestring), type(text).__name__
01112 
01113         fromToken = self.createToken(fromToken)
01114         fromToken.type = tokenType
01115         if text is not None:
01116             fromToken.text = text
01117         t = self.createWithPayload(fromToken)
01118         return t
01119 
01120 
01121     def createFromType(self, tokenType, text):
01122         assert isinstance(tokenType, (int, long)), type(tokenType).__name__
01123         assert isinstance(text, basestring), type(text).__name__
01124                           
01125         fromToken = self.createToken(tokenType=tokenType, text=text)
01126         t = self.createWithPayload(fromToken)
01127         return t
01128 
01129 
01130     def getType(self, t):
01131         return t.getType()
01132 
01133 
01134     def setType(self, t, type):
01135         raise RuntimeError("don't know enough about Tree node")
01136 
01137 
01138     def getText(self, t):
01139         return t.getText()
01140 
01141 
01142     def setText(self, t, text):
01143         raise RuntimeError("don't know enough about Tree node")
01144 
01145 
01146     def getChild(self, t, i):
01147         return t.getChild(i)
01148 
01149 
01150     def setChild(self, t, i, child):
01151         t.setChild(i, child)
01152 
01153 
01154     def deleteChild(self, t, i):
01155         return t.deleteChild(i)
01156 
01157 
01158     def getChildCount(self, t):
01159         return t.getChildCount()
01160 
01161 
01162     def getUniqueID(self, node):
01163         return hash(node)
01164 
01165 
01166     def createToken(self, fromToken=None, tokenType=None, text=None):
01167         """
01168         Tell me how to create a token for use with imaginary token nodes.
01169         For example, there is probably no input symbol associated with imaginary
01170         token DECL, but you need to create it as a payload or whatever for
01171         the DECL node as in ^(DECL type ID).
01172 
01173         If you care what the token payload objects' type is, you should
01174         override this method and any other createToken variant.
01175         """
01176 
01177         raise NotImplementedError
01178 
01179 
01180 ############################################################################
01181 #
01182 # common tree implementation
01183 #
01184 # Tree
01185 # \- BaseTree
01186 #    \- CommonTree
01187 #       \- CommonErrorNode
01188 #
01189 # TreeAdaptor
01190 # \- BaseTreeAdaptor
01191 #    \- CommonTreeAdaptor
01192 #
01193 ############################################################################
01194 
01195 
01196 class CommonTree(BaseTree):
01197     """@brief A tree node that is wrapper for a Token object.
01198 
01199     After 3.0 release
01200     while building tree rewrite stuff, it became clear that computing
01201     parent and child index is very difficult and cumbersome.  Better to
01202     spend the space in every tree node.  If you don't want these extra
01203     fields, it's easy to cut them out in your own BaseTree subclass.
01204     
01205     """
01206 
01207     def __init__(self, payload):
01208         BaseTree.__init__(self)
01209         
01210         # What token indexes bracket all tokens associated with this node
01211         # and below?
01212         self.startIndex = -1
01213         self.stopIndex = -1
01214 
01215         # Who is the parent node of this node; if null, implies node is root
01216         self.parent = None
01217         
01218         # What index is this node in the child list? Range: 0..n-1
01219         self.childIndex = -1
01220 
01221         # A single token is the payload
01222         if payload is None:
01223             self.token = None
01224             
01225         elif isinstance(payload, CommonTree):
01226             self.token = payload.token
01227             self.startIndex = payload.startIndex
01228             self.stopIndex = payload.stopIndex
01229             
01230         elif payload is None or isinstance(payload, Token):
01231             self.token = payload
01232             
01233         else:
01234             raise TypeError(type(payload).__name__)
01235 
01236 
01237 
01238     def getToken(self):
01239         return self.token
01240 
01241 
01242     def dupNode(self):
01243         return CommonTree(self)
01244 
01245 
01246     def isNil(self):
01247         return self.token is None
01248 
01249 
01250     def getType(self):
01251         if self.token is None:
01252             return INVALID_TOKEN_TYPE
01253 
01254         return self.token.getType()
01255 
01256     type = property(getType)
01257     
01258 
01259     def getText(self):
01260         if self.token is None:
01261             return None
01262         
01263         return self.token.text
01264 
01265     text = property(getText)
01266     
01267 
01268     def getLine(self):
01269         if self.token is None or self.token.getLine() == 0:
01270             if self.getChildCount():
01271                 return self.getChild(0).getLine()
01272             else:
01273                 return 0
01274 
01275         return self.token.getLine()
01276 
01277     line = property(getLine)
01278     
01279 
01280     def getCharPositionInLine(self):
01281         if self.token is None or self.token.getCharPositionInLine() == -1:
01282             if self.getChildCount():
01283                 return self.getChild(0).getCharPositionInLine()
01284             else:
01285                 return 0
01286 
01287         else:
01288             return self.token.getCharPositionInLine()
01289 
01290     charPositionInLine = property(getCharPositionInLine)
01291     
01292 
01293     def getTokenStartIndex(self):
01294         if self.startIndex == -1 and self.token is not None:
01295             return self.token.getTokenIndex()
01296         
01297         return self.startIndex
01298     
01299     def setTokenStartIndex(self, index):
01300         self.startIndex = index
01301 
01302     tokenStartIndex = property(getTokenStartIndex, setTokenStartIndex)
01303 
01304 
01305     def getTokenStopIndex(self):
01306         if self.stopIndex == -1 and self.token is not None:
01307             return self.token.getTokenIndex()
01308         
01309         return self.stopIndex
01310 
01311     def setTokenStopIndex(self, index):
01312         self.stopIndex = index
01313 
01314     tokenStopIndex = property(getTokenStopIndex, setTokenStopIndex)
01315 
01316 
01317     def setUnknownTokenBoundaries(self):
01318         """For every node in this subtree, make sure it's start/stop token's
01319         are set.  Walk depth first, visit bottom up.  Only updates nodes
01320         with at least one token index < 0.
01321         """
01322 
01323         if self.children is None:
01324             if self.startIndex < 0 or self.stopIndex < 0:
01325                 self.startIndex = self.stopIndex = self.token.getTokenIndex()
01326 
01327             return
01328  
01329         for child in self.children:
01330             child.setUnknownTokenBoundaries()
01331 
01332         if self.startIndex >= 0 and self.stopIndex >= 0:
01333             # already set
01334             return
01335 
01336         if self.children:
01337             firstChild = self.children[0]
01338             lastChild = self.children[-1]
01339             self.startIndex = firstChild.getTokenStartIndex()
01340             self.stopIndex = lastChild.getTokenStopIndex()
01341 
01342 
01343     def getChildIndex(self):
01344         #FIXME: mark as deprecated
01345         return self.childIndex
01346 
01347 
01348     def setChildIndex(self, idx):
01349         #FIXME: mark as deprecated
01350         self.childIndex = idx
01351 
01352 
01353     def getParent(self):
01354         #FIXME: mark as deprecated
01355         return self.parent
01356 
01357 
01358     def setParent(self, t):
01359         #FIXME: mark as deprecated
01360         self.parent = t
01361 
01362         
01363     def toString(self):
01364         if self.isNil():
01365             return "nil"
01366 
01367         if self.getType() == INVALID_TOKEN_TYPE:
01368             return "<errornode>"
01369 
01370         return self.token.text
01371 
01372     __str__ = toString   
01373 
01374 
01375 
01376     def toStringTree(self):
01377         if not self.children:
01378             return self.toString()
01379 
01380         ret = ''
01381         if not self.isNil():
01382             ret += '(%s ' % (self.toString())
01383         
01384         ret += ' '.join([child.toStringTree() for child in self.children])
01385 
01386         if not self.isNil():
01387             ret += ')'
01388 
01389         return ret
01390 
01391 
01392 INVALID_NODE = CommonTree(INVALID_TOKEN)
01393 
01394 
01395 class CommonErrorNode(CommonTree):
01396     """A node representing erroneous token range in token stream"""
01397 
01398     def __init__(self, input, start, stop, exc):
01399         CommonTree.__init__(self, None)
01400 
01401         if (stop is None or
01402             (stop.getTokenIndex() < start.getTokenIndex() and
01403              stop.getType() != EOF
01404              )
01405             ):
01406             # sometimes resync does not consume a token (when LT(1) is
01407             # in follow set.  So, stop will be 1 to left to start. adjust.
01408             # Also handle case where start is the first token and no token
01409             # is consumed during recovery; LT(-1) will return null.
01410             stop = start
01411 
01412         self.input = input
01413         self.start = start
01414         self.stop = stop
01415         self.trappedException = exc
01416 
01417 
01418     def isNil(self):
01419         return False
01420 
01421 
01422     def getType(self):
01423         return INVALID_TOKEN_TYPE
01424 
01425 
01426     def getText(self):
01427         if isinstance(self.start, Token):
01428             i = self.start.getTokenIndex()
01429             j = self.stop.getTokenIndex()
01430             if self.stop.getType() == EOF:
01431                 j = self.input.size()
01432 
01433             badText = self.input.toString(i, j)
01434 
01435         elif isinstance(self.start, Tree):
01436             badText = self.input.toString(self.start, self.stop)
01437 
01438         else:
01439             # people should subclass if they alter the tree type so this
01440             # next one is for sure correct.
01441             badText = "<unknown>"
01442 
01443         return badText
01444 
01445 
01446     def toString(self):
01447         if isinstance(self.trappedException, MissingTokenException):
01448             return ("<missing type: "
01449                     + str(self.trappedException.getMissingType())
01450                     + ">")
01451 
01452         elif isinstance(self.trappedException, UnwantedTokenException):
01453             return ("<extraneous: "
01454                     + str(self.trappedException.getUnexpectedToken())
01455                     + ", resync=" + self.getText() + ">")
01456 
01457         elif isinstance(self.trappedException, MismatchedTokenException):
01458             return ("<mismatched token: "
01459                     + str(self.trappedException.token)
01460                     + ", resync=" + self.getText() + ">")
01461 
01462         elif isinstance(self.trappedException, NoViableAltException):
01463             return ("<unexpected: "
01464                     + str(self.trappedException.token)
01465                     + ", resync=" + self.getText() + ">")
01466 
01467         return "<error: "+self.getText()+">"
01468 
01469 
01470 class CommonTreeAdaptor(BaseTreeAdaptor):
01471     """
01472     @brief A TreeAdaptor that works with any Tree implementation.
01473     
01474     It provides
01475     really just factory methods; all the work is done by BaseTreeAdaptor.
01476     If you would like to have different tokens created than ClassicToken
01477     objects, you need to override this and then set the parser tree adaptor to
01478     use your subclass.
01479 
01480     To get your parser to build nodes of a different type, override
01481     create(Token), errorNode(), and to be safe, YourTreeClass.dupNode().
01482     dupNode is called to duplicate nodes during rewrite operations.
01483     """
01484     
01485     def dupNode(self, treeNode):
01486         """
01487         Duplicate a node.  This is part of the factory;
01488         override if you want another kind of node to be built.
01489 
01490         I could use reflection to prevent having to override this
01491         but reflection is slow.
01492         """
01493 
01494         if treeNode is None:
01495             return None
01496         
01497         return treeNode.dupNode()
01498 
01499 
01500     def createWithPayload(self, payload):
01501         return CommonTree(payload)
01502 
01503 
01504     def createToken(self, fromToken=None, tokenType=None, text=None):
01505         """
01506         Tell me how to create a token for use with imaginary token nodes.
01507         For example, there is probably no input symbol associated with imaginary
01508         token DECL, but you need to create it as a payload or whatever for
01509         the DECL node as in ^(DECL type ID).
01510 
01511         If you care what the token payload objects' type is, you should
01512         override this method and any other createToken variant.
01513         """
01514         
01515         if fromToken is not None:
01516             return CommonToken(oldToken=fromToken)
01517 
01518         return CommonToken(type=tokenType, text=text)
01519 
01520 
01521     def setTokenBoundaries(self, t, startToken, stopToken):
01522         """
01523         Track start/stop token for subtree root created for a rule.
01524         Only works with Tree nodes.  For rules that match nothing,
01525         seems like this will yield start=i and stop=i-1 in a nil node.
01526         Might be useful info so I'll not force to be i..i.
01527         """
01528         
01529         if t is None:
01530             return
01531 
01532         start = 0
01533         stop = 0
01534         
01535         if startToken is not None:
01536             start = startToken.index
01537                 
01538         if stopToken is not None:
01539             stop = stopToken.index
01540 
01541         t.setTokenStartIndex(start)
01542         t.setTokenStopIndex(stop)
01543 
01544 
01545     def getTokenStartIndex(self, t):
01546         if t is None:
01547             return -1
01548         return t.getTokenStartIndex()
01549 
01550 
01551     def getTokenStopIndex(self, t):
01552         if t is None:
01553             return -1
01554         return t.getTokenStopIndex()
01555 
01556 
01557     def getText(self, t):
01558         if t is None:
01559             return None
01560         return t.getText()
01561 
01562 
01563     def getType(self, t):
01564         if t is None:
01565             return INVALID_TOKEN_TYPE
01566         
01567         return t.getType()
01568 
01569 
01570     def getToken(self, t):
01571         """
01572         What is the Token associated with this node?  If
01573         you are not using CommonTree, then you must
01574         override this in your own adaptor.
01575         """
01576 
01577         if isinstance(t, CommonTree):
01578             return t.getToken()
01579 
01580         return None # no idea what to do
01581 
01582 
01583     def getChild(self, t, i):
01584         if t is None:
01585             return None
01586         return t.getChild(i)
01587 
01588 
01589     def getChildCount(self, t):
01590         if t is None:
01591             return 0
01592         return t.getChildCount()
01593 
01594 
01595     def getParent(self, t):
01596         return t.getParent()
01597 
01598 
01599     def setParent(self, t, parent):
01600         t.setParent(parent)
01601 
01602 
01603     def getChildIndex(self, t):
01604         if t is None:
01605             return 0
01606         return t.getChildIndex()
01607 
01608 
01609     def setChildIndex(self, t, index):
01610         t.setChildIndex(index)
01611 
01612 
01613     def replaceChildren(self, parent, startChildIndex, stopChildIndex, t):
01614         if parent is not None:
01615             parent.replaceChildren(startChildIndex, stopChildIndex, t)
01616 
01617 
01618 ############################################################################
01619 #
01620 # streams
01621 #
01622 # TreeNodeStream
01623 # \- BaseTree
01624 #    \- CommonTree
01625 #
01626 # TreeAdaptor
01627 # \- BaseTreeAdaptor
01628 #    \- CommonTreeAdaptor
01629 #
01630 ############################################################################
01631 
01632 
01633 
01634 class TreeNodeStream(IntStream):
01635     """@brief A stream of tree nodes
01636 
01637     It accessing nodes from a tree of some kind.
01638     """
01639     
01640     # TreeNodeStream is abstract, no need to complain about not implemented
01641     # abstract methods
01642     # pylint: disable-msg=W0223
01643     
01644     def get(self, i):
01645         """Get a tree node at an absolute index i; 0..n-1.
01646         If you don't want to buffer up nodes, then this method makes no
01647         sense for you.
01648         """
01649 
01650         raise NotImplementedError
01651 
01652 
01653     def LT(self, k):
01654         """
01655         Get tree node at current input pointer + i ahead where i=1 is next node.
01656         i<0 indicates nodes in the past.  So LT(-1) is previous node, but
01657         implementations are not required to provide results for k < -1.
01658         LT(0) is undefined.  For i>=n, return null.
01659         Return null for LT(0) and any index that results in an absolute address
01660         that is negative.
01661 
01662         This is analogus to the LT() method of the TokenStream, but this
01663         returns a tree node instead of a token.  Makes code gen identical
01664         for both parser and tree grammars. :)
01665         """
01666 
01667         raise NotImplementedError
01668 
01669 
01670     def getTreeSource(self):
01671         """
01672         Where is this stream pulling nodes from?  This is not the name, but
01673         the object that provides node objects.
01674         """
01675 
01676         raise NotImplementedError
01677     
01678 
01679     def getTokenStream(self):
01680         """
01681         If the tree associated with this stream was created from a TokenStream,
01682         you can specify it here.  Used to do rule $text attribute in tree
01683         parser.  Optional unless you use tree parser rule text attribute
01684         or output=template and rewrite=true options.
01685         """
01686 
01687         raise NotImplementedError
01688 
01689 
01690     def getTreeAdaptor(self):
01691         """
01692         What adaptor can tell me how to interpret/navigate nodes and
01693         trees.  E.g., get text of a node.
01694         """
01695 
01696         raise NotImplementedError
01697         
01698 
01699     def setUniqueNavigationNodes(self, uniqueNavigationNodes):
01700         """
01701         As we flatten the tree, we use UP, DOWN nodes to represent
01702         the tree structure.  When debugging we need unique nodes
01703         so we have to instantiate new ones.  When doing normal tree
01704         parsing, it's slow and a waste of memory to create unique
01705         navigation nodes.  Default should be false;
01706         """
01707 
01708         raise NotImplementedError
01709         
01710 
01711     def toString(self, start, stop):
01712         """
01713         Return the text of all nodes from start to stop, inclusive.
01714         If the stream does not buffer all the nodes then it can still
01715         walk recursively from start until stop.  You can always return
01716         null or "" too, but users should not access $ruleLabel.text in
01717         an action of course in that case.
01718         """
01719 
01720         raise NotImplementedError
01721 
01722 
01723     # REWRITING TREES (used by tree parser)
01724     def replaceChildren(self, parent, startChildIndex, stopChildIndex, t):
01725         """
01726         Replace from start to stop child index of parent with t, which might
01727         be a list.  Number of children may be different
01728         after this call.  The stream is notified because it is walking the
01729         tree and might need to know you are monkeying with the underlying
01730         tree.  Also, it might be able to modify the node stream to avoid
01731         restreaming for future phases.
01732 
01733         If parent is null, don't do anything; must be at root of overall tree.
01734         Can't replace whatever points to the parent externally.  Do nothing.
01735         """
01736 
01737         raise NotImplementedError
01738 
01739 
01740 class CommonTreeNodeStream(TreeNodeStream):
01741     """@brief A buffered stream of tree nodes.
01742 
01743     Nodes can be from a tree of ANY kind.
01744 
01745     This node stream sucks all nodes out of the tree specified in
01746     the constructor during construction and makes pointers into
01747     the tree using an array of Object pointers. The stream necessarily
01748     includes pointers to DOWN and UP and EOF nodes.
01749 
01750     This stream knows how to mark/release for backtracking.
01751 
01752     This stream is most suitable for tree interpreters that need to
01753     jump around a lot or for tree parsers requiring speed (at cost of memory).
01754     There is some duplicated functionality here with UnBufferedTreeNodeStream
01755     but just in bookkeeping, not tree walking etc...
01756 
01757     @see UnBufferedTreeNodeStream
01758     """
01759     
01760     def __init__(self, *args):
01761         TreeNodeStream.__init__(self)
01762 
01763         if len(args) == 1:
01764             adaptor = CommonTreeAdaptor()
01765             tree = args[0]
01766 
01767             nodes = None
01768             down = None
01769             up = None
01770             eof = None
01771 
01772         elif len(args) == 2:
01773             adaptor = args[0]
01774             tree = args[1]
01775 
01776             nodes = None
01777             down = None
01778             up = None
01779             eof = None
01780 
01781         elif len(args) == 3:
01782             parent = args[0]
01783             start = args[1]
01784             stop = args[2]
01785 
01786             adaptor = parent.adaptor
01787             tree = parent.root
01788 
01789             nodes = parent.nodes[start:stop]
01790             down = parent.down
01791             up = parent.up
01792             eof = parent.eof
01793 
01794         else:
01795             raise TypeError("Invalid arguments")
01796         
01797         # all these navigation nodes are shared and hence they
01798         # cannot contain any line/column info
01799         if down is not None:
01800             self.down = down
01801         else:
01802             self.down = adaptor.createFromType(DOWN, "DOWN")
01803 
01804         if up is not None:
01805             self.up = up
01806         else:
01807             self.up = adaptor.createFromType(UP, "UP")
01808 
01809         if eof is not None:
01810             self.eof = eof
01811         else:
01812             self.eof = adaptor.createFromType(EOF, "EOF")
01813 
01814         # The complete mapping from stream index to tree node.
01815         # This buffer includes pointers to DOWN, UP, and EOF nodes.
01816         # It is built upon ctor invocation.  The elements are type
01817         #  Object as we don't what the trees look like.
01818 
01819         # Load upon first need of the buffer so we can set token types
01820         # of interest for reverseIndexing.  Slows us down a wee bit to
01821         # do all of the if p==-1 testing everywhere though.
01822         if nodes is not None:
01823             self.nodes = nodes
01824         else:
01825             self.nodes = []
01826 
01827         # Pull nodes from which tree?
01828         self.root = tree
01829 
01830         # IF this tree (root) was created from a token stream, track it.
01831         self.tokens = None
01832 
01833         # What tree adaptor was used to build these trees
01834         self.adaptor = adaptor
01835 
01836         # Reuse same DOWN, UP navigation nodes unless this is true
01837         self.uniqueNavigationNodes = False
01838 
01839         # The index into the nodes list of the current node (next node
01840         # to consume).  If -1, nodes array not filled yet.
01841         self.p = -1
01842 
01843         # Track the last mark() call result value for use in rewind().
01844         self.lastMarker = None
01845 
01846         # Stack of indexes used for push/pop calls
01847         self.calls = []
01848 
01849 
01850     def fillBuffer(self):
01851         """Walk tree with depth-first-search and fill nodes buffer.
01852         Don't do DOWN, UP nodes if its a list (t is isNil).
01853         """
01854 
01855         self._fillBuffer(self.root)
01856         self.p = 0 # buffer of nodes intialized now
01857 
01858 
01859     def _fillBuffer(self, t):
01860         nil = self.adaptor.isNil(t)
01861         
01862         if not nil:
01863             self.nodes.append(t) # add this node
01864 
01865         # add DOWN node if t has children
01866         n = self.adaptor.getChildCount(t)
01867         if not nil and n > 0:
01868             self.addNavigationNode(DOWN)
01869 
01870         # and now add all its children
01871         for c in range(n):
01872             self._fillBuffer(self.adaptor.getChild(t, c))
01873 
01874         # add UP node if t has children
01875         if not nil and n > 0:
01876             self.addNavigationNode(UP)
01877 
01878 
01879     def getNodeIndex(self, node):
01880         """What is the stream index for node? 0..n-1
01881         Return -1 if node not found.
01882         """
01883         
01884         if self.p == -1:
01885             self.fillBuffer()
01886 
01887         for i, t in enumerate(self.nodes):
01888             if t == node:
01889                 return i
01890 
01891         return -1
01892 
01893 
01894     def addNavigationNode(self, ttype):
01895         """
01896         As we flatten the tree, we use UP, DOWN nodes to represent
01897         the tree structure.  When debugging we need unique nodes
01898         so instantiate new ones when uniqueNavigationNodes is true.
01899         """
01900         
01901         navNode = None
01902         
01903         if ttype == DOWN:
01904             if self.hasUniqueNavigationNodes():
01905                 navNode = self.adaptor.createFromType(DOWN, "DOWN")
01906 
01907             else:
01908                 navNode = self.down
01909 
01910         else:
01911             if self.hasUniqueNavigationNodes():
01912                 navNode = self.adaptor.createFromType(UP, "UP")
01913                 
01914             else:
01915                 navNode = self.up
01916 
01917         self.nodes.append(navNode)
01918 
01919 
01920     def get(self, i):
01921         if self.p == -1:
01922             self.fillBuffer()
01923 
01924         return self.nodes[i]
01925 
01926 
01927     def LT(self, k):
01928         if self.p == -1:
01929             self.fillBuffer()
01930 
01931         if k == 0:
01932             return None
01933 
01934         if k < 0:
01935             return self.LB(-k)
01936 
01937         if self.p + k - 1 >= len(self.nodes):
01938             return self.eof
01939 
01940         return self.nodes[self.p + k - 1]
01941     
01942 
01943     def getCurrentSymbol(self):
01944         return self.LT(1)
01945 
01946 
01947     def LB(self, k):
01948         """Look backwards k nodes"""
01949         
01950         if k == 0:
01951             return None
01952 
01953         if self.p - k < 0:
01954             return None
01955 
01956         return self.nodes[self.p - k]
01957 
01958 
01959     def getTreeSource(self):
01960         return self.root
01961 
01962 
01963     def getSourceName(self):
01964         return self.getTokenStream().getSourceName()
01965 
01966 
01967     def getTokenStream(self):
01968         return self.tokens
01969 
01970 
01971     def setTokenStream(self, tokens):
01972         self.tokens = tokens
01973 
01974 
01975     def getTreeAdaptor(self):
01976         return self.adaptor
01977 
01978 
01979     def hasUniqueNavigationNodes(self):
01980         return self.uniqueNavigationNodes
01981 
01982 
01983     def setUniqueNavigationNodes(self, uniqueNavigationNodes):
01984         self.uniqueNavigationNodes = uniqueNavigationNodes
01985 
01986 
01987     def consume(self):
01988         if self.p == -1:
01989             self.fillBuffer()
01990             
01991         self.p += 1
01992 
01993         
01994     def LA(self, i):
01995         return self.adaptor.getType(self.LT(i))
01996 
01997 
01998     def mark(self):
01999         if self.p == -1:
02000             self.fillBuffer()
02001 
02002         
02003         self.lastMarker = self.index()
02004         return self.lastMarker
02005 
02006 
02007     def release(self, marker=None):
02008         # no resources to release
02009 
02010         pass
02011 
02012 
02013     def index(self):
02014         return self.p
02015 
02016 
02017     def rewind(self, marker=None):
02018         if marker is None:
02019             marker = self.lastMarker
02020             
02021         self.seek(marker)
02022 
02023 
02024     def seek(self, index):
02025         if self.p == -1:
02026             self.fillBuffer()
02027 
02028         self.p = index
02029 
02030 
02031     def push(self, index):
02032         """
02033         Make stream jump to a new location, saving old location.
02034         Switch back with pop().
02035         """
02036 
02037         self.calls.append(self.p) # save current index
02038         self.seek(index)
02039 
02040 
02041     def pop(self):
02042         """
02043         Seek back to previous index saved during last push() call.
02044         Return top of stack (return index).
02045         """
02046 
02047         ret = self.calls.pop(-1)
02048         self.seek(ret)
02049         return ret
02050 
02051 
02052     def reset(self):
02053         self.p = 0
02054         self.lastMarker = 0
02055         self.calls = []
02056 
02057         
02058     def size(self):
02059         if self.p == -1:
02060             self.fillBuffer()
02061 
02062         return len(self.nodes)
02063 
02064 
02065     # TREE REWRITE INTERFACE
02066 
02067     def replaceChildren(self, parent, startChildIndex, stopChildIndex, t):
02068         if parent is not None:
02069             self.adaptor.replaceChildren(
02070                 parent, startChildIndex, stopChildIndex, t
02071                 )
02072 
02073 
02074     def __str__(self):
02075         """Used for testing, just return the token type stream"""
02076 
02077         if self.p == -1:
02078             self.fillBuffer()
02079 
02080         return ' '.join([str(self.adaptor.getType(node))
02081                          for node in self.nodes
02082                          ])
02083 
02084 
02085     def toString(self, start, stop):
02086         if start is None or stop is None:
02087             return None
02088 
02089         if self.p == -1:
02090             self.fillBuffer()
02091 
02092         #System.out.println("stop: "+stop);
02093         #if ( start instanceof CommonTree )
02094         #    System.out.print("toString: "+((CommonTree)start).getToken()+", ");
02095         #else
02096         #    System.out.println(start);
02097         #if ( stop instanceof CommonTree )
02098         #    System.out.println(((CommonTree)stop).getToken());
02099         #else
02100         #    System.out.println(stop);
02101             
02102         # if we have the token stream, use that to dump text in order
02103         if self.tokens is not None:
02104             beginTokenIndex = self.adaptor.getTokenStartIndex(start)
02105             endTokenIndex = self.adaptor.getTokenStopIndex(stop)
02106             
02107             # if it's a tree, use start/stop index from start node
02108             # else use token range from start/stop nodes
02109             if self.adaptor.getType(stop) == UP:
02110                 endTokenIndex = self.adaptor.getTokenStopIndex(start)
02111 
02112             elif self.adaptor.getType(stop) == EOF:
02113                 endTokenIndex = self.size() -2 # don't use EOF
02114 
02115             return self.tokens.toString(beginTokenIndex, endTokenIndex)
02116 
02117         # walk nodes looking for start
02118         i, t = 0, None
02119         for i, t in enumerate(self.nodes):
02120             if t == start:
02121                 break
02122 
02123         # now walk until we see stop, filling string buffer with text
02124         buf = []
02125         t = self.nodes[i]
02126         while t != stop:
02127             text = self.adaptor.getText(t)
02128             if text is None:
02129                 text = " " + self.adaptor.getType(t)
02130 
02131             buf.append(text)
02132             i += 1
02133             t = self.nodes[i]
02134 
02135         # include stop node too
02136         text = self.adaptor.getText(stop)
02137         if text is None:
02138             text = " " +self.adaptor.getType(stop)
02139 
02140         buf.append(text)
02141         
02142         return ''.join(buf)
02143     
02144 
02145     ## iterator interface
02146     def __iter__(self):
02147         if self.p == -1:
02148             self.fillBuffer()
02149 
02150         for node in self.nodes:
02151             yield node
02152 
02153 
02154 #############################################################################
02155 #
02156 # tree parser
02157 #
02158 #############################################################################
02159 
02160 class TreeParser(BaseRecognizer):
02161     """@brief Baseclass for generated tree parsers.
02162     
02163     A parser for a stream of tree nodes.  "tree grammars" result in a subclass
02164     of this.  All the error reporting and recovery is shared with Parser via
02165     the BaseRecognizer superclass.
02166     """
02167 
02168     def __init__(self, input, state=None):
02169         BaseRecognizer.__init__(self, state)
02170 
02171         self.input = None
02172         self.setTreeNodeStream(input)
02173 
02174 
02175     def reset(self):
02176         BaseRecognizer.reset(self) # reset all recognizer state variables
02177         if self.input is not None:
02178             self.input.seek(0) # rewind the input
02179 
02180 
02181     def setTreeNodeStream(self, input):
02182         """Set the input stream"""
02183 
02184         self.input = input
02185 
02186 
02187     def getTreeNodeStream(self):
02188         return self.input
02189 
02190 
02191     def getSourceName(self):
02192         return self.input.getSourceName()
02193 
02194 
02195     def getCurrentInputSymbol(self, input):
02196         return input.LT(1)
02197 
02198 
02199     def getMissingSymbol(self, input, e, expectedTokenType, follow):
02200         tokenText = "<missing " + self.tokenNames[expectedTokenType] + ">"
02201         return CommonTree(CommonToken(type=expectedTokenType, text=tokenText))
02202 
02203 
02204     # precompiled regex used by inContext
02205     dotdot = ".*[^.]\\.\\.[^.].*"
02206     doubleEtc = ".*\\.\\.\\.\\s+\\.\\.\\..*"
02207     dotdotPattern = re.compile(dotdot)
02208     doubleEtcPattern = re.compile(doubleEtc)
02209 
02210     def inContext(self, context, adaptor=None, tokenName=None, t=None):
02211         """Check if current node in input has a context.
02212 
02213         Context means sequence of nodes towards root of tree.  For example,
02214         you might say context is "MULT" which means my parent must be MULT.
02215         "CLASS VARDEF" says current node must be child of a VARDEF and whose
02216         parent is a CLASS node.  You can use "..." to mean zero-or-more nodes.
02217         "METHOD ... VARDEF" means my parent is VARDEF and somewhere above
02218         that is a METHOD node.  The first node in the context is not
02219         necessarily the root.  The context matcher stops matching and returns
02220         true when it runs out of context.  There is no way to force the first
02221         node to be the root. 
02222         """
02223 
02224         return _inContext(
02225             self.input.getTreeAdaptor(), self.getTokenNames(), 
02226             self.input.LT(1), context)
02227 
02228     @classmethod
02229     def _inContext(cls, adaptor, tokenNames, t, context):
02230         """The worker for inContext.
02231 
02232         It's static and full of parameters for testing purposes.
02233         """
02234 
02235         if cls.dotdotPattern.match(context):
02236             # don't allow "..", must be "..."
02237             raise ValueError("invalid syntax: ..")
02238 
02239         if cls.doubleEtcPattern.match(context):
02240             # don't allow double "..."
02241             raise ValueError("invalid syntax: ... ...")
02242 
02243         # ensure spaces around ...
02244         context = context.replace("...", " ... ")
02245         context = context.strip()
02246         nodes = context.split()
02247 
02248         ni = len(nodes) - 1
02249         t = adaptor.getParent(t)
02250         while ni >= 0 and t is not None:
02251             if nodes[ni] == "...":
02252                 # walk upwards until we see nodes[ni-1] then continue walking
02253                 if ni == 0:
02254                     # ... at start is no-op
02255                     return True
02256                 goal = nodes[ni-1]
02257                 ancestor = cls._getAncestor(adaptor, tokenNames, t, goal)
02258                 if ancestor is None:
02259                     return False
02260                 t = ancestor
02261                 ni -= 1
02262 
02263             name = tokenNames[adaptor.getType(t)]
02264             if name != nodes[ni]:
02265                 return False
02266 
02267             # advance to parent and to previous element in context node list
02268             ni -= 1
02269             t = adaptor.getParent(t)
02270 
02271         # at root but more nodes to match
02272         if t is None and ni >= 0:
02273             return False
02274 
02275         return True
02276 
02277     @staticmethod
02278     def _getAncestor(adaptor, tokenNames, t, goal):
02279         """Helper for static inContext."""
02280         while t is not None:
02281             name = tokenNames[adaptor.getType(t)]
02282             if name == goal:
02283                 return t
02284             t = adaptor.getParent(t)
02285 
02286         return None
02287 
02288 
02289     def matchAny(self, ignore): # ignore stream, copy of this.input
02290         """
02291         Match '.' in tree parser has special meaning.  Skip node or
02292         entire tree if node has children.  If children, scan until
02293         corresponding UP node.
02294         """
02295         
02296         self._state.errorRecovery = False
02297 
02298         look = self.input.LT(1)
02299         if self.input.getTreeAdaptor().getChildCount(look) == 0:
02300             self.input.consume() # not subtree, consume 1 node and return
02301             return
02302 
02303         # current node is a subtree, skip to corresponding UP.
02304         # must count nesting level to get right UP
02305         level = 0
02306         tokenType = self.input.getTreeAdaptor().getType(look)
02307         while tokenType != EOF and not (tokenType == UP and level==0):
02308             self.input.consume()
02309             look = self.input.LT(1)
02310             tokenType = self.input.getTreeAdaptor().getType(look)
02311             if tokenType == DOWN:
02312                 level += 1
02313 
02314             elif tokenType == UP:
02315                 level -= 1
02316 
02317         self.input.consume() # consume UP
02318 
02319 
02320     def mismatch(self, input, ttype, follow):
02321         """
02322         We have DOWN/UP nodes in the stream that have no line info; override.
02323         plus we want to alter the exception type. Don't try to recover
02324         from tree parser errors inline...
02325         """
02326 
02327         raise MismatchedTreeNodeException(ttype, input)
02328 
02329 
02330     def getErrorHeader(self, e):
02331         """
02332         Prefix error message with the grammar name because message is
02333         always intended for the programmer because the parser built
02334         the input tree not the user.
02335         """
02336 
02337         return (self.getGrammarFileName() +
02338                 ": node from %sline %s:%s"
02339                 % (['', "after "][e.approximateLineInfo],
02340                    e.line,
02341                    e.charPositionInLine
02342                    )
02343                 )
02344 
02345     def getErrorMessage(self, e, tokenNames):
02346         """
02347         Tree parsers parse nodes they usually have a token object as
02348         payload. Set the exception token and do the default behavior.
02349         """
02350 
02351         if isinstance(self, TreeParser):
02352             adaptor = e.input.getTreeAdaptor()
02353             e.token = adaptor.getToken(e.node)
02354             if e.token is not None: # could be an UP/DOWN node
02355                 e.token = CommonToken(
02356                     type=adaptor.getType(e.node),
02357                     text=adaptor.getText(e.node)
02358                     )
02359 
02360         return BaseRecognizer.getErrorMessage(self, e, tokenNames)
02361 
02362 
02363     def traceIn(self, ruleName, ruleIndex):
02364         BaseRecognizer.traceIn(self, ruleName, ruleIndex, self.input.LT(1))
02365 
02366 
02367     def traceOut(self, ruleName, ruleIndex):
02368         BaseRecognizer.traceOut(self, ruleName, ruleIndex, self.input.LT(1))
02369 
02370 
02371 #############################################################################
02372 #
02373 # tree visitor
02374 #
02375 #############################################################################
02376 
02377 class TreeVisitor(object):
02378     """Do a depth first walk of a tree, applying pre() and post() actions
02379     we go.
02380     """
02381 
02382     def __init__(self, adaptor=None):
02383         if adaptor is not None:
02384             self.adaptor = adaptor
02385         else:
02386             self.adaptor = CommonTreeAdaptor()
02387     
02388     def visit(self, t, pre_action=None, post_action=None):
02389         """Visit every node in tree t and trigger an action for each node
02390         before/after having visited all of its children.  Bottom up walk.
02391         Execute both actions even if t has no children.  Ignore return
02392         results from transforming children since they will have altered
02393         the child list of this node (their parent).  Return result of
02394         applying post action to this node.
02395 
02396         The Python version differs from the Java version by taking two
02397         callables 'pre_action' and 'post_action' instead of a class instance
02398         that wraps those methods. Those callables must accept a TreeNode as
02399         their single argument and return the (potentially transformed or
02400         replaced) TreeNode.
02401         """
02402 
02403         isNil = self.adaptor.isNil(t)
02404         if pre_action is not None and not isNil:
02405             # if rewritten, walk children of new t
02406             t = pre_action(t)
02407 
02408         for idx in xrange(self.adaptor.getChildCount(t)):
02409             child = self.adaptor.getChild(t, idx)
02410             self.visit(child, pre_action, post_action)
02411 
02412         if post_action is not None and not isNil:
02413             t = post_action(t)
02414 
02415         return t
02416 
02417 
02418 #############################################################################
02419 #
02420 # streams for rule rewriting
02421 #
02422 #############################################################################
02423 
02424 class RewriteRuleElementStream(object):
02425     """@brief Internal helper class.
02426     
02427     A generic list of elements tracked in an alternative to be used in
02428     a -> rewrite rule.  We need to subclass to fill in the next() method,
02429     which returns either an AST node wrapped around a token payload or
02430     an existing subtree.
02431 
02432     Once you start next()ing, do not try to add more elements.  It will
02433     break the cursor tracking I believe.
02434 
02435     @see org.antlr.runtime.tree.RewriteRuleSubtreeStream
02436     @see org.antlr.runtime.tree.RewriteRuleTokenStream
02437     
02438     TODO: add mechanism to detect/puke on modification after reading from
02439     stream
02440     """
02441 
02442     def __init__(self, adaptor, elementDescription, elements=None):
02443         # Cursor 0..n-1.  If singleElement!=null, cursor is 0 until you next(),
02444         # which bumps it to 1 meaning no more elements.
02445         self.cursor = 0
02446 
02447         # Track single elements w/o creating a list.  Upon 2nd add, alloc list
02448         self.singleElement = None
02449 
02450         # The list of tokens or subtrees we are tracking
02451         self.elements = None
02452 
02453         # Once a node / subtree has been used in a stream, it must be dup'd
02454         # from then on.  Streams are reset after subrules so that the streams
02455         # can be reused in future subrules.  So, reset must set a dirty bit.
02456         # If dirty, then next() always returns a dup.
02457         self.dirty = False
02458         
02459         # The element or stream description; usually has name of the token or
02460         # rule reference that this list tracks.  Can include rulename too, but
02461         # the exception would track that info.
02462         self.elementDescription = elementDescription
02463 
02464         self.adaptor = adaptor
02465 
02466         if isinstance(elements, (list, tuple)):
02467             # Create a stream, but feed off an existing list
02468             self.singleElement = None
02469             self.elements = elements
02470 
02471         else:
02472             # Create a stream with one element
02473             self.add(elements)
02474 
02475 
02476     def reset(self):
02477         """
02478         Reset the condition of this stream so that it appears we have
02479         not consumed any of its elements.  Elements themselves are untouched.
02480         Once we reset the stream, any future use will need duplicates.  Set
02481         the dirty bit.
02482         """
02483         
02484         self.cursor = 0
02485         self.dirty = True
02486 
02487         
02488     def add(self, el):
02489         if el is None:
02490             return
02491 
02492         if self.elements is not None: # if in list, just add
02493             self.elements.append(el)
02494             return
02495 
02496         if self.singleElement is None: # no elements yet, track w/o list
02497             self.singleElement = el
02498             return
02499 
02500         # adding 2nd element, move to list
02501         self.elements = []
02502         self.elements.append(self.singleElement)
02503         self.singleElement = None
02504         self.elements.append(el)
02505 
02506 
02507     def nextTree(self):
02508         """
02509         Return the next element in the stream.  If out of elements, throw
02510         an exception unless size()==1.  If size is 1, then return elements[0].
02511         
02512         Return a duplicate node/subtree if stream is out of elements and
02513         size==1. If we've already used the element, dup (dirty bit set).
02514         """
02515         
02516         if (self.dirty
02517             or (self.cursor >= len(self) and len(self) == 1)
02518             ):
02519             # if out of elements and size is 1, dup
02520             el = self._next()
02521             return self.dup(el)
02522 
02523         # test size above then fetch
02524         el = self._next()
02525         return el
02526 
02527 
02528     def _next(self):
02529         """
02530         do the work of getting the next element, making sure that it's
02531         a tree node or subtree.  Deal with the optimization of single-
02532         element list versus list of size > 1.  Throw an exception
02533         if the stream is empty or we're out of elements and size>1.
02534         protected so you can override in a subclass if necessary.
02535         """
02536 
02537         if len(self) == 0:
02538             raise RewriteEmptyStreamException(self.elementDescription)
02539             
02540         if self.cursor >= len(self): # out of elements?
02541             if len(self) == 1: # if size is 1, it's ok; return and we'll dup 
02542                 return self.toTree(self.singleElement)
02543 
02544             # out of elements and size was not 1, so we can't dup
02545             raise RewriteCardinalityException(self.elementDescription)
02546 
02547         # we have elements
02548         if self.singleElement is not None:
02549             self.cursor += 1 # move cursor even for single element list
02550             return self.toTree(self.singleElement)
02551 
02552         # must have more than one in list, pull from elements
02553         o = self.toTree(self.elements[self.cursor])
02554         self.cursor += 1
02555         return o
02556 
02557 
02558     def dup(self, el):
02559         """
02560         When constructing trees, sometimes we need to dup a token or AST
02561         subtree.  Dup'ing a token means just creating another AST node
02562         around it.  For trees, you must call the adaptor.dupTree() unless
02563         the element is for a tree root; then it must be a node dup.
02564         """
02565 
02566         raise NotImplementedError
02567     
02568 
02569     def toTree(self, el):
02570         """
02571         Ensure stream emits trees; tokens must be converted to AST nodes.
02572         AST nodes can be passed through unmolested.
02573         """
02574 
02575         return el
02576 
02577 
02578     def hasNext(self):
02579         return ( (self.singleElement is not None and self.cursor < 1)
02580                  or (self.elements is not None
02581                      and self.cursor < len(self.elements)
02582                      )
02583                  )
02584 
02585                  
02586     def size(self):
02587         if self.singleElement is not None:
02588             return 1
02589 
02590         if self.elements is not None:
02591             return len(self.elements)
02592 
02593         return 0
02594 
02595     __len__ = size
02596     
02597 
02598     def getDescription(self):
02599         """Deprecated. Directly access elementDescription attribute"""
02600         
02601         return self.elementDescription
02602 
02603 
02604 class RewriteRuleTokenStream(RewriteRuleElementStream):
02605     """@brief Internal helper class."""
02606 
02607     def toTree(self, el):
02608         # Don't convert to a tree unless they explicitly call nextTree.
02609         # This way we can do hetero tree nodes in rewrite.
02610         return el
02611 
02612 
02613     def nextNode(self):
02614         t = self._next()
02615         return self.adaptor.createWithPayload(t)
02616 
02617     
02618     def nextToken(self):
02619         return self._next()
02620 
02621     
02622     def dup(self, el):
02623         raise TypeError("dup can't be called for a token stream.")
02624 
02625 
02626 class RewriteRuleSubtreeStream(RewriteRuleElementStream):
02627     """@brief Internal helper class."""
02628 
02629     def nextNode(self):
02630         """
02631         Treat next element as a single node even if it's a subtree.
02632         This is used instead of next() when the result has to be a
02633         tree root node.  Also prevents us from duplicating recently-added
02634         children; e.g., ^(type ID)+ adds ID to type and then 2nd iteration
02635         must dup the type node, but ID has been added.
02636 
02637         Referencing a rule result twice is ok; dup entire tree as
02638         we can't be adding trees as root; e.g., expr expr.
02639 
02640         Hideous code duplication here with super.next().  Can't think of
02641         a proper way to refactor.  This needs to always call dup node
02642         and super.next() doesn't know which to call: dup node or dup tree.
02643         """
02644         
02645         if (self.dirty
02646             or (self.cursor >= len(self) and len(self) == 1)
02647             ):
02648             # if out of elements and size is 1, dup (at most a single node
02649             # since this is for making root nodes).
02650             el = self._next()
02651             return self.adaptor.dupNode(el)
02652 
02653         # test size above then fetch
02654         el = self._next()
02655         return el
02656 
02657 
02658     def dup(self, el):
02659         return self.adaptor.dupTree(el)
02660 
02661 
02662 
02663 class RewriteRuleNodeStream(RewriteRuleElementStream):
02664     """
02665     Queues up nodes matched on left side of -> in a tree parser. This is
02666     the analog of RewriteRuleTokenStream for normal parsers. 
02667     """
02668     
02669     def nextNode(self):
02670         return self._next()
02671 
02672 
02673     def toTree(self, el):
02674         return self.adaptor.dupNode(el)
02675 
02676 
02677     def dup(self, el):
02678         # we dup every node, so don't have to worry about calling dup; short-
02679         #circuited next() so it doesn't call.
02680         raise TypeError("dup can't be called for a node stream.")
02681 
02682 
02683 class TreeRuleReturnScope(RuleReturnScope):
02684     """
02685     This is identical to the ParserRuleReturnScope except that
02686     the start property is a tree nodes not Token object
02687     when you are parsing trees.  To be generic the tree node types
02688     have to be Object.
02689     """
02690 
02691     def __init__(self):
02692         self.start = None
02693         self.tree = None
02694         
02695     
02696     def getStart(self):
02697         return self.start
02698 
02699     
02700     def getTree(self):
02701         return self.tree
02702 


rve_interface_gen
Author(s): Josh Faust
autogenerated on Wed Dec 11 2013 14:31:00