1 /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
2 * Use of this file is governed by the BSD 3-clause license that
3 * can be found in the LICENSE.txt file in the project root.
6 #include "NoViableAltException.h"
7 #include "misc/IntervalSet.h"
8 #include "atn/ParserATNSimulator.h"
9 #include "InputMismatchException.h"
10 #include "FailedPredicateException.h"
11 #include "ParserRuleContext.h"
12 #include "atn/RuleTransition.h"
14 #include "atn/ATNState.h"
16 #include "CommonToken.h"
17 #include "Vocabulary.h"
18 #include "support/StringUtils.h"
20 #include "DefaultErrorStrategy.h"
22 using namespace antlr4;
23 using namespace antlr4::atn;
25 using namespace antlrcpp;
27 DefaultErrorStrategy::DefaultErrorStrategy() {
28 InitializeInstanceFields();
31 DefaultErrorStrategy::~DefaultErrorStrategy() {
34 void DefaultErrorStrategy::reset(Parser *recognizer) {
35 _errorSymbols.clear();
36 endErrorCondition(recognizer);
39 void DefaultErrorStrategy::beginErrorCondition(Parser * /*recognizer*/) {
40 errorRecoveryMode = true;
43 bool DefaultErrorStrategy::inErrorRecoveryMode(Parser * /*recognizer*/) {
44 return errorRecoveryMode;
47 void DefaultErrorStrategy::endErrorCondition(Parser * /*recognizer*/) {
48 errorRecoveryMode = false;
52 void DefaultErrorStrategy::reportMatch(Parser *recognizer) {
53 endErrorCondition(recognizer);
56 void DefaultErrorStrategy::reportError(Parser *recognizer, const RecognitionException &e) {
57 // If we've already reported an error and have not matched a token
58 // yet successfully, don't report any errors.
59 if (inErrorRecoveryMode(recognizer)) {
60 return; // don't report spurious errors
63 beginErrorCondition(recognizer);
64 if (is<const NoViableAltException *>(&e)) {
65 reportNoViableAlternative(recognizer, static_cast<const NoViableAltException &>(e));
66 } else if (is<const InputMismatchException *>(&e)) {
67 reportInputMismatch(recognizer, static_cast<const InputMismatchException &>(e));
68 } else if (is<const FailedPredicateException *>(&e)) {
69 reportFailedPredicate(recognizer, static_cast<const FailedPredicateException &>(e));
70 } else if (is<const RecognitionException *>(&e)) {
71 recognizer->notifyErrorListeners(e.getOffendingToken(), e.what(), std::current_exception());
75 void DefaultErrorStrategy::recover(Parser *recognizer, std::exception_ptr /*e*/) {
76 if (lastErrorIndex == static_cast<int>(recognizer->getInputStream()->index()) &&
77 lastErrorStates.contains(recognizer->getState())) {
79 // uh oh, another error at same token index and previously-visited
80 // state in ATN; must be a case where LT(1) is in the recovery
81 // token set so nothing got consumed. Consume a single token
82 // at least to prevent an infinite loop; this is a failsafe.
83 recognizer->consume();
85 lastErrorIndex = static_cast<int>(recognizer->getInputStream()->index());
86 lastErrorStates.add(recognizer->getState());
87 misc::IntervalSet followSet = getErrorRecoverySet(recognizer);
88 consumeUntil(recognizer, followSet);
91 void DefaultErrorStrategy::sync(Parser *recognizer) {
92 atn::ATNState *s = recognizer->getInterpreter<atn::ATNSimulator>()->atn.states[recognizer->getState()];
94 // If already recovering, don't try to sync
95 if (inErrorRecoveryMode(recognizer)) {
99 TokenStream *tokens = recognizer->getTokenStream();
100 size_t la = tokens->LA(1);
102 // try cheaper subset first; might get lucky. seems to shave a wee bit off
103 auto nextTokens = recognizer->getATN().nextTokens(s);
104 if (nextTokens.contains(Token::EPSILON) || nextTokens.contains(la)) {
108 switch (s->getStateType()) {
109 case atn::ATNState::BLOCK_START:
110 case atn::ATNState::STAR_BLOCK_START:
111 case atn::ATNState::PLUS_BLOCK_START:
112 case atn::ATNState::STAR_LOOP_ENTRY:
113 // report error and recover if possible
114 if (singleTokenDeletion(recognizer) != nullptr) {
118 throw InputMismatchException(recognizer);
120 case atn::ATNState::PLUS_LOOP_BACK:
121 case atn::ATNState::STAR_LOOP_BACK: {
122 reportUnwantedToken(recognizer);
123 misc::IntervalSet expecting = recognizer->getExpectedTokens();
124 misc::IntervalSet whatFollowsLoopIterationOrRule = expecting.Or(getErrorRecoverySet(recognizer));
125 consumeUntil(recognizer, whatFollowsLoopIterationOrRule);
130 // do nothing if we can't identify the exact kind of ATN state
135 void DefaultErrorStrategy::reportNoViableAlternative(Parser *recognizer, const NoViableAltException &e) {
136 TokenStream *tokens = recognizer->getTokenStream();
138 if (tokens != nullptr) {
139 if (e.getStartToken()->getType() == Token::EOF) {
142 input = tokens->getText(e.getStartToken(), e.getOffendingToken());
145 input = "<unknown input>";
147 std::string msg = "no viable alternative at input " + escapeWSAndQuote(input);
148 recognizer->notifyErrorListeners(e.getOffendingToken(), msg, std::make_exception_ptr(e));
151 void DefaultErrorStrategy::reportInputMismatch(Parser *recognizer, const InputMismatchException &e) {
152 std::string msg = "mismatched input " + getTokenErrorDisplay(e.getOffendingToken()) +
153 " expecting " + e.getExpectedTokens().toString(recognizer->getVocabulary());
154 recognizer->notifyErrorListeners(e.getOffendingToken(), msg, std::make_exception_ptr(e));
157 void DefaultErrorStrategy::reportFailedPredicate(Parser *recognizer, const FailedPredicateException &e) {
158 const std::string& ruleName = recognizer->getRuleNames()[recognizer->getContext()->getRuleIndex()];
159 std::string msg = "rule " + ruleName + " " + e.what();
160 recognizer->notifyErrorListeners(e.getOffendingToken(), msg, std::make_exception_ptr(e));
163 void DefaultErrorStrategy::reportUnwantedToken(Parser *recognizer) {
164 if (inErrorRecoveryMode(recognizer)) {
168 beginErrorCondition(recognizer);
170 Token *t = recognizer->getCurrentToken();
171 std::string tokenName = getTokenErrorDisplay(t);
172 misc::IntervalSet expecting = getExpectedTokens(recognizer);
174 std::string msg = "extraneous input " + tokenName + " expecting " + expecting.toString(recognizer->getVocabulary());
175 recognizer->notifyErrorListeners(t, msg, nullptr);
178 void DefaultErrorStrategy::reportMissingToken(Parser *recognizer) {
179 if (inErrorRecoveryMode(recognizer)) {
183 beginErrorCondition(recognizer);
185 Token *t = recognizer->getCurrentToken();
186 misc::IntervalSet expecting = getExpectedTokens(recognizer);
187 std::string expectedText = expecting.toString(recognizer->getVocabulary());
188 std::string msg = "missing " + expectedText + " at " + getTokenErrorDisplay(t);
190 recognizer->notifyErrorListeners(t, msg, nullptr);
193 Token* DefaultErrorStrategy::recoverInline(Parser *recognizer) {
194 // Single token deletion.
195 Token *matchedSymbol = singleTokenDeletion(recognizer);
197 // We have deleted the extra token.
198 // Now, move past ttype token as if all were ok.
199 recognizer->consume();
200 return matchedSymbol;
203 // Single token insertion.
204 if (singleTokenInsertion(recognizer)) {
205 return getMissingSymbol(recognizer);
208 // Even that didn't work; must throw the exception.
209 throw InputMismatchException(recognizer);
212 bool DefaultErrorStrategy::singleTokenInsertion(Parser *recognizer) {
213 ssize_t currentSymbolType = recognizer->getInputStream()->LA(1);
215 // if current token is consistent with what could come after current
216 // ATN state, then we know we're missing a token; error recovery
217 // is free to conjure up and insert the missing token
218 atn::ATNState *currentState = recognizer->getInterpreter<atn::ATNSimulator>()->atn.states[recognizer->getState()];
219 atn::ATNState *next = currentState->transitions[0]->target;
220 const atn::ATN &atn = recognizer->getInterpreter<atn::ATNSimulator>()->atn;
221 misc::IntervalSet expectingAtLL2 = atn.nextTokens(next, recognizer->getContext());
222 if (expectingAtLL2.contains(currentSymbolType)) {
223 reportMissingToken(recognizer);
229 Token* DefaultErrorStrategy::singleTokenDeletion(Parser *recognizer) {
230 size_t nextTokenType = recognizer->getInputStream()->LA(2);
231 misc::IntervalSet expecting = getExpectedTokens(recognizer);
232 if (expecting.contains(nextTokenType)) {
233 reportUnwantedToken(recognizer);
234 recognizer->consume(); // simply delete extra token
235 // we want to return the token we're actually matching
236 Token *matchedSymbol = recognizer->getCurrentToken();
237 reportMatch(recognizer); // we know current token is correct
238 return matchedSymbol;
243 Token* DefaultErrorStrategy::getMissingSymbol(Parser *recognizer) {
244 Token *currentSymbol = recognizer->getCurrentToken();
245 misc::IntervalSet expecting = getExpectedTokens(recognizer);
246 size_t expectedTokenType = expecting.getMinElement(); // get any element
247 std::string tokenText;
248 if (expectedTokenType == Token::EOF) {
249 tokenText = "<missing EOF>";
251 tokenText = "<missing " + recognizer->getVocabulary().getDisplayName(expectedTokenType) + ">";
253 Token *current = currentSymbol;
254 Token *lookback = recognizer->getTokenStream()->LT(-1);
255 if (current->getType() == Token::EOF && lookback != nullptr) {
259 _errorSymbols.push_back(recognizer->getTokenFactory()->create(
260 { current->getTokenSource(), current->getTokenSource()->getInputStream() },
261 expectedTokenType, tokenText, Token::DEFAULT_CHANNEL, INVALID_INDEX, INVALID_INDEX,
262 current->getLine(), current->getCharPositionInLine()));
264 return _errorSymbols.back().get();
267 misc::IntervalSet DefaultErrorStrategy::getExpectedTokens(Parser *recognizer) {
268 return recognizer->getExpectedTokens();
271 std::string DefaultErrorStrategy::getTokenErrorDisplay(Token *t) {
275 std::string s = getSymbolText(t);
277 if (getSymbolType(t) == Token::EOF) {
280 s = "<" + std::to_string(getSymbolType(t)) + ">";
283 return escapeWSAndQuote(s);
286 std::string DefaultErrorStrategy::getSymbolText(Token *symbol) {
287 return symbol->getText();
290 size_t DefaultErrorStrategy::getSymbolType(Token *symbol) {
291 return symbol->getType();
294 std::string DefaultErrorStrategy::escapeWSAndQuote(const std::string &s) const {
295 std::string result = s;
296 antlrcpp::replaceAll(result, "\n", "\\n");
297 antlrcpp::replaceAll(result, "\r","\\r");
298 antlrcpp::replaceAll(result, "\t","\\t");
299 return "'" + result + "'";
302 misc::IntervalSet DefaultErrorStrategy::getErrorRecoverySet(Parser *recognizer) {
303 const atn::ATN &atn = recognizer->getInterpreter<atn::ATNSimulator>()->atn;
304 RuleContext *ctx = recognizer->getContext();
305 misc::IntervalSet recoverSet;
306 while (ctx->invokingState != ATNState::INVALID_STATE_NUMBER) {
307 // compute what follows who invoked us
308 atn::ATNState *invokingState = atn.states[ctx->invokingState];
309 atn::RuleTransition *rt = dynamic_cast<atn::RuleTransition*>(invokingState->transitions[0]);
310 misc::IntervalSet follow = atn.nextTokens(rt->followState);
311 recoverSet.addAll(follow);
313 if (ctx->parent == nullptr)
315 ctx = static_cast<RuleContext *>(ctx->parent);
317 recoverSet.remove(Token::EPSILON);
322 void DefaultErrorStrategy::consumeUntil(Parser *recognizer, const misc::IntervalSet &set) {
323 size_t ttype = recognizer->getInputStream()->LA(1);
324 while (ttype != Token::EOF && !set.contains(ttype)) {
325 recognizer->consume();
326 ttype = recognizer->getInputStream()->LA(1);
330 void DefaultErrorStrategy::InitializeInstanceFields() {
331 errorRecoveryMode = false;