Skip to content

Commit

Permalink
Merge pull request #2402 from ewanmellor/swift-1922
Browse files Browse the repository at this point in the history
[Swift] Report InputMismatchException with original context information
  • Loading branch information
parrt authored Nov 15, 2018
2 parents 11d6013 + 842d3d7 commit 66e5b3b
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,7 @@ public static class ExtraneousInput extends BaseParserTestDescriptor {

@Override
public boolean ignore(String targetName) {
return !"Java".equals(targetName);
return !"Java".equals(targetName) && !"Swift".equals(targetName);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ public static class PredFromAltTestedInLoopBack_1 extends PredFromAltTestedInLoo

@Override
public boolean ignore(String targetName) {
return !"Java".equals(targetName);
return !"Java".equals(targetName) && !"Swift".equals(targetName);
}
}

Expand Down
39 changes: 35 additions & 4 deletions runtime/Swift/Sources/Antlr4/DefaultErrorStrategy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
}

Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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)
}

Expand Down Expand Up @@ -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)
}

///
Expand Down
10 changes: 8 additions & 2 deletions runtime/Swift/Sources/Antlr4/InputMismatchException.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
}

0 comments on commit 66e5b3b

Please sign in to comment.