aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/antlr4_cpp_runtime/src/DefaultErrorStrategy.h
blob: 7b914468cf5605915c08248fa53f45f5a8469b7a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
 * Use of this file is governed by the BSD 3-clause license that
 * can be found in the LICENSE.txt file in the project root.
 */

#pragma once

#include "ANTLRErrorStrategy.h"
#include "misc/IntervalSet.h"

namespace antlr4 {

  /**
   * This is the default implementation of {@link ANTLRErrorStrategy} used for
   * error reporting and recovery in ANTLR parsers.
   */
  class ANTLR4CPP_PUBLIC DefaultErrorStrategy : public ANTLRErrorStrategy {
  public:
    DefaultErrorStrategy();
    DefaultErrorStrategy(DefaultErrorStrategy const& other) = delete;
    virtual ~DefaultErrorStrategy();

    DefaultErrorStrategy& operator = (DefaultErrorStrategy const& other) = delete;

  protected:
    /**
     * Indicates whether the error strategy is currently "recovering from an
     * error". This is used to suppress reporting multiple error messages while
     * attempting to recover from a detected syntax error.
     *
     * @see #inErrorRecoveryMode
     */
    bool errorRecoveryMode;

    /** The index into the input stream where the last error occurred.
     * 	This is used to prevent infinite loops where an error is found
     *  but no token is consumed during recovery...another error is found,
     *  ad nauseum.  This is a failsafe mechanism to guarantee that at least
     *  one token/tree node is consumed for two errors.
     */
    int lastErrorIndex;

    misc::IntervalSet lastErrorStates;

    /// <summary>
    /// {@inheritDoc}
    /// <p/>
    /// The default implementation simply calls <seealso cref="#endErrorCondition"/> to
    /// ensure that the handler is not in error recovery mode.
    /// </summary>
  public:
    virtual void reset(Parser *recognizer) override;

    /// <summary>
    /// This method is called to enter error recovery mode when a recognition
    /// exception is reported.
    /// </summary>
    /// <param name="recognizer"> the parser instance </param>
  protected:
    virtual void beginErrorCondition(Parser *recognizer);

    /// <summary>
    /// {@inheritDoc}
    /// </summary>
  public:
    virtual bool inErrorRecoveryMode(Parser *recognizer) override;

    /// <summary>
    /// This method is called to leave error recovery mode after recovering from
    /// a recognition exception.
    /// </summary>
    /// <param name="recognizer"> </param>
  protected:
    virtual void endErrorCondition(Parser *recognizer);

    /// <summary>
    /// {@inheritDoc}
    /// <p/>
    /// The default implementation simply calls <seealso cref="#endErrorCondition"/>.
    /// </summary>
  public:
    virtual void reportMatch(Parser *recognizer) override;

    /// {@inheritDoc}
    /// <p/>
    /// The default implementation returns immediately if the handler is already
    /// in error recovery mode. Otherwise, it calls <seealso cref="#beginErrorCondition"/>
    /// and dispatches the reporting task based on the runtime type of {@code e}
    /// according to the following table.
    ///
    /// <ul>
    /// <li><seealso cref="NoViableAltException"/>: Dispatches the call to
    /// <seealso cref="#reportNoViableAlternative"/></li>
    /// <li><seealso cref="InputMismatchException"/>: Dispatches the call to
    /// <seealso cref="#reportInputMismatch"/></li>
    /// <li><seealso cref="FailedPredicateException"/>: Dispatches the call to
    /// <seealso cref="#reportFailedPredicate"/></li>
    /// <li>All other types: calls <seealso cref="Parser#notifyErrorListeners"/> to report
    /// the exception</li>
    /// </ul>
    virtual void reportError(Parser *recognizer, const RecognitionException &e) override;

    /// <summary>
    /// {@inheritDoc}
    /// <p/>
    /// The default implementation resynchronizes the parser by consuming tokens
    /// until we find one in the resynchronization set--loosely the set of tokens
    /// that can follow the current rule.
    /// </summary>
    virtual void recover(Parser *recognizer, std::exception_ptr e) override;

    /**
     * The default implementation of {@link ANTLRErrorStrategy#sync} makes sure
     * that the current lookahead symbol is consistent with what were expecting
     * at this point in the ATN. You can call this anytime but ANTLR only
     * generates code to check before subrules/loops and each iteration.
     *
     * <p>Implements Jim Idle's magic sync mechanism in closures and optional
     * subrules. E.g.,</p>
     *
     * <pre>
     * a : sync ( stuff sync )* ;
     * sync : {consume to what can follow sync} ;
     * </pre>
     *
     * At the start of a sub rule upon error, {@link #sync} performs single
     * token deletion, if possible. If it can't do that, it bails on the current
     * rule and uses the default error recovery, which consumes until the
     * resynchronization set of the current rule.
     *
     * <p>If the sub rule is optional ({@code (...)?}, {@code (...)*}, or block
     * with an empty alternative), then the expected set includes what follows
     * the subrule.</p>
     *
     * <p>During loop iteration, it consumes until it sees a token that can start a
     * sub rule or what follows loop. Yes, that is pretty aggressive. We opt to
     * stay in the loop as long as possible.</p>
     *
     * <p><strong>ORIGINS</strong></p>
     *
     * <p>Previous versions of ANTLR did a poor job of their recovery within loops.
     * A single mismatch token or missing token would force the parser to bail
     * out of the entire rules surrounding the loop. So, for rule</p>
     *
     * <pre>
     * classDef : 'class' ID '{' member* '}'
     * </pre>
     *
     * input with an extra token between members would force the parser to
     * consume until it found the next class definition rather than the next
     * member definition of the current class.
     *
     * <p>This functionality cost a little bit of effort because the parser has to
     * compare token set at the start of the loop and at each iteration. If for
     * some reason speed is suffering for you, you can turn off this
     * functionality by simply overriding this method as a blank { }.</p>
     */
    virtual void sync(Parser *recognizer) override;

    /// <summary>
    /// This is called by <seealso cref="#reportError"/> when the exception is a
    /// <seealso cref="NoViableAltException"/>.
    /// </summary>
    /// <seealso cref= #reportError
    /// </seealso>
    /// <param name="recognizer"> the parser instance </param>
    /// <param name="e"> the recognition exception </param>
  protected:
    virtual void reportNoViableAlternative(Parser *recognizer, const NoViableAltException &e);

    /// <summary>
    /// This is called by <seealso cref="#reportError"/> when the exception is an
    /// <seealso cref="InputMismatchException"/>.
    /// </summary>
    /// <seealso cref= #reportError
    /// </seealso>
    /// <param name="recognizer"> the parser instance </param>
    /// <param name="e"> the recognition exception </param>
    virtual void reportInputMismatch(Parser *recognizer, const InputMismatchException &e);

    /// <summary>
    /// This is called by <seealso cref="#reportError"/> when the exception is a
    /// <seealso cref="FailedPredicateException"/>.
    /// </summary>
    /// <seealso cref= #reportError
    /// </seealso>
    /// <param name="recognizer"> the parser instance </param>
    /// <param name="e"> the recognition exception </param>
    virtual void reportFailedPredicate(Parser *recognizer, const FailedPredicateException &e);

    /**
     * This method is called to report a syntax error which requires the removal
     * of a token from the input stream. At the time this method is called, the
     * erroneous symbol is current {@code LT(1)} symbol and has not yet been
     * removed from the input stream. When this method returns,
     * {@code recognizer} is in error recovery mode.
     *
     * <p>This method is called when {@link #singleTokenDeletion} identifies
     * single-token deletion as a viable recovery strategy for a mismatched
     * input error.</p>
     *
     * <p>The default implementation simply returns if the handler is already in
     * error recovery mode. Otherwise, it calls {@link #beginErrorCondition} to
     * enter error recovery mode, followed by calling
     * {@link Parser#notifyErrorListeners}.</p>
     *
     * @param recognizer the parser instance
     */
    virtual void reportUnwantedToken(Parser *recognizer);

    /**
     * This method is called to report a syntax error which requires the
     * insertion of a missing token into the input stream. At the time this
     * method is called, the missing token has not yet been inserted. When this
     * method returns, {@code recognizer} is in error recovery mode.
     *
     * <p>This method is called when {@link #singleTokenInsertion} identifies
     * single-token insertion as a viable recovery strategy for a mismatched
     * input error.</p>
     *
     * <p>The default implementation simply returns if the handler is already in
     * error recovery mode. Otherwise, it calls {@link #beginErrorCondition} to
     * enter error recovery mode, followed by calling
     * {@link Parser#notifyErrorListeners}.</p>
     *
     * @param recognizer the parser instance
     */
    virtual void reportMissingToken(Parser *recognizer);

  public:
    /**
     * {@inheritDoc}
     *
     * <p>The default implementation attempts to recover from the mismatched input
     * by using single token insertion and deletion as described below. If the
     * recovery attempt fails, this method throws an
     * {@link InputMismatchException}.</p>
     *
     * <p><strong>EXTRA TOKEN</strong> (single token deletion)</p>
     *
     * <p>{@code LA(1)} is not what we are looking for. If {@code LA(2)} has the
     * right token, however, then assume {@code LA(1)} is some extra spurious
     * token and delete it. Then consume and return the next token (which was
     * the {@code LA(2)} token) as the successful result of the match operation.</p>
     *
     * <p>This recovery strategy is implemented by {@link #singleTokenDeletion}.</p>
     *
     * <p><strong>MISSING TOKEN</strong> (single token insertion)</p>
     *
     * <p>If current token (at {@code LA(1)}) is consistent with what could come
     * after the expected {@code LA(1)} token, then assume the token is missing
     * and use the parser's {@link TokenFactory} to create it on the fly. The
     * "insertion" is performed by returning the created token as the successful
     * result of the match operation.</p>
     *
     * <p>This recovery strategy is implemented by {@link #singleTokenInsertion}.</p>
     *
     * <p><strong>EXAMPLE</strong></p>
     *
     * <p>For example, Input {@code i=(3;} is clearly missing the {@code ')'}. When
     * the parser returns from the nested call to {@code expr}, it will have
     * call chain:</p>
     *
     * <pre>
     * stat &rarr; expr &rarr; atom
     * </pre>
     *
     * and it will be trying to match the {@code ')'} at this point in the
     * derivation:
     *
     * <pre>
     * =&gt; ID '=' '(' INT ')' ('+' atom)* ';'
     *                    ^
     * </pre>
     *
     * The attempt to match {@code ')'} will fail when it sees {@code ';'} and
     * call {@link #recoverInline}. To recover, it sees that {@code LA(1)==';'}
     * is in the set of tokens that can follow the {@code ')'} token reference
     * in rule {@code atom}. It can assume that you forgot the {@code ')'}.
     */
    virtual Token* recoverInline(Parser *recognizer) override;

    /// <summary>
    /// This method implements the single-token insertion inline error recovery
    /// strategy. It is called by <seealso cref="#recoverInline"/> if the single-token
    /// deletion strategy fails to recover from the mismatched input. If this
    /// method returns {@code true}, {@code recognizer} will be in error recovery
    /// mode.
    /// <p/>
    /// This method determines whether or not single-token insertion is viable by
    /// checking if the {@code LA(1)} input symbol could be successfully matched
    /// if it were instead the {@code LA(2)} symbol. If this method returns
    /// {@code true}, the caller is responsible for creating and inserting a
    /// token with the correct type to produce this behavior.
    /// </summary>
    /// <param name="recognizer"> the parser instance </param>
    /// <returns> {@code true} if single-token insertion is a viable recovery
    /// strategy for the current mismatched input, otherwise {@code false} </returns>
  protected:
    virtual bool singleTokenInsertion(Parser *recognizer);

    /// <summary>
    /// This method implements the single-token deletion inline error recovery
    /// strategy. It is called by <seealso cref="#recoverInline"/> to attempt to recover
    /// from mismatched input. If this method returns null, the parser and error
    /// handler state will not have changed. If this method returns non-null,
    /// {@code recognizer} will <em>not</em> be in error recovery mode since the
    /// returned token was a successful match.
    /// <p/>
    /// If the single-token deletion is successful, this method calls
    /// <seealso cref="#reportUnwantedToken"/> to report the error, followed by
    /// <seealso cref="Parser#consume"/> to actually "delete" the extraneous token. Then,
    /// before returning <seealso cref="#reportMatch"/> is called to signal a successful
    /// match.
    /// </summary>
    /// <param name="recognizer"> the parser instance </param>
    /// <returns> the successfully matched <seealso cref="Token"/> instance if single-token
    /// deletion successfully recovers from the mismatched input, otherwise
    /// {@code null} </returns>
    virtual Token* singleTokenDeletion(Parser *recognizer);

    /// <summary>
    /// Conjure up a missing token during error recovery.
    ///
    ///  The recognizer attempts to recover from single missing
    ///  symbols. But, actions might refer to that missing symbol.
    ///  For example, x=ID {f($x);}. The action clearly assumes
    ///  that there has been an identifier matched previously and that
    ///  $x points at that token. If that token is missing, but
    ///  the next token in the stream is what we want we assume that
    ///  this token is missing and we keep going. Because we
    ///  have to return some token to replace the missing token,
    ///  we have to conjure one up. This method gives the user control
    ///  over the tokens returned for missing tokens. Mostly,
    ///  you will want to create something special for identifier
    ///  tokens. For literals such as '{' and ',', the default
    ///  action in the parser or tree parser works. It simply creates
    ///  a CommonToken of the appropriate type. The text will be the token.
    ///  If you change what tokens must be created by the lexer,
    ///  override this method to create the appropriate tokens.
    /// </summary>
    virtual Token* getMissingSymbol(Parser *recognizer);

    virtual misc::IntervalSet getExpectedTokens(Parser *recognizer);

    /// <summary>
    /// How should a token be displayed in an error message? The default
    ///  is to display just the text, but during development you might
    ///  want to have a lot of information spit out.  Override in that case
    ///  to use t.toString() (which, for CommonToken, dumps everything about
    ///  the token). This is better than forcing you to override a method in
    ///  your token objects because you don't have to go modify your lexer
    ///  so that it creates a new class.
    /// </summary>
    virtual std::string getTokenErrorDisplay(Token *t);

    virtual std::string getSymbolText(Token *symbol);

    virtual size_t getSymbolType(Token *symbol);

    virtual std::string escapeWSAndQuote(const std::string &s) const;

    /*  Compute the error recovery set for the current rule.  During
     *  rule invocation, the parser pushes the set of tokens that can
     *  follow that rule reference on the stack; this amounts to
     *  computing FIRST of what follows the rule reference in the
     *  enclosing rule. See LinearApproximator.FIRST().
     *  This local follow set only includes tokens
     *  from within the rule; i.e., the FIRST computation done by
     *  ANTLR stops at the end of a rule.
     *
     *  EXAMPLE
     *
     *  When you find a "no viable alt exception", the input is not
     *  consistent with any of the alternatives for rule r.  The best
     *  thing to do is to consume tokens until you see something that
     *  can legally follow a call to r *or* any rule that called r.
     *  You don't want the exact set of viable next tokens because the
     *  input might just be missing a token--you might consume the
     *  rest of the input looking for one of the missing tokens.
     *
     *  Consider grammar:
     *
     *  a : '[' b ']'
     *    | '(' b ')'
     *    ;
     *  b : c '^' INT ;
     *  c : ID
     *    | INT
     *    ;
     *
     *  At each rule invocation, the set of tokens that could follow
     *  that rule is pushed on a stack.  Here are the various
     *  context-sensitive follow sets:
     *
     *  FOLLOW(b1_in_a) = FIRST(']') = ']'
     *  FOLLOW(b2_in_a) = FIRST(')') = ')'
     *  FOLLOW(c_in_b) = FIRST('^') = '^'
     *
     *  Upon erroneous input "[]", the call chain is
     *
     *  a -> b -> c
     *
     *  and, hence, the follow context stack is:
     *
     *  depth     follow set       start of rule execution
     *    0         <EOF>                    a (from main())
     *    1          ']'                     b
     *    2          '^'                     c
     *
     *  Notice that ')' is not included, because b would have to have
     *  been called from a different context in rule a for ')' to be
     *  included.
     *
     *  For error recovery, we cannot consider FOLLOW(c)
     *  (context-sensitive or otherwise).  We need the combined set of
     *  all context-sensitive FOLLOW sets--the set of all tokens that
     *  could follow any reference in the call chain.  We need to
     *  resync to one of those tokens.  Note that FOLLOW(c)='^' and if
     *  we resync'd to that token, we'd consume until EOF.  We need to
     *  sync to context-sensitive FOLLOWs for a, b, and c: {']','^'}.
     *  In this case, for input "[]", LA(1) is ']' and in the set, so we would
     *  not consume anything. After printing an error, rule c would
     *  return normally.  Rule b would not find the required '^' though.
     *  At this point, it gets a mismatched token error and throws an
     *  exception (since LA(1) is not in the viable following token
     *  set).  The rule exception handler tries to recover, but finds
     *  the same recovery set and doesn't consume anything.  Rule b
     *  exits normally returning to rule a.  Now it finds the ']' (and
     *  with the successful match exits errorRecovery mode).
     *
     *  So, you can see that the parser walks up the call chain looking
     *  for the token that was a member of the recovery set.
     *
     *  Errors are not generated in errorRecovery mode.
     *
     *  ANTLR's error recovery mechanism is based upon original ideas:
     *
     *  "Algorithms + Data Structures = Programs" by Niklaus Wirth
     *
     *  and
     *
     *  "A note on error recovery in recursive descent parsers":
     *  http://portal.acm.org/citation.cfm?id=947902.947905
     *
     *  Later, Josef Grosch had some good ideas:
     *
     *  "Efficient and Comfortable Error Recovery in Recursive Descent
     *  Parsers":
     *  ftp://www.cocolab.com/products/cocktail/doca4.ps/ell.ps.zip
     *
     *  Like Grosch I implement context-sensitive FOLLOW sets that are combined
     *  at run-time upon error to avoid overhead during parsing.
     */
    virtual misc::IntervalSet getErrorRecoverySet(Parser *recognizer);

    /// <summary>
    /// Consume tokens until one matches the given token set. </summary>
    virtual void consumeUntil(Parser *recognizer, const misc::IntervalSet &set);

  private:
    std::vector<std::unique_ptr<Token>> _errorSymbols; // Temporarily created token.
    void InitializeInstanceFields();
  };

} // namespace antlr4