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