From fbe8c0d2a6fd8199374f7cecc4de38710721aa75 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Sat, 21 Oct 2017 20:12:26 -0700 Subject: [PATCH] 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. --- .../Sources/Antlr4/ANTLRErrorStrategy.swift | 4 +-- .../Sources/Antlr4/BailErrorStrategy.swift | 4 +-- .../Sources/Antlr4/DefaultErrorStrategy.swift | 14 ++++------ .../Antlr4/FailedPredicateException.swift | 27 +++++++------------ .../Antlr4/InputMismatchException.swift | 8 +++--- .../Antlr4/LexerNoViableAltException.swift | 2 +- .../Sources/Antlr4/NoViableAltException.swift | 14 +++++----- .../Sources/Antlr4/ParserInterpreter.swift | 9 ++----- .../Sources/Antlr4/RecognitionException.swift | 26 +++++------------- runtime/Swift/Sources/Antlr4/Recognizer.swift | 20 +++++++++++--- .../misc/exception/ANTLRException.swift | 2 +- .../v4/tool/templates/codegen/Swift/Swift.stg | 4 +-- 12 files changed, 59 insertions(+), 75 deletions(-) diff --git a/runtime/Swift/Sources/Antlr4/ANTLRErrorStrategy.swift b/runtime/Swift/Sources/Antlr4/ANTLRErrorStrategy.swift index 325418b5e..7ca228ff8 100644 --- a/runtime/Swift/Sources/Antlr4/ANTLRErrorStrategy.swift +++ b/runtime/Swift/Sources/Antlr4/ANTLRErrorStrategy.swift @@ -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) } diff --git a/runtime/Swift/Sources/Antlr4/BailErrorStrategy.swift b/runtime/Swift/Sources/Antlr4/BailErrorStrategy.swift index 13c2176bd..d1e81140c 100644 --- a/runtime/Swift/Sources/Antlr4/BailErrorStrategy.swift +++ b/runtime/Swift/Sources/Antlr4/BailErrorStrategy.swift @@ -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 diff --git a/runtime/Swift/Sources/Antlr4/DefaultErrorStrategy.swift b/runtime/Swift/Sources/Antlr4/DefaultErrorStrategy.swift index 29c2890c4..894d4b572 100644 --- a/runtime/Swift/Sources/Antlr4/DefaultErrorStrategy.swift +++ b/runtime/Swift/Sources/Antlr4/DefaultErrorStrategy.swift @@ -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) - 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)) } /// diff --git a/runtime/Swift/Sources/Antlr4/FailedPredicateException.swift b/runtime/Swift/Sources/Antlr4/FailedPredicateException.swift index ac287bd52..c4e2bd310 100644 --- a/runtime/Swift/Sources/Antlr4/FailedPredicateException.swift +++ b/runtime/Swift/Sources/Antlr4/FailedPredicateException.swift @@ -11,23 +11,12 @@ /// Disambiguating predicate evaluation occurs when we test a predicate during /// prediction. /// -public class FailedPredicateException: RecognitionException { +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 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 } - 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 ?? "" + return "failed predicate: {\(predstr)}?" } } diff --git a/runtime/Swift/Sources/Antlr4/InputMismatchException.swift b/runtime/Swift/Sources/Antlr4/InputMismatchException.swift index 07797d6fd..8af781702 100644 --- a/runtime/Swift/Sources/Antlr4/InputMismatchException.swift +++ b/runtime/Swift/Sources/Antlr4/InputMismatchException.swift @@ -10,9 +10,11 @@ /// when the current input does not match the expected token. /// -public class InputMismatchException: RecognitionException { - 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) + } } } diff --git a/runtime/Swift/Sources/Antlr4/LexerNoViableAltException.swift b/runtime/Swift/Sources/Antlr4/LexerNoViableAltException.swift index b93086d67..eceddd8a7 100644 --- a/runtime/Swift/Sources/Antlr4/LexerNoViableAltException.swift +++ b/runtime/Swift/Sources/Antlr4/LexerNoViableAltException.swift @@ -5,7 +5,7 @@ /// -public class LexerNoViableAltException: RecognitionException, CustomStringConvertible { +public class LexerNoViableAltException: RecognitionException, CustomStringConvertible { /// /// Matching attempted at what input index? /// diff --git a/runtime/Swift/Sources/Antlr4/NoViableAltException.swift b/runtime/Swift/Sources/Antlr4/NoViableAltException.swift index 5158d0675..6a3f08fbd 100644 --- a/runtime/Swift/Sources/Antlr4/NoViableAltException.swift +++ b/runtime/Swift/Sources/Antlr4/NoViableAltException.swift @@ -10,7 +10,7 @@ /// in the various paths when the error. Reported by reportNoViableAlternative() /// -public class NoViableAltException: RecognitionException { +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 { /// 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 { self.deadEndConfigs = deadEndConfigs self.startToken = startToken - // as? Recognizer super.init(recognizer, input, ctx) self.setOffendingToken(offendingToken) } diff --git a/runtime/Swift/Sources/Antlr4/ParserInterpreter.swift b/runtime/Swift/Sources/Antlr4/ParserInterpreter.swift index 4adeee890..1e760fc84 100644 --- a/runtime/Swift/Sources/Antlr4/ParserInterpreter.swift +++ b/runtime/Swift/Sources/Antlr4/ParserInterpreter.swift @@ -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 diff --git a/runtime/Swift/Sources/Antlr4/RecognitionException.swift b/runtime/Swift/Sources/Antlr4/RecognitionException.swift index 97bb2ccb5..d308dddfd 100644 --- a/runtime/Swift/Sources/Antlr4/RecognitionException.swift +++ b/runtime/Swift/Sources/Antlr4/RecognitionException.swift @@ -11,12 +11,11 @@ /// and what kind of problem occurred. /// -public class RecognitionException { +public class RecognitionException { /// /// The _org.antlr.v4.runtime.Recognizer_ where this exception originated. /// - private final var recognizer: Recognizer? - //Recognizer? ; + private final var recognizer: RecognizerProtocol? private final let ctx: RuleContext? @@ -32,25 +31,15 @@ public class RecognitionException { private var offendingState = -1 public var message: String? - public init(_ recognizer: Recognizer?, - _ 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?, + 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 { if let recognizer = recognizer { return try? recognizer.getATN().getExpectedTokens(offendingState, ctx!) } - return nil } @@ -134,7 +122,7 @@ public class RecognitionException { /// - Returns: The recognizer where this exception occurred, or `null` if /// the recognizer is not available. /// - public func getRecognizer() -> Recognizer? { + public func getRecognizer() -> RecognizerProtocol? { return recognizer } } diff --git a/runtime/Swift/Sources/Antlr4/Recognizer.swift b/runtime/Swift/Sources/Antlr4/Recognizer.swift index 882802fa9..de4f7ca4c 100644 --- a/runtime/Swift/Sources/Antlr4/Recognizer.swift +++ b/runtime/Swift/Sources/Antlr4/Recognizer.swift @@ -5,13 +5,25 @@ import Foundation -open class Recognizer { + +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: RecognizerProtocol { //TODO: WeakKeyDictionary NSMapTable Dictionary MapTable> private let tokenTypeMapCache = HashMap() private let ruleIndexMapCache = HashMap, [String : Int]>() - private var _listeners: [ANTLRErrorListener] = [ConsoleErrorListener.INSTANCE] public var _interp: ATNInterpreter! @@ -151,8 +163,8 @@ open class Recognizer { /// /// 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)" diff --git a/runtime/Swift/Sources/Antlr4/misc/exception/ANTLRException.swift b/runtime/Swift/Sources/Antlr4/misc/exception/ANTLRException.swift index 9dec26e28..c4453384d 100644 --- a/runtime/Swift/Sources/Antlr4/misc/exception/ANTLRException.swift +++ b/runtime/Swift/Sources/Antlr4/misc/exception/ANTLRException.swift @@ -16,5 +16,5 @@ import Foundation public enum ANTLRException: Error { case cannotInvokeStartRule - case recognition(e:AnyObject) + case recognition(e: RecognitionException) } diff --git a/tool/resources/org/antlr/v4/tool/templates/codegen/Swift/Swift.stg b/tool/resources/org/antlr/v4/tool/templates/codegen/Swift/Swift.stg index 6f94b1957..2cae8daf2 100755 --- a/tool/resources/org/antlr/v4/tool/templates/codegen/Swift/Swift.stg +++ b/tool/resources/org/antlr/v4/tool/templates/codegen/Swift/Swift.stg @@ -589,7 +589,7 @@ case +1: Sync(s) ::= "sync();" -ThrowNoViableAlt(t) ::= "throw try ANTLRException.recognition(e: NoViableAltException(self))" +ThrowNoViableAlt(t) ::= "throw ANTLRException.recognition(e: NoViableAltException(self))" TestSetInline(s) ::= << }; separator=" || ">!> @@ -694,7 +694,7 @@ ArgAction(a, chunks) ::= "" SemPred(p, chunks, failChunks) ::= << setState() if (!()) { - throw try ANTLRException.recognition(e:FailedPredicateException(self, , , )) + throw ANTLRException.recognition(e:FailedPredicateException(self, , , )) } >>