xref: /aosp_15_r20/external/antlr/runtime/Python3/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-2012 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 Robotimport sys
33*16467b97STreehugger Robotfrom .constants import INVALID_TOKEN_TYPE
34*16467b97STreehugger Robotfrom .exceptions import RecognitionException
35*16467b97STreehugger Robotfrom .recognizers import Parser
36*16467b97STreehugger Robotfrom .streams import TokenStream
37*16467b97STreehugger Robotfrom .tokens import Token
38*16467b97STreehugger Robotfrom .tree import CommonTreeAdaptor, TreeAdaptor, Tree
39*16467b97STreehugger Robot
40*16467b97STreehugger Robotclass DebugParser(Parser):
41*16467b97STreehugger Robot    def __init__(self, stream, state=None, dbg=None, *args, **kwargs):
42*16467b97STreehugger Robot        # wrap token stream in DebugTokenStream (unless user already did so).
43*16467b97STreehugger Robot        if not isinstance(stream, DebugTokenStream):
44*16467b97STreehugger Robot            stream = DebugTokenStream(stream, dbg)
45*16467b97STreehugger Robot
46*16467b97STreehugger Robot        super().__init__(stream, state, *args, **kwargs)
47*16467b97STreehugger Robot
48*16467b97STreehugger Robot        # Who to notify when events in the parser occur.
49*16467b97STreehugger Robot        self._dbg = None
50*16467b97STreehugger Robot
51*16467b97STreehugger Robot        self.setDebugListener(dbg)
52*16467b97STreehugger Robot
53*16467b97STreehugger Robot
54*16467b97STreehugger Robot    def setDebugListener(self, dbg):
55*16467b97STreehugger Robot        """Provide a new debug event listener for this parser.  Notify the
56*16467b97STreehugger Robot        input stream too that it should send events to this listener.
57*16467b97STreehugger Robot        """
58*16467b97STreehugger Robot
59*16467b97STreehugger Robot        if hasattr(self.input, 'dbg'):
60*16467b97STreehugger Robot            self.input.dbg = dbg
61*16467b97STreehugger Robot
62*16467b97STreehugger Robot        self._dbg = dbg
63*16467b97STreehugger Robot
64*16467b97STreehugger Robot    def getDebugListener(self):
65*16467b97STreehugger Robot        return self._dbg
66*16467b97STreehugger Robot
67*16467b97STreehugger Robot    dbg = property(getDebugListener, setDebugListener)
68*16467b97STreehugger Robot
69*16467b97STreehugger Robot
70*16467b97STreehugger Robot    def beginResync(self):
71*16467b97STreehugger Robot        self._dbg.beginResync()
72*16467b97STreehugger Robot
73*16467b97STreehugger Robot
74*16467b97STreehugger Robot    def endResync(self):
75*16467b97STreehugger Robot        self._dbg.endResync()
76*16467b97STreehugger Robot
77*16467b97STreehugger Robot
78*16467b97STreehugger Robot    def beginBacktrack(self, level):
79*16467b97STreehugger Robot        self._dbg.beginBacktrack(level)
80*16467b97STreehugger Robot
81*16467b97STreehugger Robot
82*16467b97STreehugger Robot    def endBacktrack(self, level, successful):
83*16467b97STreehugger Robot        self._dbg.endBacktrack(level, successful)
84*16467b97STreehugger Robot
85*16467b97STreehugger Robot
86*16467b97STreehugger Robot    def reportError(self, exc):
87*16467b97STreehugger Robot        Parser.reportError(self, exc)
88*16467b97STreehugger Robot
89*16467b97STreehugger Robot        if isinstance(exc, RecognitionException):
90*16467b97STreehugger Robot            self._dbg.recognitionException(exc)
91*16467b97STreehugger Robot
92*16467b97STreehugger Robot
93*16467b97STreehugger Robotclass DebugTokenStream(TokenStream):
94*16467b97STreehugger Robot    def __init__(self, input, dbg=None):
95*16467b97STreehugger Robot        super().__init__()
96*16467b97STreehugger Robot        self.input = input
97*16467b97STreehugger Robot        self.initialStreamState = True
98*16467b97STreehugger Robot        # Track the last mark() call result value for use in rewind().
99*16467b97STreehugger Robot        self.lastMarker = None
100*16467b97STreehugger Robot
101*16467b97STreehugger Robot        self._dbg = None
102*16467b97STreehugger Robot        self.setDebugListener(dbg)
103*16467b97STreehugger Robot
104*16467b97STreehugger Robot        # force TokenStream to get at least first valid token
105*16467b97STreehugger Robot        # so we know if there are any hidden tokens first in the stream
106*16467b97STreehugger Robot        self.input.LT(1)
107*16467b97STreehugger Robot
108*16467b97STreehugger Robot
109*16467b97STreehugger Robot    def getDebugListener(self):
110*16467b97STreehugger Robot        return self._dbg
111*16467b97STreehugger Robot
112*16467b97STreehugger Robot    def setDebugListener(self, dbg):
113*16467b97STreehugger Robot        self._dbg = dbg
114*16467b97STreehugger Robot
115*16467b97STreehugger Robot    dbg = property(getDebugListener, setDebugListener)
116*16467b97STreehugger Robot
117*16467b97STreehugger Robot
118*16467b97STreehugger Robot    def consume(self):
119*16467b97STreehugger Robot        if self.initialStreamState:
120*16467b97STreehugger Robot            self.consumeInitialHiddenTokens()
121*16467b97STreehugger Robot
122*16467b97STreehugger Robot        a = self.input.index()
123*16467b97STreehugger Robot        t = self.input.LT(1)
124*16467b97STreehugger Robot        self.input.consume()
125*16467b97STreehugger Robot        b = self.input.index()
126*16467b97STreehugger Robot        self._dbg.consumeToken(t)
127*16467b97STreehugger Robot
128*16467b97STreehugger Robot        if b > a + 1:
129*16467b97STreehugger Robot            # then we consumed more than one token; must be off channel tokens
130*16467b97STreehugger Robot            for idx in range(a + 1, b):
131*16467b97STreehugger Robot                self._dbg.consumeHiddenToken(self.input.get(idx))
132*16467b97STreehugger Robot
133*16467b97STreehugger Robot
134*16467b97STreehugger Robot    def consumeInitialHiddenTokens(self):
135*16467b97STreehugger Robot        """consume all initial off-channel tokens"""
136*16467b97STreehugger Robot
137*16467b97STreehugger Robot        firstOnChannelTokenIndex = self.input.index()
138*16467b97STreehugger Robot        for idx in range(firstOnChannelTokenIndex):
139*16467b97STreehugger Robot            self._dbg.consumeHiddenToken(self.input.get(idx))
140*16467b97STreehugger Robot
141*16467b97STreehugger Robot        self.initialStreamState = False
142*16467b97STreehugger Robot
143*16467b97STreehugger Robot
144*16467b97STreehugger Robot    def LT(self, i):
145*16467b97STreehugger Robot        if self.initialStreamState:
146*16467b97STreehugger Robot            self.consumeInitialHiddenTokens()
147*16467b97STreehugger Robot
148*16467b97STreehugger Robot        t = self.input.LT(i)
149*16467b97STreehugger Robot        self._dbg.LT(i, t)
150*16467b97STreehugger Robot        return t
151*16467b97STreehugger Robot
152*16467b97STreehugger Robot
153*16467b97STreehugger Robot    def LA(self, i):
154*16467b97STreehugger Robot        if self.initialStreamState:
155*16467b97STreehugger Robot            self.consumeInitialHiddenTokens()
156*16467b97STreehugger Robot
157*16467b97STreehugger Robot        t = self.input.LT(i)
158*16467b97STreehugger Robot        self._dbg.LT(i, t)
159*16467b97STreehugger Robot        return t.type
160*16467b97STreehugger Robot
161*16467b97STreehugger Robot
162*16467b97STreehugger Robot    def get(self, i):
163*16467b97STreehugger Robot        return self.input.get(i)
164*16467b97STreehugger Robot
165*16467b97STreehugger Robot
166*16467b97STreehugger Robot    def index(self):
167*16467b97STreehugger Robot        return self.input.index()
168*16467b97STreehugger Robot
169*16467b97STreehugger Robot
170*16467b97STreehugger Robot    def mark(self):
171*16467b97STreehugger Robot        self.lastMarker = self.input.mark()
172*16467b97STreehugger Robot        self._dbg.mark(self.lastMarker)
173*16467b97STreehugger Robot        return self.lastMarker
174*16467b97STreehugger Robot
175*16467b97STreehugger Robot
176*16467b97STreehugger Robot    def rewind(self, marker=None):
177*16467b97STreehugger Robot        self._dbg.rewind(marker)
178*16467b97STreehugger Robot        self.input.rewind(marker)
179*16467b97STreehugger Robot
180*16467b97STreehugger Robot
181*16467b97STreehugger Robot    def release(self, marker):
182*16467b97STreehugger Robot        pass
183*16467b97STreehugger Robot
184*16467b97STreehugger Robot
185*16467b97STreehugger Robot    def seek(self, index):
186*16467b97STreehugger Robot        # TODO: implement seek in dbg interface
187*16467b97STreehugger Robot        # self._dbg.seek(index);
188*16467b97STreehugger Robot        self.input.seek(index)
189*16467b97STreehugger Robot
190*16467b97STreehugger Robot
191*16467b97STreehugger Robot    def size(self):
192*16467b97STreehugger Robot        return self.input.size()
193*16467b97STreehugger Robot
194*16467b97STreehugger Robot
195*16467b97STreehugger Robot    def getTokenSource(self):
196*16467b97STreehugger Robot        return self.input.getTokenSource()
197*16467b97STreehugger Robot
198*16467b97STreehugger Robot
199*16467b97STreehugger Robot    def getSourceName(self):
200*16467b97STreehugger Robot        return self.getTokenSource().getSourceName()
201*16467b97STreehugger Robot
202*16467b97STreehugger Robot
203*16467b97STreehugger Robot    def toString(self, start=None, stop=None):
204*16467b97STreehugger Robot        return self.input.toString(start, stop)
205*16467b97STreehugger Robot
206*16467b97STreehugger Robot
207*16467b97STreehugger Robotclass DebugTreeAdaptor(TreeAdaptor):
208*16467b97STreehugger Robot    """A TreeAdaptor proxy that fires debugging events to a DebugEventListener
209*16467b97STreehugger Robot    delegate and uses the TreeAdaptor delegate to do the actual work.  All
210*16467b97STreehugger Robot    AST events are triggered by this adaptor; no code gen changes are needed
211*16467b97STreehugger Robot    in generated rules.  Debugging events are triggered *after* invoking
212*16467b97STreehugger Robot    tree adaptor routines.
213*16467b97STreehugger Robot
214*16467b97STreehugger Robot    Trees created with actions in rewrite actions like "-> ^(ADD {foo} {bar})"
215*16467b97STreehugger Robot    cannot be tracked as they might not use the adaptor to create foo, bar.
216*16467b97STreehugger Robot    The debug listener has to deal with tree node IDs for which it did
217*16467b97STreehugger Robot    not see a createNode event.  A single <unknown> node is sufficient even
218*16467b97STreehugger Robot    if it represents a whole tree.
219*16467b97STreehugger Robot    """
220*16467b97STreehugger Robot
221*16467b97STreehugger Robot    def __init__(self, dbg, adaptor):
222*16467b97STreehugger Robot        super().__init__()
223*16467b97STreehugger Robot        self.dbg = dbg
224*16467b97STreehugger Robot        self.adaptor = adaptor
225*16467b97STreehugger Robot
226*16467b97STreehugger Robot
227*16467b97STreehugger Robot    def createWithPayload(self, payload):
228*16467b97STreehugger Robot        if payload.index < 0:
229*16467b97STreehugger Robot            # could be token conjured up during error recovery
230*16467b97STreehugger Robot            return self.createFromType(payload.type, payload.text)
231*16467b97STreehugger Robot
232*16467b97STreehugger Robot        node = self.adaptor.createWithPayload(payload)
233*16467b97STreehugger Robot        self.dbg.createNode(node, payload)
234*16467b97STreehugger Robot        return node
235*16467b97STreehugger Robot
236*16467b97STreehugger Robot    def createFromToken(self, tokenType, fromToken, text=None):
237*16467b97STreehugger Robot        node = self.adaptor.createFromToken(tokenType, fromToken, text)
238*16467b97STreehugger Robot        self.dbg.createNode(node)
239*16467b97STreehugger Robot        return node
240*16467b97STreehugger Robot
241*16467b97STreehugger Robot    def createFromType(self, tokenType, text):
242*16467b97STreehugger Robot        node = self.adaptor.createFromType(tokenType, text)
243*16467b97STreehugger Robot        self.dbg.createNode(node)
244*16467b97STreehugger Robot        return node
245*16467b97STreehugger Robot
246*16467b97STreehugger Robot
247*16467b97STreehugger Robot    def errorNode(self, input, start, stop, exc):
248*16467b97STreehugger Robot        node = self.adaptor.errorNode(input, start, stop, exc)
249*16467b97STreehugger Robot        if node is not None:
250*16467b97STreehugger Robot            self.dbg.errorNode(node)
251*16467b97STreehugger Robot
252*16467b97STreehugger Robot        return node
253*16467b97STreehugger Robot
254*16467b97STreehugger Robot
255*16467b97STreehugger Robot    def dupTree(self, tree):
256*16467b97STreehugger Robot        t = self.adaptor.dupTree(tree)
257*16467b97STreehugger Robot        # walk the tree and emit create and add child events
258*16467b97STreehugger Robot        # to simulate what dupTree has done. dupTree does not call this debug
259*16467b97STreehugger Robot        # adapter so I must simulate.
260*16467b97STreehugger Robot        self.simulateTreeConstruction(t)
261*16467b97STreehugger Robot        return t
262*16467b97STreehugger Robot
263*16467b97STreehugger Robot
264*16467b97STreehugger Robot    def simulateTreeConstruction(self, t):
265*16467b97STreehugger Robot        """^(A B C): emit create A, create B, add child, ..."""
266*16467b97STreehugger Robot        self.dbg.createNode(t)
267*16467b97STreehugger Robot        for i in range(self.adaptor.getChildCount(t)):
268*16467b97STreehugger Robot            child = self.adaptor.getChild(t, i)
269*16467b97STreehugger Robot            self.simulateTreeConstruction(child)
270*16467b97STreehugger Robot            self.dbg.addChild(t, child)
271*16467b97STreehugger Robot
272*16467b97STreehugger Robot
273*16467b97STreehugger Robot    def dupNode(self, treeNode):
274*16467b97STreehugger Robot        d = self.adaptor.dupNode(treeNode)
275*16467b97STreehugger Robot        self.dbg.createNode(d)
276*16467b97STreehugger Robot        return d
277*16467b97STreehugger Robot
278*16467b97STreehugger Robot
279*16467b97STreehugger Robot    def nil(self):
280*16467b97STreehugger Robot        node = self.adaptor.nil()
281*16467b97STreehugger Robot        self.dbg.nilNode(node)
282*16467b97STreehugger Robot        return node
283*16467b97STreehugger Robot
284*16467b97STreehugger Robot
285*16467b97STreehugger Robot    def isNil(self, tree):
286*16467b97STreehugger Robot        return self.adaptor.isNil(tree)
287*16467b97STreehugger Robot
288*16467b97STreehugger Robot
289*16467b97STreehugger Robot    def addChild(self, t, child):
290*16467b97STreehugger Robot        if isinstance(child, Token):
291*16467b97STreehugger Robot            n = self.createWithPayload(child)
292*16467b97STreehugger Robot            self.addChild(t, n)
293*16467b97STreehugger Robot
294*16467b97STreehugger Robot        else:
295*16467b97STreehugger Robot            if t is None or child is None:
296*16467b97STreehugger Robot                return
297*16467b97STreehugger Robot
298*16467b97STreehugger Robot            self.adaptor.addChild(t, child)
299*16467b97STreehugger Robot            self.dbg.addChild(t, child)
300*16467b97STreehugger Robot
301*16467b97STreehugger Robot    def becomeRoot(self, newRoot, oldRoot):
302*16467b97STreehugger Robot        if isinstance(newRoot, Token):
303*16467b97STreehugger Robot            n = self.createWithPayload(newRoot)
304*16467b97STreehugger Robot            self.adaptor.becomeRoot(n, oldRoot)
305*16467b97STreehugger Robot        else:
306*16467b97STreehugger Robot            n = self.adaptor.becomeRoot(newRoot, oldRoot)
307*16467b97STreehugger Robot
308*16467b97STreehugger Robot        self.dbg.becomeRoot(newRoot, oldRoot)
309*16467b97STreehugger Robot        return n
310*16467b97STreehugger Robot
311*16467b97STreehugger Robot
312*16467b97STreehugger Robot    def rulePostProcessing(self, root):
313*16467b97STreehugger Robot        return self.adaptor.rulePostProcessing(root)
314*16467b97STreehugger Robot
315*16467b97STreehugger Robot
316*16467b97STreehugger Robot    def getType(self, t):
317*16467b97STreehugger Robot        return self.adaptor.getType(t)
318*16467b97STreehugger Robot
319*16467b97STreehugger Robot
320*16467b97STreehugger Robot    def setType(self, t, type):
321*16467b97STreehugger Robot        self.adaptor.setType(t, type)
322*16467b97STreehugger Robot
323*16467b97STreehugger Robot
324*16467b97STreehugger Robot    def getText(self, t):
325*16467b97STreehugger Robot        return self.adaptor.getText(t)
326*16467b97STreehugger Robot
327*16467b97STreehugger Robot
328*16467b97STreehugger Robot    def setText(self, t, text):
329*16467b97STreehugger Robot        self.adaptor.setText(t, text)
330*16467b97STreehugger Robot
331*16467b97STreehugger Robot
332*16467b97STreehugger Robot    def getToken(self, t):
333*16467b97STreehugger Robot        return self.adaptor.getToken(t)
334*16467b97STreehugger Robot
335*16467b97STreehugger Robot
336*16467b97STreehugger Robot    def setTokenBoundaries(self, t, startToken, stopToken):
337*16467b97STreehugger Robot        self.adaptor.setTokenBoundaries(t, startToken, stopToken)
338*16467b97STreehugger Robot        if t and startToken and stopToken:
339*16467b97STreehugger Robot            self.dbg.setTokenBoundaries(
340*16467b97STreehugger Robot                t, startToken.index, stopToken.index)
341*16467b97STreehugger Robot
342*16467b97STreehugger Robot
343*16467b97STreehugger Robot    def getTokenStartIndex(self, t):
344*16467b97STreehugger Robot        return self.adaptor.getTokenStartIndex(t)
345*16467b97STreehugger Robot
346*16467b97STreehugger Robot
347*16467b97STreehugger Robot    def getTokenStopIndex(self, t):
348*16467b97STreehugger Robot        return self.adaptor.getTokenStopIndex(t)
349*16467b97STreehugger Robot
350*16467b97STreehugger Robot
351*16467b97STreehugger Robot    def getChild(self, t, i):
352*16467b97STreehugger Robot        return self.adaptor.getChild(t, i)
353*16467b97STreehugger Robot
354*16467b97STreehugger Robot
355*16467b97STreehugger Robot    def setChild(self, t, i, child):
356*16467b97STreehugger Robot        self.adaptor.setChild(t, i, child)
357*16467b97STreehugger Robot
358*16467b97STreehugger Robot
359*16467b97STreehugger Robot    def deleteChild(self, t, i):
360*16467b97STreehugger Robot        return self.adaptor.deleteChild(t, i)
361*16467b97STreehugger Robot
362*16467b97STreehugger Robot
363*16467b97STreehugger Robot    def getChildCount(self, t):
364*16467b97STreehugger Robot        return self.adaptor.getChildCount(t)
365*16467b97STreehugger Robot
366*16467b97STreehugger Robot
367*16467b97STreehugger Robot    def getUniqueID(self, node):
368*16467b97STreehugger Robot        return self.adaptor.getUniqueID(node)
369*16467b97STreehugger Robot
370*16467b97STreehugger Robot
371*16467b97STreehugger Robot    def getParent(self, t):
372*16467b97STreehugger Robot        return self.adaptor.getParent(t)
373*16467b97STreehugger Robot
374*16467b97STreehugger Robot
375*16467b97STreehugger Robot    def getChildIndex(self, t):
376*16467b97STreehugger Robot        return self.adaptor.getChildIndex(t)
377*16467b97STreehugger Robot
378*16467b97STreehugger Robot
379*16467b97STreehugger Robot    def setParent(self, t, parent):
380*16467b97STreehugger Robot        self.adaptor.setParent(t, parent)
381*16467b97STreehugger Robot
382*16467b97STreehugger Robot
383*16467b97STreehugger Robot    def setChildIndex(self, t, index):
384*16467b97STreehugger Robot        self.adaptor.setChildIndex(t, index)
385*16467b97STreehugger Robot
386*16467b97STreehugger Robot
387*16467b97STreehugger Robot    def replaceChildren(self, parent, startChildIndex, stopChildIndex, t):
388*16467b97STreehugger Robot        self.adaptor.replaceChildren(parent, startChildIndex, stopChildIndex, t)
389*16467b97STreehugger Robot
390*16467b97STreehugger Robot
391*16467b97STreehugger Robot    ## support
392*16467b97STreehugger Robot
393*16467b97STreehugger Robot    def getDebugListener(self):
394*16467b97STreehugger Robot        return self.dbg
395*16467b97STreehugger Robot
396*16467b97STreehugger Robot    def setDebugListener(self, dbg):
397*16467b97STreehugger Robot        self.dbg = dbg
398*16467b97STreehugger Robot
399*16467b97STreehugger Robot
400*16467b97STreehugger Robot    def getTreeAdaptor(self):
401*16467b97STreehugger Robot        return self.adaptor
402*16467b97STreehugger Robot
403*16467b97STreehugger Robot
404*16467b97STreehugger Robot
405*16467b97STreehugger Robotclass DebugEventListener(object):
406*16467b97STreehugger Robot    """All debugging events that a recognizer can trigger.
407*16467b97STreehugger Robot
408*16467b97STreehugger Robot    I did not create a separate AST debugging interface as it would create
409*16467b97STreehugger Robot    lots of extra classes and DebugParser has a dbg var defined, which makes
410*16467b97STreehugger Robot    it hard to change to ASTDebugEventListener.  I looked hard at this issue
411*16467b97STreehugger Robot    and it is easier to understand as one monolithic event interface for all
412*16467b97STreehugger Robot    possible events.  Hopefully, adding ST debugging stuff won't be bad.  Leave
413*16467b97STreehugger Robot    for future. 4/26/2006.
414*16467b97STreehugger Robot    """
415*16467b97STreehugger Robot
416*16467b97STreehugger Robot    # Moved to version 2 for v3.1: added grammar name to enter/exit Rule
417*16467b97STreehugger Robot    PROTOCOL_VERSION = "2"
418*16467b97STreehugger Robot
419*16467b97STreehugger Robot    def enterRule(self, grammarFileName, ruleName):
420*16467b97STreehugger Robot        """The parser has just entered a rule. No decision has been made about
421*16467b97STreehugger Robot        which alt is predicted.  This is fired AFTER init actions have been
422*16467b97STreehugger Robot        executed.  Attributes are defined and available etc...
423*16467b97STreehugger Robot        The grammarFileName allows composite grammars to jump around among
424*16467b97STreehugger Robot        multiple grammar files.
425*16467b97STreehugger Robot        """
426*16467b97STreehugger Robot
427*16467b97STreehugger Robot        pass
428*16467b97STreehugger Robot
429*16467b97STreehugger Robot
430*16467b97STreehugger Robot    def enterAlt(self, alt):
431*16467b97STreehugger Robot        """Because rules can have lots of alternatives, it is very useful to
432*16467b97STreehugger Robot        know which alt you are entering.  This is 1..n for n alts.
433*16467b97STreehugger Robot        """
434*16467b97STreehugger Robot        pass
435*16467b97STreehugger Robot
436*16467b97STreehugger Robot
437*16467b97STreehugger Robot    def exitRule(self, grammarFileName, ruleName):
438*16467b97STreehugger Robot        """This is the last thing executed before leaving a rule.  It is
439*16467b97STreehugger Robot        executed even if an exception is thrown.  This is triggered after
440*16467b97STreehugger Robot        error reporting and recovery have occurred (unless the exception is
441*16467b97STreehugger Robot        not caught in this rule).  This implies an "exitAlt" event.
442*16467b97STreehugger Robot        The grammarFileName allows composite grammars to jump around among
443*16467b97STreehugger Robot        multiple grammar files.
444*16467b97STreehugger Robot        """
445*16467b97STreehugger Robot        pass
446*16467b97STreehugger Robot
447*16467b97STreehugger Robot
448*16467b97STreehugger Robot    def enterSubRule(self, decisionNumber):
449*16467b97STreehugger Robot        """Track entry into any (...) subrule other EBNF construct"""
450*16467b97STreehugger Robot        pass
451*16467b97STreehugger Robot
452*16467b97STreehugger Robot
453*16467b97STreehugger Robot    def exitSubRule(self, decisionNumber):
454*16467b97STreehugger Robot        pass
455*16467b97STreehugger Robot
456*16467b97STreehugger Robot
457*16467b97STreehugger Robot    def enterDecision(self, decisionNumber, couldBacktrack):
458*16467b97STreehugger Robot        """Every decision, fixed k or arbitrary, has an enter/exit event
459*16467b97STreehugger Robot        so that a GUI can easily track what LT/consume events are
460*16467b97STreehugger Robot        associated with prediction.  You will see a single enter/exit
461*16467b97STreehugger Robot        subrule but multiple enter/exit decision events, one for each
462*16467b97STreehugger Robot        loop iteration.
463*16467b97STreehugger Robot        """
464*16467b97STreehugger Robot        pass
465*16467b97STreehugger Robot
466*16467b97STreehugger Robot
467*16467b97STreehugger Robot    def exitDecision(self, decisionNumber):
468*16467b97STreehugger Robot        pass
469*16467b97STreehugger Robot
470*16467b97STreehugger Robot
471*16467b97STreehugger Robot    def consumeToken(self, t):
472*16467b97STreehugger Robot        """An input token was consumed; matched by any kind of element.
473*16467b97STreehugger Robot        Trigger after the token was matched by things like match(), matchAny().
474*16467b97STreehugger Robot        """
475*16467b97STreehugger Robot        pass
476*16467b97STreehugger Robot
477*16467b97STreehugger Robot
478*16467b97STreehugger Robot    def consumeHiddenToken(self, t):
479*16467b97STreehugger Robot        """An off-channel input token was consumed.
480*16467b97STreehugger Robot        Trigger after the token was matched by things like match(), matchAny().
481*16467b97STreehugger Robot        (unless of course the hidden token is first stuff in the input stream).
482*16467b97STreehugger Robot        """
483*16467b97STreehugger Robot        pass
484*16467b97STreehugger Robot
485*16467b97STreehugger Robot
486*16467b97STreehugger Robot    def LT(self, i, t):
487*16467b97STreehugger Robot        """Somebody (anybody) looked ahead.  Note that this actually gets
488*16467b97STreehugger Robot        triggered by both LA and LT calls.  The debugger will want to know
489*16467b97STreehugger Robot        which Token object was examined.  Like consumeToken, this indicates
490*16467b97STreehugger Robot        what token was seen at that depth.  A remote debugger cannot look
491*16467b97STreehugger Robot        ahead into a file it doesn't have so LT events must pass the token
492*16467b97STreehugger Robot        even if the info is redundant.
493*16467b97STreehugger Robot        For tree parsers, if the type is UP or DOWN,
494*16467b97STreehugger Robot        then the ID is not really meaningful as it's fixed--there is
495*16467b97STreehugger Robot        just one UP node and one DOWN navigation node.
496*16467b97STreehugger Robot        """
497*16467b97STreehugger Robot        pass
498*16467b97STreehugger Robot
499*16467b97STreehugger Robot
500*16467b97STreehugger Robot    def mark(self, marker):
501*16467b97STreehugger Robot        """The parser is going to look arbitrarily ahead; mark this location,
502*16467b97STreehugger Robot        the token stream's marker is sent in case you need it.
503*16467b97STreehugger Robot        """
504*16467b97STreehugger Robot        pass
505*16467b97STreehugger Robot
506*16467b97STreehugger Robot
507*16467b97STreehugger Robot    def rewind(self, marker=None):
508*16467b97STreehugger Robot        """After an arbitrairly long lookahead as with a cyclic DFA (or with
509*16467b97STreehugger Robot        any backtrack), this informs the debugger that stream should be
510*16467b97STreehugger Robot        rewound to the position associated with marker.
511*16467b97STreehugger Robot
512*16467b97STreehugger Robot        """
513*16467b97STreehugger Robot        pass
514*16467b97STreehugger Robot
515*16467b97STreehugger Robot
516*16467b97STreehugger Robot    def beginBacktrack(self, level):
517*16467b97STreehugger Robot        pass
518*16467b97STreehugger Robot
519*16467b97STreehugger Robot
520*16467b97STreehugger Robot    def endBacktrack(self, level, successful):
521*16467b97STreehugger Robot        pass
522*16467b97STreehugger Robot
523*16467b97STreehugger Robot
524*16467b97STreehugger Robot    def location(self, line, pos):
525*16467b97STreehugger Robot        """To watch a parser move through the grammar, the parser needs to
526*16467b97STreehugger Robot        inform the debugger what line/charPos it is passing in the grammar.
527*16467b97STreehugger Robot        For now, this does not know how to switch from one grammar to the
528*16467b97STreehugger Robot        other and back for island grammars etc...
529*16467b97STreehugger Robot
530*16467b97STreehugger Robot        This should also allow breakpoints because the debugger can stop
531*16467b97STreehugger Robot        the parser whenever it hits this line/pos.
532*16467b97STreehugger Robot        """
533*16467b97STreehugger Robot        pass
534*16467b97STreehugger Robot
535*16467b97STreehugger Robot
536*16467b97STreehugger Robot    def recognitionException(self, e):
537*16467b97STreehugger Robot        """A recognition exception occurred such as NoViableAltException.  I made
538*16467b97STreehugger Robot        this a generic event so that I can alter the exception hierachy later
539*16467b97STreehugger Robot        without having to alter all the debug objects.
540*16467b97STreehugger Robot
541*16467b97STreehugger Robot        Upon error, the stack of enter rule/subrule must be properly unwound.
542*16467b97STreehugger Robot        If no viable alt occurs it is within an enter/exit decision, which
543*16467b97STreehugger Robot        also must be rewound.  Even the rewind for each mark must be unwount.
544*16467b97STreehugger Robot        In the Java target this is pretty easy using try/finally, if a bit
545*16467b97STreehugger Robot        ugly in the generated code.  The rewind is generated in DFA.predict()
546*16467b97STreehugger Robot        actually so no code needs to be generated for that.  For languages
547*16467b97STreehugger Robot        w/o this "finally" feature (C++?), the target implementor will have
548*16467b97STreehugger Robot        to build an event stack or something.
549*16467b97STreehugger Robot
550*16467b97STreehugger Robot        Across a socket for remote debugging, only the RecognitionException
551*16467b97STreehugger Robot        data fields are transmitted.  The token object or whatever that
552*16467b97STreehugger Robot        caused the problem was the last object referenced by LT.  The
553*16467b97STreehugger Robot        immediately preceding LT event should hold the unexpected Token or
554*16467b97STreehugger Robot        char.
555*16467b97STreehugger Robot
556*16467b97STreehugger Robot        Here is a sample event trace for grammar:
557*16467b97STreehugger Robot
558*16467b97STreehugger Robot        b : C ({;}A|B) // {;} is there to prevent A|B becoming a set
559*16467b97STreehugger Robot          | D
560*16467b97STreehugger Robot          ;
561*16467b97STreehugger Robot
562*16467b97STreehugger Robot        The sequence for this rule (with no viable alt in the subrule) for
563*16467b97STreehugger Robot        input 'c c' (there are 3 tokens) is:
564*16467b97STreehugger Robot
565*16467b97STreehugger Robot                commence
566*16467b97STreehugger Robot                LT(1)
567*16467b97STreehugger Robot                enterRule b
568*16467b97STreehugger Robot                location 7 1
569*16467b97STreehugger Robot                enter decision 3
570*16467b97STreehugger Robot                LT(1)
571*16467b97STreehugger Robot                exit decision 3
572*16467b97STreehugger Robot                enterAlt1
573*16467b97STreehugger Robot                location 7 5
574*16467b97STreehugger Robot                LT(1)
575*16467b97STreehugger Robot                consumeToken [c/<4>,1:0]
576*16467b97STreehugger Robot                location 7 7
577*16467b97STreehugger Robot                enterSubRule 2
578*16467b97STreehugger Robot                enter decision 2
579*16467b97STreehugger Robot                LT(1)
580*16467b97STreehugger Robot                LT(1)
581*16467b97STreehugger Robot                recognitionException NoViableAltException 2 1 2
582*16467b97STreehugger Robot                exit decision 2
583*16467b97STreehugger Robot                exitSubRule 2
584*16467b97STreehugger Robot                beginResync
585*16467b97STreehugger Robot                LT(1)
586*16467b97STreehugger Robot                consumeToken [c/<4>,1:1]
587*16467b97STreehugger Robot                LT(1)
588*16467b97STreehugger Robot                endResync
589*16467b97STreehugger Robot                LT(-1)
590*16467b97STreehugger Robot                exitRule b
591*16467b97STreehugger Robot                terminate
592*16467b97STreehugger Robot        """
593*16467b97STreehugger Robot        pass
594*16467b97STreehugger Robot
595*16467b97STreehugger Robot
596*16467b97STreehugger Robot    def beginResync(self):
597*16467b97STreehugger Robot        """Indicates the recognizer is about to consume tokens to resynchronize
598*16467b97STreehugger Robot        the parser.  Any consume events from here until the recovered event
599*16467b97STreehugger Robot        are not part of the parse--they are dead tokens.
600*16467b97STreehugger Robot        """
601*16467b97STreehugger Robot        pass
602*16467b97STreehugger Robot
603*16467b97STreehugger Robot
604*16467b97STreehugger Robot    def endResync(self):
605*16467b97STreehugger Robot        """Indicates that the recognizer has finished consuming tokens in order
606*16467b97STreehugger Robot        to resychronize.  There may be multiple beginResync/endResync pairs
607*16467b97STreehugger Robot        before the recognizer comes out of errorRecovery mode (in which
608*16467b97STreehugger Robot        multiple errors are suppressed).  This will be useful
609*16467b97STreehugger Robot        in a gui where you want to probably grey out tokens that are consumed
610*16467b97STreehugger Robot        but not matched to anything in grammar.  Anything between
611*16467b97STreehugger Robot        a beginResync/endResync pair was tossed out by the parser.
612*16467b97STreehugger Robot        """
613*16467b97STreehugger Robot        pass
614*16467b97STreehugger Robot
615*16467b97STreehugger Robot
616*16467b97STreehugger Robot    def semanticPredicate(self, result, predicate):
617*16467b97STreehugger Robot        """A semantic predicate was evaluate with this result and action text"""
618*16467b97STreehugger Robot        pass
619*16467b97STreehugger Robot
620*16467b97STreehugger Robot
621*16467b97STreehugger Robot    def commence(self):
622*16467b97STreehugger Robot        """Announce that parsing has begun.  Not technically useful except for
623*16467b97STreehugger Robot        sending events over a socket.  A GUI for example will launch a thread
624*16467b97STreehugger Robot        to connect and communicate with a remote parser.  The thread will want
625*16467b97STreehugger Robot        to notify the GUI when a connection is made.  ANTLR parsers
626*16467b97STreehugger Robot        trigger this upon entry to the first rule (the ruleLevel is used to
627*16467b97STreehugger Robot        figure this out).
628*16467b97STreehugger Robot        """
629*16467b97STreehugger Robot        pass
630*16467b97STreehugger Robot
631*16467b97STreehugger Robot
632*16467b97STreehugger Robot    def terminate(self):
633*16467b97STreehugger Robot        """Parsing is over; successfully or not.  Mostly useful for telling
634*16467b97STreehugger Robot        remote debugging listeners that it's time to quit.  When the rule
635*16467b97STreehugger Robot        invocation level goes to zero at the end of a rule, we are done
636*16467b97STreehugger Robot        parsing.
637*16467b97STreehugger Robot        """
638*16467b97STreehugger Robot        pass
639*16467b97STreehugger Robot
640*16467b97STreehugger Robot
641*16467b97STreehugger Robot    ## T r e e  P a r s i n g
642*16467b97STreehugger Robot
643*16467b97STreehugger Robot    def consumeNode(self, t):
644*16467b97STreehugger Robot        """Input for a tree parser is an AST, but we know nothing for sure
645*16467b97STreehugger Robot        about a node except its type and text (obtained from the adaptor).
646*16467b97STreehugger Robot        This is the analog of the consumeToken method.  Again, the ID is
647*16467b97STreehugger Robot        the hashCode usually of the node so it only works if hashCode is
648*16467b97STreehugger Robot        not implemented.  If the type is UP or DOWN, then
649*16467b97STreehugger Robot        the ID is not really meaningful as it's fixed--there is
650*16467b97STreehugger Robot        just one UP node and one DOWN navigation node.
651*16467b97STreehugger Robot        """
652*16467b97STreehugger Robot        pass
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().__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 {}:{}".format(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 {} {} {}".format(
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 {} {} {} {}".format(
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 {}".format(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 {}: {}, {}".format(
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 {}: {}".format(
801*16467b97STreehugger Robot                    self.adaptor.getUniqueID(t),
802*16467b97STreehugger Robot                    token.index))
803*16467b97STreehugger Robot
804*16467b97STreehugger Robot    def becomeRoot(self, newRoot, oldRoot):
805*16467b97STreehugger Robot        self.record("becomeRoot {}, {}".format(
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 {}, {}".format(
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 {}, {}, {}".format(
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().__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, debug=None):
843*16467b97STreehugger Robot        super().__init__()
844*16467b97STreehugger Robot
845*16467b97STreehugger Robot        self.grammarFileName = recognizer.getGrammarFileName()
846*16467b97STreehugger Robot
847*16467b97STreehugger Robot        # Almost certainly the recognizer will have adaptor set, but
848*16467b97STreehugger Robot        # we don't know how to cast it (Parser or TreeParser) to get
849*16467b97STreehugger Robot        # the adaptor field.  Must be set with a constructor. :(
850*16467b97STreehugger Robot        self.adaptor = adaptor
851*16467b97STreehugger Robot
852*16467b97STreehugger Robot        self.port = port or self.DEFAULT_DEBUGGER_PORT
853*16467b97STreehugger Robot
854*16467b97STreehugger Robot        self.debug = debug
855*16467b97STreehugger Robot
856*16467b97STreehugger Robot        self.socket = None
857*16467b97STreehugger Robot        self.connection = None
858*16467b97STreehugger Robot        self.input = None
859*16467b97STreehugger Robot        self.output = None
860*16467b97STreehugger Robot
861*16467b97STreehugger Robot
862*16467b97STreehugger Robot    def log(self, msg):
863*16467b97STreehugger Robot        if self.debug:
864*16467b97STreehugger Robot            self.debug.write(msg + '\n')
865*16467b97STreehugger Robot
866*16467b97STreehugger Robot
867*16467b97STreehugger Robot    def handshake(self):
868*16467b97STreehugger Robot        if self.socket is None:
869*16467b97STreehugger Robot            # create listening socket
870*16467b97STreehugger Robot            self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
871*16467b97STreehugger Robot            self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
872*16467b97STreehugger Robot            self.socket.bind(('', self.port))
873*16467b97STreehugger Robot            self.socket.listen(1)
874*16467b97STreehugger Robot            self.log("Waiting for incoming connection on port {}".format(self.port))
875*16467b97STreehugger Robot
876*16467b97STreehugger Robot            # wait for an incoming connection
877*16467b97STreehugger Robot            self.connection, addr = self.socket.accept()
878*16467b97STreehugger Robot            self.log("Accepted connection from {}:{}".format(addr[0], addr[1]))
879*16467b97STreehugger Robot
880*16467b97STreehugger Robot            self.connection.setblocking(1)
881*16467b97STreehugger Robot            self.connection.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)
882*16467b97STreehugger Robot
883*16467b97STreehugger Robot            self.output = self.connection.makefile('w', 1)
884*16467b97STreehugger Robot            self.input = self.connection.makefile('r', 1)
885*16467b97STreehugger Robot
886*16467b97STreehugger Robot            self.write("ANTLR {}".format(self.PROTOCOL_VERSION))
887*16467b97STreehugger Robot            self.write('grammar "{}"'.format(self.grammarFileName))
888*16467b97STreehugger Robot            self.ack()
889*16467b97STreehugger Robot
890*16467b97STreehugger Robot
891*16467b97STreehugger Robot    def write(self, msg):
892*16467b97STreehugger Robot        self.log("> {}".format(msg))
893*16467b97STreehugger Robot        self.output.write("{}\n".format(msg))
894*16467b97STreehugger Robot        self.output.flush()
895*16467b97STreehugger Robot
896*16467b97STreehugger Robot
897*16467b97STreehugger Robot    def ack(self):
898*16467b97STreehugger Robot        t = self.input.readline()
899*16467b97STreehugger Robot        self.log("< {}".format(t.rstrip()))
900*16467b97STreehugger Robot
901*16467b97STreehugger Robot
902*16467b97STreehugger Robot    def transmit(self, event):
903*16467b97STreehugger Robot        self.write(event)
904*16467b97STreehugger Robot        self.ack()
905*16467b97STreehugger Robot
906*16467b97STreehugger Robot
907*16467b97STreehugger Robot    def commence(self):
908*16467b97STreehugger Robot        # don't bother sending event; listener will trigger upon connection
909*16467b97STreehugger Robot        pass
910*16467b97STreehugger Robot
911*16467b97STreehugger Robot
912*16467b97STreehugger Robot    def terminate(self):
913*16467b97STreehugger Robot        self.transmit("terminate")
914*16467b97STreehugger Robot        self.output.close()
915*16467b97STreehugger Robot        self.input.close()
916*16467b97STreehugger Robot        self.connection.close()
917*16467b97STreehugger Robot        self.socket.close()
918*16467b97STreehugger Robot
919*16467b97STreehugger Robot
920*16467b97STreehugger Robot    def enterRule(self, grammarFileName, ruleName):
921*16467b97STreehugger Robot        self.transmit("enterRule\t{}\t{}".format(grammarFileName, ruleName))
922*16467b97STreehugger Robot
923*16467b97STreehugger Robot
924*16467b97STreehugger Robot    def enterAlt(self, alt):
925*16467b97STreehugger Robot        self.transmit("enterAlt\t{}".format(alt))
926*16467b97STreehugger Robot
927*16467b97STreehugger Robot
928*16467b97STreehugger Robot    def exitRule(self, grammarFileName, ruleName):
929*16467b97STreehugger Robot        self.transmit("exitRule\t{}\t{}".format(grammarFileName, ruleName))
930*16467b97STreehugger Robot
931*16467b97STreehugger Robot
932*16467b97STreehugger Robot    def enterSubRule(self, decisionNumber):
933*16467b97STreehugger Robot        self.transmit("enterSubRule\t{}".format(decisionNumber))
934*16467b97STreehugger Robot
935*16467b97STreehugger Robot
936*16467b97STreehugger Robot    def exitSubRule(self, decisionNumber):
937*16467b97STreehugger Robot        self.transmit("exitSubRule\t{}".format(decisionNumber))
938*16467b97STreehugger Robot
939*16467b97STreehugger Robot
940*16467b97STreehugger Robot    def enterDecision(self, decisionNumber, couldBacktrack):
941*16467b97STreehugger Robot        self.transmit(
942*16467b97STreehugger Robot            "enterDecision\t{}\t{:d}".format(decisionNumber, couldBacktrack))
943*16467b97STreehugger Robot
944*16467b97STreehugger Robot
945*16467b97STreehugger Robot    def exitDecision(self, decisionNumber):
946*16467b97STreehugger Robot        self.transmit("exitDecision\t{}".format(decisionNumber))
947*16467b97STreehugger Robot
948*16467b97STreehugger Robot
949*16467b97STreehugger Robot    def consumeToken(self, t):
950*16467b97STreehugger Robot        self.transmit("consumeToken\t{}".format(self.serializeToken(t)))
951*16467b97STreehugger Robot
952*16467b97STreehugger Robot
953*16467b97STreehugger Robot    def consumeHiddenToken(self, t):
954*16467b97STreehugger Robot        self.transmit("consumeHiddenToken\t{}".format(self.serializeToken(t)))
955*16467b97STreehugger Robot
956*16467b97STreehugger Robot
957*16467b97STreehugger Robot    def LT(self, i, o):
958*16467b97STreehugger Robot        if isinstance(o, Tree):
959*16467b97STreehugger Robot            return self.LT_tree(i, o)
960*16467b97STreehugger Robot        return self.LT_token(i, o)
961*16467b97STreehugger Robot
962*16467b97STreehugger Robot
963*16467b97STreehugger Robot    def LT_token(self, i, t):
964*16467b97STreehugger Robot        if t is not None:
965*16467b97STreehugger Robot            self.transmit("LT\t{}\t{}".format(i, self.serializeToken(t)))
966*16467b97STreehugger Robot
967*16467b97STreehugger Robot
968*16467b97STreehugger Robot    def mark(self, i):
969*16467b97STreehugger Robot        self.transmit("mark\t{}".format(i))
970*16467b97STreehugger Robot
971*16467b97STreehugger Robot
972*16467b97STreehugger Robot    def rewind(self, i=None):
973*16467b97STreehugger Robot        if i is not None:
974*16467b97STreehugger Robot            self.transmit("rewind\t{}".format(i))
975*16467b97STreehugger Robot        else:
976*16467b97STreehugger Robot            self.transmit("rewind")
977*16467b97STreehugger Robot
978*16467b97STreehugger Robot
979*16467b97STreehugger Robot    def beginBacktrack(self, level):
980*16467b97STreehugger Robot        self.transmit("beginBacktrack\t{}".format(level))
981*16467b97STreehugger Robot
982*16467b97STreehugger Robot
983*16467b97STreehugger Robot    def endBacktrack(self, level, successful):
984*16467b97STreehugger Robot        self.transmit("endBacktrack\t{}\t{}".format(
985*16467b97STreehugger Robot                level, '1' if successful else '0'))
986*16467b97STreehugger Robot
987*16467b97STreehugger Robot
988*16467b97STreehugger Robot    def location(self, line, pos):
989*16467b97STreehugger Robot        self.transmit("location\t{}\t{}".format(line, pos))
990*16467b97STreehugger Robot
991*16467b97STreehugger Robot
992*16467b97STreehugger Robot    def recognitionException(self, exc):
993*16467b97STreehugger Robot        self.transmit('\t'.join([
994*16467b97STreehugger Robot                    "exception",
995*16467b97STreehugger Robot                    exc.__class__.__name__,
996*16467b97STreehugger Robot                    str(int(exc.index)),
997*16467b97STreehugger Robot                    str(int(exc.line)),
998*16467b97STreehugger Robot                    str(int(exc.charPositionInLine))]))
999*16467b97STreehugger Robot
1000*16467b97STreehugger Robot
1001*16467b97STreehugger Robot    def beginResync(self):
1002*16467b97STreehugger Robot        self.transmit("beginResync")
1003*16467b97STreehugger Robot
1004*16467b97STreehugger Robot
1005*16467b97STreehugger Robot    def endResync(self):
1006*16467b97STreehugger Robot        self.transmit("endResync")
1007*16467b97STreehugger Robot
1008*16467b97STreehugger Robot
1009*16467b97STreehugger Robot    def semanticPredicate(self, result, predicate):
1010*16467b97STreehugger Robot        self.transmit('\t'.join([
1011*16467b97STreehugger Robot                    "semanticPredicate",
1012*16467b97STreehugger Robot                    str(int(result)),
1013*16467b97STreehugger Robot                    self.escapeNewlines(predicate)]))
1014*16467b97STreehugger Robot
1015*16467b97STreehugger Robot    ## A S T  P a r s i n g  E v e n t s
1016*16467b97STreehugger Robot
1017*16467b97STreehugger Robot    def consumeNode(self, t):
1018*16467b97STreehugger Robot        FIXME(31)
1019*16467b97STreehugger Robot#         StringBuffer buf = new StringBuffer(50);
1020*16467b97STreehugger Robot#         buf.append("consumeNode");
1021*16467b97STreehugger Robot#         serializeNode(buf, t);
1022*16467b97STreehugger Robot#         transmit(buf.toString());
1023*16467b97STreehugger Robot
1024*16467b97STreehugger Robot
1025*16467b97STreehugger Robot    def LT_tree(self, i, t):
1026*16467b97STreehugger Robot        FIXME(34)
1027*16467b97STreehugger Robot#         int ID = adaptor.getUniqueID(t);
1028*16467b97STreehugger Robot#         String text = adaptor.getText(t);
1029*16467b97STreehugger Robot#         int type = adaptor.getType(t);
1030*16467b97STreehugger Robot#         StringBuffer buf = new StringBuffer(50);
1031*16467b97STreehugger Robot#         buf.append("LN\t"); // lookahead node; distinguish from LT in protocol
1032*16467b97STreehugger Robot#         buf.append(i);
1033*16467b97STreehugger Robot#         serializeNode(buf, t);
1034*16467b97STreehugger Robot#         transmit(buf.toString());
1035*16467b97STreehugger Robot
1036*16467b97STreehugger Robot
1037*16467b97STreehugger Robot    def serializeNode(self, buf, t):
1038*16467b97STreehugger Robot        FIXME(33)
1039*16467b97STreehugger Robot#         int ID = adaptor.getUniqueID(t);
1040*16467b97STreehugger Robot#         String text = adaptor.getText(t);
1041*16467b97STreehugger Robot#         int type = adaptor.getType(t);
1042*16467b97STreehugger Robot#         buf.append("\t");
1043*16467b97STreehugger Robot#         buf.append(ID);
1044*16467b97STreehugger Robot#         buf.append("\t");
1045*16467b97STreehugger Robot#         buf.append(type);
1046*16467b97STreehugger Robot#         Token token = adaptor.getToken(t);
1047*16467b97STreehugger Robot#         int line = -1;
1048*16467b97STreehugger Robot#         int pos = -1;
1049*16467b97STreehugger Robot#         if ( token!=null ) {
1050*16467b97STreehugger Robot#             line = token.getLine();
1051*16467b97STreehugger Robot#             pos = token.getCharPositionInLine();
1052*16467b97STreehugger Robot#             }
1053*16467b97STreehugger Robot#         buf.append("\t");
1054*16467b97STreehugger Robot#         buf.append(line);
1055*16467b97STreehugger Robot#         buf.append("\t");
1056*16467b97STreehugger Robot#         buf.append(pos);
1057*16467b97STreehugger Robot#         int tokenIndex = adaptor.getTokenStartIndex(t);
1058*16467b97STreehugger Robot#         buf.append("\t");
1059*16467b97STreehugger Robot#         buf.append(tokenIndex);
1060*16467b97STreehugger Robot#         serializeText(buf, text);
1061*16467b97STreehugger Robot
1062*16467b97STreehugger Robot
1063*16467b97STreehugger Robot    ## A S T  E v e n t s
1064*16467b97STreehugger Robot
1065*16467b97STreehugger Robot    def nilNode(self, t):
1066*16467b97STreehugger Robot        self.transmit("nilNode\t{}".format(self.adaptor.getUniqueID(t)))
1067*16467b97STreehugger Robot
1068*16467b97STreehugger Robot
1069*16467b97STreehugger Robot    def errorNode(self, t):
1070*16467b97STreehugger Robot        self.transmit('errorNode\t{}\t{}\t"{}'.format(
1071*16467b97STreehugger Robot             self.adaptor.getUniqueID(t),
1072*16467b97STreehugger Robot             INVALID_TOKEN_TYPE,
1073*16467b97STreehugger Robot             self.escapeNewlines(t.toString())))
1074*16467b97STreehugger Robot
1075*16467b97STreehugger Robot
1076*16467b97STreehugger Robot    def createNode(self, node, token=None):
1077*16467b97STreehugger Robot        if token is not None:
1078*16467b97STreehugger Robot            self.transmit("createNode\t{}\t{}".format(
1079*16467b97STreehugger Robot                    self.adaptor.getUniqueID(node),
1080*16467b97STreehugger Robot                    token.index))
1081*16467b97STreehugger Robot
1082*16467b97STreehugger Robot        else:
1083*16467b97STreehugger Robot            self.transmit('createNodeFromTokenElements\t{}\t{}\t"{}'.format(
1084*16467b97STreehugger Robot                    self.adaptor.getUniqueID(node),
1085*16467b97STreehugger Robot                    self.adaptor.getType(node),
1086*16467b97STreehugger Robot                    self.adaptor.getText(node)))
1087*16467b97STreehugger Robot
1088*16467b97STreehugger Robot
1089*16467b97STreehugger Robot    def becomeRoot(self, newRoot, oldRoot):
1090*16467b97STreehugger Robot        self.transmit("becomeRoot\t{}\t{}".format(
1091*16467b97STreehugger Robot                self.adaptor.getUniqueID(newRoot),
1092*16467b97STreehugger Robot                self.adaptor.getUniqueID(oldRoot)))
1093*16467b97STreehugger Robot
1094*16467b97STreehugger Robot
1095*16467b97STreehugger Robot    def addChild(self, root, child):
1096*16467b97STreehugger Robot        self.transmit("addChild\t{}\t{}".format(
1097*16467b97STreehugger Robot                self.adaptor.getUniqueID(root),
1098*16467b97STreehugger Robot                self.adaptor.getUniqueID(child)))
1099*16467b97STreehugger Robot
1100*16467b97STreehugger Robot
1101*16467b97STreehugger Robot    def setTokenBoundaries(self, t, tokenStartIndex, tokenStopIndex):
1102*16467b97STreehugger Robot        self.transmit("setTokenBoundaries\t{}\t{}\t{}".format(
1103*16467b97STreehugger Robot                self.adaptor.getUniqueID(t),
1104*16467b97STreehugger Robot                tokenStartIndex, tokenStopIndex))
1105*16467b97STreehugger Robot
1106*16467b97STreehugger Robot
1107*16467b97STreehugger Robot
1108*16467b97STreehugger Robot    ## support
1109*16467b97STreehugger Robot
1110*16467b97STreehugger Robot    def setTreeAdaptor(self, adaptor):
1111*16467b97STreehugger Robot        self.adaptor = adaptor
1112*16467b97STreehugger Robot
1113*16467b97STreehugger Robot    def getTreeAdaptor(self):
1114*16467b97STreehugger Robot        return self.adaptor
1115*16467b97STreehugger Robot
1116*16467b97STreehugger Robot
1117*16467b97STreehugger Robot    def serializeToken(self, t):
1118*16467b97STreehugger Robot        buf = [str(int(t.index)),
1119*16467b97STreehugger Robot               str(int(t.type)),
1120*16467b97STreehugger Robot               str(int(t.channel)),
1121*16467b97STreehugger Robot               str(int(t.line or 0)),
1122*16467b97STreehugger Robot               str(int(t.charPositionInLine or 0)),
1123*16467b97STreehugger Robot               '"' + self.escapeNewlines(t.text)]
1124*16467b97STreehugger Robot        return '\t'.join(buf)
1125*16467b97STreehugger Robot
1126*16467b97STreehugger Robot
1127*16467b97STreehugger Robot    def escapeNewlines(self, txt):
1128*16467b97STreehugger Robot        if txt is None:
1129*16467b97STreehugger Robot            return ''
1130*16467b97STreehugger Robot
1131*16467b97STreehugger Robot        txt = txt.replace("%","%25")   # escape all escape char ;)
1132*16467b97STreehugger Robot        txt = txt.replace("\n","%0A")  # escape \n
1133*16467b97STreehugger Robot        txt = txt.replace("\r","%0D")  # escape \r
1134*16467b97STreehugger Robot        return txt
1135