1*16467b97STreehugger Robot"""ANTLR3 exception hierarchy""" 2*16467b97STreehugger Robot 3*16467b97STreehugger Robot# begin[licence] 4*16467b97STreehugger Robot# 5*16467b97STreehugger Robot# [The "BSD licence"] 6*16467b97STreehugger Robot# Copyright (c) 2005-2008 Terence Parr 7*16467b97STreehugger Robot# All rights reserved. 8*16467b97STreehugger Robot# 9*16467b97STreehugger Robot# Redistribution and use in source and binary forms, with or without 10*16467b97STreehugger Robot# modification, are permitted provided that the following conditions 11*16467b97STreehugger Robot# are met: 12*16467b97STreehugger Robot# 1. Redistributions of source code must retain the above copyright 13*16467b97STreehugger Robot# notice, this list of conditions and the following disclaimer. 14*16467b97STreehugger Robot# 2. Redistributions in binary form must reproduce the above copyright 15*16467b97STreehugger Robot# notice, this list of conditions and the following disclaimer in the 16*16467b97STreehugger Robot# documentation and/or other materials provided with the distribution. 17*16467b97STreehugger Robot# 3. The name of the author may not be used to endorse or promote products 18*16467b97STreehugger Robot# derived from this software without specific prior written permission. 19*16467b97STreehugger Robot# 20*16467b97STreehugger Robot# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21*16467b97STreehugger Robot# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22*16467b97STreehugger Robot# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23*16467b97STreehugger Robot# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24*16467b97STreehugger Robot# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25*16467b97STreehugger Robot# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26*16467b97STreehugger Robot# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27*16467b97STreehugger Robot# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28*16467b97STreehugger Robot# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29*16467b97STreehugger Robot# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30*16467b97STreehugger Robot# 31*16467b97STreehugger Robot# end[licence] 32*16467b97STreehugger Robot 33*16467b97STreehugger Robotfrom antlr3.constants import INVALID_TOKEN_TYPE 34*16467b97STreehugger Robot 35*16467b97STreehugger Robot 36*16467b97STreehugger Robotclass BacktrackingFailed(Exception): 37*16467b97STreehugger Robot """@brief Raised to signal failed backtrack attempt""" 38*16467b97STreehugger Robot 39*16467b97STreehugger Robot pass 40*16467b97STreehugger Robot 41*16467b97STreehugger Robot 42*16467b97STreehugger Robotclass RecognitionException(Exception): 43*16467b97STreehugger Robot """@brief The root of the ANTLR exception hierarchy. 44*16467b97STreehugger Robot 45*16467b97STreehugger Robot To avoid English-only error messages and to generally make things 46*16467b97STreehugger Robot as flexible as possible, these exceptions are not created with strings, 47*16467b97STreehugger Robot but rather the information necessary to generate an error. Then 48*16467b97STreehugger Robot the various reporting methods in Parser and Lexer can be overridden 49*16467b97STreehugger Robot to generate a localized error message. For example, MismatchedToken 50*16467b97STreehugger Robot exceptions are built with the expected token type. 51*16467b97STreehugger Robot So, don't expect getMessage() to return anything. 52*16467b97STreehugger Robot 53*16467b97STreehugger Robot Note that as of Java 1.4, you can access the stack trace, which means 54*16467b97STreehugger Robot that you can compute the complete trace of rules from the start symbol. 55*16467b97STreehugger Robot This gives you considerable context information with which to generate 56*16467b97STreehugger Robot useful error messages. 57*16467b97STreehugger Robot 58*16467b97STreehugger Robot ANTLR generates code that throws exceptions upon recognition error and 59*16467b97STreehugger Robot also generates code to catch these exceptions in each rule. If you 60*16467b97STreehugger Robot want to quit upon first error, you can turn off the automatic error 61*16467b97STreehugger Robot handling mechanism using rulecatch action, but you still need to 62*16467b97STreehugger Robot override methods mismatch and recoverFromMismatchSet. 63*16467b97STreehugger Robot 64*16467b97STreehugger Robot In general, the recognition exceptions can track where in a grammar a 65*16467b97STreehugger Robot problem occurred and/or what was the expected input. While the parser 66*16467b97STreehugger Robot knows its state (such as current input symbol and line info) that 67*16467b97STreehugger Robot state can change before the exception is reported so current token index 68*16467b97STreehugger Robot is computed and stored at exception time. From this info, you can 69*16467b97STreehugger Robot perhaps print an entire line of input not just a single token, for example. 70*16467b97STreehugger Robot Better to just say the recognizer had a problem and then let the parser 71*16467b97STreehugger Robot figure out a fancy report. 72*16467b97STreehugger Robot 73*16467b97STreehugger Robot """ 74*16467b97STreehugger Robot 75*16467b97STreehugger Robot def __init__(self, input=None): 76*16467b97STreehugger Robot Exception.__init__(self) 77*16467b97STreehugger Robot 78*16467b97STreehugger Robot # What input stream did the error occur in? 79*16467b97STreehugger Robot self.input = None 80*16467b97STreehugger Robot 81*16467b97STreehugger Robot # What is index of token/char were we looking at when the error 82*16467b97STreehugger Robot # occurred? 83*16467b97STreehugger Robot self.index = None 84*16467b97STreehugger Robot 85*16467b97STreehugger Robot # The current Token when an error occurred. Since not all streams 86*16467b97STreehugger Robot # can retrieve the ith Token, we have to track the Token object. 87*16467b97STreehugger Robot # For parsers. Even when it's a tree parser, token might be set. 88*16467b97STreehugger Robot self.token = None 89*16467b97STreehugger Robot 90*16467b97STreehugger Robot # If this is a tree parser exception, node is set to the node with 91*16467b97STreehugger Robot # the problem. 92*16467b97STreehugger Robot self.node = None 93*16467b97STreehugger Robot 94*16467b97STreehugger Robot # The current char when an error occurred. For lexers. 95*16467b97STreehugger Robot self.c = None 96*16467b97STreehugger Robot 97*16467b97STreehugger Robot # Track the line at which the error occurred in case this is 98*16467b97STreehugger Robot # generated from a lexer. We need to track this since the 99*16467b97STreehugger Robot # unexpected char doesn't carry the line info. 100*16467b97STreehugger Robot self.line = None 101*16467b97STreehugger Robot 102*16467b97STreehugger Robot self.charPositionInLine = None 103*16467b97STreehugger Robot 104*16467b97STreehugger Robot # If you are parsing a tree node stream, you will encounter som 105*16467b97STreehugger Robot # imaginary nodes w/o line/col info. We now search backwards looking 106*16467b97STreehugger Robot # for most recent token with line/col info, but notify getErrorHeader() 107*16467b97STreehugger Robot # that info is approximate. 108*16467b97STreehugger Robot self.approximateLineInfo = False 109*16467b97STreehugger Robot 110*16467b97STreehugger Robot 111*16467b97STreehugger Robot if input is not None: 112*16467b97STreehugger Robot self.input = input 113*16467b97STreehugger Robot self.index = input.index() 114*16467b97STreehugger Robot 115*16467b97STreehugger Robot # late import to avoid cyclic dependencies 116*16467b97STreehugger Robot from antlr3.streams import TokenStream, CharStream 117*16467b97STreehugger Robot from antlr3.tree import TreeNodeStream 118*16467b97STreehugger Robot 119*16467b97STreehugger Robot if isinstance(self.input, TokenStream): 120*16467b97STreehugger Robot self.token = self.input.LT(1) 121*16467b97STreehugger Robot self.line = self.token.line 122*16467b97STreehugger Robot self.charPositionInLine = self.token.charPositionInLine 123*16467b97STreehugger Robot 124*16467b97STreehugger Robot if isinstance(self.input, TreeNodeStream): 125*16467b97STreehugger Robot self.extractInformationFromTreeNodeStream(self.input) 126*16467b97STreehugger Robot 127*16467b97STreehugger Robot else: 128*16467b97STreehugger Robot if isinstance(self.input, CharStream): 129*16467b97STreehugger Robot self.c = self.input.LT(1) 130*16467b97STreehugger Robot self.line = self.input.line 131*16467b97STreehugger Robot self.charPositionInLine = self.input.charPositionInLine 132*16467b97STreehugger Robot 133*16467b97STreehugger Robot else: 134*16467b97STreehugger Robot self.c = self.input.LA(1) 135*16467b97STreehugger Robot 136*16467b97STreehugger Robot def extractInformationFromTreeNodeStream(self, nodes): 137*16467b97STreehugger Robot from antlr3.tree import Tree, CommonTree 138*16467b97STreehugger Robot from antlr3.tokens import CommonToken 139*16467b97STreehugger Robot 140*16467b97STreehugger Robot self.node = nodes.LT(1) 141*16467b97STreehugger Robot adaptor = nodes.adaptor 142*16467b97STreehugger Robot payload = adaptor.getToken(self.node) 143*16467b97STreehugger Robot if payload is not None: 144*16467b97STreehugger Robot self.token = payload 145*16467b97STreehugger Robot if payload.line <= 0: 146*16467b97STreehugger Robot # imaginary node; no line/pos info; scan backwards 147*16467b97STreehugger Robot i = -1 148*16467b97STreehugger Robot priorNode = nodes.LT(i) 149*16467b97STreehugger Robot while priorNode is not None: 150*16467b97STreehugger Robot priorPayload = adaptor.getToken(priorNode) 151*16467b97STreehugger Robot if priorPayload is not None and priorPayload.line > 0: 152*16467b97STreehugger Robot # we found the most recent real line / pos info 153*16467b97STreehugger Robot self.line = priorPayload.line 154*16467b97STreehugger Robot self.charPositionInLine = priorPayload.charPositionInLine 155*16467b97STreehugger Robot self.approximateLineInfo = True 156*16467b97STreehugger Robot break 157*16467b97STreehugger Robot 158*16467b97STreehugger Robot i -= 1 159*16467b97STreehugger Robot priorNode = nodes.LT(i) 160*16467b97STreehugger Robot 161*16467b97STreehugger Robot else: # node created from real token 162*16467b97STreehugger Robot self.line = payload.line 163*16467b97STreehugger Robot self.charPositionInLine = payload.charPositionInLine 164*16467b97STreehugger Robot 165*16467b97STreehugger Robot elif isinstance(self.node, Tree): 166*16467b97STreehugger Robot self.line = self.node.line 167*16467b97STreehugger Robot self.charPositionInLine = self.node.charPositionInLine 168*16467b97STreehugger Robot if isinstance(self.node, CommonTree): 169*16467b97STreehugger Robot self.token = self.node.token 170*16467b97STreehugger Robot 171*16467b97STreehugger Robot else: 172*16467b97STreehugger Robot type = adaptor.getType(self.node) 173*16467b97STreehugger Robot text = adaptor.getText(self.node) 174*16467b97STreehugger Robot self.token = CommonToken(type=type, text=text) 175*16467b97STreehugger Robot 176*16467b97STreehugger Robot 177*16467b97STreehugger Robot def getUnexpectedType(self): 178*16467b97STreehugger Robot """Return the token type or char of the unexpected input element""" 179*16467b97STreehugger Robot 180*16467b97STreehugger Robot from antlr3.streams import TokenStream 181*16467b97STreehugger Robot from antlr3.tree import TreeNodeStream 182*16467b97STreehugger Robot 183*16467b97STreehugger Robot if isinstance(self.input, TokenStream): 184*16467b97STreehugger Robot return self.token.type 185*16467b97STreehugger Robot 186*16467b97STreehugger Robot elif isinstance(self.input, TreeNodeStream): 187*16467b97STreehugger Robot adaptor = self.input.treeAdaptor 188*16467b97STreehugger Robot return adaptor.getType(self.node) 189*16467b97STreehugger Robot 190*16467b97STreehugger Robot else: 191*16467b97STreehugger Robot return self.c 192*16467b97STreehugger Robot 193*16467b97STreehugger Robot unexpectedType = property(getUnexpectedType) 194*16467b97STreehugger Robot 195*16467b97STreehugger Robot 196*16467b97STreehugger Robotclass MismatchedTokenException(RecognitionException): 197*16467b97STreehugger Robot """@brief A mismatched char or Token or tree node.""" 198*16467b97STreehugger Robot 199*16467b97STreehugger Robot def __init__(self, expecting, input): 200*16467b97STreehugger Robot RecognitionException.__init__(self, input) 201*16467b97STreehugger Robot self.expecting = expecting 202*16467b97STreehugger Robot 203*16467b97STreehugger Robot 204*16467b97STreehugger Robot def __str__(self): 205*16467b97STreehugger Robot #return "MismatchedTokenException("+self.expecting+")" 206*16467b97STreehugger Robot return "MismatchedTokenException(%r!=%r)" % ( 207*16467b97STreehugger Robot self.getUnexpectedType(), self.expecting 208*16467b97STreehugger Robot ) 209*16467b97STreehugger Robot __repr__ = __str__ 210*16467b97STreehugger Robot 211*16467b97STreehugger Robot 212*16467b97STreehugger Robotclass UnwantedTokenException(MismatchedTokenException): 213*16467b97STreehugger Robot """An extra token while parsing a TokenStream""" 214*16467b97STreehugger Robot 215*16467b97STreehugger Robot def getUnexpectedToken(self): 216*16467b97STreehugger Robot return self.token 217*16467b97STreehugger Robot 218*16467b97STreehugger Robot 219*16467b97STreehugger Robot def __str__(self): 220*16467b97STreehugger Robot exp = ", expected %s" % self.expecting 221*16467b97STreehugger Robot if self.expecting == INVALID_TOKEN_TYPE: 222*16467b97STreehugger Robot exp = "" 223*16467b97STreehugger Robot 224*16467b97STreehugger Robot if self.token is None: 225*16467b97STreehugger Robot return "UnwantedTokenException(found=%s%s)" % (None, exp) 226*16467b97STreehugger Robot 227*16467b97STreehugger Robot return "UnwantedTokenException(found=%s%s)" % (self.token.text, exp) 228*16467b97STreehugger Robot __repr__ = __str__ 229*16467b97STreehugger Robot 230*16467b97STreehugger Robot 231*16467b97STreehugger Robotclass MissingTokenException(MismatchedTokenException): 232*16467b97STreehugger Robot """ 233*16467b97STreehugger Robot We were expecting a token but it's not found. The current token 234*16467b97STreehugger Robot is actually what we wanted next. 235*16467b97STreehugger Robot """ 236*16467b97STreehugger Robot 237*16467b97STreehugger Robot def __init__(self, expecting, input, inserted): 238*16467b97STreehugger Robot MismatchedTokenException.__init__(self, expecting, input) 239*16467b97STreehugger Robot 240*16467b97STreehugger Robot self.inserted = inserted 241*16467b97STreehugger Robot 242*16467b97STreehugger Robot 243*16467b97STreehugger Robot def getMissingType(self): 244*16467b97STreehugger Robot return self.expecting 245*16467b97STreehugger Robot 246*16467b97STreehugger Robot 247*16467b97STreehugger Robot def __str__(self): 248*16467b97STreehugger Robot if self.inserted is not None and self.token is not None: 249*16467b97STreehugger Robot return "MissingTokenException(inserted %r at %r)" % ( 250*16467b97STreehugger Robot self.inserted, self.token.text) 251*16467b97STreehugger Robot 252*16467b97STreehugger Robot if self.token is not None: 253*16467b97STreehugger Robot return "MissingTokenException(at %r)" % self.token.text 254*16467b97STreehugger Robot 255*16467b97STreehugger Robot return "MissingTokenException" 256*16467b97STreehugger Robot __repr__ = __str__ 257*16467b97STreehugger Robot 258*16467b97STreehugger Robot 259*16467b97STreehugger Robotclass MismatchedRangeException(RecognitionException): 260*16467b97STreehugger Robot """@brief The next token does not match a range of expected types.""" 261*16467b97STreehugger Robot 262*16467b97STreehugger Robot def __init__(self, a, b, input): 263*16467b97STreehugger Robot RecognitionException.__init__(self, input) 264*16467b97STreehugger Robot 265*16467b97STreehugger Robot self.a = a 266*16467b97STreehugger Robot self.b = b 267*16467b97STreehugger Robot 268*16467b97STreehugger Robot 269*16467b97STreehugger Robot def __str__(self): 270*16467b97STreehugger Robot return "MismatchedRangeException(%r not in [%r..%r])" % ( 271*16467b97STreehugger Robot self.getUnexpectedType(), self.a, self.b 272*16467b97STreehugger Robot ) 273*16467b97STreehugger Robot __repr__ = __str__ 274*16467b97STreehugger Robot 275*16467b97STreehugger Robot 276*16467b97STreehugger Robotclass MismatchedSetException(RecognitionException): 277*16467b97STreehugger Robot """@brief The next token does not match a set of expected types.""" 278*16467b97STreehugger Robot 279*16467b97STreehugger Robot def __init__(self, expecting, input): 280*16467b97STreehugger Robot RecognitionException.__init__(self, input) 281*16467b97STreehugger Robot 282*16467b97STreehugger Robot self.expecting = expecting 283*16467b97STreehugger Robot 284*16467b97STreehugger Robot 285*16467b97STreehugger Robot def __str__(self): 286*16467b97STreehugger Robot return "MismatchedSetException(%r not in %r)" % ( 287*16467b97STreehugger Robot self.getUnexpectedType(), self.expecting 288*16467b97STreehugger Robot ) 289*16467b97STreehugger Robot __repr__ = __str__ 290*16467b97STreehugger Robot 291*16467b97STreehugger Robot 292*16467b97STreehugger Robotclass MismatchedNotSetException(MismatchedSetException): 293*16467b97STreehugger Robot """@brief Used for remote debugger deserialization""" 294*16467b97STreehugger Robot 295*16467b97STreehugger Robot def __str__(self): 296*16467b97STreehugger Robot return "MismatchedNotSetException(%r!=%r)" % ( 297*16467b97STreehugger Robot self.getUnexpectedType(), self.expecting 298*16467b97STreehugger Robot ) 299*16467b97STreehugger Robot __repr__ = __str__ 300*16467b97STreehugger Robot 301*16467b97STreehugger Robot 302*16467b97STreehugger Robotclass NoViableAltException(RecognitionException): 303*16467b97STreehugger Robot """@brief Unable to decide which alternative to choose.""" 304*16467b97STreehugger Robot 305*16467b97STreehugger Robot def __init__( 306*16467b97STreehugger Robot self, grammarDecisionDescription, decisionNumber, stateNumber, input 307*16467b97STreehugger Robot ): 308*16467b97STreehugger Robot RecognitionException.__init__(self, input) 309*16467b97STreehugger Robot 310*16467b97STreehugger Robot self.grammarDecisionDescription = grammarDecisionDescription 311*16467b97STreehugger Robot self.decisionNumber = decisionNumber 312*16467b97STreehugger Robot self.stateNumber = stateNumber 313*16467b97STreehugger Robot 314*16467b97STreehugger Robot 315*16467b97STreehugger Robot def __str__(self): 316*16467b97STreehugger Robot return "NoViableAltException(%r!=[%r])" % ( 317*16467b97STreehugger Robot self.unexpectedType, self.grammarDecisionDescription 318*16467b97STreehugger Robot ) 319*16467b97STreehugger Robot __repr__ = __str__ 320*16467b97STreehugger Robot 321*16467b97STreehugger Robot 322*16467b97STreehugger Robotclass EarlyExitException(RecognitionException): 323*16467b97STreehugger Robot """@brief The recognizer did not match anything for a (..)+ loop.""" 324*16467b97STreehugger Robot 325*16467b97STreehugger Robot def __init__(self, decisionNumber, input): 326*16467b97STreehugger Robot RecognitionException.__init__(self, input) 327*16467b97STreehugger Robot 328*16467b97STreehugger Robot self.decisionNumber = decisionNumber 329*16467b97STreehugger Robot 330*16467b97STreehugger Robot 331*16467b97STreehugger Robotclass FailedPredicateException(RecognitionException): 332*16467b97STreehugger Robot """@brief A semantic predicate failed during validation. 333*16467b97STreehugger Robot 334*16467b97STreehugger Robot Validation of predicates 335*16467b97STreehugger Robot occurs when normally parsing the alternative just like matching a token. 336*16467b97STreehugger Robot Disambiguating predicate evaluation occurs when we hoist a predicate into 337*16467b97STreehugger Robot a prediction decision. 338*16467b97STreehugger Robot """ 339*16467b97STreehugger Robot 340*16467b97STreehugger Robot def __init__(self, input, ruleName, predicateText): 341*16467b97STreehugger Robot RecognitionException.__init__(self, input) 342*16467b97STreehugger Robot 343*16467b97STreehugger Robot self.ruleName = ruleName 344*16467b97STreehugger Robot self.predicateText = predicateText 345*16467b97STreehugger Robot 346*16467b97STreehugger Robot 347*16467b97STreehugger Robot def __str__(self): 348*16467b97STreehugger Robot return "FailedPredicateException("+self.ruleName+",{"+self.predicateText+"}?)" 349*16467b97STreehugger Robot __repr__ = __str__ 350*16467b97STreehugger Robot 351*16467b97STreehugger Robot 352*16467b97STreehugger Robotclass MismatchedTreeNodeException(RecognitionException): 353*16467b97STreehugger Robot """@brief The next tree mode does not match the expected type.""" 354*16467b97STreehugger Robot 355*16467b97STreehugger Robot def __init__(self, expecting, input): 356*16467b97STreehugger Robot RecognitionException.__init__(self, input) 357*16467b97STreehugger Robot 358*16467b97STreehugger Robot self.expecting = expecting 359*16467b97STreehugger Robot 360*16467b97STreehugger Robot def __str__(self): 361*16467b97STreehugger Robot return "MismatchedTreeNodeException(%r!=%r)" % ( 362*16467b97STreehugger Robot self.getUnexpectedType(), self.expecting 363*16467b97STreehugger Robot ) 364*16467b97STreehugger Robot __repr__ = __str__ 365