Ответ 1
@CoronA был прав. Ошибка в лексере.. Поэтому, хотя я все еще думаю, что создание ErrorStrategy было бы лучше, это то, что на самом деле работало для меня и моя цель выбросить исключение для ввода undefined.
Сначала я создал производный класс, который наследует от BaseErrorListener
и реализует IAntlrErrorListener<T>
. Вторая часть была моей проблемой все время кажется. Поскольку мой посетитель унаследовал от FooBarBaseVistor<int>
, мой прослушиватель ошибок также должен был иметь тип, чтобы зарегистрировать его с помощью моего lexer.
class ThrowExceptionErrorListener : BaseErrorListener, IAntlrErrorListener<int>
{
//BaseErrorListener implementation; not called in my test, but left it just in case
public override void SyntaxError(IRecognizer recognizer, IToken offendingSymbol, int line, int charPositionInLine, string msg, RecognitionException e)
{
throw new ArgumentException("Invalid Expression: {0}", msg, e);
}
//IAntlrErrorListener<int> implementation; this one actually gets called.
public void SyntaxError(IRecognizer recognizer, int offendingSymbol, int line, int charPositionInLine, string msg, RecognitionException e)
{
throw new ArgumentException("Invalid Expression: {0}", msg, e);
}
}
И изменил мой класс Calculator
, чтобы привязать мой пользовательский прослушиватель ошибок к lexer. Обратите внимание, что вам не нужно удалять ConsoleListener
, как я сделал, для того, чтобы ошибка была фактически выбрана. Поскольку я на самом деле не использую его, я решил, что лучше идти вперед и делать это.
public static class Calculator
{
public static int Evaluate(string expression)
{
var lexer = new BasicMathLexer(new AntlrInputStream(expression));
lexer.RemoveErrorListeners(); //removes the default console listener
lexer.AddErrorListener(new ThrowExceptionErrorListener());
var tokens = new CommonTokenStream(lexer);
var parser = new BasicMathParser(tokens);
var tree = parser.compileUnit();
var visitor = new IntegerMathVisitor();
return visitor.Visit(tree);
}
}
И что это. Исключение аргумента бросается, и этот тест теперь проходит.
[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void BadInput()
{
var expr = "1 + 5 + 2(3)";
int value = Calculator.Evaluate(expr);
}
Одна последняя заметка. Если вы выбросите здесь RecognitionException
, он снова будет проглочен. Рекомендуется использовать ParseCancelationException
, потому что он не получается из RecognitionException
, но я выбираю ArgumentException
, потому что я чувствовал, что это наиболее важно для кода клиента С#.