xref: /aosp_15_r20/external/antlr/runtime/Python/antlr3/debug.py (revision 16467b971bd3e2009fad32dd79016f2c7e421deb)
1*16467b97STreehugger Robot# begin[licence]
2*16467b97STreehugger Robot#
3*16467b97STreehugger Robot#  [The "BSD licence"]
4*16467b97STreehugger Robot#  Copyright (c) 2005-2009 Terence Parr
5*16467b97STreehugger Robot#  All rights reserved.
6*16467b97STreehugger Robot
7*16467b97STreehugger Robot#  Redistribution and use in source and binary forms, with or without
8*16467b97STreehugger Robot#  modification, are permitted provided that the following conditions
9*16467b97STreehugger Robot#  are met:
10*16467b97STreehugger Robot#  1. Redistributions of source code must retain the above copyright
11*16467b97STreehugger Robot#     notice, this list of conditions and the following disclaimer.
12*16467b97STreehugger Robot#  2. Redistributions in binary form must reproduce the above copyright
13*16467b97STreehugger Robot#     notice, this list of conditions and the following disclaimer in the
14*16467b97STreehugger Robot#     documentation and/or other materials provided with the distribution.
15*16467b97STreehugger Robot#  3. The name of the author may not be used to endorse or promote products
16*16467b97STreehugger Robot#     derived from this software without specific prior written permission.
17*16467b97STreehugger Robot
18*16467b97STreehugger Robot#  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19*16467b97STreehugger Robot#  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20*16467b97STreehugger Robot#  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21*16467b97STreehugger Robot#  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22*16467b97STreehugger Robot#  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23*16467b97STreehugger Robot#  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*16467b97STreehugger Robot#  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*16467b97STreehugger Robot#  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*16467b97STreehugger Robot#  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27*16467b97STreehugger Robot#  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*16467b97STreehugger Robot#
29*16467b97STreehugger Robot# end[licence]
30*16467b97STreehugger Robot
31*16467b97STreehugger Robotimport socket
32*16467b97STreehugger Robotfrom antlr3 import Parser, TokenStream, RecognitionException, Token
33*16467b97STreehugger Robotfrom antlr3.tree import CommonTreeAdaptor, TreeAdaptor, Tree
34*16467b97STreehugger Robot
35*16467b97STreehugger Robotclass DebugParser(Parser):
36*16467b97STreehugger Robot    def __init__(self, stream, state=None, dbg=None, *args, **kwargs):
37*16467b97STreehugger Robot        # wrap token stream in DebugTokenStream (unless user already did so).
38*16467b97STreehugger Robot        if not isinstance(stream, DebugTokenStream):
39*16467b97STreehugger Robot            stream = DebugTokenStream(stream, dbg)
40*16467b97STreehugger Robot
41*16467b97STreehugger Robot        super(DebugParser, self).__init__(stream, state, *args, **kwargs)
42*16467b97STreehugger Robot
43*16467b97STreehugger Robot        # Who to notify when events in the parser occur.
44*16467b97STreehugger Robot        self._dbg = None
45*16467b97STreehugger Robot
46*16467b97STreehugger Robot        self.setDebugListener(dbg)
47*16467b97STreehugger Robot
48*16467b97STreehugger Robot
49*16467b97STreehugger Robot    def setDebugListener(self, dbg):
50*16467b97STreehugger Robot	"""Provide a new debug event listener for this parser.  Notify the
51*16467b97STreehugger Robot        input stream too that it should send events to this listener.
52*16467b97STreehugger Robot	"""
53*16467b97STreehugger Robot
54*16467b97STreehugger Robot        if hasattr(self.input, 'dbg'):
55*16467b97STreehugger Robot            self.input.dbg = dbg
56*16467b97STreehugger Robot
57*16467b97STreehugger Robot        self._dbg = dbg
58*16467b97STreehugger Robot
59*16467b97STreehugger Robot    def getDebugListener(self):
60*16467b97STreehugger Robot        return self._dbg
61*16467b97STreehugger Robot
62*16467b97STreehugger Robot    dbg = property(getDebugListener, setDebugListener)
63*16467b97STreehugger Robot
64*16467b97STreehugger Robot
65*16467b97STreehugger Robot    def beginResync(self):
66*16467b97STreehugger Robot        self._dbg.beginResync()
67*16467b97STreehugger Robot
68*16467b97STreehugger Robot
69*16467b97STreehugger Robot    def endResync(self):
70*16467b97STreehugger Robot        self._dbg.endResync()
71*16467b97STreehugger Robot
72*16467b97STreehugger Robot
73*16467b97STreehugger Robot    def beginBacktrack(self, level):
74*16467b97STreehugger Robot        self._dbg.beginBacktrack(level)
75*16467b97STreehugger Robot
76*16467b97STreehugger Robot
77*16467b97STreehugger Robot    def endBacktrack(self, level, successful):
78*16467b97STreehugger Robot        self._dbg.endBacktrack(level,successful)
79*16467b97STreehugger Robot
80*16467b97STreehugger Robot
81*16467b97STreehugger Robot    def reportError(self, exc):
82*16467b97STreehugger Robot        Parser.reportError(self, exc)
83*16467b97STreehugger Robot
84*16467b97STreehugger Robot        if isinstance(exc, RecognitionException):
85*16467b97STreehugger Robot            self._dbg.recognitionException(exc)
86*16467b97STreehugger Robot
87*16467b97STreehugger Robot
88*16467b97STreehugger Robotclass DebugTokenStream(TokenStream):
89*16467b97STreehugger Robot    def __init__(self, input, dbg=None):
90*16467b97STreehugger Robot        self.input = input
91*16467b97STreehugger Robot        self.initialStreamState = True
92*16467b97STreehugger Robot        # Track the last mark() call result value for use in rewind().
93*16467b97STreehugger Robot        self.lastMarker = None
94*16467b97STreehugger Robot
95*16467b97STreehugger Robot        self._dbg = None
96*16467b97STreehugger Robot        self.setDebugListener(dbg)
97*16467b97STreehugger Robot
98*16467b97STreehugger Robot        # force TokenStream to get at least first valid token
99*16467b97STreehugger Robot        # so we know if there are any hidden tokens first in the stream
100*16467b97STreehugger Robot        self.input.LT(1)
101*16467b97STreehugger Robot
102*16467b97STreehugger Robot
103*16467b97STreehugger Robot    def getDebugListener(self):
104*16467b97STreehugger Robot        return self._dbg
105*16467b97STreehugger Robot
106*16467b97STreehugger Robot    def setDebugListener(self, dbg):
107*16467b97STreehugger Robot        self._dbg = dbg
108*16467b97STreehugger Robot
109*16467b97STreehugger Robot    dbg = property(getDebugListener, setDebugListener)
110*16467b97STreehugger Robot
111*16467b97STreehugger Robot
112*16467b97STreehugger Robot    def consume(self):
113*16467b97STreehugger Robot        if self.initialStreamState:
114*16467b97STreehugger Robot            self.consumeInitialHiddenTokens()
115*16467b97STreehugger Robot
116*16467b97STreehugger Robot        a = self.input.index()
117*16467b97STreehugger Robot        t = self.input.LT(1)
118*16467b97STreehugger Robot        self.input.consume()
119*16467b97STreehugger Robot        b = self.input.index()
120*16467b97STreehugger Robot        self._dbg.consumeToken(t)
121*16467b97STreehugger Robot
122*16467b97STreehugger Robot        if b > a+1:
123*16467b97STreehugger Robot            # then we consumed more than one token; must be off channel tokens
124*16467b97STreehugger Robot            for idx in range(a+1, b):
125*16467b97STreehugger Robot                self._dbg.consumeHiddenToken(self.input.get(idx));
126*16467b97STreehugger Robot
127*16467b97STreehugger Robot
128*16467b97STreehugger Robot    def consumeInitialHiddenTokens(self):
129*16467b97STreehugger Robot        """consume all initial off-channel tokens"""
130*16467b97STreehugger Robot
131*16467b97STreehugger Robot        firstOnChannelTokenIndex = self.input.index()
132*16467b97STreehugger Robot        for idx in range(firstOnChannelTokenIndex):
133*16467b97STreehugger Robot            self._dbg.consumeHiddenToken(self.input.get(idx))
134*16467b97STreehugger Robot
135*16467b97STreehugger Robot        self.initialStreamState = False
136*16467b97STreehugger Robot
137*16467b97STreehugger Robot
138*16467b97STreehugger Robot    def LT(self, i):
139*16467b97STreehugger Robot        if self.initialStreamState:
140*16467b97STreehugger Robot            self.consumeInitialHiddenTokens()
141*16467b97STreehugger Robot
142*16467b97STreehugger Robot        t = self.input.LT(i)
143*16467b97STreehugger Robot        self._dbg.LT(i, t)
144*16467b97STreehugger Robot        return t
145*16467b97STreehugger Robot
146*16467b97STreehugger Robot
147*16467b97STreehugger Robot    def LA(self, i):
148*16467b97STreehugger Robot        if self.initialStreamState:
149*16467b97STreehugger Robot            self.consumeInitialHiddenTokens()
150*16467b97STreehugger Robot
151*16467b97STreehugger Robot        t = self.input.LT(i)
152*16467b97STreehugger Robot        self._dbg.LT(i, t)
153*16467b97STreehugger Robot        return t.type
154*16467b97STreehugger Robot
155*16467b97STreehugger Robot
156*16467b97STreehugger Robot    def get(self, i):
157*16467b97STreehugger Robot        return self.input.get(i)
158*16467b97STreehugger Robot
159*16467b97STreehugger Robot
160*16467b97STreehugger Robot    def index(self):
161*16467b97STreehugger Robot        return self.input.index()
162*16467b97STreehugger Robot
163*16467b97STreehugger Robot
164*16467b97STreehugger Robot    def mark(self):
165*16467b97STreehugger Robot        self.lastMarker = self.input.mark()
166*16467b97STreehugger Robot        self._dbg.mark(self.lastMarker)
167*16467b97STreehugger Robot        return self.lastMarker
168*16467b97STreehugger Robot
169*16467b97STreehugger Robot
170*16467b97STreehugger Robot    def rewind(self, marker=None):
171*16467b97STreehugger Robot        self._dbg.rewind(marker)
172*16467b97STreehugger Robot        self.input.rewind(marker)
173*16467b97STreehugger Robot
174*16467b97STreehugger Robot
175*16467b97STreehugger Robot    def release(self, marker):
176*16467b97STreehugger Robot        pass
177*16467b97STreehugger Robot
178*16467b97STreehugger Robot
179*16467b97STreehugger Robot    def seek(self, index):
180*16467b97STreehugger Robot        # TODO: implement seek in dbg interface
181*16467b97STreehugger Robot        # self._dbg.seek(index);
182*16467b97STreehugger Robot        self.input.seek(index)
183*16467b97STreehugger Robot
184*16467b97STreehugger Robot
185*16467b97STreehugger Robot    def size(self):
186*16467b97STreehugger Robot        return self.input.size()
187*16467b97STreehugger Robot
188*16467b97STreehugger Robot
189*16467b97STreehugger Robot    def getTokenSource(self):
190*16467b97STreehugger Robot        return self.input.getTokenSource()
191*16467b97STreehugger Robot
192*16467b97STreehugger Robot
193*16467b97STreehugger Robot    def getSourceName(self):
194*16467b97STreehugger Robot        return self.getTokenSource().getSourceName()
195*16467b97STreehugger Robot
196*16467b97STreehugger Robot
197*16467b97STreehugger Robot    def toString(self, start=None, stop=None):
198*16467b97STreehugger Robot        return self.input.toString(start, stop)
199*16467b97STreehugger Robot
200*16467b97STreehugger Robot
201*16467b97STreehugger Robotclass DebugTreeAdaptor(TreeAdaptor):
202*16467b97STreehugger Robot    """A TreeAdaptor proxy that fires debugging events to a DebugEventListener
203*16467b97STreehugger Robot    delegate and uses the TreeAdaptor delegate to do the actual work.  All
204*16467b97STreehugger Robot    AST events are triggered by this adaptor; no code gen changes are needed
205*16467b97STreehugger Robot    in generated rules.  Debugging events are triggered *after* invoking
206*16467b97STreehugger Robot    tree adaptor routines.
207*16467b97STreehugger Robot
208*16467b97STreehugger Robot    Trees created with actions in rewrite actions like "-> ^(ADD {foo} {bar})"
209*16467b97STreehugger Robot    cannot be tracked as they might not use the adaptor to create foo, bar.
210*16467b97STreehugger Robot    The debug listener has to deal with tree node IDs for which it did
211*16467b97STreehugger Robot    not see a createNode event.  A single <unknown> node is sufficient even
212*16467b97STreehugger Robot    if it represents a whole tree.
213*16467b97STreehugger Robot    """
214*16467b97STreehugger Robot
215*16467b97STreehugger Robot    def __init__(self, dbg, adaptor):
216*16467b97STreehugger Robot        self.dbg = dbg
217*16467b97STreehugger Robot        self.adaptor = adaptor
218*16467b97STreehugger Robot
219*16467b97STreehugger Robot
220*16467b97STreehugger Robot    def createWithPayload(self, payload):
221*16467b97STreehugger Robot        if payload.getTokenIndex() < 0:
222*16467b97STreehugger Robot            # could be token conjured up during error recovery
223*16467b97STreehugger Robot            return self.createFromType(payload.getType(), payload.getText())
224*16467b97STreehugger Robot
225*16467b97STreehugger Robot        node = self.adaptor.createWithPayload(payload)
226*16467b97STreehugger Robot        self.dbg.createNode(node, payload)
227*16467b97STreehugger Robot        return node
228*16467b97STreehugger Robot
229*16467b97STreehugger Robot    def createFromToken(self, tokenType, fromToken, text=None):
230*16467b97STreehugger Robot        node = self.adaptor.createFromToken(tokenType, fromToken, text)
231*16467b97STreehugger Robot        self.dbg.createNode(node)
232*16467b97STreehugger Robot        return node
233*16467b97STreehugger Robot
234*16467b97STreehugger Robot    def createFromType(self, tokenType, text):
235*16467b97STreehugger Robot        node = self.adaptor.createFromType(tokenType, text)
236*16467b97STreehugger Robot        self.dbg.createNode(node)
237*16467b97STreehugger Robot        return node
238*16467b97STreehugger Robot
239*16467b97STreehugger Robot
240*16467b97STreehugger Robot    def errorNode(self, input, start, stop, exc):
241*16467b97STreehugger Robot        node = selfadaptor.errorNode(input, start, stop, exc)
242*16467b97STreehugger Robot        if node is not None:
243*16467b97STreehugger Robot            dbg.errorNode(node)
244*16467b97STreehugger Robot
245*16467b97STreehugger Robot        return node
246*16467b97STreehugger Robot
247*16467b97STreehugger Robot
248*16467b97STreehugger Robot    def dupTree(self, tree):
249*16467b97STreehugger Robot        t = self.adaptor.dupTree(tree)
250*16467b97STreehugger Robot        # walk the tree and emit create and add child events
251*16467b97STreehugger Robot        # to simulate what dupTree has done. dupTree does not call this debug
252*16467b97STreehugger Robot        # adapter so I must simulate.
253*16467b97STreehugger Robot        self.simulateTreeConstruction(t)
254*16467b97STreehugger Robot        return t
255*16467b97STreehugger Robot
256*16467b97STreehugger Robot
257*16467b97STreehugger Robot    def simulateTreeConstruction(self, t):
258*16467b97STreehugger Robot	"""^(A B C): emit create A, create B, add child, ..."""
259*16467b97STreehugger Robot        self.dbg.createNode(t)
260*16467b97STreehugger Robot        for i in range(self.adaptor.getChildCount(t)):
261*16467b97STreehugger Robot            child = self.adaptor.getChild(t, i)
262*16467b97STreehugger Robot            self.simulateTreeConstruction(child)
263*16467b97STreehugger Robot            self.dbg.addChild(t, child)
264*16467b97STreehugger Robot
265*16467b97STreehugger Robot
266*16467b97STreehugger Robot    def dupNode(self, treeNode):
267*16467b97STreehugger Robot        d = self.adaptor.dupNode(treeNode)
268*16467b97STreehugger Robot        self.dbg.createNode(d)
269*16467b97STreehugger Robot        return d
270*16467b97STreehugger Robot
271*16467b97STreehugger Robot
272*16467b97STreehugger Robot    def nil(self):
273*16467b97STreehugger Robot        node = self.adaptor.nil()
274*16467b97STreehugger Robot        self.dbg.nilNode(node)
275*16467b97STreehugger Robot        return node
276*16467b97STreehugger Robot
277*16467b97STreehugger Robot
278*16467b97STreehugger Robot    def isNil(self, tree):
279*16467b97STreehugger Robot        return self.adaptor.isNil(tree)
280*16467b97STreehugger Robot
281*16467b97STreehugger Robot
282*16467b97STreehugger Robot    def addChild(self, t, child):
283*16467b97STreehugger Robot        if isinstance(child, Token):
284*16467b97STreehugger Robot            n = self.createWithPayload(child)
285*16467b97STreehugger Robot            self.addChild(t, n)
286*16467b97STreehugger Robot
287*16467b97STreehugger Robot        else:
288*16467b97STreehugger Robot            if t is None or child is None:
289*16467b97STreehugger Robot                return
290*16467b97STreehugger Robot
291*16467b97STreehugger Robot            self.adaptor.addChild(t, child)
292*16467b97STreehugger Robot            self.dbg.addChild(t, child)
293*16467b97STreehugger Robot
294*16467b97STreehugger Robot    def becomeRoot(self, newRoot, oldRoot):
295*16467b97STreehugger Robot        if isinstance(newRoot, Token):
296*16467b97STreehugger Robot            n = self.createWithPayload(newRoot)
297*16467b97STreehugger Robot            self.adaptor.becomeRoot(n, oldRoot)
298*16467b97STreehugger Robot        else:
299*16467b97STreehugger Robot            n = self.adaptor.becomeRoot(newRoot, oldRoot)
300*16467b97STreehugger Robot
301*16467b97STreehugger Robot        self.dbg.becomeRoot(newRoot, oldRoot)
302*16467b97STreehugger Robot        return n
303*16467b97STreehugger Robot
304*16467b97STreehugger Robot
305*16467b97STreehugger Robot    def rulePostProcessing(self, root):
306*16467b97STreehugger Robot        return self.adaptor.rulePostProcessing(root)
307*16467b97STreehugger Robot
308*16467b97STreehugger Robot
309*16467b97STreehugger Robot    def getType(self, t):
310*16467b97STreehugger Robot        return self.adaptor.getType(t)
311*16467b97STreehugger Robot
312*16467b97STreehugger Robot
313*16467b97STreehugger Robot    def setType(self, t, type):
314*16467b97STreehugger Robot        self.adaptor.setType(t, type)
315*16467b97STreehugger Robot
316*16467b97STreehugger Robot
317*16467b97STreehugger Robot    def getText(self, t):
318*16467b97STreehugger Robot        return self.adaptor.getText(t)
319*16467b97STreehugger Robot
320*16467b97STreehugger Robot
321*16467b97STreehugger Robot    def setText(self, t, text):
322*16467b97STreehugger Robot        self.adaptor.setText(t, text)
323*16467b97STreehugger Robot
324*16467b97STreehugger Robot
325*16467b97STreehugger Robot    def getToken(self, t):
326*16467b97STreehugger Robot        return self.adaptor.getToken(t)
327*16467b97STreehugger Robot
328*16467b97STreehugger Robot
329*16467b97STreehugger Robot    def setTokenBoundaries(self, t, startToken, stopToken):
330*16467b97STreehugger Robot        self.adaptor.setTokenBoundaries(t, startToken, stopToken)
331*16467b97STreehugger Robot        if t is not None and startToken is not None and stopToken is not None:
332*16467b97STreehugger Robot            self.dbg.setTokenBoundaries(
333*16467b97STreehugger Robot                t, startToken.getTokenIndex(),
334*16467b97STreehugger Robot                stopToken.getTokenIndex())
335*16467b97STreehugger Robot
336*16467b97STreehugger Robot
337*16467b97STreehugger Robot    def getTokenStartIndex(self, t):
338*16467b97STreehugger Robot        return self.adaptor.getTokenStartIndex(t)
339*16467b97STreehugger Robot
340*16467b97STreehugger Robot
341*16467b97STreehugger Robot    def getTokenStopIndex(self, t):
342*16467b97STreehugger Robot        return self.adaptor.getTokenStopIndex(t)
343*16467b97STreehugger Robot
344*16467b97STreehugger Robot
345*16467b97STreehugger Robot    def getChild(self, t, i):
346*16467b97STreehugger Robot        return self.adaptor.getChild(t, i)
347*16467b97STreehugger Robot
348*16467b97STreehugger Robot
349*16467b97STreehugger Robot    def setChild(self, t, i, child):
350*16467b97STreehugger Robot        self.adaptor.setChild(t, i, child)
351*16467b97STreehugger Robot
352*16467b97STreehugger Robot
353*16467b97STreehugger Robot    def deleteChild(self, t, i):
354*16467b97STreehugger Robot        return self.adaptor.deleteChild(t, i)
355*16467b97STreehugger Robot
356*16467b97STreehugger Robot
357*16467b97STreehugger Robot    def getChildCount(self, t):
358*16467b97STreehugger Robot        return self.adaptor.getChildCount(t)
359*16467b97STreehugger Robot
360*16467b97STreehugger Robot
361*16467b97STreehugger Robot    def getUniqueID(self, node):
362*16467b97STreehugger Robot        return self.adaptor.getUniqueID(node)
363*16467b97STreehugger Robot
364*16467b97STreehugger Robot
365*16467b97STreehugger Robot    def getParent(self, t):
366*16467b97STreehugger Robot        return self.adaptor.getParent(t)
367*16467b97STreehugger Robot
368*16467b97STreehugger Robot
369*16467b97STreehugger Robot    def getChildIndex(self, t):
370*16467b97STreehugger Robot        return self.adaptor.getChildIndex(t)
371*16467b97STreehugger Robot
372*16467b97STreehugger Robot
373*16467b97STreehugger Robot    def setParent(self, t, parent):
374*16467b97STreehugger Robot        self.adaptor.setParent(t, parent)
375*16467b97STreehugger Robot
376*16467b97STreehugger Robot
377*16467b97STreehugger Robot    def setChildIndex(self, t, index):
378*16467b97STreehugger Robot        self.adaptor.setChildIndex(t, index)
379*16467b97STreehugger Robot
380*16467b97STreehugger Robot
381*16467b97STreehugger Robot    def replaceChildren(self, parent, startChildIndex, stopChildIndex, t):
382*16467b97STreehugger Robot        self.adaptor.replaceChildren(parent, startChildIndex, stopChildIndex, t)
383*16467b97STreehugger Robot
384*16467b97STreehugger Robot
385*16467b97STreehugger Robot    ## support
386*16467b97STreehugger Robot
387*16467b97STreehugger Robot    def getDebugListener(self):
388*16467b97STreehugger Robot        return dbg
389*16467b97STreehugger Robot
390*16467b97STreehugger Robot    def setDebugListener(self, dbg):
391*16467b97STreehugger Robot        self.dbg = dbg
392*16467b97STreehugger Robot
393*16467b97STreehugger Robot
394*16467b97STreehugger Robot    def getTreeAdaptor(self):
395*16467b97STreehugger Robot        return self.adaptor
396*16467b97STreehugger Robot
397*16467b97STreehugger Robot
398*16467b97STreehugger Robot
399*16467b97STreehugger Robotclass DebugEventListener(object):
400*16467b97STreehugger Robot    """All debugging events that a recognizer can trigger.
401*16467b97STreehugger Robot
402*16467b97STreehugger Robot    I did not create a separate AST debugging interface as it would create
403*16467b97STreehugger Robot    lots of extra classes and DebugParser has a dbg var defined, which makes
404*16467b97STreehugger Robot    it hard to change to ASTDebugEventListener.  I looked hard at this issue
405*16467b97STreehugger Robot    and it is easier to understand as one monolithic event interface for all
406*16467b97STreehugger Robot    possible events.  Hopefully, adding ST debugging stuff won't be bad.  Leave
407*16467b97STreehugger Robot    for future. 4/26/2006.
408*16467b97STreehugger Robot    """
409*16467b97STreehugger Robot
410*16467b97STreehugger Robot    # Moved to version 2 for v3.1: added grammar name to enter/exit Rule
411*16467b97STreehugger Robot    PROTOCOL_VERSION = "2"
412*16467b97STreehugger Robot
413*16467b97STreehugger Robot    def enterRule(self, grammarFileName, ruleName):
414*16467b97STreehugger Robot	"""The parser has just entered a rule. No decision has been made about
415*16467b97STreehugger Robot        which alt is predicted.  This is fired AFTER init actions have been
416*16467b97STreehugger Robot        executed.  Attributes are defined and available etc...
417*16467b97STreehugger Robot        The grammarFileName allows composite grammars to jump around among
418*16467b97STreehugger Robot        multiple grammar files.
419*16467b97STreehugger Robot        """
420*16467b97STreehugger Robot
421*16467b97STreehugger Robot        pass
422*16467b97STreehugger Robot
423*16467b97STreehugger Robot
424*16467b97STreehugger Robot    def enterAlt(self, alt):
425*16467b97STreehugger Robot	"""Because rules can have lots of alternatives, it is very useful to
426*16467b97STreehugger Robot        know which alt you are entering.  This is 1..n for n alts.
427*16467b97STreehugger Robot        """
428*16467b97STreehugger Robot        pass
429*16467b97STreehugger Robot
430*16467b97STreehugger Robot
431*16467b97STreehugger Robot    def exitRule(self, grammarFileName, ruleName):
432*16467b97STreehugger Robot	"""This is the last thing executed before leaving a rule.  It is
433*16467b97STreehugger Robot        executed even if an exception is thrown.  This is triggered after
434*16467b97STreehugger Robot        error reporting and recovery have occurred (unless the exception is
435*16467b97STreehugger Robot        not caught in this rule).  This implies an "exitAlt" event.
436*16467b97STreehugger Robot        The grammarFileName allows composite grammars to jump around among
437*16467b97STreehugger Robot        multiple grammar files.
438*16467b97STreehugger Robot	"""
439*16467b97STreehugger Robot        pass
440*16467b97STreehugger Robot
441*16467b97STreehugger Robot
442*16467b97STreehugger Robot    def enterSubRule(self, decisionNumber):
443*16467b97STreehugger Robot	"""Track entry into any (...) subrule other EBNF construct"""
444*16467b97STreehugger Robot        pass
445*16467b97STreehugger Robot
446*16467b97STreehugger Robot
447*16467b97STreehugger Robot    def exitSubRule(self, decisionNumber):
448*16467b97STreehugger Robot        pass
449*16467b97STreehugger Robot
450*16467b97STreehugger Robot
451*16467b97STreehugger Robot    def enterDecision(self, decisionNumber, couldBacktrack):
452*16467b97STreehugger Robot	"""Every decision, fixed k or arbitrary, has an enter/exit event
453*16467b97STreehugger Robot        so that a GUI can easily track what LT/consume events are
454*16467b97STreehugger Robot        associated with prediction.  You will see a single enter/exit
455*16467b97STreehugger Robot        subrule but multiple enter/exit decision events, one for each
456*16467b97STreehugger Robot        loop iteration.
457*16467b97STreehugger Robot        """
458*16467b97STreehugger Robot        pass
459*16467b97STreehugger Robot
460*16467b97STreehugger Robot
461*16467b97STreehugger Robot    def exitDecision(self, decisionNumber):
462*16467b97STreehugger Robot        pass
463*16467b97STreehugger Robot
464*16467b97STreehugger Robot
465*16467b97STreehugger Robot    def consumeToken(self, t):
466*16467b97STreehugger Robot	"""An input token was consumed; matched by any kind of element.
467*16467b97STreehugger Robot        Trigger after the token was matched by things like match(), matchAny().
468*16467b97STreehugger Robot	"""
469*16467b97STreehugger Robot        pass
470*16467b97STreehugger Robot
471*16467b97STreehugger Robot
472*16467b97STreehugger Robot    def consumeHiddenToken(self, t):
473*16467b97STreehugger Robot	"""An off-channel input token was consumed.
474*16467b97STreehugger Robot        Trigger after the token was matched by things like match(), matchAny().
475*16467b97STreehugger Robot        (unless of course the hidden token is first stuff in the input stream).
476*16467b97STreehugger Robot	"""
477*16467b97STreehugger Robot        pass
478*16467b97STreehugger Robot
479*16467b97STreehugger Robot
480*16467b97STreehugger Robot    def LT(self, i, t):
481*16467b97STreehugger Robot	"""Somebody (anybody) looked ahead.  Note that this actually gets
482*16467b97STreehugger Robot        triggered by both LA and LT calls.  The debugger will want to know
483*16467b97STreehugger Robot        which Token object was examined.  Like consumeToken, this indicates
484*16467b97STreehugger Robot        what token was seen at that depth.  A remote debugger cannot look
485*16467b97STreehugger Robot        ahead into a file it doesn't have so LT events must pass the token
486*16467b97STreehugger Robot        even if the info is redundant.
487*16467b97STreehugger Robot	"""
488*16467b97STreehugger Robot        pass
489*16467b97STreehugger Robot
490*16467b97STreehugger Robot
491*16467b97STreehugger Robot    def mark(self, marker):
492*16467b97STreehugger Robot	"""The parser is going to look arbitrarily ahead; mark this location,
493*16467b97STreehugger Robot        the token stream's marker is sent in case you need it.
494*16467b97STreehugger Robot	"""
495*16467b97STreehugger Robot        pass
496*16467b97STreehugger Robot
497*16467b97STreehugger Robot
498*16467b97STreehugger Robot    def rewind(self, marker=None):
499*16467b97STreehugger Robot	"""After an arbitrairly long lookahead as with a cyclic DFA (or with
500*16467b97STreehugger Robot        any backtrack), this informs the debugger that stream should be
501*16467b97STreehugger Robot        rewound to the position associated with marker.
502*16467b97STreehugger Robot
503*16467b97STreehugger Robot        """
504*16467b97STreehugger Robot        pass
505*16467b97STreehugger Robot
506*16467b97STreehugger Robot
507*16467b97STreehugger Robot    def beginBacktrack(self, level):
508*16467b97STreehugger Robot        pass
509*16467b97STreehugger Robot
510*16467b97STreehugger Robot
511*16467b97STreehugger Robot    def endBacktrack(self, level, successful):
512*16467b97STreehugger Robot        pass
513*16467b97STreehugger Robot
514*16467b97STreehugger Robot
515*16467b97STreehugger Robot    def location(self, line, pos):
516*16467b97STreehugger Robot	"""To watch a parser move through the grammar, the parser needs to
517*16467b97STreehugger Robot        inform the debugger what line/charPos it is passing in the grammar.
518*16467b97STreehugger Robot        For now, this does not know how to switch from one grammar to the
519*16467b97STreehugger Robot        other and back for island grammars etc...
520*16467b97STreehugger Robot
521*16467b97STreehugger Robot        This should also allow breakpoints because the debugger can stop
522*16467b97STreehugger Robot        the parser whenever it hits this line/pos.
523*16467b97STreehugger Robot	"""
524*16467b97STreehugger Robot        pass
525*16467b97STreehugger Robot
526*16467b97STreehugger Robot
527*16467b97STreehugger Robot    def recognitionException(self, e):
528*16467b97STreehugger Robot	"""A recognition exception occurred such as NoViableAltException.  I made
529*16467b97STreehugger Robot        this a generic event so that I can alter the exception hierachy later
530*16467b97STreehugger Robot        without having to alter all the debug objects.
531*16467b97STreehugger Robot
532*16467b97STreehugger Robot        Upon error, the stack of enter rule/subrule must be properly unwound.
533*16467b97STreehugger Robot        If no viable alt occurs it is within an enter/exit decision, which
534*16467b97STreehugger Robot        also must be rewound.  Even the rewind for each mark must be unwount.
535*16467b97STreehugger Robot        In the Java target this is pretty easy using try/finally, if a bit
536*16467b97STreehugger Robot        ugly in the generated code.  The rewind is generated in DFA.predict()
537*16467b97STreehugger Robot        actually so no code needs to be generated for that.  For languages
538*16467b97STreehugger Robot        w/o this "finally" feature (C++?), the target implementor will have
539*16467b97STreehugger Robot        to build an event stack or something.
540*16467b97STreehugger Robot
541*16467b97STreehugger Robot        Across a socket for remote debugging, only the RecognitionException
542*16467b97STreehugger Robot        data fields are transmitted.  The token object or whatever that
543*16467b97STreehugger Robot        caused the problem was the last object referenced by LT.  The
544*16467b97STreehugger Robot        immediately preceding LT event should hold the unexpected Token or
545*16467b97STreehugger Robot        char.
546*16467b97STreehugger Robot
547*16467b97STreehugger Robot        Here is a sample event trace for grammar:
548*16467b97STreehugger Robot
549*16467b97STreehugger Robot        b : C ({;}A|B) // {;} is there to prevent A|B becoming a set
550*16467b97STreehugger Robot          | D
551*16467b97STreehugger Robot          ;
552*16467b97STreehugger Robot
553*16467b97STreehugger Robot        The sequence for this rule (with no viable alt in the subrule) for
554*16467b97STreehugger Robot        input 'c c' (there are 3 tokens) is:
555*16467b97STreehugger Robot
556*16467b97STreehugger Robot		commence
557*16467b97STreehugger Robot		LT(1)
558*16467b97STreehugger Robot		enterRule b
559*16467b97STreehugger Robot		location 7 1
560*16467b97STreehugger Robot		enter decision 3
561*16467b97STreehugger Robot		LT(1)
562*16467b97STreehugger Robot		exit decision 3
563*16467b97STreehugger Robot		enterAlt1
564*16467b97STreehugger Robot		location 7 5
565*16467b97STreehugger Robot		LT(1)
566*16467b97STreehugger Robot		consumeToken [c/<4>,1:0]
567*16467b97STreehugger Robot		location 7 7
568*16467b97STreehugger Robot		enterSubRule 2
569*16467b97STreehugger Robot		enter decision 2
570*16467b97STreehugger Robot		LT(1)
571*16467b97STreehugger Robot		LT(1)
572*16467b97STreehugger Robot		recognitionException NoViableAltException 2 1 2
573*16467b97STreehugger Robot		exit decision 2
574*16467b97STreehugger Robot		exitSubRule 2
575*16467b97STreehugger Robot		beginResync
576*16467b97STreehugger Robot		LT(1)
577*16467b97STreehugger Robot		consumeToken [c/<4>,1:1]
578*16467b97STreehugger Robot		LT(1)
579*16467b97STreehugger Robot		endResync
580*16467b97STreehugger Robot		LT(-1)
581*16467b97STreehugger Robot		exitRule b
582*16467b97STreehugger Robot		terminate
583*16467b97STreehugger Robot	"""
584*16467b97STreehugger Robot        pass
585*16467b97STreehugger Robot
586*16467b97STreehugger Robot
587*16467b97STreehugger Robot    def beginResync(self):
588*16467b97STreehugger Robot	"""Indicates the recognizer is about to consume tokens to resynchronize
589*16467b97STreehugger Robot        the parser.  Any consume events from here until the recovered event
590*16467b97STreehugger Robot        are not part of the parse--they are dead tokens.
591*16467b97STreehugger Robot        """
592*16467b97STreehugger Robot        pass
593*16467b97STreehugger Robot
594*16467b97STreehugger Robot
595*16467b97STreehugger Robot    def endResync(self):
596*16467b97STreehugger Robot	"""Indicates that the recognizer has finished consuming tokens in order
597*16467b97STreehugger Robot        to resychronize.  There may be multiple beginResync/endResync pairs
598*16467b97STreehugger Robot        before the recognizer comes out of errorRecovery mode (in which
599*16467b97STreehugger Robot        multiple errors are suppressed).  This will be useful
600*16467b97STreehugger Robot        in a gui where you want to probably grey out tokens that are consumed
601*16467b97STreehugger Robot        but not matched to anything in grammar.  Anything between
602*16467b97STreehugger Robot        a beginResync/endResync pair was tossed out by the parser.
603*16467b97STreehugger Robot	"""
604*16467b97STreehugger Robot        pass
605*16467b97STreehugger Robot
606*16467b97STreehugger Robot
607*16467b97STreehugger Robot    def semanticPredicate(self, result, predicate):
608*16467b97STreehugger Robot	"""A semantic predicate was evaluate with this result and action text"""
609*16467b97STreehugger Robot        pass
610*16467b97STreehugger Robot
611*16467b97STreehugger Robot
612*16467b97STreehugger Robot    def commence(self):
613*16467b97STreehugger Robot	"""Announce that parsing has begun.  Not technically useful except for
614*16467b97STreehugger Robot        sending events over a socket.  A GUI for example will launch a thread
615*16467b97STreehugger Robot        to connect and communicate with a remote parser.  The thread will want
616*16467b97STreehugger Robot        to notify the GUI when a connection is made.  ANTLR parsers
617*16467b97STreehugger Robot        trigger this upon entry to the first rule (the ruleLevel is used to
618*16467b97STreehugger Robot        figure this out).
619*16467b97STreehugger Robot	"""
620*16467b97STreehugger Robot        pass
621*16467b97STreehugger Robot
622*16467b97STreehugger Robot
623*16467b97STreehugger Robot    def terminate(self):
624*16467b97STreehugger Robot        """Parsing is over; successfully or not.  Mostly useful for telling
625*16467b97STreehugger Robot        remote debugging listeners that it's time to quit.  When the rule
626*16467b97STreehugger Robot        invocation level goes to zero at the end of a rule, we are done
627*16467b97STreehugger Robot        parsing.
628*16467b97STreehugger Robot	"""
629*16467b97STreehugger Robot        pass
630*16467b97STreehugger Robot
631*16467b97STreehugger Robot
632*16467b97STreehugger Robot    ## T r e e  P a r s i n g
633*16467b97STreehugger Robot
634*16467b97STreehugger Robot    def consumeNode(self, t):
635*16467b97STreehugger Robot        """Input for a tree parser is an AST, but we know nothing for sure
636*16467b97STreehugger Robot        about a node except its type and text (obtained from the adaptor).
637*16467b97STreehugger Robot        This is the analog of the consumeToken method.  Again, the ID is
638*16467b97STreehugger Robot        the hashCode usually of the node so it only works if hashCode is
639*16467b97STreehugger Robot        not implemented.  If the type is UP or DOWN, then
640*16467b97STreehugger Robot        the ID is not really meaningful as it's fixed--there is
641*16467b97STreehugger Robot        just one UP node and one DOWN navigation node.
642*16467b97STreehugger Robot        """
643*16467b97STreehugger Robot        pass
644*16467b97STreehugger Robot
645*16467b97STreehugger Robot
646*16467b97STreehugger Robot    def LT(self, i, t):
647*16467b97STreehugger Robot	"""The tree parser lookedahead.  If the type is UP or DOWN,
648*16467b97STreehugger Robot        then the ID is not really meaningful as it's fixed--there is
649*16467b97STreehugger Robot        just one UP node and one DOWN navigation node.
650*16467b97STreehugger Robot	"""
651*16467b97STreehugger Robot        pass
652*16467b97STreehugger Robot
653*16467b97STreehugger Robot
654*16467b97STreehugger Robot
655*16467b97STreehugger Robot    ## A S T  E v e n t s
656*16467b97STreehugger Robot
657*16467b97STreehugger Robot    def nilNode(self, t):
658*16467b97STreehugger Robot	"""A nil was created (even nil nodes have a unique ID...
659*16467b97STreehugger Robot        they are not "null" per se).  As of 4/28/2006, this
660*16467b97STreehugger Robot        seems to be uniquely triggered when starting a new subtree
661*16467b97STreehugger Robot        such as when entering a subrule in automatic mode and when
662*16467b97STreehugger Robot        building a tree in rewrite mode.
663*16467b97STreehugger Robot
664*16467b97STreehugger Robot        If you are receiving this event over a socket via
665*16467b97STreehugger Robot        RemoteDebugEventSocketListener then only t.ID is set.
666*16467b97STreehugger Robot	"""
667*16467b97STreehugger Robot        pass
668*16467b97STreehugger Robot
669*16467b97STreehugger Robot
670*16467b97STreehugger Robot    def errorNode(self, t):
671*16467b97STreehugger Robot	"""Upon syntax error, recognizers bracket the error with an error node
672*16467b97STreehugger Robot        if they are building ASTs.
673*16467b97STreehugger Robot        """
674*16467b97STreehugger Robot        pass
675*16467b97STreehugger Robot
676*16467b97STreehugger Robot
677*16467b97STreehugger Robot    def createNode(self, node, token=None):
678*16467b97STreehugger Robot	"""Announce a new node built from token elements such as type etc...
679*16467b97STreehugger Robot
680*16467b97STreehugger Robot        If you are receiving this event over a socket via
681*16467b97STreehugger Robot        RemoteDebugEventSocketListener then only t.ID, type, text are
682*16467b97STreehugger Robot        set.
683*16467b97STreehugger Robot	"""
684*16467b97STreehugger Robot        pass
685*16467b97STreehugger Robot
686*16467b97STreehugger Robot
687*16467b97STreehugger Robot    def becomeRoot(self, newRoot, oldRoot):
688*16467b97STreehugger Robot	"""Make a node the new root of an existing root.
689*16467b97STreehugger Robot
690*16467b97STreehugger Robot        Note: the newRootID parameter is possibly different
691*16467b97STreehugger Robot        than the TreeAdaptor.becomeRoot() newRoot parameter.
692*16467b97STreehugger Robot        In our case, it will always be the result of calling
693*16467b97STreehugger Robot        TreeAdaptor.becomeRoot() and not root_n or whatever.
694*16467b97STreehugger Robot
695*16467b97STreehugger Robot        The listener should assume that this event occurs
696*16467b97STreehugger Robot        only when the current subrule (or rule) subtree is
697*16467b97STreehugger Robot        being reset to newRootID.
698*16467b97STreehugger Robot
699*16467b97STreehugger Robot        If you are receiving this event over a socket via
700*16467b97STreehugger Robot        RemoteDebugEventSocketListener then only IDs are set.
701*16467b97STreehugger Robot
702*16467b97STreehugger Robot        @see antlr3.tree.TreeAdaptor.becomeRoot()
703*16467b97STreehugger Robot	"""
704*16467b97STreehugger Robot        pass
705*16467b97STreehugger Robot
706*16467b97STreehugger Robot
707*16467b97STreehugger Robot    def addChild(self, root, child):
708*16467b97STreehugger Robot	"""Make childID a child of rootID.
709*16467b97STreehugger Robot
710*16467b97STreehugger Robot        If you are receiving this event over a socket via
711*16467b97STreehugger Robot        RemoteDebugEventSocketListener then only IDs are set.
712*16467b97STreehugger Robot
713*16467b97STreehugger Robot        @see antlr3.tree.TreeAdaptor.addChild()
714*16467b97STreehugger Robot        """
715*16467b97STreehugger Robot        pass
716*16467b97STreehugger Robot
717*16467b97STreehugger Robot
718*16467b97STreehugger Robot    def setTokenBoundaries(self, t, tokenStartIndex, tokenStopIndex):
719*16467b97STreehugger Robot	"""Set the token start/stop token index for a subtree root or node.
720*16467b97STreehugger Robot
721*16467b97STreehugger Robot        If you are receiving this event over a socket via
722*16467b97STreehugger Robot        RemoteDebugEventSocketListener then only t.ID is set.
723*16467b97STreehugger Robot	"""
724*16467b97STreehugger Robot        pass
725*16467b97STreehugger Robot
726*16467b97STreehugger Robot
727*16467b97STreehugger Robotclass BlankDebugEventListener(DebugEventListener):
728*16467b97STreehugger Robot    """A blank listener that does nothing; useful for real classes so
729*16467b97STreehugger Robot    they don't have to have lots of blank methods and are less
730*16467b97STreehugger Robot    sensitive to updates to debug interface.
731*16467b97STreehugger Robot
732*16467b97STreehugger Robot    Note: this class is identical to DebugEventListener and exists purely
733*16467b97STreehugger Robot    for compatibility with Java.
734*16467b97STreehugger Robot    """
735*16467b97STreehugger Robot    pass
736*16467b97STreehugger Robot
737*16467b97STreehugger Robot
738*16467b97STreehugger Robotclass TraceDebugEventListener(DebugEventListener):
739*16467b97STreehugger Robot    """A listener that simply records text representations of the events.
740*16467b97STreehugger Robot
741*16467b97STreehugger Robot    Useful for debugging the debugging facility ;)
742*16467b97STreehugger Robot
743*16467b97STreehugger Robot    Subclasses can override the record() method (which defaults to printing to
744*16467b97STreehugger Robot    stdout) to record the events in a different way.
745*16467b97STreehugger Robot    """
746*16467b97STreehugger Robot
747*16467b97STreehugger Robot    def __init__(self, adaptor=None):
748*16467b97STreehugger Robot        super(TraceDebugEventListener, self).__init__()
749*16467b97STreehugger Robot
750*16467b97STreehugger Robot        if adaptor is None:
751*16467b97STreehugger Robot            adaptor = CommonTreeAdaptor()
752*16467b97STreehugger Robot        self.adaptor = adaptor
753*16467b97STreehugger Robot
754*16467b97STreehugger Robot    def record(self, event):
755*16467b97STreehugger Robot        sys.stdout.write(event + '\n')
756*16467b97STreehugger Robot
757*16467b97STreehugger Robot    def enterRule(self, grammarFileName, ruleName):
758*16467b97STreehugger Robot        self.record("enterRule "+ruleName)
759*16467b97STreehugger Robot
760*16467b97STreehugger Robot    def exitRule(self, grammarFileName, ruleName):
761*16467b97STreehugger Robot        self.record("exitRule "+ruleName)
762*16467b97STreehugger Robot
763*16467b97STreehugger Robot    def enterSubRule(self, decisionNumber):
764*16467b97STreehugger Robot        self.record("enterSubRule")
765*16467b97STreehugger Robot
766*16467b97STreehugger Robot    def exitSubRule(self, decisionNumber):
767*16467b97STreehugger Robot        self.record("exitSubRule")
768*16467b97STreehugger Robot
769*16467b97STreehugger Robot    def location(self, line, pos):
770*16467b97STreehugger Robot        self.record("location %s:%s" % (line, pos))
771*16467b97STreehugger Robot
772*16467b97STreehugger Robot    ## Tree parsing stuff
773*16467b97STreehugger Robot
774*16467b97STreehugger Robot    def consumeNode(self, t):
775*16467b97STreehugger Robot        self.record("consumeNode %s %s %s" % (
776*16467b97STreehugger Robot                self.adaptor.getUniqueID(t),
777*16467b97STreehugger Robot                self.adaptor.getText(t),
778*16467b97STreehugger Robot                self.adaptor.getType(t)))
779*16467b97STreehugger Robot
780*16467b97STreehugger Robot    def LT(self, i, t):
781*16467b97STreehugger Robot        self.record("LT %s %s %s %s" % (
782*16467b97STreehugger Robot                i,
783*16467b97STreehugger Robot                self.adaptor.getUniqueID(t),
784*16467b97STreehugger Robot                self.adaptor.getText(t),
785*16467b97STreehugger Robot                self.adaptor.getType(t)))
786*16467b97STreehugger Robot
787*16467b97STreehugger Robot
788*16467b97STreehugger Robot    ## AST stuff
789*16467b97STreehugger Robot    def nilNode(self, t):
790*16467b97STreehugger Robot        self.record("nilNode %s" % self.adaptor.getUniqueID(t))
791*16467b97STreehugger Robot
792*16467b97STreehugger Robot    def createNode(self, t, token=None):
793*16467b97STreehugger Robot        if token is None:
794*16467b97STreehugger Robot            self.record("create %s: %s, %s" % (
795*16467b97STreehugger Robot                    self.adaptor.getUniqueID(t),
796*16467b97STreehugger Robot                    self.adaptor.getText(t),
797*16467b97STreehugger Robot                    self.adaptor.getType(t)))
798*16467b97STreehugger Robot
799*16467b97STreehugger Robot        else:
800*16467b97STreehugger Robot            self.record("create %s: %s" % (
801*16467b97STreehugger Robot                    self.adaptor.getUniqueID(t),
802*16467b97STreehugger Robot                    token.getTokenIndex()))
803*16467b97STreehugger Robot
804*16467b97STreehugger Robot    def becomeRoot(self, newRoot, oldRoot):
805*16467b97STreehugger Robot        self.record("becomeRoot %s, %s" % (
806*16467b97STreehugger Robot                self.adaptor.getUniqueID(newRoot),
807*16467b97STreehugger Robot                self.adaptor.getUniqueID(oldRoot)))
808*16467b97STreehugger Robot
809*16467b97STreehugger Robot    def addChild(self, root, child):
810*16467b97STreehugger Robot        self.record("addChild %s, %s" % (
811*16467b97STreehugger Robot                self.adaptor.getUniqueID(root),
812*16467b97STreehugger Robot                self.adaptor.getUniqueID(child)))
813*16467b97STreehugger Robot
814*16467b97STreehugger Robot    def setTokenBoundaries(self, t, tokenStartIndex, tokenStopIndex):
815*16467b97STreehugger Robot        self.record("setTokenBoundaries %s, %s, %s" % (
816*16467b97STreehugger Robot                self.adaptor.getUniqueID(t),
817*16467b97STreehugger Robot                tokenStartIndex, tokenStopIndex))
818*16467b97STreehugger Robot
819*16467b97STreehugger Robot
820*16467b97STreehugger Robotclass RecordDebugEventListener(TraceDebugEventListener):
821*16467b97STreehugger Robot    """A listener that records events as strings in an array."""
822*16467b97STreehugger Robot
823*16467b97STreehugger Robot    def __init__(self, adaptor=None):
824*16467b97STreehugger Robot        super(RecordDebugEventListener, self).__init__(adaptor)
825*16467b97STreehugger Robot
826*16467b97STreehugger Robot        self.events = []
827*16467b97STreehugger Robot
828*16467b97STreehugger Robot    def record(self, event):
829*16467b97STreehugger Robot        self.events.append(event)
830*16467b97STreehugger Robot
831*16467b97STreehugger Robot
832*16467b97STreehugger Robotclass DebugEventSocketProxy(DebugEventListener):
833*16467b97STreehugger Robot    """A proxy debug event listener that forwards events over a socket to
834*16467b97STreehugger Robot    a debugger (or any other listener) using a simple text-based protocol;
835*16467b97STreehugger Robot    one event per line.  ANTLRWorks listens on server socket with a
836*16467b97STreehugger Robot    RemoteDebugEventSocketListener instance.  These two objects must therefore
837*16467b97STreehugger Robot    be kept in sync.  New events must be handled on both sides of socket.
838*16467b97STreehugger Robot    """
839*16467b97STreehugger Robot
840*16467b97STreehugger Robot    DEFAULT_DEBUGGER_PORT = 49100
841*16467b97STreehugger Robot
842*16467b97STreehugger Robot    def __init__(self, recognizer, adaptor=None, port=None,
843*16467b97STreehugger Robot                 debug=None):
844*16467b97STreehugger Robot        super(DebugEventSocketProxy, self).__init__()
845*16467b97STreehugger Robot
846*16467b97STreehugger Robot        self.grammarFileName = recognizer.getGrammarFileName()
847*16467b97STreehugger Robot
848*16467b97STreehugger Robot	# Almost certainly the recognizer will have adaptor set, but
849*16467b97STreehugger Robot        # we don't know how to cast it (Parser or TreeParser) to get
850*16467b97STreehugger Robot        # the adaptor field.  Must be set with a constructor. :(
851*16467b97STreehugger Robot        self.adaptor = adaptor
852*16467b97STreehugger Robot
853*16467b97STreehugger Robot        self.port = port or self.DEFAULT_DEBUGGER_PORT
854*16467b97STreehugger Robot
855*16467b97STreehugger Robot        self.debug = debug
856*16467b97STreehugger Robot
857*16467b97STreehugger Robot        self.socket = None
858*16467b97STreehugger Robot        self.connection = None
859*16467b97STreehugger Robot        self.input = None
860*16467b97STreehugger Robot        self.output = None
861*16467b97STreehugger Robot
862*16467b97STreehugger Robot
863*16467b97STreehugger Robot    def log(self, msg):
864*16467b97STreehugger Robot        if self.debug is not None:
865*16467b97STreehugger Robot            self.debug.write(msg + '\n')
866*16467b97STreehugger Robot
867*16467b97STreehugger Robot
868*16467b97STreehugger Robot    def handshake(self):
869*16467b97STreehugger Robot        if self.socket is None:
870*16467b97STreehugger Robot            # create listening socket
871*16467b97STreehugger Robot            self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
872*16467b97STreehugger Robot            self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
873*16467b97STreehugger Robot            self.socket.bind(('', self.port))
874*16467b97STreehugger Robot            self.socket.listen(1)
875*16467b97STreehugger Robot            self.log("Waiting for incoming connection on port %d" % self.port)
876*16467b97STreehugger Robot
877*16467b97STreehugger Robot            # wait for an incoming connection
878*16467b97STreehugger Robot            self.connection, addr = self.socket.accept()
879*16467b97STreehugger Robot            self.log("Accepted connection from %s:%d" % addr)
880*16467b97STreehugger Robot
881*16467b97STreehugger Robot            self.connection.setblocking(1)
882*16467b97STreehugger Robot            self.connection.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)
883*16467b97STreehugger Robot
884*16467b97STreehugger Robot            # FIXME(pink): wrap into utf8 encoding stream
885*16467b97STreehugger Robot            self.output = self.connection.makefile('w', 0)
886*16467b97STreehugger Robot            self.input = self.connection.makefile('r', 0)
887*16467b97STreehugger Robot
888*16467b97STreehugger Robot            self.write("ANTLR %s" % self.PROTOCOL_VERSION)
889*16467b97STreehugger Robot            self.write("grammar \"%s" % self.grammarFileName)
890*16467b97STreehugger Robot            self.ack()
891*16467b97STreehugger Robot
892*16467b97STreehugger Robot
893*16467b97STreehugger Robot    def write(self, msg):
894*16467b97STreehugger Robot        self.log("> %s" % msg)
895*16467b97STreehugger Robot        self.output.write("%s\n" % msg)
896*16467b97STreehugger Robot        self.output.flush()
897*16467b97STreehugger Robot
898*16467b97STreehugger Robot
899*16467b97STreehugger Robot    def ack(self):
900*16467b97STreehugger Robot        t = self.input.readline()
901*16467b97STreehugger Robot        self.log("< %s" % t.rstrip())
902*16467b97STreehugger Robot
903*16467b97STreehugger Robot
904*16467b97STreehugger Robot    def transmit(self, event):
905*16467b97STreehugger Robot        self.write(event);
906*16467b97STreehugger Robot        self.ack();
907*16467b97STreehugger Robot
908*16467b97STreehugger Robot
909*16467b97STreehugger Robot    def commence(self):
910*16467b97STreehugger Robot        # don't bother sending event; listener will trigger upon connection
911*16467b97STreehugger Robot        pass
912*16467b97STreehugger Robot
913*16467b97STreehugger Robot
914*16467b97STreehugger Robot    def terminate(self):
915*16467b97STreehugger Robot        self.transmit("terminate")
916*16467b97STreehugger Robot        self.output.close()
917*16467b97STreehugger Robot        self.input.close()
918*16467b97STreehugger Robot        self.connection.close()
919*16467b97STreehugger Robot        self.socket.close()
920*16467b97STreehugger Robot
921*16467b97STreehugger Robot
922*16467b97STreehugger Robot    def enterRule(self, grammarFileName, ruleName):
923*16467b97STreehugger Robot        self.transmit("enterRule\t%s\t%s" % (grammarFileName, ruleName))
924*16467b97STreehugger Robot
925*16467b97STreehugger Robot
926*16467b97STreehugger Robot    def enterAlt(self, alt):
927*16467b97STreehugger Robot        self.transmit("enterAlt\t%d" % alt)
928*16467b97STreehugger Robot
929*16467b97STreehugger Robot
930*16467b97STreehugger Robot    def exitRule(self, grammarFileName, ruleName):
931*16467b97STreehugger Robot        self.transmit("exitRule\t%s\t%s" % (grammarFileName, ruleName))
932*16467b97STreehugger Robot
933*16467b97STreehugger Robot
934*16467b97STreehugger Robot    def enterSubRule(self, decisionNumber):
935*16467b97STreehugger Robot        self.transmit("enterSubRule\t%d" % decisionNumber)
936*16467b97STreehugger Robot
937*16467b97STreehugger Robot
938*16467b97STreehugger Robot    def exitSubRule(self, decisionNumber):
939*16467b97STreehugger Robot        self.transmit("exitSubRule\t%d" % decisionNumber)
940*16467b97STreehugger Robot
941*16467b97STreehugger Robot
942*16467b97STreehugger Robot    def enterDecision(self, decisionNumber, couldBacktrack):
943*16467b97STreehugger Robot        self.transmit(
944*16467b97STreehugger Robot            "enterDecision\t%d\t%d" % (decisionNumber, couldBacktrack))
945*16467b97STreehugger Robot
946*16467b97STreehugger Robot
947*16467b97STreehugger Robot    def exitDecision(self, decisionNumber):
948*16467b97STreehugger Robot        self.transmit("exitDecision\t%d" % decisionNumber)
949*16467b97STreehugger Robot
950*16467b97STreehugger Robot
951*16467b97STreehugger Robot    def consumeToken(self, t):
952*16467b97STreehugger Robot        self.transmit("consumeToken\t%s" % self.serializeToken(t))
953*16467b97STreehugger Robot
954*16467b97STreehugger Robot
955*16467b97STreehugger Robot    def consumeHiddenToken(self, t):
956*16467b97STreehugger Robot        self.transmit("consumeHiddenToken\t%s" % self.serializeToken(t))
957*16467b97STreehugger Robot
958*16467b97STreehugger Robot
959*16467b97STreehugger Robot    def LT(self, i, o):
960*16467b97STreehugger Robot        if isinstance(o, Tree):
961*16467b97STreehugger Robot            return self.LT_tree(i, o)
962*16467b97STreehugger Robot        return self.LT_token(i, o)
963*16467b97STreehugger Robot
964*16467b97STreehugger Robot
965*16467b97STreehugger Robot    def LT_token(self, i, t):
966*16467b97STreehugger Robot        if t is not None:
967*16467b97STreehugger Robot            self.transmit("LT\t%d\t%s" % (i, self.serializeToken(t)))
968*16467b97STreehugger Robot
969*16467b97STreehugger Robot
970*16467b97STreehugger Robot    def mark(self, i):
971*16467b97STreehugger Robot        self.transmit("mark\t%d" % i)
972*16467b97STreehugger Robot
973*16467b97STreehugger Robot
974*16467b97STreehugger Robot    def rewind(self, i=None):
975*16467b97STreehugger Robot        if i is not None:
976*16467b97STreehugger Robot            self.transmit("rewind\t%d" % i)
977*16467b97STreehugger Robot        else:
978*16467b97STreehugger Robot            self.transmit("rewind")
979*16467b97STreehugger Robot
980*16467b97STreehugger Robot
981*16467b97STreehugger Robot    def beginBacktrack(self, level):
982*16467b97STreehugger Robot        self.transmit("beginBacktrack\t%d" % level)
983*16467b97STreehugger Robot
984*16467b97STreehugger Robot
985*16467b97STreehugger Robot    def endBacktrack(self, level, successful):
986*16467b97STreehugger Robot        self.transmit("endBacktrack\t%d\t%s" % (
987*16467b97STreehugger Robot                level, ['0', '1'][bool(successful)]))
988*16467b97STreehugger Robot
989*16467b97STreehugger Robot
990*16467b97STreehugger Robot    def location(self, line, pos):
991*16467b97STreehugger Robot        self.transmit("location\t%d\t%d" % (line, pos))
992*16467b97STreehugger Robot
993*16467b97STreehugger Robot
994*16467b97STreehugger Robot    def recognitionException(self, exc):
995*16467b97STreehugger Robot        self.transmit('\t'.join([
996*16467b97STreehugger Robot                    "exception",
997*16467b97STreehugger Robot                    exc.__class__.__name__,
998*16467b97STreehugger Robot                    str(int(exc.index)),
999*16467b97STreehugger Robot                    str(int(exc.line)),
1000*16467b97STreehugger Robot                    str(int(exc.charPositionInLine))]))
1001*16467b97STreehugger Robot
1002*16467b97STreehugger Robot
1003*16467b97STreehugger Robot    def beginResync(self):
1004*16467b97STreehugger Robot        self.transmit("beginResync")
1005*16467b97STreehugger Robot
1006*16467b97STreehugger Robot
1007*16467b97STreehugger Robot    def endResync(self):
1008*16467b97STreehugger Robot        self.transmit("endResync")
1009*16467b97STreehugger Robot
1010*16467b97STreehugger Robot
1011*16467b97STreehugger Robot    def semanticPredicate(self, result, predicate):
1012*16467b97STreehugger Robot        self.transmit('\t'.join([
1013*16467b97STreehugger Robot                    "semanticPredicate",
1014*16467b97STreehugger Robot                    str(int(result)),
1015*16467b97STreehugger Robot                    self.escapeNewlines(predicate)]))
1016*16467b97STreehugger Robot
1017*16467b97STreehugger Robot    ## A S T  P a r s i n g  E v e n t s
1018*16467b97STreehugger Robot
1019*16467b97STreehugger Robot    def consumeNode(self, t):
1020*16467b97STreehugger Robot        FIXME(31)
1021*16467b97STreehugger Robot#         StringBuffer buf = new StringBuffer(50);
1022*16467b97STreehugger Robot#         buf.append("consumeNode");
1023*16467b97STreehugger Robot#         serializeNode(buf, t);
1024*16467b97STreehugger Robot#         transmit(buf.toString());
1025*16467b97STreehugger Robot
1026*16467b97STreehugger Robot
1027*16467b97STreehugger Robot    def LT_tree(self, i, t):
1028*16467b97STreehugger Robot        FIXME(34)
1029*16467b97STreehugger Robot#         int ID = adaptor.getUniqueID(t);
1030*16467b97STreehugger Robot#         String text = adaptor.getText(t);
1031*16467b97STreehugger Robot#         int type = adaptor.getType(t);
1032*16467b97STreehugger Robot#         StringBuffer buf = new StringBuffer(50);
1033*16467b97STreehugger Robot#         buf.append("LN\t"); // lookahead node; distinguish from LT in protocol
1034*16467b97STreehugger Robot#         buf.append(i);
1035*16467b97STreehugger Robot#         serializeNode(buf, t);
1036*16467b97STreehugger Robot#         transmit(buf.toString());
1037*16467b97STreehugger Robot
1038*16467b97STreehugger Robot
1039*16467b97STreehugger Robot    def serializeNode(self, buf, t):
1040*16467b97STreehugger Robot        FIXME(33)
1041*16467b97STreehugger Robot#         int ID = adaptor.getUniqueID(t);
1042*16467b97STreehugger Robot#         String text = adaptor.getText(t);
1043*16467b97STreehugger Robot#         int type = adaptor.getType(t);
1044*16467b97STreehugger Robot#         buf.append("\t");
1045*16467b97STreehugger Robot#         buf.append(ID);
1046*16467b97STreehugger Robot#         buf.append("\t");
1047*16467b97STreehugger Robot#         buf.append(type);
1048*16467b97STreehugger Robot#         Token token = adaptor.getToken(t);
1049*16467b97STreehugger Robot#         int line = -1;
1050*16467b97STreehugger Robot#         int pos = -1;
1051*16467b97STreehugger Robot#         if ( token!=null ) {
1052*16467b97STreehugger Robot#             line = token.getLine();
1053*16467b97STreehugger Robot#             pos = token.getCharPositionInLine();
1054*16467b97STreehugger Robot#             }
1055*16467b97STreehugger Robot#         buf.append("\t");
1056*16467b97STreehugger Robot#         buf.append(line);
1057*16467b97STreehugger Robot#         buf.append("\t");
1058*16467b97STreehugger Robot#         buf.append(pos);
1059*16467b97STreehugger Robot#         int tokenIndex = adaptor.getTokenStartIndex(t);
1060*16467b97STreehugger Robot#         buf.append("\t");
1061*16467b97STreehugger Robot#         buf.append(tokenIndex);
1062*16467b97STreehugger Robot#         serializeText(buf, text);
1063*16467b97STreehugger Robot
1064*16467b97STreehugger Robot
1065*16467b97STreehugger Robot    ## A S T  E v e n t s
1066*16467b97STreehugger Robot
1067*16467b97STreehugger Robot    def nilNode(self, t):
1068*16467b97STreehugger Robot        self.transmit("nilNode\t%d" % self.adaptor.getUniqueID(t))
1069*16467b97STreehugger Robot
1070*16467b97STreehugger Robot
1071*16467b97STreehugger Robot    def errorNode(self, t):
1072*16467b97STreehugger Robot        self.transmit("errorNode\t%d\t%d\t\"%s" % (
1073*16467b97STreehugger Robot             self.adaptor.getUniqueID(t),
1074*16467b97STreehugger Robot             Token.INVALID_TOKEN_TYPE,
1075*16467b97STreehugger Robot             self.escapeNewlines(t.toString())))
1076*16467b97STreehugger Robot
1077*16467b97STreehugger Robot
1078*16467b97STreehugger Robot
1079*16467b97STreehugger Robot    def createNode(self, node, token=None):
1080*16467b97STreehugger Robot        if token is not None:
1081*16467b97STreehugger Robot            self.transmit("createNode\t%d\t%d" % (
1082*16467b97STreehugger Robot                    self.adaptor.getUniqueID(node),
1083*16467b97STreehugger Robot                    token.getTokenIndex()))
1084*16467b97STreehugger Robot
1085*16467b97STreehugger Robot        else:
1086*16467b97STreehugger Robot            self.transmit("createNodeFromTokenElements\t%d\t%d\t\"%s" % (
1087*16467b97STreehugger Robot                    self.adaptor.getUniqueID(node),
1088*16467b97STreehugger Robot                    self.adaptor.getType(node),
1089*16467b97STreehugger Robot                    self.adaptor.getText(node)))
1090*16467b97STreehugger Robot
1091*16467b97STreehugger Robot
1092*16467b97STreehugger Robot    def becomeRoot(self, newRoot, oldRoot):
1093*16467b97STreehugger Robot        self.transmit("becomeRoot\t%d\t%d" % (
1094*16467b97STreehugger Robot                self.adaptor.getUniqueID(newRoot),
1095*16467b97STreehugger Robot                self.adaptor.getUniqueID(oldRoot)))
1096*16467b97STreehugger Robot
1097*16467b97STreehugger Robot
1098*16467b97STreehugger Robot    def addChild(self, root, child):
1099*16467b97STreehugger Robot        self.transmit("addChild\t%d\t%d" % (
1100*16467b97STreehugger Robot                self.adaptor.getUniqueID(root),
1101*16467b97STreehugger Robot                self.adaptor.getUniqueID(child)))
1102*16467b97STreehugger Robot
1103*16467b97STreehugger Robot
1104*16467b97STreehugger Robot    def setTokenBoundaries(self, t, tokenStartIndex, tokenStopIndex):
1105*16467b97STreehugger Robot        self.transmit("setTokenBoundaries\t%d\t%d\t%d" % (
1106*16467b97STreehugger Robot                self.adaptor.getUniqueID(t),
1107*16467b97STreehugger Robot                tokenStartIndex, tokenStopIndex))
1108*16467b97STreehugger Robot
1109*16467b97STreehugger Robot
1110*16467b97STreehugger Robot
1111*16467b97STreehugger Robot    ## support
1112*16467b97STreehugger Robot
1113*16467b97STreehugger Robot    def setTreeAdaptor(self, adaptor):
1114*16467b97STreehugger Robot        self.adaptor = adaptor
1115*16467b97STreehugger Robot
1116*16467b97STreehugger Robot    def getTreeAdaptor(self):
1117*16467b97STreehugger Robot        return self.adaptor
1118*16467b97STreehugger Robot
1119*16467b97STreehugger Robot
1120*16467b97STreehugger Robot    def serializeToken(self, t):
1121*16467b97STreehugger Robot        buf = [str(int(t.getTokenIndex())),
1122*16467b97STreehugger Robot               str(int(t.getType())),
1123*16467b97STreehugger Robot               str(int(t.getChannel())),
1124*16467b97STreehugger Robot               str(int(t.getLine() or 0)),
1125*16467b97STreehugger Robot               str(int(t.getCharPositionInLine() or 0)),
1126*16467b97STreehugger Robot               '\"' + self.escapeNewlines(t.getText())]
1127*16467b97STreehugger Robot        return '\t'.join(buf)
1128*16467b97STreehugger Robot
1129*16467b97STreehugger Robot
1130*16467b97STreehugger Robot    def escapeNewlines(self, txt):
1131*16467b97STreehugger Robot        if txt is None:
1132*16467b97STreehugger Robot            return ''
1133*16467b97STreehugger Robot
1134*16467b97STreehugger Robot        txt = txt.replace("%","%25")   # escape all escape char ;)
1135*16467b97STreehugger Robot        txt = txt.replace("\n","%0A")  # escape \n
1136*16467b97STreehugger Robot        txt = txt.replace("\r","%0D")  # escape \r
1137*16467b97STreehugger Robot        return txt
1138