1"""ANTLR3 exception hierarchy""" 2 3# begin[licence] 4# 5# [The "BSD licence"] 6# Copyright (c) 2005-2012 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 .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 super().__init__() 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: 112 self.input = input 113 self.index = input.index() 114 115 # late import to avoid cyclic dependencies 116 from .streams import TokenStream, CharStream 117 from .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 .tree import Tree, CommonTree 138 from .tokens import CommonToken 139 140 self.node = nodes.LT(1) 141 adaptor = nodes.adaptor 142 payload = adaptor.getToken(self.node) 143 if payload: 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: 150 priorPayload = adaptor.getToken(priorNode) 151 if priorPayload 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 .streams import TokenStream 181 from .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 super().__init__(input) 201 self.expecting = expecting 202 203 204 def __str__(self): 205 return "MismatchedTokenException({!r}!={!r})".format( 206 self.getUnexpectedType(), self.expecting 207 ) 208 __repr__ = __str__ 209 210 211class UnwantedTokenException(MismatchedTokenException): 212 """An extra token while parsing a TokenStream""" 213 214 def getUnexpectedToken(self): 215 return self.token 216 217 218 def __str__(self): 219 exp = ", expected {}".format(self.expecting) 220 if self.expecting == INVALID_TOKEN_TYPE: 221 exp = "" 222 223 if not self.token: 224 return "UnwantedTokenException(found={}{})".format(None, exp) 225 226 return "UnwantedTokenException(found={}{})".format(self.token.text, exp) 227 __repr__ = __str__ 228 229 230class MissingTokenException(MismatchedTokenException): 231 """ 232 We were expecting a token but it's not found. The current token 233 is actually what we wanted next. 234 """ 235 236 def __init__(self, expecting, input, inserted): 237 super().__init__(expecting, input) 238 239 self.inserted = inserted 240 241 242 def getMissingType(self): 243 return self.expecting 244 245 246 def __str__(self): 247 if self.token: 248 if self.inserted: 249 return "MissingTokenException(inserted {!r} at {!r})".format( 250 self.inserted, self.token.text) 251 252 return "MissingTokenException(at {!r})".format(self.token.text) 253 254 return "MissingTokenException" 255 __repr__ = __str__ 256 257 258class MismatchedRangeException(RecognitionException): 259 """@brief The next token does not match a range of expected types.""" 260 261 def __init__(self, a, b, input): 262 super().__init__(input) 263 264 self.a = a 265 self.b = b 266 267 268 def __str__(self): 269 return "MismatchedRangeException({!r} not in [{!r}..{!r}])".format( 270 self.getUnexpectedType(), self.a, self.b 271 ) 272 __repr__ = __str__ 273 274 275class MismatchedSetException(RecognitionException): 276 """@brief The next token does not match a set of expected types.""" 277 278 def __init__(self, expecting, input): 279 super().__init__(input) 280 281 self.expecting = expecting 282 283 284 def __str__(self): 285 return "MismatchedSetException({!r} not in {!r})".format( 286 self.getUnexpectedType(), self.expecting 287 ) 288 __repr__ = __str__ 289 290 291class MismatchedNotSetException(MismatchedSetException): 292 """@brief Used for remote debugger deserialization""" 293 294 def __str__(self): 295 return "MismatchedNotSetException({!r}!={!r})".format( 296 self.getUnexpectedType(), self.expecting 297 ) 298 __repr__ = __str__ 299 300 301class NoViableAltException(RecognitionException): 302 """@brief Unable to decide which alternative to choose.""" 303 304 def __init__( 305 self, grammarDecisionDescription, decisionNumber, stateNumber, input 306 ): 307 super().__init__(input) 308 309 self.grammarDecisionDescription = grammarDecisionDescription 310 self.decisionNumber = decisionNumber 311 self.stateNumber = stateNumber 312 313 314 def __str__(self): 315 return "NoViableAltException({!r}!=[{!r}])".format( 316 self.unexpectedType, self.grammarDecisionDescription 317 ) 318 __repr__ = __str__ 319 320 321class EarlyExitException(RecognitionException): 322 """@brief The recognizer did not match anything for a (..)+ loop.""" 323 324 def __init__(self, decisionNumber, input): 325 super().__init__(input) 326 327 self.decisionNumber = decisionNumber 328 329 330class FailedPredicateException(RecognitionException): 331 """@brief A semantic predicate failed during validation. 332 333 Validation of predicates 334 occurs when normally parsing the alternative just like matching a token. 335 Disambiguating predicate evaluation occurs when we hoist a predicate into 336 a prediction decision. 337 """ 338 339 def __init__(self, input, ruleName, predicateText): 340 super().__init__(input) 341 342 self.ruleName = ruleName 343 self.predicateText = predicateText 344 345 346 def __str__(self): 347 return "FailedPredicateException({},{{{}}}?)".format( 348 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 super().__init__(input) 357 358 self.expecting = expecting 359 360 def __str__(self): 361 return "MismatchedTreeNodeException({!r}!={!r})".format( 362 self.getUnexpectedType(), self.expecting 363 ) 364 __repr__ = __str__ 365