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