| """ANTLR3 exception hierarchy""" |
| |
| # begin[licence] |
| # |
| # [The "BSD licence"] |
| # Copyright (c) 2005-2008 Terence Parr |
| # All rights reserved. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions |
| # are met: |
| # 1. Redistributions of source code must retain the above copyright |
| # notice, this list of conditions and the following disclaimer. |
| # 2. Redistributions in binary form must reproduce the above copyright |
| # notice, this list of conditions and the following disclaimer in the |
| # documentation and/or other materials provided with the distribution. |
| # 3. The name of the author may not be used to endorse or promote products |
| # derived from this software without specific prior written permission. |
| # |
| # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
| # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
| # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| # |
| # end[licence] |
| |
| from antlr3.constants import INVALID_TOKEN_TYPE |
| |
| |
| class BacktrackingFailed(Exception): |
| """@brief Raised to signal failed backtrack attempt""" |
| |
| pass |
| |
| |
| class RecognitionException(Exception): |
| """@brief The root of the ANTLR exception hierarchy. |
| |
| To avoid English-only error messages and to generally make things |
| as flexible as possible, these exceptions are not created with strings, |
| but rather the information necessary to generate an error. Then |
| the various reporting methods in Parser and Lexer can be overridden |
| to generate a localized error message. For example, MismatchedToken |
| exceptions are built with the expected token type. |
| So, don't expect getMessage() to return anything. |
| |
| Note that as of Java 1.4, you can access the stack trace, which means |
| that you can compute the complete trace of rules from the start symbol. |
| This gives you considerable context information with which to generate |
| useful error messages. |
| |
| ANTLR generates code that throws exceptions upon recognition error and |
| also generates code to catch these exceptions in each rule. If you |
| want to quit upon first error, you can turn off the automatic error |
| handling mechanism using rulecatch action, but you still need to |
| override methods mismatch and recoverFromMismatchSet. |
| |
| In general, the recognition exceptions can track where in a grammar a |
| problem occurred and/or what was the expected input. While the parser |
| knows its state (such as current input symbol and line info) that |
| state can change before the exception is reported so current token index |
| is computed and stored at exception time. From this info, you can |
| perhaps print an entire line of input not just a single token, for example. |
| Better to just say the recognizer had a problem and then let the parser |
| figure out a fancy report. |
| |
| """ |
| |
| def __init__(self, input=None): |
| Exception.__init__(self) |
| |
| # What input stream did the error occur in? |
| self.input = None |
| |
| # What is index of token/char were we looking at when the error |
| # occurred? |
| self.index = None |
| |
| # The current Token when an error occurred. Since not all streams |
| # can retrieve the ith Token, we have to track the Token object. |
| # For parsers. Even when it's a tree parser, token might be set. |
| self.token = None |
| |
| # If this is a tree parser exception, node is set to the node with |
| # the problem. |
| self.node = None |
| |
| # The current char when an error occurred. For lexers. |
| self.c = None |
| |
| # Track the line at which the error occurred in case this is |
| # generated from a lexer. We need to track this since the |
| # unexpected char doesn't carry the line info. |
| self.line = None |
| |
| self.charPositionInLine = None |
| |
| # If you are parsing a tree node stream, you will encounter som |
| # imaginary nodes w/o line/col info. We now search backwards looking |
| # for most recent token with line/col info, but notify getErrorHeader() |
| # that info is approximate. |
| self.approximateLineInfo = False |
| |
| |
| if input is not None: |
| self.input = input |
| self.index = input.index() |
| |
| # late import to avoid cyclic dependencies |
| from antlr3.streams import TokenStream, CharStream |
| from antlr3.tree import TreeNodeStream |
| |
| if isinstance(self.input, TokenStream): |
| self.token = self.input.LT(1) |
| self.line = self.token.line |
| self.charPositionInLine = self.token.charPositionInLine |
| |
| if isinstance(self.input, TreeNodeStream): |
| self.extractInformationFromTreeNodeStream(self.input) |
| |
| else: |
| if isinstance(self.input, CharStream): |
| self.c = self.input.LT(1) |
| self.line = self.input.line |
| self.charPositionInLine = self.input.charPositionInLine |
| |
| else: |
| self.c = self.input.LA(1) |
| |
| def extractInformationFromTreeNodeStream(self, nodes): |
| from antlr3.tree import Tree, CommonTree |
| from antlr3.tokens import CommonToken |
| |
| self.node = nodes.LT(1) |
| adaptor = nodes.adaptor |
| payload = adaptor.getToken(self.node) |
| if payload is not None: |
| self.token = payload |
| if payload.line <= 0: |
| # imaginary node; no line/pos info; scan backwards |
| i = -1 |
| priorNode = nodes.LT(i) |
| while priorNode is not None: |
| priorPayload = adaptor.getToken(priorNode) |
| if priorPayload is not None and priorPayload.line > 0: |
| # we found the most recent real line / pos info |
| self.line = priorPayload.line |
| self.charPositionInLine = priorPayload.charPositionInLine |
| self.approximateLineInfo = True |
| break |
| |
| i -= 1 |
| priorNode = nodes.LT(i) |
| |
| else: # node created from real token |
| self.line = payload.line |
| self.charPositionInLine = payload.charPositionInLine |
| |
| elif isinstance(self.node, Tree): |
| self.line = self.node.line |
| self.charPositionInLine = self.node.charPositionInLine |
| if isinstance(self.node, CommonTree): |
| self.token = self.node.token |
| |
| else: |
| type = adaptor.getType(self.node) |
| text = adaptor.getText(self.node) |
| self.token = CommonToken(type=type, text=text) |
| |
| |
| def getUnexpectedType(self): |
| """Return the token type or char of the unexpected input element""" |
| |
| from antlr3.streams import TokenStream |
| from antlr3.tree import TreeNodeStream |
| |
| if isinstance(self.input, TokenStream): |
| return self.token.type |
| |
| elif isinstance(self.input, TreeNodeStream): |
| adaptor = self.input.treeAdaptor |
| return adaptor.getType(self.node) |
| |
| else: |
| return self.c |
| |
| unexpectedType = property(getUnexpectedType) |
| |
| |
| class MismatchedTokenException(RecognitionException): |
| """@brief A mismatched char or Token or tree node.""" |
| |
| def __init__(self, expecting, input): |
| RecognitionException.__init__(self, input) |
| self.expecting = expecting |
| |
| |
| def __str__(self): |
| #return "MismatchedTokenException("+self.expecting+")" |
| return "MismatchedTokenException(%r!=%r)" % ( |
| self.getUnexpectedType(), self.expecting |
| ) |
| __repr__ = __str__ |
| |
| |
| class UnwantedTokenException(MismatchedTokenException): |
| """An extra token while parsing a TokenStream""" |
| |
| def getUnexpectedToken(self): |
| return self.token |
| |
| |
| def __str__(self): |
| exp = ", expected %s" % self.expecting |
| if self.expecting == INVALID_TOKEN_TYPE: |
| exp = "" |
| |
| if self.token is None: |
| return "UnwantedTokenException(found=%s%s)" % (None, exp) |
| |
| return "UnwantedTokenException(found=%s%s)" % (self.token.text, exp) |
| __repr__ = __str__ |
| |
| |
| class MissingTokenException(MismatchedTokenException): |
| """ |
| We were expecting a token but it's not found. The current token |
| is actually what we wanted next. |
| """ |
| |
| def __init__(self, expecting, input, inserted): |
| MismatchedTokenException.__init__(self, expecting, input) |
| |
| self.inserted = inserted |
| |
| |
| def getMissingType(self): |
| return self.expecting |
| |
| |
| def __str__(self): |
| if self.inserted is not None and self.token is not None: |
| return "MissingTokenException(inserted %r at %r)" % ( |
| self.inserted, self.token.text) |
| |
| if self.token is not None: |
| return "MissingTokenException(at %r)" % self.token.text |
| |
| return "MissingTokenException" |
| __repr__ = __str__ |
| |
| |
| class MismatchedRangeException(RecognitionException): |
| """@brief The next token does not match a range of expected types.""" |
| |
| def __init__(self, a, b, input): |
| RecognitionException.__init__(self, input) |
| |
| self.a = a |
| self.b = b |
| |
| |
| def __str__(self): |
| return "MismatchedRangeException(%r not in [%r..%r])" % ( |
| self.getUnexpectedType(), self.a, self.b |
| ) |
| __repr__ = __str__ |
| |
| |
| class MismatchedSetException(RecognitionException): |
| """@brief The next token does not match a set of expected types.""" |
| |
| def __init__(self, expecting, input): |
| RecognitionException.__init__(self, input) |
| |
| self.expecting = expecting |
| |
| |
| def __str__(self): |
| return "MismatchedSetException(%r not in %r)" % ( |
| self.getUnexpectedType(), self.expecting |
| ) |
| __repr__ = __str__ |
| |
| |
| class MismatchedNotSetException(MismatchedSetException): |
| """@brief Used for remote debugger deserialization""" |
| |
| def __str__(self): |
| return "MismatchedNotSetException(%r!=%r)" % ( |
| self.getUnexpectedType(), self.expecting |
| ) |
| __repr__ = __str__ |
| |
| |
| class NoViableAltException(RecognitionException): |
| """@brief Unable to decide which alternative to choose.""" |
| |
| def __init__( |
| self, grammarDecisionDescription, decisionNumber, stateNumber, input |
| ): |
| RecognitionException.__init__(self, input) |
| |
| self.grammarDecisionDescription = grammarDecisionDescription |
| self.decisionNumber = decisionNumber |
| self.stateNumber = stateNumber |
| |
| |
| def __str__(self): |
| return "NoViableAltException(%r!=[%r])" % ( |
| self.unexpectedType, self.grammarDecisionDescription |
| ) |
| __repr__ = __str__ |
| |
| |
| class EarlyExitException(RecognitionException): |
| """@brief The recognizer did not match anything for a (..)+ loop.""" |
| |
| def __init__(self, decisionNumber, input): |
| RecognitionException.__init__(self, input) |
| |
| self.decisionNumber = decisionNumber |
| |
| |
| class FailedPredicateException(RecognitionException): |
| """@brief A semantic predicate failed during validation. |
| |
| Validation of predicates |
| occurs when normally parsing the alternative just like matching a token. |
| Disambiguating predicate evaluation occurs when we hoist a predicate into |
| a prediction decision. |
| """ |
| |
| def __init__(self, input, ruleName, predicateText): |
| RecognitionException.__init__(self, input) |
| |
| self.ruleName = ruleName |
| self.predicateText = predicateText |
| |
| |
| def __str__(self): |
| return "FailedPredicateException("+self.ruleName+",{"+self.predicateText+"}?)" |
| __repr__ = __str__ |
| |
| |
| class MismatchedTreeNodeException(RecognitionException): |
| """@brief The next tree mode does not match the expected type.""" |
| |
| def __init__(self, expecting, input): |
| RecognitionException.__init__(self, input) |
| |
| self.expecting = expecting |
| |
| def __str__(self): |
| return "MismatchedTreeNodeException(%r!=%r)" % ( |
| self.getUnexpectedType(), self.expecting |
| ) |
| __repr__ = __str__ |