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 /// - throws: _RecognitionException_ if the error strategy could not recover from
/// the recognition exception /// 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 /// This method provides the error handler with an opportunity to handle
@ -115,5 +115,5 @@ public protocol ANTLRErrorStrategy {
/// - parameter recognizer: the parser instance /// - parameter recognizer: the parser instance
/// - parameter e: the recognition exception to report /// - 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 /// rule function catches. Use _Exception#getCause()_ to get the
/// original _org.antlr.v4.runtime.RecognitionException_. /// 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() var context = recognizer.getContext()
while let contextWrap = context { while let contextWrap = context {
contextWrap.exception = e contextWrap.exception = e
@ -56,7 +56,7 @@ public class BailErrorStrategy: DefaultErrorStrategy {
/// ///
override override
public func recoverInline(_ recognizer: Parser) throws -> Token { public func recoverInline(_ recognizer: Parser) throws -> Token {
let e = try InputMismatchException(recognizer) let e = InputMismatchException(recognizer)
var context = recognizer.getContext() var context = recognizer.getContext()
while let contextWrap = context { while let contextWrap = context {
contextWrap.exception = e contextWrap.exception = e

View File

@ -90,7 +90,7 @@ public class DefaultErrorStrategy: ANTLRErrorStrategy {
/// the exception /// the exception
/// ///
public func reportError(_ recognizer: Parser, public func reportError(_ recognizer: Parser,
_ e: AnyObject) { _ e: RecognitionException) {
// if we've already reported an error and have not matched a token // if we've already reported an error and have not matched a token
// yet successfully, don't report any errors. // yet successfully, don't report any errors.
if inErrorRecoveryMode(recognizer) { if inErrorRecoveryMode(recognizer) {
@ -109,8 +109,7 @@ public class DefaultErrorStrategy: ANTLRErrorStrategy {
} }
else { else {
errPrint("unknown recognition error type: " + String(describing: type(of: e))) errPrint("unknown recognition error type: " + String(describing: type(of: e)))
let re = (e as! RecognitionException<ParserATNSimulator>) recognizer.notifyErrorListeners(e.getOffendingToken(), e.message ?? "", e)
recognizer.notifyErrorListeners(re.getOffendingToken(), re.message ?? "", e)
} }
} }
@ -119,7 +118,7 @@ public class DefaultErrorStrategy: ANTLRErrorStrategy {
/// until we find one in the resynchronization set--loosely the set of tokens /// until we find one in the resynchronization set--loosely the set of tokens
/// that can follow the current rule. /// 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()+ // print("recover in "+recognizer.getRuleInvocationStack()+
// " index="+getTokenStream(recognizer).index()+ // " index="+getTokenStream(recognizer).index()+
// ", lastErrorIndex="+ // ", lastErrorIndex="+
@ -219,7 +218,7 @@ public class DefaultErrorStrategy: ANTLRErrorStrategy {
if try singleTokenDeletion(recognizer) != nil { if try singleTokenDeletion(recognizer) != nil {
return return
} }
throw try ANTLRException.recognition(e: InputMismatchException(recognizer)) throw ANTLRException.recognition(e: InputMismatchException(recognizer))
case ATNState.PLUS_LOOP_BACK: fallthrough case ATNState.PLUS_LOOP_BACK: fallthrough
case ATNState.STAR_LOOP_BACK: case ATNState.STAR_LOOP_BACK:
@ -418,11 +417,8 @@ public class DefaultErrorStrategy: ANTLRErrorStrategy {
if try singleTokenInsertion(recognizer) { if try singleTokenInsertion(recognizer) {
return try getMissingSymbol(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 // 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 /// Disambiguating predicate evaluation occurs when we test a predicate during
/// prediction. /// prediction.
/// ///
public class FailedPredicateException: RecognitionException<ParserATNSimulator> { public class FailedPredicateException: RecognitionException {
private final var ruleIndex: Int private final var ruleIndex: Int
private final var predicateIndex: Int private final var predicateIndex: Int
private final var predicate: String? private final var predicate: String?
public convenience init(_ recognizer: Parser) throws { public init(_ recognizer: Parser, _ predicate: String? = nil, _ message: String? = nil) {
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
{
let s = recognizer.getInterpreter().atn.states[recognizer.getState()]! let s = recognizer.getInterpreter().atn.states[recognizer.getState()]!
let trans = s.transition(0) as! AbstractPredicateTransition let trans = s.transition(0) as! AbstractPredicateTransition
@ -42,9 +31,10 @@ public class FailedPredicateException: RecognitionException<ParserATNSimulator>
self.predicate = predicate self.predicate = predicate
super.init(FailedPredicateException.formatMessage(predicate!, message), recognizer , recognizer.getInputStream()!, recognizer._ctx) super.init(recognizer, recognizer.getInputStream()!, recognizer._ctx, FailedPredicateException.formatMessage(predicate, message))
if let token = try? recognizer.getCurrentToken() {
try self.setOffendingToken(recognizer.getCurrentToken()) setOffendingToken(token)
}
} }
public func getRuleIndex() -> Int { 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 { if message != nil {
return message! 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. /// when the current input does not match the expected token.
/// ///
public class InputMismatchException: RecognitionException<ParserATNSimulator> { public class InputMismatchException: RecognitionException {
public init(_ recognizer: Parser) throws { public init(_ recognizer: Parser) {
super.init(recognizer, recognizer.getInputStream()!, recognizer._ctx) 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? /// Matching attempted at what input index?
/// ///

View File

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

View File

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

View File

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

View File

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

View File

@ -16,5 +16,5 @@ import Foundation
public enum ANTLRException: Error { public enum ANTLRException: Error {
case cannotInvokeStartRule 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>);" 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) ::= << TestSetInline(s) ::= <<
<!<s.bitsets:{bits | <if(rest(rest(bits.ttypes)))><bitsetBitfieldComparison(s, bits)><else><bitsetInlineComparison(s, bits)><endif>}; separator=" || ">!> <!<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) ::= << SemPred(p, chunks, failChunks) ::= <<
setState(<p.stateNumber>) setState(<p.stateNumber>)
if (!(<chunks>)) { 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>))
} }
>> >>