Skip to main content

antlr4_runtime/
parser.rs

1use std::collections::{BTreeMap, BTreeSet};
2
3use crate::atn::{Atn, AtnState, AtnStateKind, Transition};
4use crate::errors::AntlrError;
5use crate::int_stream::IntStream;
6use crate::recognizer::{Recognizer, RecognizerData};
7use crate::token::{CommonToken, TOKEN_EOF, Token, TokenSource, TokenSourceError};
8use crate::token_stream::CommonTokenStream;
9use crate::tree::{ErrorNode, ParseTree, ParserRuleContext, RuleNode, TerminalNode};
10use crate::vocabulary::Vocabulary;
11
12/// Upper bound for the recursive metadata recognizer before it treats a path as
13/// non-viable. Long expression-regression descriptors legitimately walk tens
14/// of thousands of ATN edges.
15const RECOGNITION_DEPTH_LIMIT: usize = 100_000;
16
17/// Parser semantic action reached while recognizing one ATN path.
18///
19/// Generated parsers use `source_state` to dispatch back to the grammar action
20/// rendered for that ATN action transition. The token interval is the current
21/// rule's input span at the action site, which covers common target templates
22/// such as `$text`. Rule-init actions do not have an ATN action source state,
23/// so they are marked separately and may carry an ATN state for expected-token
24/// rendering.
25#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
26pub struct ParserAction {
27    source_state: usize,
28    rule_index: usize,
29    start_index: usize,
30    stop_index: Option<usize>,
31    rule_init: bool,
32    expected_state: Option<usize>,
33}
34
35impl ParserAction {
36    /// Creates an action event for a recognized parser path.
37    pub const fn new(
38        source_state: usize,
39        rule_index: usize,
40        start_index: usize,
41        stop_index: Option<usize>,
42    ) -> Self {
43        Self {
44            source_state,
45            rule_index,
46            start_index,
47            stop_index,
48            rule_init: false,
49            expected_state: None,
50        }
51    }
52
53    /// Creates an action event for a rule-level `@init` action.
54    pub const fn new_rule_init(
55        rule_index: usize,
56        start_index: usize,
57        expected_state: Option<usize>,
58    ) -> Self {
59        Self {
60            source_state: usize::MAX,
61            rule_index,
62            start_index,
63            stop_index: None,
64            rule_init: true,
65            expected_state,
66        }
67    }
68
69    /// ATN state that owns the semantic-action transition.
70    pub const fn source_state(&self) -> usize {
71        self.source_state
72    }
73
74    /// Grammar rule index recorded by the serialized ATN action transition.
75    pub const fn rule_index(&self) -> usize {
76        self.rule_index
77    }
78
79    /// Token-stream index where the active rule began.
80    pub const fn start_index(&self) -> usize {
81        self.start_index
82    }
83
84    /// Last token-stream index consumed before the action was reached.
85    pub const fn stop_index(&self) -> Option<usize> {
86        self.stop_index
87    }
88
89    /// Reports whether this event represents a rule-level `@init` action.
90    pub const fn is_rule_init(&self) -> bool {
91        self.rule_init
92    }
93
94    /// ATN state used to compute expected-token display for this action.
95    pub const fn expected_state(&self) -> Option<usize> {
96        self.expected_state
97    }
98}
99
100/// Parser semantic predicate rendered from a supported target template.
101///
102/// The metadata recognizer evaluates these at the token-stream index where the
103/// predicate transition is reached. Unsupported or absent predicate templates
104/// remain unconditional so existing generated parsers keep their previous
105/// behavior unless the generator opts into this table.
106#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
107pub enum ParserPredicate {
108    True,
109    False,
110    /// Predicate that always fails and carries ANTLR's `<fail='...'>` message.
111    FalseWithMessage {
112        message: &'static str,
113    },
114    /// Target-template test helper that reports predicate evaluation before
115    /// returning the wrapped boolean value.
116    Invoke {
117        value: bool,
118    },
119    LookaheadTextEquals {
120        offset: isize,
121        text: &'static str,
122    },
123    LookaheadNotEquals {
124        offset: isize,
125        token_type: i32,
126    },
127    /// Compares the current rule invocation's integer argument with a literal
128    /// value from a supported `ValEquals("$i", "...")` target template.
129    LocalIntEquals {
130        value: i64,
131    },
132    /// Checks ANTLR-style raw predicates like `5 >= $_p` against the current
133    /// rule invocation's integer argument.
134    LocalIntLessOrEqual {
135        value: i64,
136    },
137    /// Compares a generated parser integer member modulo a literal value.
138    MemberModuloEquals {
139        member: usize,
140        modulus: i64,
141        value: i64,
142        equals: bool,
143    },
144}
145
146/// Prediction strategy requested by generated parser harnesses.
147#[derive(Clone, Copy, Debug, Eq, PartialEq)]
148pub enum PredictionMode {
149    /// Prefer the clean full-context outcome when alternatives reach the same
150    /// input position.
151    Ll,
152    /// Preserve SLL's first-viable alternative bias at a decision, even when a
153    /// later full-context alternative could avoid recovery.
154    Sll,
155}
156
157/// Integer argument metadata for a generated parser rule invocation.
158///
159/// ANTLR's serialized ATN does not retain Rust-target rule argument values, so
160/// the generator records the rule-transition source state and the value that
161/// should be visible to semantic predicates inside the callee.
162#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
163pub struct ParserRuleArg {
164    /// ATN state containing the rule transition that receives this argument.
165    pub source_state: usize,
166    /// Callee rule index for the transition.
167    pub rule_index: usize,
168    /// Literal fallback value to expose in the callee.
169    pub value: i64,
170    /// Whether the callee should inherit the caller's current integer argument.
171    pub inherit_local: bool,
172}
173
174/// Integer member mutation attached to an ATN action transition.
175#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
176pub struct ParserMemberAction {
177    /// ATN state containing the action transition.
178    pub source_state: usize,
179    /// Generator-assigned integer member id.
180    pub member: usize,
181    /// Delta applied when the action is reached on one speculative path.
182    pub delta: i64,
183}
184
185/// Integer return-value assignment attached to an ATN action transition.
186///
187/// Generated parsers use this metadata when target actions assign a simple
188/// return field such as `$y=1000;`. The interpreter applies it while selecting
189/// the recognized path so the finished parse tree can answer later
190/// `$label.y` action templates.
191#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
192pub struct ParserReturnAction {
193    /// ATN state containing the action transition.
194    pub source_state: usize,
195    /// Rule index recorded by the serialized action transition.
196    pub rule_index: usize,
197    /// Return-field name as it appears in the grammar.
198    pub name: &'static str,
199    /// Literal integer value assigned by the action.
200    pub value: i64,
201}
202
203/// Optional generated-runtime metadata for metadata-driven parser execution.
204#[derive(Clone, Copy, Debug, Default)]
205pub struct ParserRuntimeOptions<'a> {
206    /// Rule indexes whose `@init` actions should be replayed.
207    pub init_action_rules: &'a [usize],
208    /// Whether generated parse-tree contexts should retain alternative numbers.
209    pub track_alt_numbers: bool,
210    /// Semantic predicate table keyed by serialized `(rule_index, pred_index)`.
211    pub predicates: &'a [(usize, usize, ParserPredicate)],
212    /// Rule-call integer argument table keyed by ATN source state.
213    pub rule_args: &'a [ParserRuleArg],
214    /// Integer member mutations keyed by ATN action source state.
215    pub member_actions: &'a [ParserMemberAction],
216    /// Integer return assignments keyed by ATN action source state.
217    pub return_actions: &'a [ParserReturnAction],
218}
219
220pub trait Parser: Recognizer {
221    /// Reports whether generated parser rules should build parse-tree nodes
222    /// while recognizing input.
223    fn build_parse_trees(&self) -> bool;
224
225    /// Enables or disables parse-tree construction for subsequent rule calls.
226    fn set_build_parse_trees(&mut self, build: bool);
227
228    /// Reports whether prediction diagnostic-listener messages are emitted
229    /// during parser ATN recognition.
230    fn report_diagnostic_errors(&self) -> bool {
231        false
232    }
233
234    /// Enables or disables ANTLR-style prediction diagnostics for subsequent
235    /// rule calls.
236    fn set_report_diagnostic_errors(&mut self, _report: bool) {}
237
238    /// Reports the prediction strategy used when selecting among alternatives.
239    fn prediction_mode(&self) -> PredictionMode {
240        PredictionMode::Ll
241    }
242
243    /// Sets the prediction strategy for subsequent rule calls.
244    fn set_prediction_mode(&mut self, _mode: PredictionMode) {}
245}
246
247#[derive(Debug)]
248pub struct BaseParser<S> {
249    input: CommonTokenStream<S>,
250    data: RecognizerData,
251    build_parse_trees: bool,
252    report_diagnostic_errors: bool,
253    prediction_mode: PredictionMode,
254    prediction_diagnostics: Vec<ParserDiagnostic>,
255    reported_prediction_diagnostics: BTreeSet<(usize, usize, String)>,
256    int_members: BTreeMap<usize, i64>,
257    /// Predicate side effects are observable in a few target-template tests;
258    /// speculative recognition may revisit the same coordinate, so replay it
259    /// once per parser instance.
260    invoked_predicates: Vec<(usize, usize)>,
261}
262
263#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
264struct RecognizeOutcome {
265    index: usize,
266    consumed_eof: bool,
267    alt_number: usize,
268    member_values: BTreeMap<usize, i64>,
269    return_values: BTreeMap<String, i64>,
270    diagnostics: Vec<ParserDiagnostic>,
271    decisions: Vec<usize>,
272    actions: Vec<ParserAction>,
273    nodes: Vec<RecognizedNode>,
274}
275
276#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
277enum RecognizedNode {
278    Token {
279        index: usize,
280    },
281    ErrorToken {
282        index: usize,
283    },
284    MissingToken {
285        token_type: i32,
286        at_index: usize,
287        text: String,
288    },
289    Rule {
290        rule_index: usize,
291        invoking_state: isize,
292        alt_number: usize,
293        start_index: usize,
294        stop_index: Option<usize>,
295        return_values: BTreeMap<String, i64>,
296        children: Vec<Self>,
297    },
298    LeftRecursiveBoundary {
299        rule_index: usize,
300    },
301}
302
303#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
304struct FastRecognizeOutcome {
305    index: usize,
306    consumed_eof: bool,
307    diagnostics: Vec<ParserDiagnostic>,
308}
309
310#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
311struct ParserDiagnostic {
312    line: usize,
313    column: usize,
314    message: String,
315}
316
317#[derive(Clone, Debug, Default, Eq, PartialEq)]
318struct ExpectedTokens {
319    index: Option<usize>,
320    symbols: BTreeSet<i32>,
321    no_viable: Option<NoViableAlternative>,
322}
323
324#[derive(Clone, Copy, Debug, Eq, PartialEq)]
325struct NoViableAlternative {
326    start_index: usize,
327    error_index: usize,
328}
329
330impl ExpectedTokens {
331    /// Records the expected symbols for the farthest token index reached by any
332    /// failed ATN path.
333    fn record_transition(&mut self, index: usize, transition: &Transition, max_token_type: i32) {
334        let symbols = transition_expected_symbols(transition, max_token_type);
335        match self.index {
336            Some(current) if index < current => {}
337            Some(current) if index == current => self.symbols.extend(symbols),
338            _ => {
339                self.index = Some(index);
340                self.symbols = symbols;
341            }
342        }
343    }
344
345    /// Records an ambiguous decision that failed after consuming a shared
346    /// prefix, which ANTLR reports as `no viable alternative`.
347    const fn record_no_viable(&mut self, start_index: usize, error_index: usize) {
348        match self.no_viable {
349            Some(current) if error_index < current.error_index => {}
350            _ => {
351                self.no_viable = Some(NoViableAlternative {
352                    start_index,
353                    error_index,
354                });
355            }
356        }
357    }
358}
359
360/// Converts one consuming transition into the token types that would satisfy it
361/// for diagnostic reporting.
362fn transition_expected_symbols(transition: &Transition, max_token_type: i32) -> BTreeSet<i32> {
363    let mut symbols = BTreeSet::new();
364    match transition {
365        Transition::Atom { label, .. } => {
366            symbols.insert(*label);
367        }
368        Transition::Range { start, stop, .. } => {
369            symbols.extend(*start..=*stop);
370        }
371        Transition::Set { set, .. } => {
372            for (start, stop) in set.ranges() {
373                symbols.extend(*start..=*stop);
374            }
375        }
376        Transition::NotSet { set, .. } => {
377            symbols.extend((1..=max_token_type).filter(|symbol| !set.contains(*symbol)));
378        }
379        Transition::Wildcard { .. } => {
380            symbols.extend(1..=max_token_type);
381        }
382        Transition::Epsilon { .. }
383        | Transition::Rule { .. }
384        | Transition::Predicate { .. }
385        | Transition::Action { .. }
386        | Transition::Precedence { .. } => {}
387    }
388    symbols
389}
390
391/// Returns the consuming-token expectations reachable from an ATN state through
392/// epsilon transitions. Recovery diagnostics need this closure so alternatives
393/// and loop exits report the same expectation set ANTLR users see.
394fn state_expected_symbols(atn: &Atn, state_number: usize) -> BTreeSet<i32> {
395    let mut symbols = BTreeSet::new();
396    let mut stack = vec![state_number];
397    let mut visited = BTreeSet::new();
398    while let Some(current) = stack.pop() {
399        if !visited.insert(current) {
400            continue;
401        }
402        let Some(state) = atn.state(current) else {
403            continue;
404        };
405        for transition in &state.transitions {
406            let transition_symbols = transition_expected_symbols(transition, atn.max_token_type());
407            if transition_symbols.is_empty() {
408                if transition.is_epsilon() {
409                    stack.push(transition.target());
410                }
411            } else {
412                symbols.extend(transition_symbols);
413            }
414        }
415    }
416    symbols
417}
418
419/// Returns token types that can resume parsing from `state_number` after a
420/// failed child rule, following rule calls as well as epsilon transitions.
421fn state_sync_symbols(atn: &Atn, state_number: usize, stop_state: usize) -> BTreeSet<i32> {
422    let mut symbols = BTreeSet::new();
423    state_sync_symbols_inner(
424        atn,
425        state_number,
426        stop_state,
427        &mut BTreeSet::new(),
428        &mut symbols,
429    );
430    symbols
431}
432
433/// Walks epsilon-like continuations from a parent follow state until it finds
434/// consuming tokens that can anchor recovery, or EOF if the parent rule can end.
435fn state_sync_symbols_inner(
436    atn: &Atn,
437    state_number: usize,
438    stop_state: usize,
439    visited: &mut BTreeSet<usize>,
440    symbols: &mut BTreeSet<i32>,
441) {
442    if !visited.insert(state_number) {
443        return;
444    }
445    if state_number == stop_state {
446        symbols.insert(TOKEN_EOF);
447        return;
448    }
449    let Some(state) = atn.state(state_number) else {
450        return;
451    };
452    for transition in &state.transitions {
453        let transition_symbols = transition_expected_symbols(transition, atn.max_token_type());
454        if transition_symbols.is_empty() {
455            match transition {
456                Transition::Rule { target, .. }
457                | Transition::Epsilon { target }
458                | Transition::Action { target, .. }
459                | Transition::Predicate { target, .. }
460                | Transition::Precedence { target, .. } => {
461                    state_sync_symbols_inner(atn, *target, stop_state, visited, symbols);
462                }
463                Transition::Atom { .. }
464                | Transition::Range { .. }
465                | Transition::Set { .. }
466                | Transition::NotSet { .. }
467                | Transition::Wildcard { .. } => {}
468            }
469        } else {
470            symbols.extend(transition_symbols);
471        }
472    }
473}
474
475/// Carries recovery expectations and their restart state through epsilon-only
476/// paths. ANTLR can report and repair at the decision state even when the
477/// failed consuming transition is nested under block or loop epsilon edges.
478fn next_recovery_context(
479    atn: &Atn,
480    state: &AtnState,
481    inherited: &BTreeSet<i32>,
482    inherited_state: Option<usize>,
483) -> (BTreeSet<i32>, Option<usize>) {
484    let state_symbols = state_expected_symbols(atn, state.state_number);
485    if state.transitions.len() > 1 && !state_symbols.is_empty() {
486        let mut symbols = state_symbols;
487        symbols.extend(inherited.iter().copied());
488        return (symbols, Some(state.state_number));
489    }
490    (inherited.clone(), inherited_state)
491}
492
493fn recovery_expected_symbols(
494    atn: &Atn,
495    state_number: usize,
496    inherited: &BTreeSet<i32>,
497) -> BTreeSet<i32> {
498    let mut symbols = state_expected_symbols(atn, state_number);
499    symbols.extend(inherited.iter().copied());
500    symbols
501}
502
503/// Applies generated integer-member side effects to one speculative path.
504fn apply_member_actions(
505    source_state: usize,
506    actions: &[ParserMemberAction],
507    values: &mut BTreeMap<usize, i64>,
508) {
509    for action in actions
510        .iter()
511        .filter(|action| action.source_state == source_state)
512    {
513        *values.entry(action.member).or_default() += action.delta;
514    }
515}
516
517/// Returns the speculative member state after replaying one ATN action state.
518fn member_values_after_action(
519    source_state: usize,
520    actions: &[ParserMemberAction],
521    values: &BTreeMap<usize, i64>,
522) -> BTreeMap<usize, i64> {
523    let mut values = values.clone();
524    apply_member_actions(source_state, actions, &mut values);
525    values
526}
527
528/// Returns the speculative rule-return state after replaying one ATN action.
529fn return_values_after_action(
530    source_state: usize,
531    rule_index: usize,
532    actions: &[ParserReturnAction],
533    values: &BTreeMap<String, i64>,
534) -> BTreeMap<String, i64> {
535    let mut values = values.clone();
536    for action in actions
537        .iter()
538        .filter(|action| action.source_state == source_state && action.rule_index == rule_index)
539    {
540        values.insert(action.name.to_owned(), action.value);
541    }
542    values
543}
544
545/// Resolves the integer argument visible to a child rule invocation.
546fn rule_local_int_arg(
547    rule_args: &[ParserRuleArg],
548    source_state: usize,
549    rule_index: usize,
550    local_int_arg: Option<(usize, i64)>,
551) -> Option<(usize, i64)> {
552    rule_args
553        .iter()
554        .find(|arg| arg.source_state == source_state && arg.rule_index == rule_index)
555        .map(|arg| {
556            let value = if arg.inherit_local {
557                local_int_arg.map_or(arg.value, |(_, value)| value)
558            } else {
559                arg.value
560            };
561            (rule_index, value)
562        })
563}
564
565/// Builds the terminal recognition outcome for a path that reached its stop
566/// state.
567fn stop_outcome(
568    index: usize,
569    consumed_eof: bool,
570    rule_alt_number: usize,
571    member_values: BTreeMap<usize, i64>,
572    return_values: BTreeMap<String, i64>,
573) -> Vec<RecognizeOutcome> {
574    vec![RecognizeOutcome {
575        index,
576        consumed_eof,
577        alt_number: rule_alt_number,
578        member_values,
579        return_values,
580        diagnostics: Vec::new(),
581        decisions: Vec::new(),
582        actions: Vec::new(),
583        nodes: Vec::new(),
584    }]
585}
586
587#[derive(Clone, Debug, Eq, PartialEq)]
588struct RecognizeRequest<'a> {
589    state_number: usize,
590    stop_state: usize,
591    index: usize,
592    rule_start_index: usize,
593    decision_start_index: Option<usize>,
594    init_action_rules: &'a BTreeSet<usize>,
595    predicates: &'a [(usize, usize, ParserPredicate)],
596    rule_args: &'a [ParserRuleArg],
597    member_actions: &'a [ParserMemberAction],
598    return_actions: &'a [ParserReturnAction],
599    local_int_arg: Option<(usize, i64)>,
600    member_values: BTreeMap<usize, i64>,
601    return_values: BTreeMap<String, i64>,
602    rule_alt_number: usize,
603    track_alt_numbers: bool,
604    consumed_eof: bool,
605    /// Current left-recursive precedence threshold, matching ANTLR's
606    /// `precpred(_ctx, k)` check for generated precedence rules.
607    precedence: i32,
608    depth: usize,
609    recovery_symbols: BTreeSet<i32>,
610    recovery_state: Option<usize>,
611}
612
613#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
614struct RecognizeKey {
615    state_number: usize,
616    stop_state: usize,
617    index: usize,
618    rule_start_index: usize,
619    decision_start_index: Option<usize>,
620    local_int_arg: Option<(usize, i64)>,
621    member_values: BTreeMap<usize, i64>,
622    return_values: BTreeMap<String, i64>,
623    rule_alt_number: usize,
624    track_alt_numbers: bool,
625    consumed_eof: bool,
626    precedence: i32,
627    recovery_symbols: BTreeSet<i32>,
628    recovery_state: Option<usize>,
629}
630
631#[derive(Clone, Debug, Eq, PartialEq)]
632struct EpsilonActionStep {
633    source_state: usize,
634    target: usize,
635    action_rule_index: Option<usize>,
636    left_recursive_boundary: Option<usize>,
637    decision: Option<usize>,
638    decision_start_index: Option<usize>,
639    alt_number: usize,
640    recovery_symbols: BTreeSet<i32>,
641    recovery_state: Option<usize>,
642}
643
644struct RecognizeScratch<'a> {
645    visiting: &'a mut BTreeSet<RecognizeKey>,
646    memo: &'a mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
647    expected: &'a mut ExpectedTokens,
648}
649
650#[derive(Clone, Debug, Eq, PartialEq)]
651struct FastRecognizeRequest {
652    state_number: usize,
653    stop_state: usize,
654    index: usize,
655    rule_start_index: usize,
656    decision_start_index: Option<usize>,
657    precedence: i32,
658    depth: usize,
659    recovery_symbols: BTreeSet<i32>,
660    recovery_state: Option<usize>,
661}
662
663#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
664struct FastRecognizeKey {
665    state_number: usize,
666    stop_state: usize,
667    index: usize,
668    rule_start_index: usize,
669    decision_start_index: Option<usize>,
670    precedence: i32,
671    recovery_symbols: BTreeSet<i32>,
672    recovery_state: Option<usize>,
673}
674
675struct FastRecoveryRequest<'a, 'b> {
676    atn: &'a Atn,
677    transition: &'a Transition,
678    expected_symbols: BTreeSet<i32>,
679    target: usize,
680    request: FastRecognizeRequest,
681    visiting: &'b mut BTreeSet<FastRecognizeKey>,
682    memo: &'b mut BTreeMap<FastRecognizeKey, Vec<FastRecognizeOutcome>>,
683    expected: &'b mut ExpectedTokens,
684}
685
686struct FastCurrentTokenDeletionRequest<'a, 'b> {
687    atn: &'a Atn,
688    expected_symbols: BTreeSet<i32>,
689    request: FastRecognizeRequest,
690    visiting: &'b mut BTreeSet<FastRecognizeKey>,
691    memo: &'b mut BTreeMap<FastRecognizeKey, Vec<FastRecognizeOutcome>>,
692    expected: &'b mut ExpectedTokens,
693}
694
695struct RecoveryRequest<'a, 'b> {
696    atn: &'a Atn,
697    transition: &'a Transition,
698    expected_symbols: BTreeSet<i32>,
699    target: usize,
700    request: RecognizeRequest<'a>,
701    visiting: &'b mut BTreeSet<RecognizeKey>,
702    memo: &'b mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
703    expected: &'b mut ExpectedTokens,
704}
705
706struct CurrentTokenDeletionRequest<'a, 'b> {
707    atn: &'a Atn,
708    expected_symbols: BTreeSet<i32>,
709    request: RecognizeRequest<'a>,
710    visiting: &'b mut BTreeSet<RecognizeKey>,
711    memo: &'b mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
712    expected: &'b mut ExpectedTokens,
713}
714
715/// Carries the state needed after the normal token-recovery strategies fail
716/// for a consuming transition.
717struct ConsumingFailureFallback<'a> {
718    atn: &'a Atn,
719    target: usize,
720    request: RecognizeRequest<'a>,
721    symbol: i32,
722    expected_symbols: BTreeSet<i32>,
723    decision_start_index: Option<usize>,
724    decision: Option<usize>,
725}
726
727/// Captures the parent-rule context needed when a called rule fails before it
728/// can produce a normal outcome.
729struct ChildRuleFailureRecovery<'a> {
730    atn: &'a Atn,
731    rule_index: usize,
732    start_index: usize,
733    follow_state: usize,
734    stop_state: usize,
735    member_values: BTreeMap<usize, i64>,
736    expected: &'a ExpectedTokens,
737}
738
739/// Bundles the context needed to evaluate one semantic predicate transition.
740#[derive(Clone, Copy, Debug)]
741struct PredicateEval<'a> {
742    index: usize,
743    rule_index: usize,
744    pred_index: usize,
745    predicates: &'a [(usize, usize, ParserPredicate)],
746    local_int_arg: Option<(usize, i64)>,
747    member_values: &'a BTreeMap<usize, i64>,
748}
749
750/// Captures predicate-failure recovery metadata for fail-option predicates.
751struct PredicateFailureRecovery<'a> {
752    rule_index: usize,
753    index: usize,
754    message: &'a str,
755    member_values: BTreeMap<usize, i64>,
756    return_values: BTreeMap<String, i64>,
757    rule_alt_number: usize,
758}
759
760impl<S> BaseParser<S>
761where
762    S: TokenSource,
763{
764    /// Creates a parser base over a buffered token stream and recognizer
765    /// metadata.
766    pub const fn new(input: CommonTokenStream<S>, data: RecognizerData) -> Self {
767        Self {
768            input,
769            data,
770            build_parse_trees: true,
771            report_diagnostic_errors: false,
772            prediction_mode: PredictionMode::Ll,
773            prediction_diagnostics: Vec::new(),
774            reported_prediction_diagnostics: BTreeSet::new(),
775            int_members: BTreeMap::new(),
776            invoked_predicates: Vec::new(),
777        }
778    }
779
780    pub const fn input(&mut self) -> &mut CommonTokenStream<S> {
781        &mut self.input
782    }
783
784    pub fn la(&mut self, offset: isize) -> i32 {
785        self.input.la_token(offset)
786    }
787
788    pub fn consume(&mut self) {
789        IntStream::consume(&mut self.input);
790    }
791
792    /// Sets a generated integer member value used by target-template tests.
793    pub fn set_int_member(&mut self, member: usize, value: i64) {
794        self.int_members.insert(member, value);
795    }
796
797    /// Reads a generated integer member value.
798    pub fn int_member(&self, member: usize) -> Option<i64> {
799        self.int_members.get(&member).copied()
800    }
801
802    /// Adds `delta` to a generated integer member and returns the new value.
803    pub fn add_int_member(&mut self, member: usize, delta: i64) -> i64 {
804        let value = self.int_members.entry(member).or_default();
805        *value += delta;
806        *value
807    }
808
809    /// Matches and consumes the current token when it has the expected token
810    /// type.
811    ///
812    /// On success the consumed token is wrapped as a terminal parse-tree node.
813    /// On mismatch the error carries vocabulary display names so diagnostics are
814    /// stable across literal and symbolic token naming.
815    pub fn match_token(&mut self, token_type: i32) -> Result<ParseTree, AntlrError> {
816        let current = self
817            .input
818            .lt(1)
819            .cloned()
820            .ok_or_else(|| AntlrError::ParserError {
821                line: 0,
822                column: 0,
823                message: "missing current token".to_owned(),
824            })?;
825        if current.token_type() == token_type {
826            self.consume();
827            Ok(ParseTree::Terminal(TerminalNode::new(current)))
828        } else {
829            Err(AntlrError::MismatchedInput {
830                expected: self.vocabulary().display_name(token_type),
831                found: self.vocabulary().display_name(current.token_type()),
832            })
833        }
834    }
835
836    pub fn match_eof(&mut self) -> Result<ParseTree, AntlrError> {
837        self.match_token(TOKEN_EOF)
838    }
839
840    pub const fn rule_node(&self, context: ParserRuleContext) -> ParseTree {
841        ParseTree::Rule(RuleNode::new(context))
842    }
843
844    /// Parses a generated rule by interpreting the parser ATN from the rule's
845    /// start state to its stop state.
846    ///
847    /// The recognizer backtracks across alternatives and loop exits using token
848    /// stream indices instead of committing to input consumption immediately.
849    /// Once a viable ATN path is found, the parser consumes the accepted token
850    /// interval and returns a rule node. The initial tree is intentionally flat;
851    /// nested rule-node construction will be layered on top of the same
852    /// recognition routine.
853    pub fn parse_atn_rule(
854        &mut self,
855        atn: &Atn,
856        rule_index: usize,
857    ) -> Result<ParseTree, AntlrError> {
858        let start_state = atn
859            .rule_to_start_state()
860            .get(rule_index)
861            .copied()
862            .ok_or_else(|| {
863                AntlrError::Unsupported(format!("rule {rule_index} has no start state"))
864            })?;
865        let stop_state = atn
866            .rule_to_stop_state()
867            .get(rule_index)
868            .copied()
869            .filter(|state| *state != usize::MAX)
870            .ok_or_else(|| {
871                AntlrError::Unsupported(format!("rule {rule_index} has no stop state"))
872            })?;
873
874        let start_index = self.current_visible_index();
875        self.clear_prediction_diagnostics();
876        let mut visiting = BTreeSet::new();
877        let mut memo = BTreeMap::new();
878        let mut expected = ExpectedTokens::default();
879        let outcomes = self.recognize_state_fast(
880            atn,
881            FastRecognizeRequest {
882                state_number: start_state,
883                stop_state,
884                index: start_index,
885                rule_start_index: start_index,
886                decision_start_index: None,
887                precedence: 0,
888                depth: 0,
889                recovery_symbols: BTreeSet::new(),
890                recovery_state: None,
891            },
892            &mut visiting,
893            &mut memo,
894            &mut expected,
895        );
896        let Some(outcome) = select_best_fast_outcome(outcomes.into_iter(), self.prediction_mode)
897        else {
898            let error = self.recognition_error(rule_index, start_index, &expected);
899            report_token_source_errors(&self.input.drain_source_errors());
900            return Err(error);
901        };
902
903        report_parser_diagnostics(&self.prediction_diagnostics);
904        report_parser_diagnostics(&outcome.diagnostics);
905        report_token_source_errors(&self.input.drain_source_errors());
906        let mut context = ParserRuleContext::new(rule_index, self.state());
907        if let Some(token) = self.token_at(start_index) {
908            context.set_start(token);
909        }
910        if let Some(token) = self.rule_stop_token(outcome.index, outcome.consumed_eof) {
911            context.set_stop(token);
912        }
913        self.input.seek(start_index);
914        while self.input.index() < outcome.index {
915            let token_type = self.la(1);
916            let child = self.match_token(token_type)?;
917            if self.build_parse_trees {
918                context.add_child(child);
919            }
920        }
921        if outcome.consumed_eof && self.la(1) == TOKEN_EOF && self.build_parse_trees {
922            context.add_child(self.match_eof()?);
923        }
924
925        Ok(self.rule_node(context))
926    }
927
928    /// Parses a generated rule and returns semantic actions reached on the
929    /// selected ATN path.
930    ///
931    /// This slower path preserves action ordering and token intervals for
932    /// generated code that replays target-specific action templates after the
933    /// recognizer has chosen one viable parse path.
934    pub fn parse_atn_rule_with_actions(
935        &mut self,
936        atn: &Atn,
937        rule_index: usize,
938    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
939        self.parse_atn_rule_with_action_options(atn, rule_index, &[], false)
940    }
941
942    /// Parses a generated rule and emits ATN actions plus selected rule-init
943    /// actions reached on the chosen path.
944    ///
945    /// Generated parsers use this when a grammar contains rule-level `@init`
946    /// templates that must run for nested rule invocations. The runtime keeps
947    /// the action list path-sensitive, so init templates are replayed only for
948    /// rules that were actually entered by the selected parse.
949    pub fn parse_atn_rule_with_action_inits(
950        &mut self,
951        atn: &Atn,
952        rule_index: usize,
953        init_action_rules: &[usize],
954    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
955        self.parse_atn_rule_with_action_options(atn, rule_index, init_action_rules, false)
956    }
957
958    /// Parses a generated rule with optional semantic-action replay features.
959    ///
960    /// `track_alt_numbers` is used by grammars that opt into ANTLR's
961    /// alt-numbered context behavior. It keeps ordinary parse-tree rendering
962    /// unchanged for grammars that do not request that target template.
963    pub fn parse_atn_rule_with_action_options(
964        &mut self,
965        atn: &Atn,
966        rule_index: usize,
967        init_action_rules: &[usize],
968        track_alt_numbers: bool,
969    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
970        self.parse_atn_rule_with_runtime_options(
971            atn,
972            rule_index,
973            ParserRuntimeOptions {
974                init_action_rules,
975                track_alt_numbers,
976                ..ParserRuntimeOptions::default()
977            },
978        )
979    }
980
981    /// Parses a generated rule with action replay and parser predicate support.
982    ///
983    /// `predicates` maps serialized `(rule_index, pred_index)` coordinates to
984    /// target-template predicate semantics emitted by the generator. Missing
985    /// entries are treated as true so unsupported predicate-free grammars keep
986    /// the previous unconditional transition behavior.
987    pub fn parse_atn_rule_with_runtime_options(
988        &mut self,
989        atn: &Atn,
990        rule_index: usize,
991        options: ParserRuntimeOptions<'_>,
992    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
993        let ParserRuntimeOptions {
994            init_action_rules,
995            track_alt_numbers,
996            predicates,
997            rule_args,
998            member_actions,
999            return_actions,
1000        } = options;
1001        let start_state = atn
1002            .rule_to_start_state()
1003            .get(rule_index)
1004            .copied()
1005            .ok_or_else(|| {
1006                AntlrError::Unsupported(format!("rule {rule_index} has no start state"))
1007            })?;
1008        let stop_state = atn
1009            .rule_to_stop_state()
1010            .get(rule_index)
1011            .copied()
1012            .filter(|state| *state != usize::MAX)
1013            .ok_or_else(|| {
1014                AntlrError::Unsupported(format!("rule {rule_index} has no stop state"))
1015            })?;
1016
1017        let start_index = self.current_visible_index();
1018        self.clear_prediction_diagnostics();
1019        let init_action_rules = init_action_rules.iter().copied().collect::<BTreeSet<_>>();
1020        let mut visiting = BTreeSet::new();
1021        let mut memo = BTreeMap::new();
1022        let mut expected = ExpectedTokens::default();
1023        let member_values = self.int_members.clone();
1024        let return_values = BTreeMap::new();
1025        let outcomes = self.recognize_state(
1026            atn,
1027            RecognizeRequest {
1028                state_number: start_state,
1029                stop_state,
1030                index: start_index,
1031                rule_start_index: start_index,
1032                decision_start_index: None,
1033                init_action_rules: &init_action_rules,
1034                predicates,
1035                rule_args,
1036                member_actions,
1037                return_actions,
1038                local_int_arg: None,
1039                member_values,
1040                return_values,
1041                rule_alt_number: 0,
1042                track_alt_numbers,
1043                consumed_eof: false,
1044                precedence: 0,
1045                depth: 0,
1046                recovery_symbols: BTreeSet::new(),
1047                recovery_state: None,
1048            },
1049            &mut visiting,
1050            &mut memo,
1051            &mut expected,
1052        );
1053        let Some(outcome) = select_best_outcome(outcomes.into_iter(), self.prediction_mode) else {
1054            let error = self.recognition_error(rule_index, start_index, &expected);
1055            report_token_source_errors(&self.input.drain_source_errors());
1056            return Err(error);
1057        };
1058
1059        report_parser_diagnostics(&self.prediction_diagnostics);
1060        report_parser_diagnostics(&outcome.diagnostics);
1061        report_token_source_errors(&self.input.drain_source_errors());
1062        let mut actions = outcome.actions;
1063        if init_action_rules.contains(&rule_index) {
1064            actions.insert(
1065                0,
1066                ParserAction::new_rule_init(rule_index, start_index, Some(start_state)),
1067            );
1068        }
1069        let mut context = ParserRuleContext::new(rule_index, self.state());
1070        if track_alt_numbers {
1071            context.set_alt_number(outcome.alt_number);
1072        }
1073        for (name, value) in outcome.return_values {
1074            context.set_int_return(name, value);
1075        }
1076        if let Some(token) = self.token_at(start_index) {
1077            context.set_start(token);
1078        }
1079        if let Some(token) = self.rule_stop_token(outcome.index, outcome.consumed_eof) {
1080            context.set_stop(token);
1081        }
1082        if self.build_parse_trees {
1083            let nodes = fold_left_recursive_boundaries(outcome.nodes);
1084            for node in &nodes {
1085                context.add_child(self.recognized_node_tree(node, track_alt_numbers)?);
1086            }
1087        }
1088        self.input.seek(outcome.index);
1089
1090        Ok((self.rule_node(context), actions))
1091    }
1092
1093    /// Temporary parser entry used by generated parser methods while the parser
1094    /// ATN simulator is being implemented.
1095    ///
1096    /// This keeps generated parser crates buildable and gives us a stable method
1097    /// surface for every grammar rule. It intentionally accepts all remaining
1098    /// tokens into one rule context; it is not the final parser semantics.
1099    pub fn parse_interpreted_rule(&mut self, rule_index: usize) -> Result<ParseTree, AntlrError> {
1100        let mut context = ParserRuleContext::new(rule_index, self.state());
1101        while self.la(1) != TOKEN_EOF {
1102            let token_type = self.la(1);
1103            let child = self.match_token(token_type)?;
1104            if self.build_parse_trees {
1105                context.add_child(child);
1106            }
1107        }
1108        if self.build_parse_trees {
1109            context.add_child(self.match_eof()?);
1110        }
1111        Ok(self.rule_node(context))
1112    }
1113
1114    /// Builds the parser error reported when no ATN path can reach the active
1115    /// rule stop state.
1116    fn recognition_error(
1117        &mut self,
1118        rule_index: usize,
1119        start_index: usize,
1120        expected: &ExpectedTokens,
1121    ) -> AntlrError {
1122        let (index, message) = self.expected_error_message(rule_index, start_index, expected);
1123        self.input.seek(index);
1124        let current = self.input.lt(1).cloned();
1125        let line = current.as_ref().map(Token::line).unwrap_or_default();
1126        let column = current.as_ref().map(Token::column).unwrap_or_default();
1127        AntlrError::ParserError {
1128            line,
1129            column,
1130            message,
1131        }
1132    }
1133
1134    /// Builds the token index and ANTLR-compatible message for a failed rule.
1135    fn expected_error_message(
1136        &mut self,
1137        rule_index: usize,
1138        start_index: usize,
1139        expected: &ExpectedTokens,
1140    ) -> (usize, String) {
1141        let index = expected
1142            .index
1143            .or_else(|| expected.no_viable.map(|no_viable| no_viable.error_index))
1144            .unwrap_or_else(|| self.input.index());
1145        self.input.seek(index);
1146        let current = self.input.lt(1).cloned();
1147        let message = if expected
1148            .no_viable
1149            .as_ref()
1150            .is_some_and(|no_viable| no_viable.error_index == index)
1151        {
1152            let start = expected
1153                .no_viable
1154                .as_ref()
1155                .map_or(start_index, |no_viable| no_viable.start_index);
1156            let text = display_input_text(&self.input.text(start, index));
1157            format!("no viable alternative at input '{text}'")
1158        } else if expected.symbols.is_empty() {
1159            if expected.index.is_some() {
1160                let found = current
1161                    .as_ref()
1162                    .map_or_else(|| "'<EOF>'".to_owned(), token_input_display);
1163                if current
1164                    .as_ref()
1165                    .is_some_and(|token| token.token_type() == TOKEN_EOF)
1166                {
1167                    format!(
1168                        "missing {} at {found}",
1169                        self.expected_symbols_display(&expected.symbols)
1170                    )
1171                } else {
1172                    format!("mismatched input {found}")
1173                }
1174            } else {
1175                format!("no viable alternative while parsing rule {rule_index}")
1176            }
1177        } else {
1178            format!(
1179                "mismatched input {} expecting {}",
1180                current
1181                    .as_ref()
1182                    .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
1183                self.expected_symbols_display(&expected.symbols)
1184            )
1185        };
1186        (index, message)
1187    }
1188
1189    /// Converts a failed child rule into a recovered outcome so the parent can
1190    /// continue after reporting the child diagnostic.
1191    fn child_rule_failure_recovery(
1192        &mut self,
1193        rule_index: usize,
1194        start_index: usize,
1195        sync_symbols: &BTreeSet<i32>,
1196        member_values: BTreeMap<usize, i64>,
1197        expected: &ExpectedTokens,
1198    ) -> Option<RecognizeOutcome> {
1199        let (error_index, message) = self.expected_error_message(rule_index, start_index, expected);
1200        let token = self.token_at(error_index);
1201        let mut next_index = error_index;
1202        loop {
1203            let symbol = self.token_type_at(next_index);
1204            if sync_symbols.contains(&symbol) {
1205                if next_index == error_index {
1206                    return None;
1207                }
1208                break;
1209            }
1210            if symbol == TOKEN_EOF {
1211                break;
1212            }
1213            let after = self.consume_index(next_index, symbol);
1214            if after == next_index {
1215                break;
1216            }
1217            next_index = after;
1218        }
1219        Some(RecognizeOutcome {
1220            index: next_index,
1221            consumed_eof: false,
1222            alt_number: 0,
1223            member_values,
1224            return_values: BTreeMap::new(),
1225            diagnostics: vec![diagnostic_for_token(token.as_ref(), message)],
1226            decisions: Vec::new(),
1227            actions: Vec::new(),
1228            nodes: vec![RecognizedNode::ErrorToken { index: error_index }],
1229        })
1230    }
1231
1232    /// Adapts the optional recovery result to the normal outcome list used by
1233    /// rule-call transitions.
1234    fn child_rule_failure_recovery_outcomes(
1235        &mut self,
1236        request: ChildRuleFailureRecovery<'_>,
1237    ) -> Vec<RecognizeOutcome> {
1238        let sync_symbols =
1239            state_sync_symbols(request.atn, request.follow_state, request.stop_state);
1240        self.child_rule_failure_recovery(
1241            request.rule_index,
1242            request.start_index,
1243            &sync_symbols,
1244            request.member_values,
1245            request.expected,
1246        )
1247        .into_iter()
1248        .collect()
1249    }
1250
1251    /// Formats expected token types using ANTLR's single-token or set syntax.
1252    fn expected_symbols_display(&self, symbols: &BTreeSet<i32>) -> String {
1253        expected_symbols_display(symbols, self.vocabulary())
1254    }
1255
1256    /// Returns the single-token deletion repair if the token after `index`
1257    /// satisfies the failed consuming transition.
1258    fn single_token_deletion(
1259        &mut self,
1260        transition: &Transition,
1261        index: usize,
1262        max_token_type: i32,
1263        expected_symbols: &BTreeSet<i32>,
1264    ) -> Option<(ParserDiagnostic, usize, i32)> {
1265        let current_symbol = self.token_type_at(index);
1266        if current_symbol == TOKEN_EOF {
1267            return None;
1268        }
1269        let next_index = self.consume_index(index, current_symbol);
1270        if next_index == index {
1271            return None;
1272        }
1273        let next_symbol = self.token_type_at(next_index);
1274        if !transition.matches(next_symbol, 1, max_token_type) {
1275            return None;
1276        }
1277        let transition_expected = transition_expected_symbols(transition, max_token_type);
1278        let expected_display = self.expected_symbols_display(if expected_symbols.is_empty() {
1279            &transition_expected
1280        } else {
1281            expected_symbols
1282        });
1283        let current = self.token_at(index);
1284        let message = format!(
1285            "extraneous input {} expecting {expected_display}",
1286            current
1287                .as_ref()
1288                .map_or_else(|| "'<EOF>'".to_owned(), token_input_display)
1289        );
1290        Some((
1291            diagnostic_for_token(current.as_ref(), message),
1292            next_index,
1293            next_symbol,
1294        ))
1295    }
1296
1297    /// Returns the repair used when deleting the current token lets a recovery
1298    /// state continue with the following token.
1299    fn current_token_deletion(
1300        &mut self,
1301        index: usize,
1302        expected_symbols: &BTreeSet<i32>,
1303    ) -> Option<(ParserDiagnostic, usize, Vec<usize>)> {
1304        if expected_symbols.is_empty() {
1305            return None;
1306        }
1307        let current_symbol = self.token_type_at(index);
1308        if current_symbol == TOKEN_EOF {
1309            return None;
1310        }
1311        let current = self.token_at(index);
1312        let message = format!(
1313            "extraneous input {} expecting {}",
1314            current
1315                .as_ref()
1316                .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
1317            self.expected_symbols_display(expected_symbols)
1318        );
1319        let diagnostic = diagnostic_for_token(current.as_ref(), message);
1320        let mut skipped = Vec::new();
1321        let mut cursor = index;
1322        loop {
1323            let symbol = self.token_type_at(cursor);
1324            if symbol == TOKEN_EOF {
1325                return None;
1326            }
1327            skipped.push(cursor);
1328            let next_index = self.consume_index(cursor, symbol);
1329            if next_index == cursor {
1330                return None;
1331            }
1332            let next_symbol = self.token_type_at(next_index);
1333            if expected_symbols.contains(&next_symbol) {
1334                return Some((diagnostic, next_index, skipped));
1335            }
1336            cursor = next_index;
1337        }
1338    }
1339
1340    /// Returns the single-token insertion repair for a failed consuming
1341    /// transition. The caller validates the repair by continuing from the
1342    /// transition target at the same input index.
1343    fn single_token_insertion(
1344        &mut self,
1345        transition: &Transition,
1346        index: usize,
1347        max_token_type: i32,
1348        expected_symbols: &BTreeSet<i32>,
1349        follow_symbols: &BTreeSet<i32>,
1350    ) -> Option<(ParserDiagnostic, i32, String)> {
1351        let current_symbol = self.token_type_at(index);
1352        if !follow_symbols.contains(&current_symbol) {
1353            return None;
1354        }
1355        let transition_expected = transition_expected_symbols(transition, max_token_type);
1356        let token_type = transition_expected.iter().next().copied()?;
1357        let expected_display = self.expected_symbols_display(if expected_symbols.is_empty() {
1358            &transition_expected
1359        } else {
1360            expected_symbols
1361        });
1362        let mut token_symbols = BTreeSet::new();
1363        token_symbols.insert(token_type);
1364        let missing_token_display = self.expected_symbols_display(&token_symbols);
1365        let current = self.token_at(index);
1366        let message = format!(
1367            "missing {expected_display} at {}",
1368            current
1369                .as_ref()
1370                .map_or_else(|| "'<EOF>'".to_owned(), token_input_display)
1371        );
1372        let text = format!("<missing {missing_token_display}>");
1373        Some((
1374            diagnostic_for_token(current.as_ref(), message),
1375            token_type,
1376            text,
1377        ))
1378    }
1379
1380    /// Explores ANTLR's single-token deletion recovery for the fast recognizer:
1381    /// skip the unexpected current token when the following token satisfies the
1382    /// transition that failed.
1383    fn fast_single_token_deletion_recovery(
1384        &mut self,
1385        recovery: FastRecoveryRequest<'_, '_>,
1386    ) -> Vec<FastRecognizeOutcome> {
1387        let FastRecoveryRequest {
1388            atn,
1389            transition,
1390            expected_symbols,
1391            target,
1392            request,
1393            visiting,
1394            memo,
1395            expected,
1396        } = recovery;
1397        let FastRecognizeRequest {
1398            stop_state,
1399            index,
1400            rule_start_index,
1401            decision_start_index,
1402            precedence,
1403            depth,
1404            ..
1405        } = request;
1406        let Some((diagnostic, next_index, next_symbol)) =
1407            self.single_token_deletion(transition, index, atn.max_token_type(), &expected_symbols)
1408        else {
1409            return Vec::new();
1410        };
1411        let after_next = self.consume_index(next_index, next_symbol);
1412        self.recognize_state_fast(
1413            atn,
1414            FastRecognizeRequest {
1415                state_number: target,
1416                stop_state,
1417                index: after_next,
1418                rule_start_index,
1419                decision_start_index,
1420                precedence,
1421                depth: depth + 1,
1422                recovery_symbols: BTreeSet::new(),
1423                recovery_state: None,
1424            },
1425            visiting,
1426            memo,
1427            expected,
1428        )
1429        .into_iter()
1430        .map(|mut outcome| {
1431            outcome.consumed_eof |= next_symbol == TOKEN_EOF;
1432            outcome.diagnostics.insert(0, diagnostic.clone());
1433            outcome
1434        })
1435        .collect()
1436    }
1437
1438    /// Explores ANTLR's single-token insertion recovery for the fast recognizer:
1439    /// pretend the expected transition token was present and continue without
1440    /// consuming the current token.
1441    fn fast_single_token_insertion_recovery(
1442        &mut self,
1443        recovery: FastRecoveryRequest<'_, '_>,
1444    ) -> Vec<FastRecognizeOutcome> {
1445        let FastRecoveryRequest {
1446            atn,
1447            transition,
1448            expected_symbols,
1449            target,
1450            request,
1451            visiting,
1452            memo,
1453            expected,
1454        } = recovery;
1455        let FastRecognizeRequest {
1456            stop_state,
1457            index,
1458            rule_start_index,
1459            decision_start_index,
1460            precedence,
1461            depth,
1462            ..
1463        } = request;
1464        let follow_symbols = state_expected_symbols(atn, transition.target());
1465        let Some((diagnostic, _token_type, _text)) = self.single_token_insertion(
1466            transition,
1467            index,
1468            atn.max_token_type(),
1469            &expected_symbols,
1470            &follow_symbols,
1471        ) else {
1472            return Vec::new();
1473        };
1474        self.recognize_state_fast(
1475            atn,
1476            FastRecognizeRequest {
1477                state_number: target,
1478                stop_state,
1479                index,
1480                rule_start_index,
1481                decision_start_index,
1482                precedence,
1483                depth: depth + 1,
1484                recovery_symbols: BTreeSet::new(),
1485                recovery_state: None,
1486            },
1487            visiting,
1488            memo,
1489            expected,
1490        )
1491        .into_iter()
1492        .map(|mut outcome| {
1493            outcome.diagnostics.insert(0, diagnostic.clone());
1494            outcome
1495        })
1496        .collect()
1497    }
1498
1499    /// Retries the current fast-recognition state after deleting one
1500    /// unexpected token that precedes a valid loop or block continuation.
1501    fn fast_current_token_deletion_recovery(
1502        &mut self,
1503        recovery: FastCurrentTokenDeletionRequest<'_, '_>,
1504    ) -> Vec<FastRecognizeOutcome> {
1505        let FastCurrentTokenDeletionRequest {
1506            atn,
1507            expected_symbols,
1508            mut request,
1509            visiting,
1510            memo,
1511            expected,
1512        } = recovery;
1513        if request.index == request.rule_start_index {
1514            return Vec::new();
1515        }
1516        let Some((diagnostic, next_index, _skipped)) =
1517            self.current_token_deletion(request.index, &expected_symbols)
1518        else {
1519            return Vec::new();
1520        };
1521        request.state_number = request.recovery_state.unwrap_or(request.state_number);
1522        request.index = next_index;
1523        request.depth += 1;
1524        request.recovery_state = None;
1525        self.recognize_state_fast(atn, request, visiting, memo, expected)
1526            .into_iter()
1527            .map(|mut outcome| {
1528                outcome.diagnostics.insert(0, diagnostic.clone());
1529                outcome
1530            })
1531            .collect()
1532    }
1533
1534    /// Attempts to reach `stop_state` from `state_number` without committing
1535    /// token consumption to the parser's public stream position.
1536    fn recognize_state_fast(
1537        &mut self,
1538        atn: &Atn,
1539        request: FastRecognizeRequest,
1540        visiting: &mut BTreeSet<FastRecognizeKey>,
1541        memo: &mut BTreeMap<FastRecognizeKey, Vec<FastRecognizeOutcome>>,
1542        expected: &mut ExpectedTokens,
1543    ) -> Vec<FastRecognizeOutcome> {
1544        let FastRecognizeRequest {
1545            state_number,
1546            stop_state,
1547            index,
1548            rule_start_index,
1549            decision_start_index,
1550            precedence,
1551            depth,
1552            recovery_symbols,
1553            recovery_state,
1554        } = request;
1555        if depth > RECOGNITION_DEPTH_LIMIT {
1556            return Vec::new();
1557        }
1558        if state_number == stop_state {
1559            return vec![FastRecognizeOutcome {
1560                index,
1561                consumed_eof: false,
1562                diagnostics: Vec::new(),
1563            }];
1564        }
1565        let key = FastRecognizeKey {
1566            state_number,
1567            stop_state,
1568            index,
1569            rule_start_index,
1570            decision_start_index,
1571            precedence,
1572            recovery_symbols: recovery_symbols.clone(),
1573            recovery_state,
1574        };
1575        if let Some(outcomes) = memo.get(&key) {
1576            return outcomes.clone();
1577        }
1578
1579        let visit_key = key.clone();
1580        if !visiting.insert(visit_key.clone()) {
1581            return Vec::new();
1582        }
1583
1584        let Some(state) = atn.state(state_number) else {
1585            visiting.remove(&visit_key);
1586            return Vec::new();
1587        };
1588        let next_decision_start_index = if starts_prediction_decision(state) {
1589            Some(index)
1590        } else {
1591            decision_start_index
1592        };
1593        let (epsilon_recovery_symbols, epsilon_recovery_state) =
1594            next_recovery_context(atn, state, &recovery_symbols, recovery_state);
1595        let mut outcomes = Vec::new();
1596        for transition in &state.transitions {
1597            match transition {
1598                Transition::Epsilon { target }
1599                | Transition::Predicate { target, .. }
1600                | Transition::Action { target, .. } => {
1601                    outcomes.extend(self.recognize_state_fast(
1602                        atn,
1603                        FastRecognizeRequest {
1604                            state_number: *target,
1605                            stop_state,
1606                            index,
1607                            rule_start_index,
1608                            decision_start_index: next_decision_start_index,
1609                            precedence,
1610                            depth: depth + 1,
1611                            recovery_symbols: epsilon_recovery_symbols.clone(),
1612                            recovery_state: epsilon_recovery_state,
1613                        },
1614                        visiting,
1615                        memo,
1616                        expected,
1617                    ));
1618                }
1619                Transition::Precedence {
1620                    target,
1621                    precedence: transition_precedence,
1622                } => {
1623                    if *transition_precedence >= precedence {
1624                        outcomes.extend(self.recognize_state_fast(
1625                            atn,
1626                            FastRecognizeRequest {
1627                                state_number: *target,
1628                                stop_state,
1629                                index,
1630                                rule_start_index,
1631                                decision_start_index: next_decision_start_index,
1632                                precedence,
1633                                depth: depth + 1,
1634                                recovery_symbols: epsilon_recovery_symbols.clone(),
1635                                recovery_state: epsilon_recovery_state,
1636                            },
1637                            visiting,
1638                            memo,
1639                            expected,
1640                        ));
1641                    }
1642                }
1643                Transition::Rule {
1644                    target,
1645                    rule_index,
1646                    follow_state,
1647                    precedence: rule_precedence,
1648                    ..
1649                } => {
1650                    let Some(child_stop) = atn.rule_to_stop_state().get(*rule_index).copied()
1651                    else {
1652                        continue;
1653                    };
1654                    let expected_before_child = expected.clone();
1655                    let children = self.recognize_state_fast(
1656                        atn,
1657                        FastRecognizeRequest {
1658                            state_number: *target,
1659                            stop_state: child_stop,
1660                            index,
1661                            rule_start_index: index,
1662                            decision_start_index: None,
1663                            precedence: *rule_precedence,
1664                            depth: depth + 1,
1665                            recovery_symbols: epsilon_recovery_symbols.clone(),
1666                            recovery_state: epsilon_recovery_state,
1667                        },
1668                        visiting,
1669                        memo,
1670                        expected,
1671                    );
1672                    if children
1673                        .iter()
1674                        .any(|child| child.diagnostics.is_empty() && child.index > index)
1675                    {
1676                        *expected = expected_before_child;
1677                    }
1678                    for child in children {
1679                        outcomes.extend(
1680                            self.recognize_state_fast(
1681                                atn,
1682                                FastRecognizeRequest {
1683                                    state_number: *follow_state,
1684                                    stop_state,
1685                                    index: child.index,
1686                                    rule_start_index,
1687                                    decision_start_index: next_decision_start_index,
1688                                    precedence,
1689                                    depth: depth + 1,
1690                                    recovery_symbols: BTreeSet::new(),
1691                                    recovery_state: None,
1692                                },
1693                                visiting,
1694                                memo,
1695                                expected,
1696                            )
1697                            .into_iter()
1698                            .map(|mut outcome| {
1699                                outcome.consumed_eof |= child.consumed_eof;
1700                                let mut diagnostics = child.diagnostics.clone();
1701                                diagnostics.append(&mut outcome.diagnostics);
1702                                outcome.diagnostics = diagnostics;
1703                                outcome
1704                            }),
1705                        );
1706                    }
1707                }
1708                Transition::Atom { target, .. }
1709                | Transition::Range { target, .. }
1710                | Transition::Set { target, .. }
1711                | Transition::NotSet { target, .. }
1712                | Transition::Wildcard { target, .. } => {
1713                    let symbol = self.token_type_at(index);
1714                    if transition.matches(symbol, 1, atn.max_token_type()) {
1715                        let next_index = self.consume_index(index, symbol);
1716                        outcomes.extend(
1717                            self.recognize_state_fast(
1718                                atn,
1719                                FastRecognizeRequest {
1720                                    state_number: *target,
1721                                    stop_state,
1722                                    index: next_index,
1723                                    rule_start_index,
1724                                    decision_start_index: next_decision_start_index,
1725                                    precedence,
1726                                    depth: depth + 1,
1727                                    recovery_symbols: BTreeSet::new(),
1728                                    recovery_state: None,
1729                                },
1730                                visiting,
1731                                memo,
1732                                expected,
1733                            )
1734                            .into_iter()
1735                            .map(|mut outcome| {
1736                                outcome.consumed_eof |= symbol == TOKEN_EOF;
1737                                outcome
1738                            }),
1739                        );
1740                    } else {
1741                        let expected_symbols =
1742                            recovery_expected_symbols(atn, state.state_number, &recovery_symbols);
1743                        if expected_symbols.contains(&symbol) {
1744                            continue;
1745                        }
1746                        expected.record_transition(index, transition, atn.max_token_type());
1747                        record_no_viable_if_ambiguous(expected, next_decision_start_index, index);
1748                        outcomes.extend(self.fast_single_token_deletion_recovery(
1749                            FastRecoveryRequest {
1750                                atn,
1751                                transition,
1752                                expected_symbols: expected_symbols.clone(),
1753                                target: *target,
1754                                request: FastRecognizeRequest {
1755                                    state_number,
1756                                    stop_state,
1757                                    index,
1758                                    rule_start_index,
1759                                    decision_start_index,
1760                                    precedence,
1761                                    depth,
1762                                    recovery_symbols: recovery_symbols.clone(),
1763                                    recovery_state,
1764                                },
1765                                visiting,
1766                                memo,
1767                                expected,
1768                            },
1769                        ));
1770                        if !state_is_left_recursive_rule(atn, state) {
1771                            outcomes.extend(self.fast_single_token_insertion_recovery(
1772                                FastRecoveryRequest {
1773                                    atn,
1774                                    transition,
1775                                    expected_symbols: expected_symbols.clone(),
1776                                    target: *target,
1777                                    request: FastRecognizeRequest {
1778                                        state_number,
1779                                        stop_state,
1780                                        index,
1781                                        rule_start_index,
1782                                        decision_start_index,
1783                                        precedence,
1784                                        depth,
1785                                        recovery_symbols: recovery_symbols.clone(),
1786                                        recovery_state,
1787                                    },
1788                                    visiting,
1789                                    memo,
1790                                    expected,
1791                                },
1792                            ));
1793                        }
1794                        outcomes.extend(self.fast_current_token_deletion_recovery(
1795                            FastCurrentTokenDeletionRequest {
1796                                atn,
1797                                expected_symbols,
1798                                request: FastRecognizeRequest {
1799                                    state_number,
1800                                    stop_state,
1801                                    index,
1802                                    rule_start_index,
1803                                    decision_start_index,
1804                                    precedence,
1805                                    depth,
1806                                    recovery_symbols: recovery_symbols.clone(),
1807                                    recovery_state,
1808                                },
1809                                visiting,
1810                                memo,
1811                                expected,
1812                            },
1813                        ));
1814                    }
1815                }
1816            }
1817        }
1818
1819        visiting.remove(&visit_key);
1820        if self.prediction_mode == PredictionMode::Ll {
1821            discard_recovered_fast_outcomes_if_clean_path_exists(&mut outcomes);
1822        }
1823        dedupe_fast_outcomes(&mut outcomes);
1824        memo.insert(key, outcomes.clone());
1825        outcomes
1826    }
1827
1828    /// Explores single-token deletion recovery while preserving the matched
1829    /// token and skipped error token in the selected parse tree path.
1830    fn single_token_deletion_recovery(
1831        &mut self,
1832        recovery: RecoveryRequest<'_, '_>,
1833    ) -> Vec<RecognizeOutcome> {
1834        let RecoveryRequest {
1835            atn,
1836            transition,
1837            expected_symbols,
1838            target,
1839            request,
1840            visiting,
1841            memo,
1842            expected,
1843        } = recovery;
1844        let RecognizeRequest {
1845            stop_state,
1846            index,
1847            rule_start_index,
1848            decision_start_index,
1849            init_action_rules,
1850            predicates,
1851            rule_args,
1852            member_actions,
1853            return_actions,
1854            local_int_arg,
1855            member_values,
1856            return_values,
1857            rule_alt_number,
1858            track_alt_numbers,
1859            consumed_eof,
1860            precedence,
1861            depth,
1862            ..
1863        } = request;
1864        let Some((diagnostic, next_index, next_symbol)) =
1865            self.single_token_deletion(transition, index, atn.max_token_type(), &expected_symbols)
1866        else {
1867            return Vec::new();
1868        };
1869        let after_next = self.consume_index(next_index, next_symbol);
1870        self.recognize_state(
1871            atn,
1872            RecognizeRequest {
1873                state_number: target,
1874                stop_state,
1875                index: after_next,
1876                rule_start_index,
1877                decision_start_index,
1878                init_action_rules,
1879                predicates,
1880                rule_args,
1881                member_actions,
1882                return_actions,
1883                local_int_arg,
1884                member_values,
1885                return_values,
1886                rule_alt_number,
1887                track_alt_numbers,
1888                consumed_eof: consumed_eof || next_symbol == TOKEN_EOF,
1889                precedence,
1890                depth: depth + 1,
1891                recovery_symbols: BTreeSet::new(),
1892                recovery_state: None,
1893            },
1894            visiting,
1895            memo,
1896            expected,
1897        )
1898        .into_iter()
1899        .map(|mut outcome| {
1900            outcome.consumed_eof |= next_symbol == TOKEN_EOF;
1901            outcome.diagnostics.insert(0, diagnostic.clone());
1902            outcome
1903                .nodes
1904                .insert(0, RecognizedNode::Token { index: next_index });
1905            outcome
1906                .nodes
1907                .insert(0, RecognizedNode::ErrorToken { index });
1908            outcome
1909        })
1910        .collect()
1911    }
1912
1913    /// Retries the current recognition state after deleting one unexpected
1914    /// token, preserving the deleted token as an error node in the parse tree.
1915    fn current_token_deletion_recovery(
1916        &mut self,
1917        recovery: CurrentTokenDeletionRequest<'_, '_>,
1918    ) -> Vec<RecognizeOutcome> {
1919        let CurrentTokenDeletionRequest {
1920            atn,
1921            expected_symbols,
1922            mut request,
1923            visiting,
1924            memo,
1925            expected,
1926        } = recovery;
1927        let error_index = request.index;
1928        if error_index == request.rule_start_index {
1929            return Vec::new();
1930        }
1931        let Some((diagnostic, next_index, skipped)) =
1932            self.current_token_deletion(error_index, &expected_symbols)
1933        else {
1934            return Vec::new();
1935        };
1936        request.state_number = request.recovery_state.unwrap_or(request.state_number);
1937        request.index = next_index;
1938        request.depth += 1;
1939        request.recovery_state = None;
1940        self.recognize_state(atn, request, visiting, memo, expected)
1941            .into_iter()
1942            .map(|mut outcome| {
1943                outcome.diagnostics.insert(0, diagnostic.clone());
1944                for index in skipped.iter().rev() {
1945                    outcome
1946                        .nodes
1947                        .insert(0, RecognizedNode::ErrorToken { index: *index });
1948                }
1949                outcome
1950            })
1951            .collect()
1952    }
1953
1954    /// Falls back after deletion/insertion repairs cannot continue from a
1955    /// failed consuming transition.
1956    fn consuming_failure_fallback(
1957        &mut self,
1958        fallback: ConsumingFailureFallback<'_>,
1959        visiting: &mut BTreeSet<RecognizeKey>,
1960        memo: &mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
1961        expected: &mut ExpectedTokens,
1962    ) -> Vec<RecognizeOutcome> {
1963        if fallback.expected_symbols.is_empty() {
1964            return Vec::new();
1965        }
1966        if fallback.symbol == TOKEN_EOF {
1967            return self.eof_consuming_failure_fallback(fallback, expected);
1968        }
1969        self.non_eof_consuming_failure_fallback(fallback, visiting, memo, expected)
1970    }
1971
1972    /// Keeps unexpected non-EOF input visible as an error node when no repair
1973    /// path can otherwise reach the transition target.
1974    fn non_eof_consuming_failure_fallback(
1975        &mut self,
1976        fallback: ConsumingFailureFallback<'_>,
1977        visiting: &mut BTreeSet<RecognizeKey>,
1978        memo: &mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
1979        expected: &mut ExpectedTokens,
1980    ) -> Vec<RecognizeOutcome> {
1981        let ConsumingFailureFallback {
1982            atn,
1983            target,
1984            request,
1985            symbol,
1986            expected_symbols,
1987            decision_start_index,
1988            decision,
1989        } = fallback;
1990        let error_index = request.index;
1991        let diagnostic =
1992            self.recovery_failure_diagnostic(error_index, decision_start_index, &expected_symbols);
1993        let next_index = self.consume_index(error_index, symbol);
1994        self.recognize_state(
1995            atn,
1996            RecognizeRequest {
1997                state_number: target,
1998                stop_state: request.stop_state,
1999                index: next_index,
2000                rule_start_index: request.rule_start_index,
2001                decision_start_index,
2002                init_action_rules: request.init_action_rules,
2003                predicates: request.predicates,
2004                rule_args: request.rule_args,
2005                member_actions: request.member_actions,
2006                return_actions: request.return_actions,
2007                local_int_arg: request.local_int_arg,
2008                member_values: request.member_values,
2009                return_values: request.return_values,
2010                rule_alt_number: request.rule_alt_number,
2011                track_alt_numbers: request.track_alt_numbers,
2012                consumed_eof: request.consumed_eof,
2013                precedence: request.precedence,
2014                depth: request.depth + 1,
2015                recovery_symbols: BTreeSet::new(),
2016                recovery_state: None,
2017            },
2018            visiting,
2019            memo,
2020            expected,
2021        )
2022        .into_iter()
2023        .map(|mut outcome| {
2024            prepend_decision(&mut outcome, decision);
2025            outcome.diagnostics.insert(0, diagnostic.clone());
2026            outcome
2027                .nodes
2028                .insert(0, RecognizedNode::ErrorToken { index: error_index });
2029            outcome
2030        })
2031        .collect()
2032    }
2033
2034    /// Stops the current rule at EOF after a nested failure, matching ANTLR's
2035    /// behavior of unwinding instead of inserting caller tokens at EOF.
2036    fn eof_consuming_failure_fallback(
2037        &mut self,
2038        fallback: ConsumingFailureFallback<'_>,
2039        expected: &ExpectedTokens,
2040    ) -> Vec<RecognizeOutcome> {
2041        let request = fallback.request;
2042        if request.index == request.rule_start_index {
2043            return Vec::new();
2044        }
2045        let diagnostic =
2046            self.eof_rule_recovery_diagnostic(request.index, &fallback.expected_symbols, expected);
2047        vec![RecognizeOutcome {
2048            index: request.index,
2049            consumed_eof: request.consumed_eof,
2050            alt_number: request.rule_alt_number,
2051            member_values: request.member_values,
2052            return_values: request.return_values,
2053            diagnostics: vec![diagnostic],
2054            decisions: Vec::new(),
2055            actions: Vec::new(),
2056            nodes: Vec::new(),
2057        }]
2058    }
2059
2060    /// Explores single-token insertion recovery while adding a conjured
2061    /// missing-token error node to the selected parse tree path.
2062    fn single_token_insertion_recovery(
2063        &mut self,
2064        recovery: RecoveryRequest<'_, '_>,
2065    ) -> Vec<RecognizeOutcome> {
2066        let RecoveryRequest {
2067            atn,
2068            transition,
2069            expected_symbols,
2070            target,
2071            request,
2072            visiting,
2073            memo,
2074            expected,
2075        } = recovery;
2076        let RecognizeRequest {
2077            stop_state,
2078            index,
2079            rule_start_index,
2080            decision_start_index,
2081            init_action_rules,
2082            predicates,
2083            rule_args,
2084            member_actions,
2085            return_actions,
2086            local_int_arg,
2087            member_values,
2088            return_values,
2089            rule_alt_number,
2090            track_alt_numbers,
2091            consumed_eof,
2092            precedence,
2093            depth,
2094            ..
2095        } = request;
2096        let follow_symbols = state_expected_symbols(atn, transition.target());
2097        let Some((diagnostic, token_type, text)) = self.single_token_insertion(
2098            transition,
2099            index,
2100            atn.max_token_type(),
2101            &expected_symbols,
2102            &follow_symbols,
2103        ) else {
2104            return Vec::new();
2105        };
2106        self.recognize_state(
2107            atn,
2108            RecognizeRequest {
2109                state_number: target,
2110                stop_state,
2111                index,
2112                rule_start_index,
2113                decision_start_index,
2114                init_action_rules,
2115                predicates,
2116                rule_args,
2117                member_actions,
2118                return_actions,
2119                local_int_arg,
2120                member_values,
2121                return_values,
2122                rule_alt_number,
2123                track_alt_numbers,
2124                consumed_eof,
2125                precedence,
2126                depth: depth + 1,
2127                recovery_symbols: BTreeSet::new(),
2128                recovery_state: None,
2129            },
2130            visiting,
2131            memo,
2132            expected,
2133        )
2134        .into_iter()
2135        .map(|mut outcome| {
2136            outcome.diagnostics.insert(0, diagnostic.clone());
2137            outcome.nodes.insert(
2138                0,
2139                RecognizedNode::MissingToken {
2140                    token_type,
2141                    at_index: index,
2142                    text: text.clone(),
2143                },
2144            );
2145            outcome
2146        })
2147        .collect()
2148    }
2149
2150    /// Attempts to reach `stop_state` and carries semantic actions for the
2151    /// selected parser path.
2152    fn recognize_state(
2153        &mut self,
2154        atn: &Atn,
2155        request: RecognizeRequest<'_>,
2156        visiting: &mut BTreeSet<RecognizeKey>,
2157        memo: &mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
2158        expected: &mut ExpectedTokens,
2159    ) -> Vec<RecognizeOutcome> {
2160        let request_template = request.clone();
2161        let RecognizeRequest {
2162            state_number,
2163            stop_state,
2164            index,
2165            rule_start_index,
2166            decision_start_index,
2167            init_action_rules,
2168            predicates,
2169            rule_args,
2170            member_actions,
2171            return_actions,
2172            local_int_arg,
2173            member_values,
2174            return_values,
2175            rule_alt_number,
2176            track_alt_numbers,
2177            consumed_eof,
2178            precedence,
2179            depth,
2180            recovery_symbols,
2181            recovery_state,
2182        } = request;
2183        if depth > RECOGNITION_DEPTH_LIMIT {
2184            return Vec::new();
2185        }
2186        if state_number == stop_state {
2187            return stop_outcome(
2188                index,
2189                consumed_eof,
2190                rule_alt_number,
2191                member_values,
2192                return_values,
2193            );
2194        }
2195        let key = RecognizeKey {
2196            state_number,
2197            stop_state,
2198            index,
2199            rule_start_index,
2200            decision_start_index,
2201            local_int_arg,
2202            member_values: member_values.clone(),
2203            return_values: return_values.clone(),
2204            rule_alt_number,
2205            track_alt_numbers,
2206            consumed_eof,
2207            precedence,
2208            recovery_symbols: recovery_symbols.clone(),
2209            recovery_state,
2210        };
2211        if let Some(outcomes) = memo.get(&key) {
2212            return outcomes.clone();
2213        }
2214
2215        let visit_key = key.clone();
2216        if !visiting.insert(visit_key.clone()) {
2217            return Vec::new();
2218        }
2219
2220        let Some(state) = atn.state(state_number) else {
2221            visiting.remove(&visit_key);
2222            return Vec::new();
2223        };
2224        let next_decision_start_index = if starts_prediction_decision(state) {
2225            Some(index)
2226        } else {
2227            decision_start_index
2228        };
2229        let (epsilon_recovery_symbols, epsilon_recovery_state) =
2230            next_recovery_context(atn, state, &recovery_symbols, recovery_state);
2231        let mut outcomes = Vec::new();
2232        for (transition_index, transition) in state.transitions.iter().enumerate() {
2233            let decision = transition_decision(atn, state, transition_index, predicates);
2234            let next_alt_number =
2235                next_alt_number(state, transition_index, rule_alt_number, track_alt_numbers);
2236            match transition {
2237                Transition::Epsilon { target } | Transition::Action { target, .. } => {
2238                    let action_rule_index = match transition {
2239                        Transition::Action { rule_index, .. } => Some(*rule_index),
2240                        _ => None,
2241                    };
2242                    outcomes.extend(self.recognize_epsilon_or_action_step(
2243                        atn,
2244                        &request_template,
2245                        EpsilonActionStep {
2246                            source_state: state_number,
2247                            target: *target,
2248                            action_rule_index,
2249                            left_recursive_boundary: left_recursive_boundary(atn, state, *target),
2250                            decision,
2251                            decision_start_index: next_decision_start_index,
2252                            alt_number: next_alt_number,
2253                            recovery_symbols: epsilon_recovery_symbols.clone(),
2254                            recovery_state: epsilon_recovery_state,
2255                        },
2256                        RecognizeScratch {
2257                            visiting,
2258                            memo,
2259                            expected,
2260                        },
2261                    ));
2262                }
2263                Transition::Predicate {
2264                    target,
2265                    rule_index,
2266                    pred_index,
2267                    ..
2268                } => {
2269                    let predicate = PredicateEval {
2270                        index,
2271                        rule_index: *rule_index,
2272                        pred_index: *pred_index,
2273                        predicates,
2274                        local_int_arg,
2275                        member_values: &member_values,
2276                    };
2277                    if self.parser_predicate_matches(predicate) {
2278                        let left_recursive_boundary = left_recursive_boundary(atn, state, *target);
2279                        outcomes.extend(
2280                            self.recognize_state(
2281                                atn,
2282                                RecognizeRequest {
2283                                    state_number: *target,
2284                                    stop_state,
2285                                    index,
2286                                    rule_start_index,
2287                                    decision_start_index: next_decision_start_index,
2288                                    init_action_rules,
2289                                    predicates,
2290                                    rule_args,
2291                                    member_actions,
2292                                    return_actions,
2293                                    local_int_arg,
2294                                    member_values: member_values.clone(),
2295                                    return_values: return_values.clone(),
2296                                    rule_alt_number: next_alt_number,
2297                                    track_alt_numbers,
2298                                    consumed_eof,
2299                                    precedence,
2300                                    depth: depth + 1,
2301                                    recovery_symbols: epsilon_recovery_symbols.clone(),
2302                                    recovery_state: epsilon_recovery_state,
2303                                },
2304                                visiting,
2305                                memo,
2306                                expected,
2307                            )
2308                            .into_iter()
2309                            .map(|mut outcome| {
2310                                prepend_decision(&mut outcome, decision);
2311                                if let Some(rule_index) = left_recursive_boundary {
2312                                    outcome.nodes.insert(
2313                                        0,
2314                                        RecognizedNode::LeftRecursiveBoundary { rule_index },
2315                                    );
2316                                }
2317                                outcome
2318                            }),
2319                        );
2320                    } else if let Some(message) =
2321                        self.parser_predicate_failure_message(*rule_index, *pred_index, predicates)
2322                    {
2323                        outcomes.push(self.predicate_failure_recovery(PredicateFailureRecovery {
2324                            rule_index: *rule_index,
2325                            index,
2326                            message,
2327                            member_values: member_values.clone(),
2328                            return_values: return_values.clone(),
2329                            rule_alt_number,
2330                        }));
2331                    } else {
2332                        record_predicate_no_viable(expected, next_decision_start_index, index);
2333                    }
2334                }
2335                Transition::Precedence {
2336                    target,
2337                    precedence: transition_precedence,
2338                } => {
2339                    if *transition_precedence >= precedence {
2340                        outcomes.extend(
2341                            self.recognize_state(
2342                                atn,
2343                                RecognizeRequest {
2344                                    state_number: *target,
2345                                    stop_state,
2346                                    index,
2347                                    rule_start_index,
2348                                    decision_start_index: next_decision_start_index,
2349                                    init_action_rules,
2350                                    predicates,
2351                                    rule_args,
2352                                    member_actions,
2353                                    return_actions,
2354                                    local_int_arg,
2355                                    member_values: member_values.clone(),
2356                                    return_values: return_values.clone(),
2357                                    rule_alt_number: next_alt_number,
2358                                    track_alt_numbers,
2359                                    consumed_eof,
2360                                    precedence,
2361                                    depth: depth + 1,
2362                                    recovery_symbols: epsilon_recovery_symbols.clone(),
2363                                    recovery_state: epsilon_recovery_state,
2364                                },
2365                                visiting,
2366                                memo,
2367                                expected,
2368                            )
2369                            .into_iter()
2370                            .map(|mut outcome| {
2371                                prepend_decision(&mut outcome, decision);
2372                                outcome
2373                            }),
2374                        );
2375                    }
2376                }
2377                Transition::Rule {
2378                    target,
2379                    rule_index,
2380                    follow_state,
2381                    precedence: rule_precedence,
2382                    ..
2383                } => {
2384                    let Some(child_stop) = atn.rule_to_stop_state().get(*rule_index).copied()
2385                    else {
2386                        continue;
2387                    };
2388                    let child_local_int_arg =
2389                        rule_local_int_arg(rule_args, state_number, *rule_index, local_int_arg);
2390                    let expected_before_child = expected.clone();
2391                    let children = self.recognize_state(
2392                        atn,
2393                        RecognizeRequest {
2394                            state_number: *target,
2395                            stop_state: child_stop,
2396                            index,
2397                            rule_start_index: index,
2398                            decision_start_index: None,
2399                            init_action_rules,
2400                            predicates,
2401                            rule_args,
2402                            member_actions,
2403                            return_actions,
2404                            local_int_arg: child_local_int_arg,
2405                            member_values: member_values.clone(),
2406                            return_values: BTreeMap::new(),
2407                            rule_alt_number: 0,
2408                            track_alt_numbers,
2409                            consumed_eof: false,
2410                            precedence: *rule_precedence,
2411                            depth: depth + 1,
2412                            recovery_symbols: epsilon_recovery_symbols.clone(),
2413                            recovery_state: epsilon_recovery_state,
2414                        },
2415                        visiting,
2416                        memo,
2417                        expected,
2418                    );
2419                    let children = if children.is_empty() {
2420                        self.child_rule_failure_recovery_outcomes(ChildRuleFailureRecovery {
2421                            atn,
2422                            rule_index: *rule_index,
2423                            start_index: index,
2424                            follow_state: *follow_state,
2425                            stop_state,
2426                            member_values: member_values.clone(),
2427                            expected,
2428                        })
2429                    } else {
2430                        children
2431                    };
2432                    let preserve_child_expected =
2433                        self.child_expected_reaches_clean_eof(&children, expected);
2434                    restore_expected(
2435                        &children,
2436                        index,
2437                        expected,
2438                        expected_before_child,
2439                        preserve_child_expected,
2440                    );
2441                    for child in children {
2442                        let child_node = RecognizedNode::Rule {
2443                            rule_index: *rule_index,
2444                            invoking_state: invoking_state_number(state_number),
2445                            alt_number: child.alt_number,
2446                            start_index: index,
2447                            stop_index: self.rule_stop_token_index(child.index, child.consumed_eof),
2448                            return_values: child.return_values.clone(),
2449                            children: fold_left_recursive_boundaries(child.nodes.clone()),
2450                        };
2451                        outcomes.extend(
2452                            self.recognize_state(
2453                                atn,
2454                                RecognizeRequest {
2455                                    state_number: *follow_state,
2456                                    stop_state,
2457                                    index: child.index,
2458                                    rule_start_index,
2459                                    decision_start_index: next_decision_start_index,
2460                                    init_action_rules,
2461                                    predicates,
2462                                    rule_args,
2463                                    member_actions,
2464                                    return_actions,
2465                                    local_int_arg,
2466                                    member_values: child.member_values.clone(),
2467                                    return_values: return_values.clone(),
2468                                    rule_alt_number,
2469                                    track_alt_numbers,
2470                                    consumed_eof: consumed_eof || child.consumed_eof,
2471                                    precedence,
2472                                    depth: depth + 1,
2473                                    recovery_symbols: BTreeSet::new(),
2474                                    recovery_state: None,
2475                                },
2476                                visiting,
2477                                memo,
2478                                expected,
2479                            )
2480                            .into_iter()
2481                            .map(|mut outcome| {
2482                                outcome.consumed_eof |= child.consumed_eof;
2483                                let mut diagnostics = child.diagnostics.clone();
2484                                diagnostics.append(&mut outcome.diagnostics);
2485                                outcome.diagnostics = diagnostics;
2486                                let mut decisions = child.decisions.clone();
2487                                decisions.append(&mut outcome.decisions);
2488                                outcome.decisions = decisions;
2489                                prepend_decision(&mut outcome, decision);
2490                                let mut actions = child.actions.clone();
2491                                if init_action_rules.contains(rule_index) {
2492                                    actions.insert(
2493                                        0,
2494                                        ParserAction::new_rule_init(
2495                                            *rule_index,
2496                                            index,
2497                                            Some(*follow_state),
2498                                        ),
2499                                    );
2500                                }
2501                                actions.append(&mut outcome.actions);
2502                                outcome.actions = actions;
2503                                outcome.nodes.insert(0, child_node.clone());
2504                                outcome
2505                            }),
2506                        );
2507                    }
2508                }
2509                Transition::Atom { target, .. }
2510                | Transition::Range { target, .. }
2511                | Transition::Set { target, .. }
2512                | Transition::NotSet { target, .. }
2513                | Transition::Wildcard { target, .. } => {
2514                    let symbol = self.token_type_at(index);
2515                    if transition.matches(symbol, 1, atn.max_token_type()) {
2516                        let next_index = self.consume_index(index, symbol);
2517                        outcomes.extend(
2518                            self.recognize_state(
2519                                atn,
2520                                RecognizeRequest {
2521                                    state_number: *target,
2522                                    stop_state,
2523                                    index: next_index,
2524                                    rule_start_index,
2525                                    decision_start_index: next_decision_start_index,
2526                                    init_action_rules,
2527                                    predicates,
2528                                    rule_args,
2529                                    member_actions,
2530                                    return_actions,
2531                                    local_int_arg,
2532                                    member_values: member_values.clone(),
2533                                    return_values: return_values.clone(),
2534                                    rule_alt_number: next_alt_number,
2535                                    track_alt_numbers,
2536                                    consumed_eof: consumed_eof || symbol == TOKEN_EOF,
2537                                    precedence,
2538                                    depth: depth + 1,
2539                                    recovery_symbols: BTreeSet::new(),
2540                                    recovery_state: None,
2541                                },
2542                                visiting,
2543                                memo,
2544                                expected,
2545                            )
2546                            .into_iter()
2547                            .map(|mut outcome| {
2548                                prepend_decision(&mut outcome, decision);
2549                                outcome.consumed_eof |= symbol == TOKEN_EOF;
2550                                outcome.nodes.insert(0, RecognizedNode::Token { index });
2551                                outcome
2552                            }),
2553                        );
2554                    } else {
2555                        let expected_symbols =
2556                            recovery_expected_symbols(atn, state.state_number, &recovery_symbols);
2557                        if expected_symbols.contains(&symbol) {
2558                            continue;
2559                        }
2560                        expected.record_transition(index, transition, atn.max_token_type());
2561                        record_no_viable_if_ambiguous(expected, next_decision_start_index, index);
2562                        let before_recovery = outcomes.len();
2563                        let recovery_request = request_template.clone();
2564                        outcomes.extend(
2565                            self.single_token_deletion_recovery(RecoveryRequest {
2566                                atn,
2567                                transition,
2568                                expected_symbols: expected_symbols.clone(),
2569                                target: *target,
2570                                request: recovery_request.clone(),
2571                                visiting,
2572                                memo,
2573                                expected,
2574                            })
2575                            .into_iter()
2576                            .map(|mut outcome| {
2577                                prepend_decision(&mut outcome, decision);
2578                                outcome
2579                            }),
2580                        );
2581                        if !state_is_left_recursive_rule(atn, state) {
2582                            outcomes.extend(
2583                                self.single_token_insertion_recovery(RecoveryRequest {
2584                                    atn,
2585                                    transition,
2586                                    expected_symbols: expected_symbols.clone(),
2587                                    target: *target,
2588                                    request: recovery_request.clone(),
2589                                    visiting,
2590                                    memo,
2591                                    expected,
2592                                })
2593                                .into_iter()
2594                                .map(|mut outcome| {
2595                                    prepend_decision(&mut outcome, decision);
2596                                    outcome
2597                                }),
2598                            );
2599                        }
2600                        outcomes.extend(self.current_token_deletion_recovery(
2601                            CurrentTokenDeletionRequest {
2602                                atn,
2603                                expected_symbols: expected_symbols.clone(),
2604                                request: recovery_request.clone(),
2605                                visiting,
2606                                memo,
2607                                expected,
2608                            },
2609                        ));
2610                        if outcomes.len() == before_recovery {
2611                            outcomes.extend(self.consuming_failure_fallback(
2612                                ConsumingFailureFallback {
2613                                    atn,
2614                                    target: *target,
2615                                    request: recovery_request,
2616                                    symbol,
2617                                    expected_symbols,
2618                                    decision_start_index: next_decision_start_index,
2619                                    decision,
2620                                },
2621                                visiting,
2622                                memo,
2623                                expected,
2624                            ));
2625                        }
2626                    }
2627                }
2628            }
2629        }
2630
2631        visiting.remove(&visit_key);
2632        self.record_prediction_diagnostics(atn, state, index, &outcomes);
2633        if self.prediction_mode == PredictionMode::Ll {
2634            discard_recovered_outcomes_if_clean_path_exists(&mut outcomes);
2635        }
2636        dedupe_outcomes(&mut outcomes);
2637        memo.insert(key, outcomes.clone());
2638        outcomes
2639    }
2640
2641    /// Follows an epsilon or semantic-action transition while preserving the
2642    /// path-local side effects that may later become generated action output.
2643    fn recognize_epsilon_or_action_step(
2644        &mut self,
2645        atn: &Atn,
2646        request: &RecognizeRequest<'_>,
2647        step: EpsilonActionStep,
2648        scratch: RecognizeScratch<'_>,
2649    ) -> Vec<RecognizeOutcome> {
2650        let RecognizeScratch {
2651            visiting,
2652            memo,
2653            expected,
2654        } = scratch;
2655        let action = step.action_rule_index.map(|rule_index| {
2656            ParserAction::new(
2657                step.source_state,
2658                rule_index,
2659                request.rule_start_index,
2660                self.rule_stop_token_index(request.index, request.consumed_eof),
2661            )
2662        });
2663        let next_member_values = if action.is_some() {
2664            member_values_after_action(
2665                step.source_state,
2666                request.member_actions,
2667                &request.member_values,
2668            )
2669        } else {
2670            request.member_values.clone()
2671        };
2672        let next_return_values = action.map_or_else(
2673            || request.return_values.clone(),
2674            |action| {
2675                return_values_after_action(
2676                    step.source_state,
2677                    action.rule_index(),
2678                    request.return_actions,
2679                    &request.return_values,
2680                )
2681            },
2682        );
2683
2684        self.recognize_state(
2685            atn,
2686            RecognizeRequest {
2687                state_number: step.target,
2688                stop_state: request.stop_state,
2689                index: request.index,
2690                rule_start_index: request.rule_start_index,
2691                decision_start_index: step.decision_start_index,
2692                init_action_rules: request.init_action_rules,
2693                predicates: request.predicates,
2694                rule_args: request.rule_args,
2695                member_actions: request.member_actions,
2696                return_actions: request.return_actions,
2697                local_int_arg: request.local_int_arg,
2698                member_values: next_member_values,
2699                return_values: next_return_values,
2700                rule_alt_number: step.alt_number,
2701                track_alt_numbers: request.track_alt_numbers,
2702                consumed_eof: request.consumed_eof,
2703                precedence: request.precedence,
2704                depth: request.depth + 1,
2705                recovery_symbols: step.recovery_symbols,
2706                recovery_state: step.recovery_state,
2707            },
2708            visiting,
2709            memo,
2710            expected,
2711        )
2712        .into_iter()
2713        .map(|mut outcome| {
2714            prepend_decision(&mut outcome, step.decision);
2715            if let Some(rule_index) = step.left_recursive_boundary {
2716                outcome
2717                    .nodes
2718                    .insert(0, RecognizedNode::LeftRecursiveBoundary { rule_index });
2719            }
2720            if let Some(action) = action {
2721                outcome.actions.insert(0, action);
2722            }
2723            outcome
2724        })
2725        .collect()
2726    }
2727
2728    /// Reads the token type at an absolute token-stream index.
2729    fn token_type_at(&mut self, index: usize) -> i32 {
2730        self.input.seek(index);
2731        self.input.la_token(1)
2732    }
2733
2734    /// Clones the visible token at an absolute token-stream index.
2735    fn token_at(&mut self, index: usize) -> Option<CommonToken> {
2736        self.input.get(index).cloned()
2737    }
2738
2739    /// Normalizes the current token-stream cursor to the next parser-visible
2740    /// token before capturing a rule start boundary.
2741    fn current_visible_index(&mut self) -> usize {
2742        let index = self.input.index();
2743        self.input.seek(index);
2744        self.input.index()
2745    }
2746
2747    /// Reports whether a child rule reached EOF cleanly while also recording
2748    /// an EOF expectation from a longer path inside that child.
2749    fn child_expected_reaches_clean_eof(
2750        &mut self,
2751        children: &[RecognizeOutcome],
2752        expected: &ExpectedTokens,
2753    ) -> bool {
2754        let Some(index) = expected.index else {
2755            return false;
2756        };
2757        self.token_type_at(index) == TOKEN_EOF
2758            && children
2759                .iter()
2760                .any(|child| child.diagnostics.is_empty() && child.index == index)
2761    }
2762
2763    /// Finds the previous token visible to the parser before `index`.
2764    ///
2765    /// The token stream cursor skips hidden-channel tokens, so subtracting one
2766    /// from a visible-token index can point at whitespace. Parser intervals use
2767    /// this helper to stop at the previous visible token while preserving hidden
2768    /// text inside the rendered interval.
2769    fn previous_token_index(&mut self, index: usize) -> Option<usize> {
2770        self.input.previous_visible_token_index(index)
2771    }
2772
2773    /// Returns the token-stream index used as a rule stop boundary.
2774    ///
2775    /// EOF transitions keep the cursor on EOF, so a rule that consumed EOF must
2776    /// stop at `index` rather than at the previous visible token.
2777    fn rule_stop_token_index(&mut self, index: usize, consumed_eof: bool) -> Option<usize> {
2778        if consumed_eof && self.token_type_at(index) == TOKEN_EOF {
2779            Some(index)
2780        } else {
2781            self.previous_token_index(index)
2782        }
2783    }
2784
2785    /// Returns the rule stop token for a selected parse path.
2786    ///
2787    /// EOF transitions do not advance the token-stream cursor, so an EOF match
2788    /// must use the current token rather than the previous visible token.
2789    fn rule_stop_token(&mut self, index: usize, consumed_eof: bool) -> Option<CommonToken> {
2790        self.rule_stop_token_index(index, consumed_eof)
2791            .and_then(|token_index| self.token_at(token_index))
2792    }
2793
2794    /// Recovers from a semantic predicate with an ANTLR `<fail='...'>` option.
2795    ///
2796    /// Generated Java reports the failed-predicate message at the current
2797    /// lookahead, then consumes until rule recovery can resume. The metadata
2798    /// runtime models the same visible tree shape by keeping skipped tokens as
2799    /// error nodes and returning from the active rule at EOF.
2800    fn predicate_failure_recovery(
2801        &mut self,
2802        request: PredicateFailureRecovery<'_>,
2803    ) -> RecognizeOutcome {
2804        let PredicateFailureRecovery {
2805            rule_index,
2806            index,
2807            message,
2808            member_values,
2809            return_values,
2810            rule_alt_number,
2811        } = request;
2812        let rule_name = self
2813            .rule_names()
2814            .get(rule_index)
2815            .map_or_else(|| rule_index.to_string(), Clone::clone);
2816        let diagnostic = diagnostic_for_token(
2817            self.token_at(index).as_ref(),
2818            format!("rule {rule_name} {message}"),
2819        );
2820        let mut nodes = Vec::new();
2821        let mut next_index = index;
2822        loop {
2823            let symbol = self.token_type_at(next_index);
2824            if symbol == TOKEN_EOF {
2825                break;
2826            }
2827            nodes.push(RecognizedNode::ErrorToken { index: next_index });
2828            let after = self.consume_index(next_index, symbol);
2829            if after == next_index {
2830                break;
2831            }
2832            next_index = after;
2833        }
2834        RecognizeOutcome {
2835            index: next_index,
2836            consumed_eof: false,
2837            alt_number: rule_alt_number,
2838            member_values,
2839            return_values,
2840            diagnostics: vec![diagnostic],
2841            decisions: Vec::new(),
2842            actions: Vec::new(),
2843            nodes,
2844        }
2845    }
2846
2847    /// Evaluates a supported parser predicate at a speculative input index.
2848    ///
2849    /// Parser ATN simulation is index-based, so predicate evaluation seeks to
2850    /// the candidate index before applying lookahead. A missing predicate entry
2851    /// means the generator did not opt into runtime evaluation for that
2852    /// coordinate and the transition remains viable.
2853    fn parser_predicate_matches(&mut self, eval: PredicateEval<'_>) -> bool {
2854        let PredicateEval {
2855            index,
2856            rule_index,
2857            pred_index,
2858            predicates,
2859            local_int_arg,
2860            member_values,
2861        } = eval;
2862        let Some((_, _, predicate)) = predicates
2863            .iter()
2864            .find(|(rule, pred, _)| *rule == rule_index && *pred == pred_index)
2865        else {
2866            return true;
2867        };
2868        self.input.seek(index);
2869        match predicate {
2870            ParserPredicate::True => true,
2871            ParserPredicate::False => false,
2872            ParserPredicate::FalseWithMessage { .. } => false,
2873            ParserPredicate::Invoke { value } => {
2874                let key = (rule_index, pred_index);
2875                if !self.invoked_predicates.contains(&key) {
2876                    self.invoked_predicates.push(key);
2877                    use std::io::Write as _;
2878                    let mut stdout = std::io::stdout().lock();
2879                    let _ = writeln!(stdout, "eval={value}");
2880                }
2881                *value
2882            }
2883            ParserPredicate::LookaheadTextEquals { offset, text } => {
2884                self.input.lt(*offset).and_then(Token::text) == Some(*text)
2885            }
2886            ParserPredicate::LookaheadNotEquals { offset, token_type } => {
2887                self.la(*offset) != *token_type
2888            }
2889            ParserPredicate::LocalIntEquals { value } => {
2890                local_int_arg.is_none_or(|(_, actual)| actual == *value)
2891            }
2892            ParserPredicate::LocalIntLessOrEqual { value } => {
2893                local_int_arg.is_none_or(|(_, actual)| actual <= *value)
2894            }
2895            ParserPredicate::MemberModuloEquals {
2896                member,
2897                modulus,
2898                value,
2899                equals,
2900            } => {
2901                if *modulus == 0 {
2902                    return false;
2903                }
2904                let actual = member_values.get(member).copied().unwrap_or_default() % *modulus;
2905                (actual == *value) == *equals
2906            }
2907        }
2908    }
2909
2910    /// Returns a generated fail-option message for a predicate coordinate.
2911    fn parser_predicate_failure_message(
2912        &self,
2913        rule_index: usize,
2914        pred_index: usize,
2915        predicates: &[(usize, usize, ParserPredicate)],
2916    ) -> Option<&'static str> {
2917        predicates
2918            .iter()
2919            .find_map(|(rule, pred, predicate)| match predicate {
2920                ParserPredicate::FalseWithMessage { message }
2921                    if *rule == rule_index && *pred == pred_index =>
2922                {
2923                    Some(*message)
2924                }
2925                _ => None,
2926            })
2927    }
2928
2929    /// Returns the token-stream index after consuming `symbol` at `index`.
2930    ///
2931    /// EOF is not advanced by ANTLR token streams, so EOF transitions keep the
2932    /// index stable and rely on `consumed_eof` to record that EOF was matched.
2933    fn consume_index(&mut self, index: usize, symbol: i32) -> usize {
2934        self.input.seek(index);
2935        if symbol != TOKEN_EOF {
2936            self.consume();
2937        }
2938        self.input.index()
2939    }
2940
2941    /// Builds ANTLR's no-viable-alternative diagnostic for an ambiguous
2942    /// decision that failed after consuming a shared prefix.
2943    fn no_viable_alternative(
2944        &mut self,
2945        start_index: usize,
2946        error_index: usize,
2947    ) -> ParserDiagnostic {
2948        let text = display_input_text(&self.input.text(start_index, error_index));
2949        diagnostic_for_token(
2950            self.token_at(error_index).as_ref(),
2951            format!("no viable alternative at input '{text}'"),
2952        )
2953    }
2954
2955    /// Selects the diagnostic for a failed consuming transition after all
2956    /// recovery repairs have been ruled out.
2957    fn recovery_failure_diagnostic(
2958        &mut self,
2959        index: usize,
2960        decision_start_index: Option<usize>,
2961        expected_symbols: &BTreeSet<i32>,
2962    ) -> ParserDiagnostic {
2963        if expected_symbols.len() > 1 {
2964            if let Some(decision_start) = no_viable_decision_start(decision_start_index, index) {
2965                return self.no_viable_alternative(decision_start, index);
2966            }
2967        }
2968        diagnostic_for_token(
2969            self.token_at(index).as_ref(),
2970            format!(
2971                "mismatched input {} expecting {}",
2972                self.token_at(index)
2973                    .as_ref()
2974                    .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
2975                self.expected_symbols_display(expected_symbols)
2976            ),
2977        )
2978    }
2979
2980    /// Builds the EOF diagnostic used when ANTLR unwinds a failed nested rule
2981    /// instead of inserting missing tokens in the caller.
2982    fn eof_rule_recovery_diagnostic(
2983        &mut self,
2984        index: usize,
2985        expected_symbols: &BTreeSet<i32>,
2986        expected: &ExpectedTokens,
2987    ) -> ParserDiagnostic {
2988        let symbols = if expected.index == Some(index) && !expected.symbols.is_empty() {
2989            &expected.symbols
2990        } else {
2991            expected_symbols
2992        };
2993        diagnostic_for_token(
2994            self.token_at(index).as_ref(),
2995            format!(
2996                "mismatched input {} expecting {}",
2997                self.token_at(index)
2998                    .as_ref()
2999                    .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
3000                self.expected_symbols_display(symbols)
3001            ),
3002        )
3003    }
3004
3005    /// Returns token text for a buffered token interval used by generated
3006    /// `$text` actions.
3007    ///
3008    /// ANTLR treats EOF as a range boundary rather than printable input text,
3009    /// even when an action interval explicitly stops at the EOF token.
3010    pub fn text_interval(&mut self, start: usize, stop: Option<usize>) -> String {
3011        let Some(stop) = stop else {
3012            return String::new();
3013        };
3014        let stop = if self
3015            .token_at(stop)
3016            .is_some_and(|token| token.token_type() == TOKEN_EOF)
3017        {
3018            let Some(previous) = self.previous_token_index(stop) else {
3019                return String::new();
3020            };
3021            previous
3022        } else {
3023            stop
3024        };
3025        self.input.text(start, stop)
3026    }
3027
3028    /// Resets per-parse prediction diagnostics while keeping the parser-level
3029    /// reporting flag configured by generated harness code.
3030    fn clear_prediction_diagnostics(&mut self) {
3031        self.prediction_diagnostics.clear();
3032        self.reported_prediction_diagnostics.clear();
3033    }
3034
3035    /// Buffers ANTLR-style diagnostic-listener messages for decision states
3036    /// where multiple clean alternatives survive full-context recognition.
3037    fn record_prediction_diagnostics(
3038        &mut self,
3039        atn: &Atn,
3040        state: &AtnState,
3041        start_index: usize,
3042        outcomes: &[RecognizeOutcome],
3043    ) {
3044        if !self.report_diagnostic_errors || state.transitions.len() < 2 {
3045            return;
3046        }
3047        let Some(decision) = atn
3048            .decision_to_state()
3049            .iter()
3050            .position(|state_number| *state_number == state.state_number)
3051        else {
3052            return;
3053        };
3054        let Some(rule_index) = state.rule_index else {
3055            return;
3056        };
3057        let mut alts_by_end = BTreeMap::<usize, BTreeSet<usize>>::new();
3058        for outcome in outcomes
3059            .iter()
3060            .filter(|outcome| outcome.diagnostics.is_empty())
3061        {
3062            let Some(alt) = outcome.decisions.first() else {
3063                continue;
3064            };
3065            alts_by_end
3066                .entry(outcome.index)
3067                .or_default()
3068                .insert(alt + 1);
3069        }
3070        let Some((&end_index, ambig_alts)) = alts_by_end
3071            .iter()
3072            .filter(|(_, alts)| alts.len() > 1)
3073            .max_by_key(|(end, _)| *end)
3074        else {
3075            return;
3076        };
3077        let rule_name = self
3078            .rule_names()
3079            .get(rule_index)
3080            .map_or_else(|| "<unknown>".to_owned(), Clone::clone);
3081        let stop_index = self.previous_token_index(end_index).unwrap_or(start_index);
3082        let input = display_input_text(&self.input.text(start_index, stop_index));
3083        let alts = ambig_alts
3084            .iter()
3085            .map(usize::to_string)
3086            .collect::<Vec<_>>()
3087            .join(", ");
3088        let key = (decision, start_index, format!("{alts}:{input}"));
3089        if !self.reported_prediction_diagnostics.insert(key) {
3090            return;
3091        }
3092        let start_token = self.token_at(start_index);
3093        let stop_token = self.token_at(stop_index);
3094        self.prediction_diagnostics.push(diagnostic_for_token(
3095            start_token.as_ref(),
3096            format!("reportAttemptingFullContext d={decision} ({rule_name}), input='{input}'"),
3097        ));
3098        self.prediction_diagnostics.push(diagnostic_for_token(
3099            stop_token.as_ref(),
3100            format!(
3101                "reportAmbiguity d={decision} ({rule_name}): ambigAlts={{{alts}}}, input='{input}'"
3102            ),
3103        ));
3104    }
3105
3106    /// Formats the tokens expected from an ATN state using ANTLR display names.
3107    pub fn expected_tokens_at_state(&self, atn: &Atn, state_number: usize) -> String {
3108        expected_symbols_display(
3109            &state_expected_symbols(atn, state_number),
3110            self.vocabulary(),
3111        )
3112    }
3113
3114    /// Formats a buffered token in ANTLR's diagnostic token display form.
3115    pub fn token_display_at(&mut self, index: usize) -> Option<String> {
3116        self.token_at(index).map(|token| format!("{token}"))
3117    }
3118
3119    /// Converts a recognized internal node into a public parse-tree node.
3120    fn recognized_node_tree(
3121        &mut self,
3122        node: &RecognizedNode,
3123        track_alt_numbers: bool,
3124    ) -> Result<ParseTree, AntlrError> {
3125        match node {
3126            RecognizedNode::Token { index } => {
3127                let token =
3128                    self.input
3129                        .get(*index)
3130                        .cloned()
3131                        .ok_or_else(|| AntlrError::ParserError {
3132                            line: 0,
3133                            column: 0,
3134                            message: format!("missing token at index {index}"),
3135                        })?;
3136                Ok(ParseTree::Terminal(TerminalNode::new(token)))
3137            }
3138            RecognizedNode::ErrorToken { index } => {
3139                let token =
3140                    self.input
3141                        .get(*index)
3142                        .cloned()
3143                        .ok_or_else(|| AntlrError::ParserError {
3144                            line: 0,
3145                            column: 0,
3146                            message: format!("missing error token at index {index}"),
3147                        })?;
3148                Ok(ParseTree::Error(ErrorNode::new(token)))
3149            }
3150            RecognizedNode::MissingToken {
3151                token_type,
3152                at_index,
3153                text,
3154            } => {
3155                let current = self.token_at(*at_index);
3156                let token = CommonToken::new(*token_type)
3157                    .with_text(text)
3158                    .with_span(usize::MAX, usize::MAX)
3159                    .with_position(
3160                        current.as_ref().map(Token::line).unwrap_or_default(),
3161                        current.as_ref().map(Token::column).unwrap_or_default(),
3162                    );
3163                Ok(ParseTree::Error(ErrorNode::new(token)))
3164            }
3165            RecognizedNode::Rule {
3166                rule_index,
3167                invoking_state,
3168                alt_number,
3169                start_index,
3170                stop_index,
3171                return_values,
3172                children,
3173            } => {
3174                let mut context = ParserRuleContext::new(*rule_index, *invoking_state);
3175                if track_alt_numbers {
3176                    context.set_alt_number(*alt_number);
3177                }
3178                for (name, value) in return_values {
3179                    context.set_int_return(name.clone(), *value);
3180                }
3181                if let Some(token) = self.token_at(*start_index) {
3182                    context.set_start(token);
3183                }
3184                if let Some(token) = stop_index.and_then(|index| self.token_at(index)) {
3185                    context.set_stop(token);
3186                }
3187                for child in children {
3188                    context.add_child(self.recognized_node_tree(child, track_alt_numbers)?);
3189                }
3190                Ok(self.rule_node(context))
3191            }
3192            RecognizedNode::LeftRecursiveBoundary { rule_index } => Err(AntlrError::Unsupported(
3193                format!("unfolded left-recursive boundary for rule {rule_index}"),
3194            )),
3195        }
3196    }
3197}
3198
3199/// Detects the loop edge where ANTLR would call `pushNewRecursionContext` for a
3200/// transformed left-recursive rule.
3201fn left_recursive_boundary(atn: &Atn, state: &AtnState, target: usize) -> Option<usize> {
3202    if !state.precedence_rule_decision {
3203        return None;
3204    }
3205    let target_state = atn.state(target)?;
3206    if target_state.kind == AtnStateKind::LoopEnd {
3207        return None;
3208    }
3209    state.rule_index
3210}
3211
3212/// Selects the first outer alternative observed for a rule path.
3213///
3214/// ANTLR's alt-numbered tree contexts store the rule alternative chosen at the
3215/// outer decision. The metadata recognizer only needs this when a generated
3216/// grammar opts into that target template; otherwise the value remains `0` and
3217/// parse-tree rendering is unchanged.
3218const fn next_alt_number(
3219    state: &AtnState,
3220    transition_index: usize,
3221    current_alt_number: usize,
3222    track_alt_numbers: bool,
3223) -> usize {
3224    if !track_alt_numbers || current_alt_number != 0 || state.transitions.len() <= 1 {
3225        return current_alt_number;
3226    }
3227    if matches!(
3228        state.kind,
3229        AtnStateKind::Basic
3230            | AtnStateKind::BlockStart
3231            | AtnStateKind::PlusBlockStart
3232            | AtnStateKind::StarBlockStart
3233            | AtnStateKind::StarLoopEntry
3234    ) && !state.precedence_rule_decision
3235    {
3236        return transition_index + 1;
3237    }
3238    current_alt_number
3239}
3240
3241/// Folds boundary markers emitted at precedence-loop entries into nested rule
3242/// nodes, matching ANTLR's recursive-context parse-tree shape.
3243fn fold_left_recursive_boundaries(nodes: Vec<RecognizedNode>) -> Vec<RecognizedNode> {
3244    let mut folded = Vec::new();
3245    for node in nodes {
3246        match node {
3247            RecognizedNode::LeftRecursiveBoundary { rule_index } => {
3248                if !folded.is_empty() {
3249                    let children = std::mem::take(&mut folded);
3250                    let start_index = recognized_nodes_start_index(&children).unwrap_or_default();
3251                    let stop_index = recognized_nodes_stop_index(&children);
3252                    folded.push(RecognizedNode::Rule {
3253                        rule_index,
3254                        invoking_state: -1,
3255                        alt_number: 0,
3256                        start_index,
3257                        stop_index,
3258                        return_values: BTreeMap::new(),
3259                        children,
3260                    });
3261                }
3262            }
3263            node => folded.push(node),
3264        }
3265    }
3266    folded
3267}
3268
3269fn recognized_nodes_start_index(nodes: &[RecognizedNode]) -> Option<usize> {
3270    nodes.iter().find_map(recognized_node_start_index)
3271}
3272
3273const fn recognized_node_start_index(node: &RecognizedNode) -> Option<usize> {
3274    match node {
3275        RecognizedNode::Token { index } | RecognizedNode::ErrorToken { index } => Some(*index),
3276        RecognizedNode::MissingToken { at_index, .. } => Some(*at_index),
3277        RecognizedNode::Rule { start_index, .. } => Some(*start_index),
3278        RecognizedNode::LeftRecursiveBoundary { .. } => None,
3279    }
3280}
3281
3282fn recognized_nodes_stop_index(nodes: &[RecognizedNode]) -> Option<usize> {
3283    nodes.iter().rev().find_map(recognized_node_stop_index)
3284}
3285
3286/// Converts an ATN state number into the signed invoking-state slot used by
3287/// ANTLR parse-tree contexts, saturating only for impossible platform widths.
3288fn invoking_state_number(state_number: usize) -> isize {
3289    isize::try_from(state_number).unwrap_or(isize::MAX)
3290}
3291
3292const fn recognized_node_stop_index(node: &RecognizedNode) -> Option<usize> {
3293    match node {
3294        RecognizedNode::Token { index } | RecognizedNode::ErrorToken { index } => Some(*index),
3295        RecognizedNode::MissingToken { at_index, .. } => at_index.checked_sub(1),
3296        RecognizedNode::Rule { stop_index, .. } => *stop_index,
3297        RecognizedNode::LeftRecursiveBoundary { .. } => None,
3298    }
3299}
3300
3301fn token_input_display(token: &impl Token) -> String {
3302    format!("'{}'", token.text().unwrap_or("<EOF>"))
3303}
3304
3305fn display_input_text(text: &str) -> String {
3306    let mut out = String::new();
3307    for ch in text.chars() {
3308        match ch {
3309            '\n' => out.push_str("\\n"),
3310            '\r' => out.push_str("\\r"),
3311            '\t' => out.push_str("\\t"),
3312            other => out.push(other),
3313        }
3314    }
3315    out
3316}
3317
3318fn diagnostic_for_token(token: Option<&impl Token>, message: String) -> ParserDiagnostic {
3319    ParserDiagnostic {
3320        line: token.map(Token::line).unwrap_or_default(),
3321        column: token.map(Token::column).unwrap_or_default(),
3322        message,
3323    }
3324}
3325
3326/// Emits parser diagnostics for the selected recovered parse path.
3327#[allow(clippy::print_stderr)]
3328fn report_parser_diagnostics(diagnostics: &[ParserDiagnostic]) {
3329    for diagnostic in diagnostics {
3330        eprintln!(
3331            "line {}:{} {}",
3332            diagnostic.line, diagnostic.column, diagnostic.message
3333        );
3334    }
3335}
3336
3337/// Emits buffered token-source diagnostics after parser diagnostics that were
3338/// discovered while speculatively reading the same token stream.
3339#[allow(clippy::print_stderr)]
3340fn report_token_source_errors(errors: &[TokenSourceError]) {
3341    for error in errors {
3342        eprintln!("line {}:{} {}", error.line, error.column, error.message);
3343    }
3344}
3345
3346fn expected_symbols_display(symbols: &BTreeSet<i32>, vocabulary: &Vocabulary) -> String {
3347    let items = symbols
3348        .iter()
3349        .map(|symbol| expected_symbol_display(*symbol, vocabulary))
3350        .collect::<Vec<_>>();
3351    if let [single] = items.as_slice() {
3352        return single.clone();
3353    }
3354    format!("{{{}}}", items.join(", "))
3355}
3356
3357fn expected_symbol_display(symbol: i32, vocabulary: &Vocabulary) -> String {
3358    if symbol == TOKEN_EOF {
3359        return "<EOF>".to_owned();
3360    }
3361    vocabulary.display_name(symbol)
3362}
3363
3364/// Returns whether `state` belongs to an ANTLR-transformed left-recursive rule.
3365/// Inline insertion in those precedence loops can synthesize a missing operand
3366/// before an operator and then block the legitimate loop-exit path.
3367fn state_is_left_recursive_rule(atn: &Atn, state: &AtnState) -> bool {
3368    let Some(rule_index) = state.rule_index else {
3369        return false;
3370    };
3371    atn.rule_to_start_state()
3372        .get(rule_index)
3373        .and_then(|state_number| atn.state(*state_number))
3374        .is_some_and(|rule_start| rule_start.left_recursive_rule)
3375}
3376
3377/// Chooses the outermost parse result that consumed the most input.
3378///
3379/// The recognizer intentionally keeps shorter endpoints available while walking
3380/// nested rule transitions so callers can satisfy following tokens such as
3381/// `expr 'and' expr`. Only the public rule entry commits to one endpoint.
3382fn select_best_fast_outcome(
3383    outcomes: impl Iterator<Item = FastRecognizeOutcome>,
3384    prediction_mode: PredictionMode,
3385) -> Option<FastRecognizeOutcome> {
3386    outcomes.reduce(|best, outcome| {
3387        let outcome_position = (outcome.index, outcome.consumed_eof);
3388        let best_position = (best.index, best.consumed_eof);
3389        let better = match prediction_mode {
3390            PredictionMode::Ll => outcome_is_better(
3391                outcome_position,
3392                &outcome.diagnostics,
3393                best_position,
3394                &best.diagnostics,
3395            ),
3396            PredictionMode::Sll => outcome.index > best.index,
3397        };
3398        if better {
3399            return outcome;
3400        }
3401        best
3402    })
3403}
3404
3405fn select_best_outcome(
3406    outcomes: impl Iterator<Item = RecognizeOutcome>,
3407    prediction_mode: PredictionMode,
3408) -> Option<RecognizeOutcome> {
3409    let outcomes = outcomes.collect::<Vec<_>>();
3410    let prefer_first_tie = outcomes
3411        .iter()
3412        .any(|outcome| nodes_need_stable_tie(&outcome.nodes));
3413    outcomes.into_iter().reduce(|best, outcome| {
3414        let outcome_position = (outcome.index, outcome.consumed_eof);
3415        let best_position = (best.index, best.consumed_eof);
3416        let better = match prediction_mode {
3417            PredictionMode::Ll => {
3418                outcome_is_better(
3419                    outcome_position,
3420                    &outcome.diagnostics,
3421                    best_position,
3422                    &best.diagnostics,
3423                ) || (!prefer_first_tie
3424                    && outcome_position == best_position
3425                    && outcome.diagnostics.len() == best.diagnostics.len()
3426                    && diagnostic_recovery_rank(&outcome.diagnostics)
3427                        == diagnostic_recovery_rank(&best.diagnostics)
3428                    && (outcome.decisions < best.decisions
3429                        || (outcome.decisions == best.decisions && outcome.actions > best.actions)))
3430            }
3431            PredictionMode::Sll => {
3432                outcome_position > best_position
3433                    || (outcome_position == best_position
3434                        && !prefer_first_tie
3435                        && (outcome.decisions < best.decisions
3436                            || (outcome.decisions == best.decisions
3437                                && outcome_is_better(
3438                                    outcome_position,
3439                                    &outcome.diagnostics,
3440                                    best_position,
3441                                    &best.diagnostics,
3442                                ))))
3443            }
3444        };
3445        if better {
3446            return outcome;
3447        }
3448        best
3449    })
3450}
3451
3452/// Records the serialized transition order at parser decision states.
3453///
3454/// When two clean paths consume the same input, ANTLR's adaptive prediction
3455/// chooses by alternative order. Keeping this compact trace lets the metadata
3456/// recognizer distinguish greedy and non-greedy optional blocks without a full
3457/// prediction simulator.
3458fn transition_decision(
3459    atn: &Atn,
3460    state: &AtnState,
3461    transition_index: usize,
3462    predicates: &[(usize, usize, ParserPredicate)],
3463) -> Option<usize> {
3464    if state.transitions.len() <= 1
3465        || state.precedence_rule_decision
3466        || decision_reaches_unsupported_predicate(atn, state, predicates)
3467    {
3468        return None;
3469    }
3470    Some(transition_index)
3471}
3472
3473/// Reports whether a state should reset the active no-viable decision start.
3474///
3475/// Loop entry/back states are continuations of the surrounding adaptive
3476/// prediction; resetting at those states would turn LL-star failures back into
3477/// ordinary mismatches.
3478const fn starts_prediction_decision(state: &AtnState) -> bool {
3479    state.transitions.len() > 1
3480        && !matches!(
3481            state.kind,
3482            AtnStateKind::PlusLoopBack | AtnStateKind::StarLoopBack | AtnStateKind::StarLoopEntry
3483        )
3484}
3485
3486/// Marks a farthest expected-token set as no-viable when multiple alternatives
3487/// failed after the active decision had already consumed input.
3488fn record_no_viable_if_ambiguous(
3489    expected: &mut ExpectedTokens,
3490    decision_start_index: Option<usize>,
3491    index: usize,
3492) {
3493    if expected.index == Some(index) && expected.symbols.len() > 1 {
3494        if let Some(decision_start) = no_viable_decision_start(decision_start_index, index) {
3495            expected.record_no_viable(decision_start, index);
3496        }
3497    }
3498}
3499
3500/// Records a no-viable decision caused by a failed semantic predicate before
3501/// any consuming transition can contribute an expected-token set.
3502const fn record_predicate_no_viable(
3503    expected: &mut ExpectedTokens,
3504    decision_start_index: Option<usize>,
3505    index: usize,
3506) {
3507    if let Some(decision_start) = decision_start_index {
3508        expected.record_no_viable(decision_start, index);
3509    }
3510}
3511
3512/// Returns the active decision start only when the error is past that start.
3513const fn no_viable_decision_start(
3514    decision_start_index: Option<usize>,
3515    index: usize,
3516) -> Option<usize> {
3517    match decision_start_index {
3518        Some(start) if index > start => Some(start),
3519        _ => None,
3520    }
3521}
3522
3523/// Restores expected-token bookkeeping when a child rule found a clean
3524/// consuming path; failures in longer child alternatives should not pollute the
3525/// caller's final expectation set.
3526fn restore_expected(
3527    children: &[RecognizeOutcome],
3528    child_start_index: usize,
3529    expected: &mut ExpectedTokens,
3530    snapshot: ExpectedTokens,
3531    preserve_child_expected: bool,
3532) {
3533    if preserve_child_expected {
3534        return;
3535    }
3536    if children
3537        .iter()
3538        .any(|child| child.diagnostics.is_empty() && child.index > child_start_index)
3539    {
3540        *expected = snapshot;
3541    }
3542}
3543
3544/// Reports whether a decision can reach a predicate the generator did not
3545/// translate. Static alternative order is unsafe for those context predicates.
3546fn decision_reaches_unsupported_predicate(
3547    atn: &Atn,
3548    state: &AtnState,
3549    predicates: &[(usize, usize, ParserPredicate)],
3550) -> bool {
3551    state.transitions.iter().any(|transition| {
3552        transition_reaches_unsupported_predicate(atn, transition, predicates, &mut BTreeSet::new())
3553    })
3554}
3555
3556/// Walks epsilon-like edges from one transition to find unsupported predicates.
3557fn transition_reaches_unsupported_predicate(
3558    atn: &Atn,
3559    transition: &Transition,
3560    predicates: &[(usize, usize, ParserPredicate)],
3561    visited: &mut BTreeSet<usize>,
3562) -> bool {
3563    match transition {
3564        Transition::Predicate {
3565            rule_index,
3566            pred_index,
3567            ..
3568        } => !predicates
3569            .iter()
3570            .any(|(rule, pred, _)| rule == rule_index && pred == pred_index),
3571        Transition::Epsilon { target }
3572        | Transition::Action { target, .. }
3573        | Transition::Rule { target, .. } => {
3574            state_reaches_unsupported_predicate(atn, *target, predicates, visited)
3575        }
3576        Transition::Precedence { .. }
3577        | Transition::Atom { .. }
3578        | Transition::Range { .. }
3579        | Transition::Set { .. }
3580        | Transition::NotSet { .. }
3581        | Transition::Wildcard { .. } => false,
3582    }
3583}
3584
3585/// Finds an unsupported predicate reachable before a consuming transition.
3586fn state_reaches_unsupported_predicate(
3587    atn: &Atn,
3588    state_number: usize,
3589    predicates: &[(usize, usize, ParserPredicate)],
3590    visited: &mut BTreeSet<usize>,
3591) -> bool {
3592    if !visited.insert(state_number) {
3593        return false;
3594    }
3595    let Some(state) = atn.state(state_number) else {
3596        return false;
3597    };
3598    state.transitions.iter().any(|transition| {
3599        transition_reaches_unsupported_predicate(atn, transition, predicates, visited)
3600    })
3601}
3602
3603/// Adds a decision step to the front of an already-recognized suffix path.
3604fn prepend_decision(outcome: &mut RecognizeOutcome, decision: Option<usize>) {
3605    if let Some(decision) = decision {
3606        outcome.decisions.insert(0, decision);
3607    }
3608}
3609
3610fn outcome_is_better(
3611    outcome_position: (usize, bool),
3612    outcome_diagnostics: &[ParserDiagnostic],
3613    best_position: (usize, bool),
3614    best_diagnostics: &[ParserDiagnostic],
3615) -> bool {
3616    outcome_position > best_position
3617        || (outcome_position == best_position
3618            && (outcome_diagnostics.len() < best_diagnostics.len()
3619                || (outcome_diagnostics.len() == best_diagnostics.len()
3620                    && diagnostic_recovery_rank(outcome_diagnostics)
3621                        < diagnostic_recovery_rank(best_diagnostics))))
3622}
3623
3624/// Ranks concrete recovery repairs ahead of generic non-EOF mismatch fallbacks
3625/// when speculative paths otherwise consume the same input.
3626fn diagnostic_recovery_rank(diagnostics: &[ParserDiagnostic]) -> usize {
3627    diagnostics
3628        .iter()
3629        .filter(|diagnostic| {
3630            diagnostic.message.starts_with("mismatched input ")
3631                && !diagnostic.message.starts_with("mismatched input '<EOF>' ")
3632        })
3633        .count()
3634}
3635
3636fn discard_recovered_fast_outcomes_if_clean_path_exists(outcomes: &mut Vec<FastRecognizeOutcome>) {
3637    if outcomes
3638        .iter()
3639        .any(|outcome| outcome.diagnostics.is_empty())
3640    {
3641        outcomes.retain(|outcome| outcome.diagnostics.is_empty());
3642    }
3643}
3644
3645fn discard_recovered_outcomes_if_clean_path_exists(outcomes: &mut Vec<RecognizeOutcome>) {
3646    if outcomes.iter().any(outcome_has_rule_failure_diagnostic) {
3647        return;
3648    }
3649    if outcomes
3650        .iter()
3651        .any(|outcome| outcome.diagnostics.is_empty())
3652    {
3653        outcomes.retain(|outcome| outcome.diagnostics.is_empty());
3654    }
3655}
3656
3657/// Reports whether a recovered outcome came from an explicit predicate
3658/// fail-option and therefore should compete with shorter clean loop exits.
3659fn outcome_has_rule_failure_diagnostic(outcome: &RecognizeOutcome) -> bool {
3660    outcome
3661        .diagnostics
3662        .iter()
3663        .any(|diagnostic| diagnostic.message.starts_with("rule "))
3664}
3665
3666/// Reports whether a candidate contains recursive tree structure where ANTLR's
3667/// first viable candidate preserves the correct left-recursive context shape.
3668fn nodes_need_stable_tie(nodes: &[RecognizedNode]) -> bool {
3669    nodes.iter().any(node_needs_stable_tie)
3670}
3671
3672fn node_needs_stable_tie(node: &RecognizedNode) -> bool {
3673    match node {
3674        RecognizedNode::Token { .. }
3675        | RecognizedNode::ErrorToken { .. }
3676        | RecognizedNode::MissingToken { .. } => false,
3677        RecognizedNode::LeftRecursiveBoundary { .. } => true,
3678        RecognizedNode::Rule {
3679            rule_index,
3680            children,
3681            ..
3682        } => children.iter().any(|child| {
3683            matches!(
3684                child,
3685                RecognizedNode::Rule {
3686                    rule_index: child_rule,
3687                    ..
3688                } if child_rule == rule_index
3689            ) || node_needs_stable_tie(child)
3690        }),
3691    }
3692}
3693
3694/// Sorts and removes equivalent endpoints before memoizing a state result.
3695fn dedupe_fast_outcomes(outcomes: &mut Vec<FastRecognizeOutcome>) {
3696    outcomes.sort_unstable();
3697    outcomes.dedup();
3698}
3699
3700/// Sorts and removes equivalent endpoints, including their action traces.
3701fn dedupe_outcomes(outcomes: &mut Vec<RecognizeOutcome>) {
3702    outcomes.sort_unstable();
3703    outcomes.dedup();
3704}
3705
3706impl<S> Recognizer for BaseParser<S>
3707where
3708    S: TokenSource,
3709{
3710    fn data(&self) -> &RecognizerData {
3711        &self.data
3712    }
3713
3714    fn data_mut(&mut self) -> &mut RecognizerData {
3715        &mut self.data
3716    }
3717}
3718
3719impl<S> Parser for BaseParser<S>
3720where
3721    S: TokenSource,
3722{
3723    fn build_parse_trees(&self) -> bool {
3724        self.build_parse_trees
3725    }
3726
3727    fn set_build_parse_trees(&mut self, build: bool) {
3728        self.build_parse_trees = build;
3729    }
3730
3731    fn report_diagnostic_errors(&self) -> bool {
3732        self.report_diagnostic_errors
3733    }
3734
3735    fn set_report_diagnostic_errors(&mut self, report: bool) {
3736        self.report_diagnostic_errors = report;
3737    }
3738
3739    fn prediction_mode(&self) -> PredictionMode {
3740        self.prediction_mode
3741    }
3742
3743    fn set_prediction_mode(&mut self, mode: PredictionMode) {
3744        self.prediction_mode = mode;
3745    }
3746}
3747
3748#[cfg(test)]
3749mod tests {
3750    use super::*;
3751    use crate::atn::serialized::{AtnDeserializer, SerializedAtn};
3752    use crate::token::{CommonToken, HIDDEN_CHANNEL, Token};
3753    use crate::token_stream::CommonTokenStream;
3754    use crate::vocabulary::Vocabulary;
3755
3756    #[derive(Debug)]
3757    struct Source {
3758        tokens: Vec<CommonToken>,
3759        index: usize,
3760    }
3761
3762    impl TokenSource for Source {
3763        fn next_token(&mut self) -> CommonToken {
3764            let token = self
3765                .tokens
3766                .get(self.index)
3767                .cloned()
3768                .unwrap_or_else(|| CommonToken::eof("parser-test", self.index, 1, self.index));
3769            self.index += 1;
3770            token
3771        }
3772
3773        fn line(&self) -> usize {
3774            1
3775        }
3776
3777        fn column(&self) -> usize {
3778            self.index
3779        }
3780
3781        fn source_name(&self) -> &'static str {
3782            "parser-test"
3783        }
3784    }
3785
3786    fn mini_parser(tokens: Vec<CommonToken>) -> BaseParser<Source> {
3787        let data = RecognizerData::new(
3788            "Mini.g4",
3789            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
3790        );
3791        BaseParser::new(CommonTokenStream::new(Source { tokens, index: 0 }), data)
3792    }
3793
3794    fn token_then_eof_atn() -> Atn {
3795        AtnDeserializer::new(&SerializedAtn::from_i32(&[
3796            4, 1, 2, // version, parser, max token type
3797            3, // states
3798            2, 0, // rule start
3799            1, 0, // basic
3800            7, 0, // rule stop
3801            0, // non-greedy states
3802            0, // precedence states
3803            1, // rules
3804            0, // rule 0 start
3805            0, // modes
3806            0, // sets
3807            2, // transitions
3808            0, 1, 5, 1, 0, 0, // match token 1
3809            1, 2, 5, -1, 0, 0, // match EOF
3810            0, // decisions
3811        ]))
3812        .deserialize()
3813        .expect("artificial parser ATN should deserialize")
3814    }
3815
3816    fn eof_then_action_atn() -> Atn {
3817        AtnDeserializer::new(&SerializedAtn::from_i32(&[
3818            4, 1, 1, // version, parser, max token type
3819            3, // states
3820            2, 0, // rule start
3821            1, 0, // basic
3822            7, 0, // rule stop
3823            0, // non-greedy states
3824            0, // precedence states
3825            1, // rules
3826            0, // rule 0 start
3827            0, // modes
3828            0, // sets
3829            2, // transitions
3830            0, 1, 5, -1, 0, 0, // match EOF
3831            1, 2, 6, 0, 0, 0, // parser action
3832            0, // decisions
3833        ]))
3834        .deserialize()
3835        .expect("artificial parser ATN should deserialize")
3836    }
3837
3838    #[test]
3839    fn parser_matches_token_and_reports_mismatch() {
3840        let source = Source {
3841            tokens: vec![
3842                CommonToken::new(1).with_text("x"),
3843                CommonToken::eof("parser-test", 1, 1, 1),
3844            ],
3845            index: 0,
3846        };
3847        let data = RecognizerData::new(
3848            "Mini.g4",
3849            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
3850        );
3851        let mut parser = BaseParser::new(CommonTokenStream::new(source), data);
3852        assert_eq!(
3853            parser.match_token(1).expect("token 1 should match").text(),
3854            "x"
3855        );
3856        assert!(parser.match_token(1).is_err());
3857    }
3858
3859    #[test]
3860    fn parser_interprets_simple_atn_rule() {
3861        let atn = token_then_eof_atn();
3862        let mut parser = mini_parser(vec![
3863            CommonToken::new(1).with_text("x"),
3864            CommonToken::eof("parser-test", 1, 1, 1),
3865        ]);
3866
3867        let tree = parser
3868            .parse_atn_rule(&atn, 0)
3869            .expect("artificial parser rule should parse");
3870        assert_eq!(tree.text(), "x<EOF>");
3871        assert_eq!(
3872            tree.first_rule_stop(0)
3873                .expect("rule should stop at EOF")
3874                .token_type(),
3875            TOKEN_EOF
3876        );
3877
3878        let mut parser = mini_parser(vec![
3879            CommonToken::new(1).with_text("x"),
3880            CommonToken::eof("parser-test", 1, 1, 1),
3881        ]);
3882        let (tree, actions) = parser
3883            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
3884            .expect("runtime-option parser rule should parse");
3885        assert!(actions.is_empty());
3886        assert_eq!(
3887            tree.first_rule_stop(0)
3888                .expect("rule should stop at EOF")
3889                .token_type(),
3890            TOKEN_EOF
3891        );
3892    }
3893
3894    #[test]
3895    fn parser_rule_start_skips_leading_hidden_tokens() {
3896        let atn = token_then_eof_atn();
3897        let mut parser = mini_parser(vec![
3898            CommonToken::new(99)
3899                .with_text(" ")
3900                .with_channel(HIDDEN_CHANNEL),
3901            CommonToken::new(1).with_text("x"),
3902            CommonToken::eof("parser-test", 2, 1, 2),
3903        ]);
3904
3905        let tree = parser
3906            .parse_atn_rule(&atn, 0)
3907            .expect("artificial parser rule should parse");
3908        let Some(ParseTree::Rule(rule)) = tree.first_rule(0) else {
3909            panic!("rule node should be present");
3910        };
3911        assert_eq!(
3912            rule.context()
3913                .start()
3914                .expect("rule should have a start token")
3915                .token_type(),
3916            1
3917        );
3918    }
3919
3920    #[test]
3921    fn parser_action_after_eof_stops_at_eof_token() {
3922        let atn = eof_then_action_atn();
3923        let mut parser = mini_parser(vec![CommonToken::eof("parser-test", 0, 1, 0)]);
3924
3925        let (_, actions) = parser
3926            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
3927            .expect("EOF action rule should parse");
3928
3929        assert_eq!(actions.len(), 1);
3930        assert_eq!(actions[0].stop_index(), Some(0));
3931        assert_eq!(
3932            parser.text_interval(actions[0].start_index(), actions[0].stop_index()),
3933            ""
3934        );
3935    }
3936
3937    #[test]
3938    fn fast_outcome_selection_respects_sll_tie_order() {
3939        let first = FastRecognizeOutcome {
3940            index: 1,
3941            consumed_eof: false,
3942            diagnostics: vec![ParserDiagnostic {
3943                line: 1,
3944                column: 0,
3945                message: "mismatched input 'x'".to_owned(),
3946            }],
3947        };
3948        let second = FastRecognizeOutcome {
3949            index: first.index,
3950            consumed_eof: first.consumed_eof,
3951            diagnostics: Vec::new(),
3952        };
3953
3954        let selected = select_best_fast_outcome(
3955            [first.clone(), second.clone()].into_iter(),
3956            PredictionMode::Sll,
3957        )
3958        .expect("one outcome should be selected");
3959        assert_eq!(selected.diagnostics.len(), 1);
3960        let eof_second = FastRecognizeOutcome {
3961            index: second.index,
3962            consumed_eof: true,
3963            diagnostics: Vec::new(),
3964        };
3965        let selected =
3966            select_best_fast_outcome([first.clone(), eof_second].into_iter(), PredictionMode::Sll)
3967                .expect("one outcome should be selected");
3968        assert!(!selected.consumed_eof);
3969        let selected = select_best_fast_outcome([first, second].into_iter(), PredictionMode::Ll)
3970            .expect("one outcome should be selected");
3971        assert!(selected.diagnostics.is_empty());
3972    }
3973
3974    #[test]
3975    fn parser_error_with_empty_expected_set_omits_empty_set_display() {
3976        let source = Source {
3977            tokens: vec![
3978                CommonToken::new(1).with_text("x"),
3979                CommonToken::eof("parser-test", 1, 1, 1),
3980            ],
3981            index: 0,
3982        };
3983        let data = RecognizerData::new(
3984            "Mini.g4",
3985            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
3986        );
3987        let mut parser = BaseParser::new(CommonTokenStream::new(source), data);
3988        let expected = ExpectedTokens {
3989            index: Some(0),
3990            symbols: BTreeSet::new(),
3991            no_viable: None,
3992        };
3993
3994        let (_, message) = parser.expected_error_message(0, 0, &expected);
3995
3996        assert_eq!(message, "mismatched input 'x'");
3997    }
3998
3999    #[test]
4000    fn eof_rule_stop_index_points_at_eof_token() {
4001        let source = Source {
4002            tokens: vec![
4003                CommonToken::new(1).with_text("x"),
4004                CommonToken::eof("parser-test", 1, 1, 1),
4005            ],
4006            index: 0,
4007        };
4008        let data = RecognizerData::new(
4009            "Mini.g4",
4010            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
4011        );
4012        let mut parser = BaseParser::new(CommonTokenStream::new(source), data);
4013
4014        assert_eq!(parser.rule_stop_token_index(1, true), Some(1));
4015        assert_eq!(parser.rule_stop_token_index(1, false), Some(0));
4016    }
4017
4018    #[test]
4019    fn folds_left_recursive_boundary_into_rule_node() {
4020        let nodes = fold_left_recursive_boundaries(vec![
4021            RecognizedNode::Token { index: 0 },
4022            RecognizedNode::LeftRecursiveBoundary { rule_index: 1 },
4023            RecognizedNode::Token { index: 1 },
4024        ]);
4025
4026        assert_eq!(
4027            nodes,
4028            vec![
4029                RecognizedNode::Rule {
4030                    rule_index: 1,
4031                    invoking_state: -1,
4032                    alt_number: 0,
4033                    start_index: 0,
4034                    stop_index: Some(0),
4035                    return_values: BTreeMap::new(),
4036                    children: vec![RecognizedNode::Token { index: 0 }],
4037                },
4038                RecognizedNode::Token { index: 1 },
4039            ]
4040        );
4041    }
4042
4043    #[test]
4044    fn outcome_ties_keep_later_non_recursive_alternative() {
4045        let first = RecognizeOutcome {
4046            index: 1,
4047            consumed_eof: false,
4048            alt_number: 0,
4049            member_values: BTreeMap::new(),
4050            return_values: BTreeMap::new(),
4051            diagnostics: Vec::new(),
4052            decisions: Vec::new(),
4053            actions: vec![ParserAction::new(1, 0, 0, None)],
4054            nodes: vec![RecognizedNode::Token { index: 0 }],
4055        };
4056        let second = RecognizeOutcome {
4057            actions: vec![ParserAction::new(2, 0, 0, None)],
4058            ..first.clone()
4059        };
4060
4061        let selected = select_best_outcome([first, second].into_iter(), PredictionMode::Ll)
4062            .expect("one outcome should be selected");
4063        assert_eq!(selected.actions[0].source_state(), 2);
4064    }
4065
4066    #[test]
4067    fn outcome_ties_prefer_more_actions_for_non_recursive_paths() {
4068        let first = RecognizeOutcome {
4069            index: 1,
4070            consumed_eof: false,
4071            alt_number: 0,
4072            member_values: BTreeMap::new(),
4073            return_values: BTreeMap::new(),
4074            diagnostics: Vec::new(),
4075            decisions: Vec::new(),
4076            actions: vec![ParserAction::new(1, 0, 0, None)],
4077            nodes: vec![RecognizedNode::Token { index: 0 }],
4078        };
4079        let second = RecognizeOutcome {
4080            actions: vec![
4081                ParserAction::new(2, 0, 0, None),
4082                ParserAction::new(3, 0, 0, None),
4083            ],
4084            ..first.clone()
4085        };
4086
4087        let selected = select_best_outcome([second, first].into_iter(), PredictionMode::Ll)
4088            .expect("one outcome should be selected");
4089        assert_eq!(selected.actions.len(), 2);
4090    }
4091
4092    #[test]
4093    fn outcome_ties_prefer_later_action_stop_for_greedy_optional_paths() {
4094        let first = RecognizeOutcome {
4095            index: 7,
4096            consumed_eof: false,
4097            alt_number: 0,
4098            member_values: BTreeMap::new(),
4099            return_values: BTreeMap::new(),
4100            diagnostics: Vec::new(),
4101            decisions: vec![1, 0],
4102            actions: vec![
4103                ParserAction::new(23, 2, 2, Some(4)),
4104                ParserAction::new(23, 2, 0, Some(6)),
4105            ],
4106            nodes: vec![RecognizedNode::Token { index: 0 }],
4107        };
4108        let second = RecognizeOutcome {
4109            decisions: vec![0, 1],
4110            actions: vec![
4111                ParserAction::new(23, 2, 2, Some(6)),
4112                ParserAction::new(23, 2, 0, Some(6)),
4113            ],
4114            ..first.clone()
4115        };
4116
4117        let selected = select_best_outcome([first, second].into_iter(), PredictionMode::Ll)
4118            .expect("one outcome should be selected");
4119        assert_eq!(selected.actions[0].stop_index(), Some(6));
4120    }
4121
4122    #[test]
4123    fn outcome_ties_keep_first_recursive_tree_shape() {
4124        let recursive_nodes = vec![RecognizedNode::Rule {
4125            rule_index: 1,
4126            invoking_state: -1,
4127            alt_number: 0,
4128            start_index: 0,
4129            stop_index: Some(0),
4130            return_values: BTreeMap::new(),
4131            children: vec![RecognizedNode::Rule {
4132                rule_index: 1,
4133                invoking_state: -1,
4134                alt_number: 0,
4135                start_index: 0,
4136                stop_index: Some(0),
4137                return_values: BTreeMap::new(),
4138                children: vec![RecognizedNode::Token { index: 0 }],
4139            }],
4140        }];
4141        let first = RecognizeOutcome {
4142            index: 1,
4143            consumed_eof: false,
4144            alt_number: 0,
4145            member_values: BTreeMap::new(),
4146            return_values: BTreeMap::new(),
4147            diagnostics: Vec::new(),
4148            decisions: Vec::new(),
4149            actions: vec![ParserAction::new(1, 0, 0, None)],
4150            nodes: recursive_nodes.clone(),
4151        };
4152        let second = RecognizeOutcome {
4153            index: 1,
4154            consumed_eof: false,
4155            alt_number: 0,
4156            member_values: BTreeMap::new(),
4157            return_values: BTreeMap::new(),
4158            diagnostics: Vec::new(),
4159            decisions: Vec::new(),
4160            actions: vec![ParserAction::new(2, 0, 0, None)],
4161            nodes: recursive_nodes,
4162        };
4163
4164        let selected = select_best_outcome([first, second].into_iter(), PredictionMode::Ll)
4165            .expect("one outcome should be selected");
4166        assert_eq!(selected.actions[0].source_state(), 1);
4167    }
4168
4169    #[test]
4170    fn sll_outcome_selection_keeps_earlier_recovered_alt() {
4171        let first_alt = RecognizeOutcome {
4172            index: 2,
4173            consumed_eof: true,
4174            alt_number: 0,
4175            member_values: BTreeMap::new(),
4176            return_values: BTreeMap::new(),
4177            diagnostics: vec![ParserDiagnostic {
4178                line: 1,
4179                column: 3,
4180                message: "missing 'Y' at '<EOF>'".to_owned(),
4181            }],
4182            decisions: vec![0],
4183            actions: vec![ParserAction::new(1, 0, 0, None)],
4184            nodes: vec![RecognizedNode::Token { index: 0 }],
4185        };
4186        let second_alt = RecognizeOutcome {
4187            diagnostics: Vec::new(),
4188            decisions: vec![1],
4189            actions: vec![ParserAction::new(2, 0, 0, None)],
4190            ..first_alt.clone()
4191        };
4192
4193        let selected =
4194            select_best_outcome([second_alt, first_alt].into_iter(), PredictionMode::Sll)
4195                .expect("one outcome should be selected");
4196        assert_eq!(selected.diagnostics.len(), 1);
4197        assert_eq!(selected.decisions, [0]);
4198    }
4199}