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