Report InputMismatchException with original context information

Fixes #1922
This commit is contained in:
Sam Harwell 2017-07-26 07:21:27 -05:00
parent c41426c87e
commit 0803c74eb2
4 changed files with 74 additions and 4 deletions

View File

@ -618,4 +618,28 @@ public class ParserErrorsDescriptors {
public String grammar;
}
public static class ExtraneousInput extends BaseParserTestDescriptor {
public String input = "baa";
public String output = null;
public String errors = "line 1:0 mismatched input 'b' expecting {<EOF>, 'a'}\n";
public String startRule = "file";
public String grammarName = "T";
/**
grammar T;
member : 'a';
body : member*;
file : body EOF;
B : 'b';
*/
@CommentHasStringValue
public String grammar;
@Override
public boolean ignore(String targetName) {
return !"Java".equals(targetName);
}
}
}

View File

@ -283,11 +283,16 @@ public class SemPredEvalParserDescriptors {
public String input = "s\n\n\nx\n";
public String output = "(file_ (para (paraContent s) \\n \\n) (para (paraContent \\n x \\n)) <EOF>)\n";
/**
line 5:0 mismatched input '<EOF>' expecting '
'
line 5:0 mismatched input '<EOF>' expecting {'s', '
', 'x'}
*/
@CommentHasStringValue
public String errors;
@Override
public boolean ignore(String targetName) {
return !"Java".equals(targetName);
}
}
public static class PredFromAltTestedInLoopBack_2 extends PredFromAltTestedInLoopBack {

View File

@ -36,6 +36,21 @@ public class DefaultErrorStrategy implements ANTLRErrorStrategy {
protected IntervalSet lastErrorStates;
/**
* This field is used to propagate information about the lookahead following
* the previous match. Since prediction prefers completing the current rule
* to error recovery efforts, error reporting may occur later than the
* original point where it was discoverable. The original context is used to
* compute the true expected sets as though the reporting occurred as early
* as possible.
*/
protected ParserRuleContext nextTokensContext;
/**
* @see #nextTokensContext
*/
protected int nextTokensState;
/**
* {@inheritDoc}
*
@ -225,7 +240,20 @@ public class DefaultErrorStrategy implements ANTLRErrorStrategy {
// try cheaper subset first; might get lucky. seems to shave a wee bit off
IntervalSet nextTokens = recognizer.getATN().nextTokens(s);
if (nextTokens.contains(Token.EPSILON) || nextTokens.contains(la)) {
if (nextTokens.contains(la)) {
// We are sure the token matches
nextTokensContext = null;
nextTokensState = ATNState.INVALID_STATE_NUMBER;
return;
}
if (nextTokens.contains(Token.EPSILON)) {
if (nextTokensContext == null) {
// It's possible the next token won't match; information tracked
// by sync is restricted for performance.
nextTokensContext = recognizer.getContext();
nextTokensState = recognizer.getState();
}
return;
}
@ -450,7 +478,14 @@ public class DefaultErrorStrategy implements ANTLRErrorStrategy {
}
// even that didn't work; must throw the exception
throw new InputMismatchException(recognizer);
InputMismatchException e;
if (nextTokensContext == null) {
e = new InputMismatchException(recognizer);
} else {
e = new InputMismatchException(recognizer, nextTokensState, nextTokensContext);
}
throw e;
}
/**

View File

@ -13,4 +13,10 @@ public class InputMismatchException extends RecognitionException {
super(recognizer, recognizer.getInputStream(), recognizer._ctx);
this.setOffendingToken(recognizer.getCurrentToken());
}
public InputMismatchException(Parser recognizer, int state, ParserRuleContext ctx) {
super(recognizer, recognizer.getInputStream(), ctx);
this.setOffendingState(state);
this.setOffendingToken(recognizer.getCurrentToken());
}
}