[Swift] Report InputMismatchException with original context information

Port 0803c74 from the Java runtime to Swift.  This was issue #1922.
Enable the corresponding tests for Swift.
This commit is contained in:
Ewan Mellor 2018-11-10 11:13:01 -08:00
parent 11d601348e
commit 842d3d7597
No known key found for this signature in database
GPG Key ID: 7CE1C6BC9EC8645D
4 changed files with 45 additions and 8 deletions

View File

@ -639,7 +639,7 @@ public class ParserErrorsDescriptors {
@Override
public boolean ignore(String targetName) {
return !"Java".equals(targetName);
return !"Java".equals(targetName) && !"Swift".equals(targetName);
}
}
}

View File

@ -291,7 +291,7 @@ public class SemPredEvalParserDescriptors {
@Override
public boolean ignore(String targetName) {
return !"Java".equals(targetName);
return !"Java".equals(targetName) && !"Swift".equals(targetName);
}
}

View File

@ -32,6 +32,22 @@ open class DefaultErrorStrategy: ANTLRErrorStrategy {
open var lastErrorStates: IntervalSet?
/**
* 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.
*/
open var nextTokensContext: ParserRuleContext?
/**
* @see #nextTokensContext
*/
open var nextTokensState = ATNState.INVALID_STATE_NUMBER
public init() {
}
@ -207,7 +223,20 @@ open class DefaultErrorStrategy: ANTLRErrorStrategy {
// try cheaper subset first; might get lucky. seems to shave a wee bit off
let nextToks = recognizer.getATN().nextTokens(s)
if nextToks.contains(CommonToken.EPSILON) || nextToks.contains(la) {
if nextToks.contains(la) {
// We are sure the token matches
nextTokensContext = nil
nextTokensState = ATNState.INVALID_STATE_NUMBER
return
}
if nextToks.contains(CommonToken.EPSILON) {
if nextTokensContext == nil {
// It's possible the next token won't match; information tracked
// by sync is restricted for performance.
nextTokensContext = recognizer.getContext()
nextTokensState = recognizer.getState()
}
return
}
@ -274,8 +303,9 @@ open class DefaultErrorStrategy: ANTLRErrorStrategy {
/// - parameter e: the recognition exception
///
open func reportInputMismatch(_ recognizer: Parser, _ e: InputMismatchException) {
let msg = "mismatched input " + getTokenErrorDisplay(e.getOffendingToken()) +
" expecting " + e.getExpectedTokens()!.toString(recognizer.getVocabulary())
let tok = getTokenErrorDisplay(e.getOffendingToken())
let expected = e.getExpectedTokens()?.toString(recognizer.getVocabulary()) ?? "<missing>"
let msg = "mismatched input \(tok) expecting \(expected)"
recognizer.notifyErrorListeners(e.getOffendingToken(), msg, e)
}
@ -423,7 +453,8 @@ open class DefaultErrorStrategy: ANTLRErrorStrategy {
return try getMissingSymbol(recognizer)
}
// even that didn't work; must throw the exception
throw ANTLRException.recognition(e: InputMismatchException(recognizer))
let exn = InputMismatchException(recognizer, state: nextTokensState, ctx: nextTokensContext)
throw ANTLRException.recognition(e: exn)
}
///

View File

@ -11,10 +11,16 @@
///
public class InputMismatchException: RecognitionException {
public init(_ recognizer: Parser) {
super.init(recognizer, recognizer.getInputStream()!, recognizer._ctx)
public init(_ recognizer: Parser, state: Int = ATNState.INVALID_STATE_NUMBER, ctx: ParserRuleContext? = nil) {
let bestCtx = ctx ?? recognizer._ctx
super.init(recognizer, recognizer.getInputStream()!, bestCtx)
if let token = try? recognizer.getCurrentToken() {
setOffendingToken(token)
}
if (state != ATNState.INVALID_STATE_NUMBER) {
setOffendingState(state)
}
}
}