Home | History | Annotate | Download | only in antlr3
      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 
     33 from antlr3.constants import INVALID_TOKEN_TYPE
     34 
     35 
     36 class BacktrackingFailed(Exception):
     37     """@brief Raised to signal failed backtrack attempt"""
     38 
     39     pass
     40 
     41 
     42 class 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 
    196 class 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 
    212 class 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 
    231 class 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 
    259 class 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 
    276 class 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 
    292 class 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 
    302 class 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 
    322 class 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 
    331 class 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 
    352 class 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