Tidy up the exception handling around RecognitionException.

This removes the generic parameter on RecognitionException, to make it
easier to handle them.  This means that we no longer need to store them as
AnyObject and cast them back again.  To do this, we add RecognizerProtocol,
which is a non-generic equivalent of the Recognizer interface (at least, the
parts of it that we need for error handling).

Remove all paths where the RecognitionException subclasses were throwing
exceptions in their initializers.  This is just insane.
This commit is contained in:
Ewan Mellor 2017-10-21 20:12:26 -07:00
parent 7e03b0857a
commit fbe8c0d2a6
No known key found for this signature in database
GPG Key ID: 7CE1C6BC9EC8645D
12 changed files with 59 additions and 75 deletions

View File

@ -63,7 +63,7 @@ public protocol ANTLRErrorStrategy {
/// - throws: _RecognitionException_ if the error strategy could not recover from
/// the recognition exception
///
func recover(_ recognizer: Parser, _ e: AnyObject) throws
func recover(_ recognizer: Parser, _ e: RecognitionException) throws
///
/// This method provides the error handler with an opportunity to handle
@ -115,5 +115,5 @@ public protocol ANTLRErrorStrategy {
/// - parameter recognizer: the parser instance
/// - parameter e: the recognition exception to report
///
func reportError(_ recognizer: Parser, _ e: AnyObject)
func reportError(_ recognizer: Parser, _ e: RecognitionException)
}

View File

@ -40,7 +40,7 @@ public class BailErrorStrategy: DefaultErrorStrategy {
/// rule function catches. Use _Exception#getCause()_ to get the
/// original _org.antlr.v4.runtime.RecognitionException_.
///
override public func recover(_ recognizer: Parser, _ e: AnyObject) throws {
override public func recover(_ recognizer: Parser, _ e: RecognitionException) throws {
var context = recognizer.getContext()
while let contextWrap = context {
contextWrap.exception = e
@ -56,7 +56,7 @@ public class BailErrorStrategy: DefaultErrorStrategy {
///
override
public func recoverInline(_ recognizer: Parser) throws -> Token {
let e = try InputMismatchException(recognizer)
let e = InputMismatchException(recognizer)
var context = recognizer.getContext()
while let contextWrap = context {
contextWrap.exception = e

View File

@ -90,7 +90,7 @@ public class DefaultErrorStrategy: ANTLRErrorStrategy {
/// the exception
///
public func reportError(_ recognizer: Parser,
_ e: AnyObject) {
_ e: RecognitionException) {
// if we've already reported an error and have not matched a token
// yet successfully, don't report any errors.
if inErrorRecoveryMode(recognizer) {
@ -109,8 +109,7 @@ public class DefaultErrorStrategy: ANTLRErrorStrategy {
}
else {
errPrint("unknown recognition error type: " + String(describing: type(of: e)))
let re = (e as! RecognitionException<ParserATNSimulator>)
recognizer.notifyErrorListeners(re.getOffendingToken(), re.message ?? "", e)
recognizer.notifyErrorListeners(e.getOffendingToken(), e.message ?? "", e)
}
}
@ -119,7 +118,7 @@ public class DefaultErrorStrategy: ANTLRErrorStrategy {
/// until we find one in the resynchronization set--loosely the set of tokens
/// that can follow the current rule.
///
public func recover(_ recognizer: Parser, _ e: AnyObject) throws {
public func recover(_ recognizer: Parser, _ e: RecognitionException) throws {
// print("recover in "+recognizer.getRuleInvocationStack()+
// " index="+getTokenStream(recognizer).index()+
// ", lastErrorIndex="+
@ -219,7 +218,7 @@ public class DefaultErrorStrategy: ANTLRErrorStrategy {
if try singleTokenDeletion(recognizer) != nil {
return
}
throw try ANTLRException.recognition(e: InputMismatchException(recognizer))
throw ANTLRException.recognition(e: InputMismatchException(recognizer))
case ATNState.PLUS_LOOP_BACK: fallthrough
case ATNState.STAR_LOOP_BACK:
@ -418,11 +417,8 @@ public class DefaultErrorStrategy: ANTLRErrorStrategy {
if try singleTokenInsertion(recognizer) {
return try getMissingSymbol(recognizer)
}
throw try ANTLRException.recognition(e: InputMismatchException(recognizer))
// throw try ANTLRException.InputMismatch(e: InputMismatchException(recognizer) )
//RuntimeException("InputMismatchException")
// even that didn't work; must throw the exception
//throwException() /* throw InputMismatchException(recognizer); */
throw ANTLRException.recognition(e: InputMismatchException(recognizer))
}
///

View File

@ -11,23 +11,12 @@
/// Disambiguating predicate evaluation occurs when we test a predicate during
/// prediction.
///
public class FailedPredicateException: RecognitionException<ParserATNSimulator> {
public class FailedPredicateException: RecognitionException {
private final var ruleIndex: Int
private final var predicateIndex: Int
private final var predicate: String?
public convenience init(_ recognizer: Parser) throws {
try self.init(recognizer, nil)
}
public convenience init(_ recognizer: Parser, _ predicate: String?)throws {
try self.init(recognizer, predicate, nil)
}
public init(_ recognizer: Parser,
_ predicate: String?,
_ message: String?) throws
{
public init(_ recognizer: Parser, _ predicate: String? = nil, _ message: String? = nil) {
let s = recognizer.getInterpreter().atn.states[recognizer.getState()]!
let trans = s.transition(0) as! AbstractPredicateTransition
@ -42,9 +31,10 @@ public class FailedPredicateException: RecognitionException<ParserATNSimulator>
self.predicate = predicate
super.init(FailedPredicateException.formatMessage(predicate!, message), recognizer , recognizer.getInputStream()!, recognizer._ctx)
try self.setOffendingToken(recognizer.getCurrentToken())
super.init(recognizer, recognizer.getInputStream()!, recognizer._ctx, FailedPredicateException.formatMessage(predicate, message))
if let token = try? recognizer.getCurrentToken() {
setOffendingToken(token)
}
}
public func getRuleIndex() -> Int {
@ -60,11 +50,12 @@ public class FailedPredicateException: RecognitionException<ParserATNSimulator>
}
private static func formatMessage(_ predicate: String, _ message: String?) -> String {
private static func formatMessage(_ predicate: String?, _ message: String?) -> String {
if message != nil {
return message!
}
return "failed predicate: {predicate}?" //String.format(Locale.getDefault(), "failed predicate: {%s}?", predicate);
let predstr = predicate ?? "<unknown>"
return "failed predicate: {\(predstr)}?"
}
}

View File

@ -10,9 +10,11 @@
/// when the current input does not match the expected token.
///
public class InputMismatchException: RecognitionException<ParserATNSimulator> {
public init(_ recognizer: Parser) throws {
public class InputMismatchException: RecognitionException {
public init(_ recognizer: Parser) {
super.init(recognizer, recognizer.getInputStream()!, recognizer._ctx)
self.setOffendingToken(try recognizer.getCurrentToken())
if let token = try? recognizer.getCurrentToken() {
setOffendingToken(token)
}
}
}

View File

@ -5,7 +5,7 @@
///
public class LexerNoViableAltException: RecognitionException<LexerATNSimulator>, CustomStringConvertible {
public class LexerNoViableAltException: RecognitionException, CustomStringConvertible {
///
/// Matching attempted at what input index?
///

View File

@ -10,7 +10,7 @@
/// in the various paths when the error. Reported by reportNoViableAlternative()
///
public class NoViableAltException: RecognitionException<ParserATNSimulator> {
public class NoViableAltException: RecognitionException {
/// Which configurations did we try at input.index() that couldn't match input.LT(1)?
private final var deadEndConfigs: ATNConfigSet?
@ -22,14 +22,15 @@ public class NoViableAltException: RecognitionException<ParserATNSimulator> {
///
private final var startToken: Token
public convenience init(_ recognizer: Parser?) throws {
public convenience init(_ recognizer: Parser) {
// LL(1) error
let token = try! recognizer.getCurrentToken()
self.init(recognizer,
recognizer!.getInputStream()!,
try recognizer!.getCurrentToken(),
try recognizer!.getCurrentToken(),
recognizer.getInputStream()!,
token,
token,
nil,
recognizer!._ctx)
recognizer._ctx)
}
public init(_ recognizer: Parser?,
@ -42,7 +43,6 @@ public class NoViableAltException: RecognitionException<ParserATNSimulator> {
self.deadEndConfigs = deadEndConfigs
self.startToken = startToken
// as? Recognizer<AnyObject, ATNSimulator>
super.init(recognizer, input, ctx)
self.setOffendingToken(offendingToken)
}

View File

@ -237,11 +237,8 @@ public class ParserInterpreter: Parser {
case Transition.PREDICATE:
let predicateTransition = transition as! PredicateTransition
if try !sempred(_ctx!, predicateTransition.ruleIndex, predicateTransition.predIndex) {
throw try ANTLRException.recognition(e: FailedPredicateException(self))
throw ANTLRException.recognition(e: FailedPredicateException(self))
}
break
case Transition.ACTION:
@ -251,9 +248,7 @@ public class ParserInterpreter: Parser {
case Transition.PRECEDENCE:
if !precpred(_ctx!, (transition as! PrecedencePredicateTransition).precedence) {
throw try ANTLRException.recognition(e: FailedPredicateException(self, "precpred(_ctx,\((transition as! PrecedencePredicateTransition).precedence))"))
throw ANTLRException.recognition(e: FailedPredicateException(self, "precpred(_ctx,\((transition as! PrecedencePredicateTransition).precedence))"))
}
break

View File

@ -11,12 +11,11 @@
/// and what kind of problem occurred.
///
public class RecognitionException<T:ATNSimulator> {
public class RecognitionException {
///
/// The _org.antlr.v4.runtime.Recognizer_ where this exception originated.
///
private final var recognizer: Recognizer<T>?
//Recognizer<AnyObject,ATNSimulator>? ;
private final var recognizer: RecognizerProtocol?
private final let ctx: RuleContext?
@ -32,25 +31,15 @@ public class RecognitionException<T:ATNSimulator> {
private var offendingState = -1
public var message: String?
public init(_ recognizer: Recognizer<T>?,
_ input: IntStream,
_ ctx: ParserRuleContext?) {
self.recognizer = recognizer
self.input = input
self.ctx = ctx
if let recognizer = recognizer {
self.offendingState = recognizer.getState()
}
}
public init(_ message: String,
_ recognizer: Recognizer<T>?,
public init(_ recognizer: RecognizerProtocol?,
_ input: IntStream,
_ ctx: ParserRuleContext?) {
self.message = message
_ ctx: ParserRuleContext? = nil,
_ message: String? = nil) {
self.recognizer = recognizer
self.input = input
self.ctx = ctx
self.message = message
if let recognizer = recognizer {
self.offendingState = recognizer.getState()
}
@ -87,7 +76,6 @@ public class RecognitionException<T:ATNSimulator> {
if let recognizer = recognizer {
return try? recognizer.getATN().getExpectedTokens(offendingState, ctx!)
}
return nil
}
@ -134,7 +122,7 @@ public class RecognitionException<T:ATNSimulator> {
/// - Returns: The recognizer where this exception occurred, or `null` if
/// the recognizer is not available.
///
public func getRecognizer() -> Recognizer<T>? {
public func getRecognizer() -> RecognizerProtocol? {
return recognizer
}
}

View File

@ -5,13 +5,25 @@
import Foundation
open class Recognizer<ATNInterpreter:ATNSimulator> {
public protocol RecognizerProtocol {
func getATN() -> ATN
func getGrammarFileName() -> String
func getParseInfo() -> ParseInfo?
func getRuleNames() -> [String]
func getSerializedATN() -> String
func getState() -> Int
func getTokenType(_ tokenName: String) -> Int
func getVocabulary() -> Vocabulary
}
open class Recognizer<ATNInterpreter: ATNSimulator>: RecognizerProtocol {
//TODO: WeakKeyDictionary NSMapTable Dictionary MapTable<Vocabulary,HashMap<String, Int>>
private let tokenTypeMapCache = HashMap<Vocabulary, [String : Int]>()
private let ruleIndexMapCache = HashMap<ArrayWrapper<String>, [String : Int]>()
private var _listeners: [ANTLRErrorListener] = [ConsoleErrorListener.INSTANCE]
public var _interp: ATNInterpreter!
@ -151,8 +163,8 @@ open class Recognizer<ATNInterpreter:ATNSimulator> {
///
/// What is the error header, normally line/character position information?
///
open func getErrorHeader(_ e: AnyObject) -> String {
let offending = (e as! RecognitionException).getOffendingToken()
open func getErrorHeader(_ e: RecognitionException) -> String {
let offending = e.getOffendingToken()
let line = offending.getLine()
let charPositionInLine = offending.getCharPositionInLine()
return "line \(line):\(charPositionInLine)"

View File

@ -16,5 +16,5 @@ import Foundation
public enum ANTLRException: Error {
case cannotInvokeStartRule
case recognition(e:AnyObject)
case recognition(e: RecognitionException)
}

View File

@ -589,7 +589,7 @@ case <i><if(!choice.ast.greedy)>+1<endif>:
Sync(s) ::= "sync(<s.expecting.name>);"
ThrowNoViableAlt(t) ::= "throw try ANTLRException.recognition(e: NoViableAltException(self))"
ThrowNoViableAlt(t) ::= "throw ANTLRException.recognition(e: NoViableAltException(self))"
TestSetInline(s) ::= <<
<!<s.bitsets:{bits | <if(rest(rest(bits.ttypes)))><bitsetBitfieldComparison(s, bits)><else><bitsetInlineComparison(s, bits)><endif>}; separator=" || ">!>
@ -694,7 +694,7 @@ ArgAction(a, chunks) ::= "<chunks>"
SemPred(p, chunks, failChunks) ::= <<
setState(<p.stateNumber>)
if (!(<chunks>)) {
throw try ANTLRException.recognition(e:FailedPredicateException(self, <p.predicate><if(failChunks)>, <failChunks><elseif(p.msg)>, <p.msg><endif>))
throw ANTLRException.recognition(e:FailedPredicateException(self, <p.predicate><if(failChunks)>, <failChunks><elseif(p.msg)>, <p.msg><endif>))
}
>>