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