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