Skip to main content

antlr4_runtime/
parser.rs

1// `HashMap`/`HashSet` here are used as parser-internal caches keyed on
2// stable ATN coordinates (state numbers, token indices). They're never
3// iterated externally, so the project's `disallowed_types` lint (which
4// guards against non-deterministic iteration order leaking out) does not
5// apply to these uses.
6use std::cell::RefCell;
7use std::cmp::Ordering;
8#[allow(clippy::disallowed_types)]
9use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
10use std::hash::{BuildHasherDefault, Hash, Hasher};
11use std::rc::Rc;
12
13/// Rotate constant copied from rustc-hash / `FxHash`. The default
14/// `RandomState` hasher seeds itself from the OS RNG and runs `SipHash` on
15/// every key, which dominates `recognize_state_fast`'s memo lookups;
16/// `FxHasher` is a streaming integer hasher with near-zero per-call overhead
17/// and matches the access pattern of small integer keys that the parser memo
18/// uses.
19#[derive(Clone, Copy, Default)]
20struct FxHasher {
21    hash: u64,
22}
23
24const FX_ROT: u32 = 5;
25const FX_SEED: u64 = 0x51_7c_c1_b7_27_22_0a_95;
26
27impl Hasher for FxHasher {
28    /// Folds bytes 8 at a time so a `write(&[u8; 8])` call hashes to the same
29    /// state as a `write_u64` of the same little-endian bits. The `Hash` impls
30    /// for `String`, `[u8; N]`, and slice-like types reach the hasher through
31    /// `write`; matching the typed-method behaviour avoids the silent
32    /// divergence flagged in PR #5 review (Greptile P2). Tail bytes that do
33    /// not form a full word are mixed one at a time with the same constants,
34    /// keeping behaviour deterministic regardless of the slice length.
35    #[inline]
36    fn write(&mut self, mut bytes: &[u8]) {
37        while bytes.len() >= 8 {
38            let (head, rest) = bytes.split_at(8);
39            let word = u64::from_le_bytes(head.try_into().expect("8-byte chunk"));
40            self.hash = (self.hash.rotate_left(FX_ROT) ^ word).wrapping_mul(FX_SEED);
41            bytes = rest;
42        }
43        for byte in bytes {
44            self.hash = (self.hash.rotate_left(FX_ROT) ^ u64::from(*byte)).wrapping_mul(FX_SEED);
45        }
46    }
47    #[inline]
48    fn write_u64(&mut self, value: u64) {
49        self.hash = (self.hash.rotate_left(FX_ROT) ^ value).wrapping_mul(FX_SEED);
50    }
51    #[inline]
52    fn write_usize(&mut self, value: usize) {
53        self.write_u64(value as u64);
54    }
55    #[inline]
56    fn write_u32(&mut self, value: u32) {
57        self.write_u64(u64::from(value));
58    }
59    #[inline]
60    fn write_i32(&mut self, value: i32) {
61        self.write_u64(u64::from(i32::cast_unsigned(value)));
62    }
63    #[inline]
64    fn finish(&self) -> u64 {
65        self.hash
66    }
67}
68
69type FxBuildHasher = BuildHasherDefault<FxHasher>;
70#[allow(clippy::disallowed_types)]
71type FxHashMap<K, V> = HashMap<K, V, FxBuildHasher>;
72#[allow(clippy::disallowed_types)]
73type FxHashSet<K> = HashSet<K, FxBuildHasher>;
74
75use crate::atn::AtnStateKind;
76use crate::atn::parser::{
77    ParserAtnPrediction, ParserAtnPredictionDiagnosticKind, ParserAtnSimulator,
78};
79use crate::atn::parser_atn::{
80    ParserAtn as Atn, ParserAtnState as AtnState, ParserIntervalSet, ParserTransition,
81    ParserTransitionData as Transition, ParserTransitionKind,
82};
83#[cfg(test)]
84use crate::atn::parser_atn::{ParserAtnBuilder, ParserTransitionSpec};
85use crate::char_stream::CharStream;
86use crate::errors::AntlrError;
87use crate::int_stream::IntStream;
88use crate::lexer::{LexerCustomAction, LexerLifecycleCtx, LexerSemCtx};
89use crate::recognizer::{Recognizer, RecognizerData};
90use crate::semir::{self, AStmt, ArithOp, CmpOp, ExprId, HookId, PExpr, SemIr, StmtId};
91use crate::token::{
92    TOKEN_EOF, Token, TokenId, TokenSource, TokenSourceError, TokenSpec, TokenStore, TokenView,
93};
94use crate::token_stream::CommonTokenStream;
95use crate::tree::{
96    Node, NodeId, ParseTreeCheckpoint, ParseTreeStorage, ParsedFile, ParserRuleContext,
97};
98use crate::vocabulary::Vocabulary;
99
100type ParseTree = NodeId;
101
102/// Upper bound for the recursive metadata recognizer before it treats a path as
103/// non-viable. Long expression-regression descriptors legitimately walk tens
104/// of thousands of ATN edges.
105const RECOGNITION_DEPTH_LIMIT: usize = 32_768;
106/// Preserve the recursive hot path while checking native stack capacity often
107/// enough that one unchecked group cannot cross the protected red zone.
108const FAST_RECOGNIZE_STACK_CHECK_INTERVAL: usize = 8;
109const FAST_RECOGNIZE_RED_ZONE: usize = 1024 * 1024;
110const FAST_RECOGNIZE_STACK_SIZE: usize = 4 * 1024 * 1024;
111/// Whole-rule direct adaptive execution is allowed to give up and fall back to
112/// the existing recognizer. Keep the guard at the same order of magnitude as
113/// speculative recognition so malformed cyclic ATNs cannot spin forever.
114const ADAPTIVE_DIRECT_STEP_LIMIT: usize = RECOGNITION_DEPTH_LIMIT;
115/// Probe window for deciding whether clean-pass memo entries are reusable
116/// enough to keep caching. High-cardinality parses mostly produce one-shot
117/// entries; compact ambiguous loops repeatedly hit the same keys.
118const CLEAN_MEMO_PROBE_LIMIT: usize = 4096;
119const CLEAN_MEMO_REPEAT_LIMIT: usize = 8;
120/// Sparse parses periodically reopen the bounded probe so a repeat-heavy
121/// region that starts later in the token stream can promote memoization.
122const CLEAN_MEMO_REPROBE_INTERVAL: usize = 262_144;
123const FAST_RECOGNIZE_VISITING_CAPACITY: usize = 256;
124const FAST_RECOGNIZE_MIN_MEMO_CAPACITY: usize = 256;
125const FAST_RECOGNIZE_MAX_MEMO_CAPACITY: usize = 524_288;
126const FAST_RECOGNIZE_MAX_RETAINED_MEMO_CAPACITY: usize = 65_536;
127
128#[derive(Clone, Copy, Debug, Eq, PartialEq)]
129enum CleanMemoMode {
130    Probe,
131    Promote,
132    Sparse,
133}
134
135fn interval_set_contains(intervals: &[(i32, i32)], symbol: i32) -> bool {
136    intervals
137        .iter()
138        .any(|(start, stop)| (*start..=*stop).contains(&symbol))
139}
140
141fn interval_symbols(intervals: &[(i32, i32)]) -> BTreeSet<i32> {
142    let mut symbols = BTreeSet::new();
143    for (start, stop) in intervals {
144        symbols.extend(*start..=*stop);
145    }
146    symbols
147}
148
149fn interval_complement_symbols(
150    intervals: &[(i32, i32)],
151    min_vocabulary: i32,
152    max_vocabulary: i32,
153) -> BTreeSet<i32> {
154    (min_vocabulary..=max_vocabulary)
155        .filter(|symbol| !interval_set_contains(intervals, *symbol))
156        .collect()
157}
158
159#[cfg(feature = "perf-counters")]
160mod perf_counters {
161    use std::cell::Cell;
162    thread_local! {
163        pub(super) static RFS_CALLS: Cell<u64> = const { Cell::new(0) };
164        pub(super) static RFS_MEMO_HITS: Cell<u64> = const { Cell::new(0) };
165        pub(super) static RFS_MEMO_MISSES: Cell<u64> = const { Cell::new(0) };
166        pub(super) static RFS_VISITING_CYCLE: Cell<u64> = const { Cell::new(0) };
167        pub(super) static MEMO_INSERTED: Cell<u64> = const { Cell::new(0) };
168        pub(super) static OUTCOMES_PUSHED: Cell<u64> = const { Cell::new(0) };
169        pub(super) static OUTCOMES_CLONED: Cell<u64> = const { Cell::new(0) };
170        pub(super) static OUTCOME_DEDUPE_INPUTS: Cell<u64> = const { Cell::new(0) };
171        pub(super) static OUTCOME_DEDUPE_REMOVED: Cell<u64> = const { Cell::new(0) };
172        pub(super) static OUTCOME_DEDUPE_INLINE: Cell<u64> = const { Cell::new(0) };
173        pub(super) static OUTCOME_DEDUPE_DENSE: Cell<u64> = const { Cell::new(0) };
174        pub(super) static OUTCOME_DEDUPE_SPARSE: Cell<u64> = const { Cell::new(0) };
175        pub(super) static OUTCOME_DEDUPE_DENSE_WORDS: Cell<u64> = const { Cell::new(0) };
176    }
177    pub(super) fn inc(c: &'static std::thread::LocalKey<Cell<u64>>, n: u64) {
178        c.with(|v| v.set(v.get() + n));
179    }
180    thread_local! {
181        pub(super) static EPSILON_TRANSITIONS: Cell<u64> = const { Cell::new(0) };
182        pub(super) static RULE_TRANSITIONS: Cell<u64> = const { Cell::new(0) };
183        pub(super) static ATOM_RANGE_TRANSITIONS: Cell<u64> = const { Cell::new(0) };
184        pub(super) static SINGLE_TRANS_BODY: Cell<u64> = const { Cell::new(0) };
185        pub(super) static MULTI_TRANS_BODY: Cell<u64> = const { Cell::new(0) };
186        pub(super) static SINGLE_TRANS_RULE: Cell<u64> = const { Cell::new(0) };
187        pub(super) static SINGLE_TRANS_ATOM: Cell<u64> = const { Cell::new(0) };
188        pub(super) static SINGLE_TRANS_OTHER: Cell<u64> = const { Cell::new(0) };
189        pub(super) static OUTCOMES_RETURN_0: Cell<u64> = const { Cell::new(0) };
190        pub(super) static OUTCOMES_RETURN_1: Cell<u64> = const { Cell::new(0) };
191        pub(super) static OUTCOMES_RETURN_N: Cell<u64> = const { Cell::new(0) };
192    }
193    pub(super) fn snapshot() -> [(&'static str, u64); 24] {
194        [
195            ("rfs_calls", RFS_CALLS.with(Cell::get)),
196            ("rfs_memo_hits", RFS_MEMO_HITS.with(Cell::get)),
197            ("rfs_memo_misses", RFS_MEMO_MISSES.with(Cell::get)),
198            ("rfs_visiting_cycle", RFS_VISITING_CYCLE.with(Cell::get)),
199            ("memo_inserted", MEMO_INSERTED.with(Cell::get)),
200            ("outcomes_pushed", OUTCOMES_PUSHED.with(Cell::get)),
201            ("outcomes_cloned", OUTCOMES_CLONED.with(Cell::get)),
202            (
203                "outcome_dedupe_inputs",
204                OUTCOME_DEDUPE_INPUTS.with(Cell::get),
205            ),
206            (
207                "outcome_dedupe_removed",
208                OUTCOME_DEDUPE_REMOVED.with(Cell::get),
209            ),
210            (
211                "outcome_dedupe_inline",
212                OUTCOME_DEDUPE_INLINE.with(Cell::get),
213            ),
214            ("outcome_dedupe_dense", OUTCOME_DEDUPE_DENSE.with(Cell::get)),
215            (
216                "outcome_dedupe_sparse",
217                OUTCOME_DEDUPE_SPARSE.with(Cell::get),
218            ),
219            (
220                "outcome_dedupe_dense_words",
221                OUTCOME_DEDUPE_DENSE_WORDS.with(Cell::get),
222            ),
223            ("epsilon_transitions", EPSILON_TRANSITIONS.with(Cell::get)),
224            ("rule_transitions", RULE_TRANSITIONS.with(Cell::get)),
225            (
226                "atom_range_transitions",
227                ATOM_RANGE_TRANSITIONS.with(Cell::get),
228            ),
229            ("single_trans_body", SINGLE_TRANS_BODY.with(Cell::get)),
230            ("multi_trans_body", MULTI_TRANS_BODY.with(Cell::get)),
231            ("single_trans_rule", SINGLE_TRANS_RULE.with(Cell::get)),
232            ("single_trans_atom", SINGLE_TRANS_ATOM.with(Cell::get)),
233            ("single_trans_other", SINGLE_TRANS_OTHER.with(Cell::get)),
234            ("outcomes_return_0", OUTCOMES_RETURN_0.with(Cell::get)),
235            ("outcomes_return_1", OUTCOMES_RETURN_1.with(Cell::get)),
236            ("outcomes_return_n", OUTCOMES_RETURN_N.with(Cell::get)),
237        ]
238    }
239    pub fn reset() {
240        RFS_CALLS.with(|c| c.set(0));
241        RFS_MEMO_HITS.with(|c| c.set(0));
242        RFS_MEMO_MISSES.with(|c| c.set(0));
243        RFS_VISITING_CYCLE.with(|c| c.set(0));
244        MEMO_INSERTED.with(|c| c.set(0));
245        OUTCOMES_PUSHED.with(|c| c.set(0));
246        OUTCOMES_CLONED.with(|c| c.set(0));
247        OUTCOME_DEDUPE_INPUTS.with(|c| c.set(0));
248        OUTCOME_DEDUPE_REMOVED.with(|c| c.set(0));
249        OUTCOME_DEDUPE_INLINE.with(|c| c.set(0));
250        OUTCOME_DEDUPE_DENSE.with(|c| c.set(0));
251        OUTCOME_DEDUPE_SPARSE.with(|c| c.set(0));
252        OUTCOME_DEDUPE_DENSE_WORDS.with(|c| c.set(0));
253        EPSILON_TRANSITIONS.with(|c| c.set(0));
254        RULE_TRANSITIONS.with(|c| c.set(0));
255        ATOM_RANGE_TRANSITIONS.with(|c| c.set(0));
256        SINGLE_TRANS_BODY.with(|c| c.set(0));
257        MULTI_TRANS_BODY.with(|c| c.set(0));
258        SINGLE_TRANS_RULE.with(|c| c.set(0));
259        SINGLE_TRANS_ATOM.with(|c| c.set(0));
260        SINGLE_TRANS_OTHER.with(|c| c.set(0));
261        OUTCOMES_RETURN_0.with(|c| c.set(0));
262        OUTCOMES_RETURN_1.with(|c| c.set(0));
263        OUTCOMES_RETURN_N.with(|c| c.set(0));
264    }
265    pub fn dump() {
266        for (name, value) in snapshot() {
267            #[allow(clippy::print_stderr)]
268            {
269                eprintln!("perf {name}={value}");
270            }
271        }
272    }
273}
274
275#[cfg(feature = "perf-counters")]
276pub use perf_counters::{dump as dump_perf_counters, reset as reset_perf_counters};
277/// Preserve lazy lexing for short or failing inputs, but eagerly fill once the
278/// fast recognizer has probed far enough that per-token stream sync dominates.
279/// Sixty-four tokens is a small rule-sized window: it keeps startup lazy while
280/// switching long inputs to the cheaper filled-stream path before large fanout.
281const FAST_RECOGNIZER_DEFERRED_FILL_AT: usize = 64;
282/// Parser semantic action reached while recognizing one ATN path.
283///
284/// Generated parsers use `source_state` to dispatch back to the grammar action
285/// rendered for that ATN action transition. The token interval is the current
286/// rule's input span at the action site, which covers common target templates
287/// such as `$text`. Rule-init actions do not have an ATN action source state,
288/// so they are marked separately and may carry an ATN state for expected-token
289/// rendering.
290#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
291pub struct ParserAction {
292    source_state: usize,
293    rule_index: usize,
294    start_index: usize,
295    stop_index: Option<usize>,
296    rule_init: bool,
297    expected_state: Option<usize>,
298}
299
300impl ParserAction {
301    /// Creates an action event for a recognized parser path.
302    pub const fn new(
303        source_state: usize,
304        rule_index: usize,
305        start_index: usize,
306        stop_index: Option<usize>,
307    ) -> Self {
308        Self {
309            source_state,
310            rule_index,
311            start_index,
312            stop_index,
313            rule_init: false,
314            expected_state: None,
315        }
316    }
317
318    /// Creates an action event for a rule-level `@init` action.
319    pub const fn new_rule_init(
320        rule_index: usize,
321        start_index: usize,
322        expected_state: Option<usize>,
323    ) -> Self {
324        Self {
325            source_state: usize::MAX,
326            rule_index,
327            start_index,
328            stop_index: None,
329            rule_init: true,
330            expected_state,
331        }
332    }
333
334    /// ATN state that owns the semantic-action transition.
335    pub const fn source_state(&self) -> usize {
336        self.source_state
337    }
338
339    /// Grammar rule index recorded by the serialized ATN action transition.
340    pub const fn rule_index(&self) -> usize {
341        self.rule_index
342    }
343
344    /// Token-stream index where the active rule began.
345    pub const fn start_index(&self) -> usize {
346        self.start_index
347    }
348
349    /// Last token-stream index consumed before the action was reached.
350    pub const fn stop_index(&self) -> Option<usize> {
351        self.stop_index
352    }
353
354    /// Reports whether this event represents a rule-level `@init` action.
355    pub const fn is_rule_init(&self) -> bool {
356        self.rule_init
357    }
358
359    /// ATN state used to compute expected-token display for this action.
360    pub const fn expected_state(&self) -> Option<usize> {
361        self.expected_state
362    }
363}
364
365/// Runtime view passed to parser semantic hooks.
366///
367/// The context is intentionally read-only with respect to parser structure:
368/// predicates may run speculatively during prediction, and hooks can be called
369/// more than once for paths that are later abandoned. Lookahead methods may
370/// buffer tokens from the underlying token source, matching normal parser
371/// prediction behavior.
372pub struct ParserSemCtx<'a, S>
373where
374    S: TokenSource,
375{
376    input: &'a mut CommonTokenStream<S>,
377    tree_storage: &'a ParseTreeStorage,
378    rule_index: usize,
379    coordinate_index: usize,
380    rule_name: Option<String>,
381    context: Option<&'a ParserRuleContext>,
382    tree: Option<ParseTree>,
383    local_int_arg: Option<(usize, i64)>,
384    member_values: &'a BTreeMap<usize, i64>,
385    action: Option<ParserAction>,
386}
387
388impl<S> std::fmt::Debug for ParserSemCtx<'_, S>
389where
390    S: TokenSource,
391{
392    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
393        f.debug_struct("ParserSemCtx")
394            .field("rule_index", &self.rule_index)
395            .field("coordinate_index", &self.coordinate_index)
396            .field("rule_name", &self.rule_name)
397            .field("context", &self.context)
398            .field("tree", &self.tree)
399            .field("local_int_arg", &self.local_int_arg)
400            .field("member_values", &self.member_values)
401            .field("action", &self.action)
402            .finish_non_exhaustive()
403    }
404}
405
406impl<'a, S> ParserSemCtx<'a, S>
407where
408    S: TokenSource,
409{
410    /// Rule index that owns the predicate/action coordinate.
411    #[must_use]
412    pub const fn rule_index(&self) -> usize {
413        self.rule_index
414    }
415
416    /// Rule name that owns the coordinate, when recognizer metadata has it.
417    #[must_use]
418    pub fn rule_name(&self) -> Option<&str> {
419        self.rule_name.as_deref()
420    }
421
422    /// Predicate/action index inside the owning rule. Parser actions keyed only
423    /// by ATN source state report `usize::MAX` here; use [`Self::action`] for
424    /// the stable action event.
425    #[must_use]
426    pub const fn coordinate_index(&self) -> usize {
427        self.coordinate_index
428    }
429
430    /// Current token-stream index.
431    #[must_use]
432    pub fn input_index(&self) -> usize {
433        self.input.index()
434    }
435
436    /// Token type at one-based lookahead/lookbehind offset.
437    pub fn la(&mut self, offset: isize) -> i32 {
438        self.input.la(offset)
439    }
440
441    /// Token at one-based lookahead/lookbehind offset.
442    pub fn lt(&self, offset: isize) -> Option<TokenView<'_>> {
443        self.input.lt(offset)
444    }
445
446    /// Borrowing token view for text inspection at a one-based offset.
447    pub fn token_text(&self, offset: isize) -> Option<TokenView<'_>> {
448        self.lt(offset)
449    }
450
451    /// Token at an absolute buffered index, including hidden/custom channels.
452    ///
453    /// Unlike [`Self::lt`], this does not apply the token stream's channel
454    /// filter and does not move its cursor. It is intended for semantic helpers
455    /// such as automatic-semicolon-insertion checks that inspect trivia
456    /// immediately before the current visible token.
457    pub fn token_at(&self, index: usize) -> Option<TokenView<'_>> {
458        self.input.get(index)
459    }
460
461    /// Current generated rule context, when a generated rule predicate supplied
462    /// one.
463    #[must_use]
464    pub const fn context(&self) -> Option<&'a ParserRuleContext> {
465        self.context
466    }
467
468    /// Flat tree storage containing completed children visible to this hook.
469    #[must_use]
470    pub const fn parse_tree_storage(&self) -> &'a ParseTreeStorage {
471        self.tree_storage
472    }
473
474    /// Canonical token store used by completed flat-tree nodes.
475    #[must_use]
476    pub const fn token_store(&self) -> &TokenStore {
477        self.input.token_store()
478    }
479
480    /// Completed parse-tree root ID passed to a replayed action hook.
481    #[must_use]
482    pub const fn tree_id(&self) -> Option<NodeId> {
483        self.tree
484    }
485
486    /// Completed parse tree passed to an action hook, if the action is being
487    /// replayed after recognition.
488    #[must_use]
489    pub fn tree(&self) -> Option<Node<'_>> {
490        self.tree
491            .and_then(|id| self.tree_storage.node(self.input.token_store(), id))
492    }
493
494    /// Integer local argument visible to this predicate coordinate.
495    #[must_use]
496    pub fn local_int_arg(&self) -> Option<i64> {
497        self.local_int_arg.map(|(_, value)| value)
498    }
499
500    /// Integer member value observed on the current speculative path.
501    #[must_use]
502    pub fn member_int(&self, member: usize) -> Option<i64> {
503        self.member_values.get(&member).copied()
504    }
505
506    /// Parser action event being replayed, when this context belongs to an
507    /// action hook.
508    #[must_use]
509    pub const fn action(&self) -> Option<ParserAction> {
510        self.action
511    }
512
513    /// Text covered by a parser action event.
514    ///
515    /// Mirrors [`BaseParser::text_interval`] / `$text`: when the stop token is
516    /// EOF the interval ends at the previous *visible* token, so trailing hidden
517    /// tokens (and the EOF marker) are excluded rather than blindly subtracting
518    /// one, which could point at hidden whitespace. `CommonTokenStream::text`
519    /// itself guards `start > stop`, so an empty interval yields `""`.
520    pub fn action_text(&self) -> String {
521        let Some(action) = self.action else {
522            return String::new();
523        };
524        let Some(stop) = action.stop_index() else {
525            return String::new();
526        };
527        let stop = if self
528            .input
529            .get(stop)
530            .is_some_and(|token| token.token_type() == TOKEN_EOF)
531        {
532            let Some(previous) = self.input.previous_visible_token_index(stop) else {
533                return String::new();
534            };
535            previous
536        } else {
537            stop
538        };
539        self.input.text(action.start_index(), stop)
540    }
541}
542
543/// User extension point for parser semantic predicates and actions that the
544/// metadata generator did not translate into built-in runtime metadata.
545///
546/// Returning `None`/`false` says "not handled", so the runtime falls through
547/// to the configured [`UnknownSemanticPolicy`]. Predicate hooks may run during
548/// speculative prediction and must be replay-safe.
549pub trait SemanticHooks {
550    /// Whether generated lexers should route lifecycle callbacks through this
551    /// hook object.
552    ///
553    /// User hook implementations opt in by default. [`NoSemanticHooks`]
554    /// overrides this to keep generated lexers on the direct no-extension
555    /// token path.
556    const ENABLES_LEXER_LIFECYCLE: bool = true;
557
558    /// Whether this hook object may observe parser predicate transitions.
559    ///
560    /// Custom hooks default to conservative predicate handling so the fast
561    /// recognizer does not bypass a `sempred` implementation.
562    fn observes_parser_predicates(&self) -> bool {
563        true
564    }
565
566    /// Whether this hook object may override interpreted parser decisions.
567    ///
568    /// This remains disabled by default so ordinary generated parsers retain
569    /// the fast recognizer path.
570    fn observes_parser_decisions(&self) -> bool {
571        false
572    }
573
574    /// Overrides one interpreted parser decision with a one-based alternative.
575    ///
576    /// Returning `None` leaves normal adaptive prediction in control. Hooks
577    /// that return an alternative own any one-shot or input-index filtering
578    /// they require.
579    fn parser_decision_override(
580        &mut self,
581        decision: usize,
582        input_index: usize,
583        alternative_count: usize,
584    ) -> Option<usize> {
585        let _ = (decision, input_index, alternative_count);
586        None
587    }
588
589    fn sempred<S>(
590        &mut self,
591        ctx: &mut ParserSemCtx<'_, S>,
592        rule_index: usize,
593        pred_index: usize,
594    ) -> Option<bool>
595    where
596        S: TokenSource,
597    {
598        let _ = (ctx, rule_index, pred_index);
599        None
600    }
601
602    fn action<S>(&mut self, ctx: &mut ParserSemCtx<'_, S>, action: ParserAction) -> bool
603    where
604        S: TokenSource,
605    {
606        let _ = (ctx, action);
607        false
608    }
609
610    fn lexer_sempred<I>(
611        &mut self,
612        ctx: &mut LexerSemCtx<'_, I>,
613        rule_index: usize,
614        pred_index: usize,
615    ) -> Option<bool>
616    where
617        I: CharStream,
618    {
619        let _ = (ctx, rule_index, pred_index);
620        None
621    }
622
623    /// Runs a lexer custom action on the committed lexing path. Returns whether
624    /// the hook handled the action.
625    ///
626    /// The action runs post-accept, so `ctx` carries a mutable lexer borrow: a
627    /// hook may change lexer state, including [`LexerSemCtx::set_type`],
628    /// [`LexerSemCtx::set_channel`], mode changes, input consumption, and
629    /// queued prefix tokens, just like the closure-based `custom_action` API.
630    /// (The speculative predicate context in [`Self::lexer_sempred`] is a shared
631    /// borrow, so those mutators are inert there.)
632    fn lexer_action<I>(&mut self, ctx: &mut LexerSemCtx<'_, I>, action: LexerCustomAction) -> bool
633    where
634        I: CharStream,
635    {
636        let _ = (ctx, action);
637        false
638    }
639
640    /// Runs after runtime-owned lexer state has been reset for reuse.
641    ///
642    /// Implementations should clear extension-owned transient state here.
643    fn lexer_reset<I>(&mut self, ctx: &mut LexerLifecycleCtx<'_, I>)
644    where
645        I: CharStream,
646    {
647        let _ = ctx;
648    }
649
650    /// Runs before the runtime returns a queued token or starts a new ATN
651    /// token match.
652    ///
653    /// The callback also runs between internal `skip`/`more` matches, so it
654    /// observes every point where another ATN match may start.
655    fn lexer_before_token<I>(&mut self, ctx: &mut LexerLifecycleCtx<'_, I>)
656    where
657        I: CharStream,
658    {
659        let _ = ctx;
660    }
661
662    /// Runs after the accepted path's portable and custom actions, but before
663    /// the token span is finalized and emitted.
664    ///
665    /// Accepted paths that selected `skip` or `more` are included, and the hook
666    /// may observe or override that pending token type.
667    ///
668    /// This callback has no synthetic ATN coordinate. It therefore also runs
669    /// for accepted rules that contain no action or predicate.
670    fn lexer_after_accept<I>(&mut self, ctx: &mut LexerLifecycleCtx<'_, I>)
671    where
672        I: CharStream,
673    {
674        let _ = ctx;
675    }
676
677    /// Observes a token after committed lexer actions and portable commands
678    /// have run and the token has been emitted, immediately before it is
679    /// returned to the token stream.
680    ///
681    /// Hidden and custom-channel tokens are included. `skip` and intermediate
682    /// `more` matches do not produce callbacks.
683    fn lexer_token_emitted(&mut self, token: TokenView<'_>) {
684        let _ = token;
685    }
686}
687
688/// Default hook object used by parsers that do not need user-supplied
689/// semantics.
690#[derive(Clone, Copy, Debug, Default)]
691pub struct NoSemanticHooks;
692
693impl SemanticHooks for NoSemanticHooks {
694    const ENABLES_LEXER_LIFECYCLE: bool = false;
695
696    fn observes_parser_predicates(&self) -> bool {
697        false
698    }
699}
700
701/// Parser semantic predicate rendered from a supported target template.
702///
703/// The metadata recognizer evaluates these at the token-stream index where the
704/// predicate transition is reached. Unsupported or absent predicate templates
705/// remain unconditional so existing generated parsers keep their previous
706/// behavior unless the generator opts into this table.
707#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
708pub enum ParserPredicate {
709    True,
710    False,
711    /// Predicate that always fails and carries ANTLR's `<fail='...'>` message.
712    FalseWithMessage {
713        message: &'static str,
714    },
715    /// Target-template test helper that reports predicate evaluation before
716    /// returning the wrapped boolean value.
717    Invoke {
718        value: bool,
719    },
720    LookaheadTextEquals {
721        offset: isize,
722        text: &'static str,
723    },
724    LookaheadNotEquals {
725        offset: isize,
726        token_type: i32,
727    },
728    /// Checks that the last two consumed visible tokens were adjacent in the
729    /// token stream. Used by C# parser predicates for split operator tokens.
730    TokenPairAdjacent,
731    /// Checks a generated parser context child by rule index and text.
732    ///
733    /// If the child is absent the predicate succeeds, matching target helpers
734    /// that treat incomplete or non-matching contexts as non-restrictive.
735    ContextChildRuleTextNotEquals {
736        rule_index: usize,
737        text: &'static str,
738    },
739    /// Compares the current rule invocation's integer argument with a literal
740    /// value from a supported `ValEquals("$i", "...")` target template.
741    LocalIntEquals {
742        value: i64,
743    },
744    /// Checks ANTLR-style raw predicates like `5 >= $_p` against the current
745    /// rule invocation's integer argument.
746    LocalIntLessOrEqual {
747        value: i64,
748    },
749    /// Compares a generated parser integer member modulo a literal value.
750    MemberModuloEquals {
751        member: usize,
752        modulus: i64,
753        value: i64,
754        equals: bool,
755    },
756    /// Compares a generated parser integer member with a literal value.
757    MemberEquals {
758        member: usize,
759        value: i64,
760        equals: bool,
761    },
762}
763
764impl ParserPredicate {
765    /// Lowers the legacy predicate metadata variant into `SemIR`.
766    ///
767    /// This is the compatibility adapter for generated parsers produced while
768    /// the runtime still emitted closed enum tables. Newer generated parsers
769    /// emit `SemIR` directly.
770    pub fn lower_into_semir(self, ir: &mut SemIr) -> ExprId {
771        match self {
772            Self::True => ir.expr(PExpr::Bool(true)),
773            Self::False | Self::FalseWithMessage { .. } => ir.expr(PExpr::Bool(false)),
774            Self::Invoke { value } => ir.expr(PExpr::EvalTrace(value)),
775            Self::LookaheadTextEquals { offset, text } => {
776                let token = ir.expr(PExpr::TokenText(offset));
777                let text = ir.intern(text);
778                let text = ir.expr(PExpr::Str(text));
779                ir.expr(PExpr::Cmp(CmpOp::Eq, token, text))
780            }
781            Self::LookaheadNotEquals { offset, token_type } => {
782                let actual = ir.expr(PExpr::La(offset));
783                let expected = ir.expr(PExpr::Int(i64::from(token_type)));
784                ir.expr(PExpr::Cmp(CmpOp::Ne, actual, expected))
785            }
786            Self::TokenPairAdjacent => ir.expr(PExpr::TokenIndexAdjacent),
787            Self::ContextChildRuleTextNotEquals { rule_index, text } => {
788                let actual = ir.expr(PExpr::CtxRuleText(rule_index));
789                let expected = ir.intern(text);
790                let expected = ir.expr(PExpr::Str(expected));
791                ir.expr(PExpr::Cmp(CmpOp::Ne, actual, expected))
792            }
793            Self::LocalIntEquals { value } => local_arg_comparison(ir, CmpOp::Eq, value),
794            Self::LocalIntLessOrEqual { value } => local_arg_comparison(ir, CmpOp::Le, value),
795            Self::MemberModuloEquals {
796                member,
797                modulus,
798                value,
799                equals,
800            } => {
801                if modulus == 0 {
802                    return ir.expr(PExpr::Bool(false));
803                }
804                let member = ir.expr(PExpr::Member(member));
805                let modulus = ir.expr(PExpr::Int(modulus));
806                let actual = ir.expr(PExpr::Arith(ArithOp::Mod, member, modulus));
807                let expected = ir.expr(PExpr::Int(value));
808                ir.expr(PExpr::Cmp(
809                    if equals { CmpOp::Eq } else { CmpOp::Ne },
810                    actual,
811                    expected,
812                ))
813            }
814            Self::MemberEquals {
815                member,
816                value,
817                equals,
818            } => {
819                let actual = ir.expr(PExpr::Member(member));
820                let expected = ir.expr(PExpr::Int(value));
821                ir.expr(PExpr::Cmp(
822                    if equals { CmpOp::Eq } else { CmpOp::Ne },
823                    actual,
824                    expected,
825                ))
826            }
827        }
828    }
829
830    #[must_use]
831    pub const fn failure_message(self) -> Option<&'static str> {
832        match self {
833            Self::FalseWithMessage { message } => Some(message),
834            Self::True
835            | Self::False
836            | Self::Invoke { .. }
837            | Self::LookaheadTextEquals { .. }
838            | Self::LookaheadNotEquals { .. }
839            | Self::TokenPairAdjacent
840            | Self::ContextChildRuleTextNotEquals { .. }
841            | Self::LocalIntEquals { .. }
842            | Self::LocalIntLessOrEqual { .. }
843            | Self::MemberModuloEquals { .. }
844            | Self::MemberEquals { .. } => None,
845        }
846    }
847}
848
849fn local_arg_comparison(ir: &mut SemIr, op: CmpOp, value: i64) -> ExprId {
850    let local = ir.expr(PExpr::LocalArg);
851    let absent = ir.expr(PExpr::IsNull(local));
852    let expected = ir.expr(PExpr::Int(value));
853    let comparison = ir.expr(PExpr::Cmp(op, local, expected));
854    ir.expr(PExpr::Or([absent, comparison].into()))
855}
856
857/// Policy for semantic predicate coordinates that have no runtime
858/// implementation.
859///
860/// ANTLR grammars may embed target-language predicates that the metadata
861/// generator could not translate into a [`ParserPredicate`] table entry. When
862/// recognition reaches such a coordinate the runtime cannot know the grammar
863/// author's intent, so the caller chooses how to proceed.
864///
865/// The default is [`Self::AssumeTrue`], matching the historical behavior of
866/// this runtime. That default is deprecated and will change to [`Self::Error`]
867/// in a future minor release; grammars relying on unconditional predicates
868/// should opt in explicitly.
869#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
870pub enum UnknownSemanticPolicy {
871    /// Treat the predicate as passing, as if it were absent from the grammar.
872    #[default]
873    AssumeTrue,
874    /// Treat the predicate as failing, removing the guarded alternative.
875    AssumeFalse,
876    /// Fail the parse with [`AntlrError::Unsupported`] naming every unknown
877    /// coordinate that recognition evaluated.
878    Error,
879}
880
881/// Resolves a predicate coordinate that neither a translated table entry nor a
882/// user hook could answer, applying the active [`UnknownSemanticPolicy`].
883///
884/// Under [`UnknownSemanticPolicy::Error`] the coordinate is recorded in `hits`
885/// so the parse entry can surface every unresolved coordinate afterwards. Both
886/// the legacy [`ParserPredicate`] path and the [`semir::PExpr::Hook`] path
887/// funnel through here so a missing implementation is never silently coerced
888/// to a boolean (design goal G1: never silently mis-parse).
889fn apply_unknown_predicate_policy(
890    policy: UnknownSemanticPolicy,
891    rule_index: usize,
892    pred_index: usize,
893    hits: &mut Vec<(usize, usize)>,
894) -> bool {
895    match policy {
896        UnknownSemanticPolicy::AssumeTrue => true,
897        UnknownSemanticPolicy::AssumeFalse => false,
898        UnknownSemanticPolicy::Error => {
899            let coordinate = (rule_index, pred_index);
900            if !hits.contains(&coordinate) {
901                hits.push(coordinate);
902            }
903            false
904        }
905    }
906}
907
908/// Interval-set of expected token types, displayable through a vocabulary —
909/// the shape ANTLR's `getExpectedTokens().toString(vocabulary)` exposes to
910/// generated test actions.
911#[derive(Clone, Debug, Eq, PartialEq)]
912pub struct ExpectedTokenSet {
913    symbols: BTreeSet<i32>,
914}
915
916impl ExpectedTokenSet {
917    /// Formats the set using ANTLR token display names, e.g. `{'a', 'b'}`.
918    #[must_use]
919    pub fn to_token_string(&self, vocabulary: &Vocabulary) -> String {
920        expected_symbols_display(&self.symbols, vocabulary)
921    }
922}
923
924/// Marker error strategy matching ANTLR's `BailErrorStrategy`.
925///
926/// The first syntax error aborts the parse instead of recovering. Generated
927/// recognizers accept it through `set_error_handler(BailErrorStrategy::new())`.
928#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
929pub struct BailErrorStrategy;
930
931impl BailErrorStrategy {
932    #[must_use]
933    pub const fn new() -> Self {
934        Self
935    }
936}
937
938/// Prediction strategy requested by generated parser harnesses.
939#[derive(Clone, Copy, Debug, Eq, PartialEq)]
940pub enum PredictionMode {
941    /// Prefer the clean full-context outcome when alternatives reach the same
942    /// input position.
943    Ll,
944    /// Preserve SLL's first-viable alternative bias at a decision, even when a
945    /// later full-context alternative could avoid recovery.
946    Sll,
947    /// Full LL prediction with exact ambiguity detection for diagnostic runs.
948    LlExactAmbigDetection,
949}
950
951/// Integer argument metadata for a generated parser rule invocation.
952///
953/// ANTLR's serialized ATN does not retain Rust-target rule argument values, so
954/// the generator records the rule-transition source state and the value that
955/// should be visible to semantic predicates inside the callee.
956#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
957pub struct ParserRuleArg {
958    /// ATN state containing the rule transition that receives this argument.
959    pub source_state: usize,
960    /// Callee rule index for the transition.
961    pub rule_index: usize,
962    /// Literal fallback value to expose in the callee.
963    pub value: i64,
964    /// Whether the callee should inherit the caller's current integer argument.
965    pub inherit_local: bool,
966}
967
968/// Integer member mutation attached to an ATN action transition.
969#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
970pub struct ParserMemberAction {
971    /// ATN state containing the action transition.
972    pub source_state: usize,
973    /// Generator-assigned integer member id.
974    pub member: usize,
975    /// Delta applied when the action is reached on one speculative path.
976    pub delta: i64,
977}
978
979/// Integer return-value assignment attached to an ATN action transition.
980///
981/// Generated parsers use this metadata when target actions assign a simple
982/// return field such as `$y=1000;`. The interpreter applies it while selecting
983/// the recognized path so the finished parse tree can answer later
984/// `$label.y` action templates.
985#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
986pub struct ParserReturnAction {
987    /// ATN state containing the action transition.
988    pub source_state: usize,
989    /// Rule index recorded by the serialized action transition.
990    pub rule_index: usize,
991    /// Return-field name as it appears in the grammar.
992    pub name: &'static str,
993    /// Literal integer value assigned by the action.
994    pub value: i64,
995}
996
997impl ParserMemberAction {
998    /// Lowers this speculative member mutation into a `SemIR` action.
999    pub fn lower_into_semir(self, ir: &mut SemIr) -> ParserSemanticAction {
1000        let delta = ir.expr(PExpr::Int(self.delta));
1001        ParserSemanticAction {
1002            source_state: self.source_state,
1003            rule_index: usize::MAX,
1004            stmt: ir.stmt(AStmt::AddMember(self.member, delta)),
1005            speculative: true,
1006        }
1007    }
1008}
1009
1010impl ParserReturnAction {
1011    /// Lowers this committed return-value assignment into a `SemIR` action.
1012    pub fn lower_into_semir(self, ir: &mut SemIr) -> ParserSemanticAction {
1013        let name = ir.intern(self.name);
1014        let value = ir.expr(PExpr::Int(self.value));
1015        ParserSemanticAction {
1016            source_state: self.source_state,
1017            rule_index: self.rule_index,
1018            stmt: ir.stmt(AStmt::SetReturn(name, value)),
1019            speculative: false,
1020        }
1021    }
1022}
1023
1024/// Parser predicate coordinate lowered into [`SemIr`].
1025#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1026pub struct ParserSemanticPredicate {
1027    /// Serialized rule index that owns this predicate.
1028    pub rule_index: usize,
1029    /// Predicate index inside the owning rule.
1030    pub pred_index: usize,
1031    /// Root expression in the associated [`ParserSemantics::ir`] arena.
1032    pub expr: ExprId,
1033    /// ANTLR `<fail='...'>` message for predicates that intentionally fail.
1034    pub failure_message: Option<&'static str>,
1035}
1036
1037/// Parser action coordinate lowered into [`SemIr`].
1038#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1039pub struct ParserSemanticAction {
1040    /// ATN state containing the action transition.
1041    pub source_state: usize,
1042    /// Serialized rule index recorded by the action transition.
1043    pub rule_index: usize,
1044    /// Root statement in the associated [`ParserSemantics::ir`] arena.
1045    pub stmt: StmtId,
1046    /// Whether this action may run on speculative recognition paths.
1047    pub speculative: bool,
1048}
1049
1050/// Data-driven semantic tables emitted by generated parsers.
1051///
1052/// This is the runtime representation for issue #9's `SemIR` path. Existing
1053/// `ParserPredicate`, `ParserMemberAction`, and `ParserReturnAction` tables
1054/// remain accepted as deprecated adapters for generated code produced before
1055/// this table existed.
1056#[derive(Clone, Debug, Default, Eq, PartialEq)]
1057pub struct ParserSemantics {
1058    pub ir: SemIr,
1059    pub predicates: Vec<ParserSemanticPredicate>,
1060    pub actions: Vec<ParserSemanticAction>,
1061}
1062
1063/// Optional generated-runtime metadata for metadata-driven parser execution.
1064#[derive(Clone, Copy, Debug, Default)]
1065pub struct ParserRuntimeOptions<'a> {
1066    /// Rule indexes whose `@init` actions should be replayed.
1067    pub init_action_rules: &'a [usize],
1068    /// Whether generated parse-tree contexts should retain alternative numbers.
1069    pub track_alt_numbers: bool,
1070    /// Whether generated typed contexts should retain private dispatch alternatives.
1071    ///
1072    /// Unlike `track_alt_numbers`, this metadata does not affect the public
1073    /// alternative number or parse-tree rendering.
1074    #[doc(hidden)]
1075    pub track_context_alt_numbers: bool,
1076    /// Semantic predicate table keyed by serialized `(rule_index, pred_index)`.
1077    pub predicates: &'a [(usize, usize, ParserPredicate)],
1078    /// `SemIR` predicate/action table emitted by newer generated parsers.
1079    pub semantics: Option<&'a ParserSemantics>,
1080    /// Rule-call integer argument table keyed by ATN source state.
1081    pub rule_args: &'a [ParserRuleArg],
1082    /// Integer member mutations keyed by ATN action source state.
1083    pub member_actions: &'a [ParserMemberAction],
1084    /// Integer return assignments keyed by ATN action source state.
1085    pub return_actions: &'a [ParserReturnAction],
1086    /// How to evaluate semantic predicate coordinates absent from
1087    /// `predicates`.
1088    pub unknown_predicate_policy: UnknownSemanticPolicy,
1089}
1090
1091pub trait Parser: Recognizer {
1092    /// Reports whether generated parser rules should build parse-tree nodes
1093    /// while recognizing input.
1094    fn build_parse_trees(&self) -> bool;
1095
1096    /// Enables or disables parse-tree construction for subsequent rule calls.
1097    fn set_build_parse_trees(&mut self, build: bool);
1098
1099    /// Returns the number of parser syntax errors recorded by committed parse
1100    /// paths so far.
1101    fn number_of_syntax_errors(&self) -> usize {
1102        0
1103    }
1104
1105    /// Reports whether prediction diagnostic-listener messages are emitted
1106    /// during parser ATN recognition.
1107    fn report_diagnostic_errors(&self) -> bool {
1108        false
1109    }
1110
1111    /// Enables or disables ANTLR-style prediction diagnostics for subsequent
1112    /// rule calls.
1113    fn set_report_diagnostic_errors(&mut self, _report: bool) {}
1114
1115    /// Reports the prediction strategy used when selecting among alternatives.
1116    fn prediction_mode(&self) -> PredictionMode {
1117        PredictionMode::Ll
1118    }
1119
1120    /// Sets the prediction strategy for subsequent rule calls.
1121    fn set_prediction_mode(&mut self, _mode: PredictionMode) {}
1122}
1123
1124#[derive(Debug)]
1125struct LeftRecursiveCallerOverlap {
1126    atn_key: SharedAtnCacheKey,
1127    state_number: usize,
1128    symbol: i32,
1129    context_version: usize,
1130    overlaps: bool,
1131}
1132
1133const LEFT_RECURSIVE_CALLER_OVERLAP_CACHE_SIZE: usize = 16;
1134
1135#[derive(Debug)]
1136pub struct BaseParser<S, H = NoSemanticHooks> {
1137    input: CommonTokenStream<S>,
1138    tree: ParseTreeStorage,
1139    data: RecognizerData,
1140    semantic_hooks: H,
1141    decision_override_generation: usize,
1142    build_parse_trees: bool,
1143    syntax_errors: usize,
1144    report_diagnostic_errors: bool,
1145    prediction_mode: PredictionMode,
1146    prediction_diagnostics: Vec<ParserDiagnostic>,
1147    reported_prediction_diagnostics: BTreeSet<(usize, usize, String)>,
1148    generated_parser_diagnostics: Vec<ParserDiagnostic>,
1149    generated_sync_expected: Option<TokenBitSet>,
1150    generated_recovery_error_index: Option<usize>,
1151    generated_recovery_error_states: BTreeSet<isize>,
1152    int_members: BTreeMap<usize, i64>,
1153    rule_context_stack: Vec<RuleContextFrame>,
1154    rule_context_version: usize,
1155    left_recursive_caller_overlap_cache:
1156        [Option<LeftRecursiveCallerOverlap>; LEFT_RECURSIVE_CALLER_OVERLAP_CACHE_SIZE],
1157    pending_invoking_states: Vec<isize>,
1158    precedence_stack: Vec<i32>,
1159    /// Predicate side effects are observable in a few target-template tests;
1160    /// speculative recognition may revisit the same coordinate, so replay it
1161    /// once per parser instance.
1162    invoked_predicates: Vec<(usize, usize)>,
1163    /// Bail error strategy: the first syntax error aborts the parse instead of
1164    /// recovering (ANTLR's `BailErrorStrategy`). Generated recognizers set it
1165    /// through `set_error_handler(BailErrorStrategy::new())`.
1166    bail_on_error: bool,
1167    /// How to evaluate predicate coordinates missing from the active
1168    /// predicate table. Set from [`ParserRuntimeOptions`] at each parse entry.
1169    unknown_predicate_policy: UnknownSemanticPolicy,
1170    /// Unknown predicate coordinates evaluated by the current parse, recorded
1171    /// so [`UnknownSemanticPolicy::Error`] can report them after recognition.
1172    unknown_predicate_hits: Vec<(usize, usize)>,
1173    /// Committed parser action coordinates offered to [`SemanticHooks::action`]
1174    /// that no hook handled, recorded so a generated `hook`/error-disposed
1175    /// action fails loud instead of being silently dropped. Keyed by
1176    /// `(rule_index, source_state)`.
1177    unhandled_action_hits: Vec<(usize, usize)>,
1178    /// Per-parse rule FIRST-set cache keyed by rule start state. This keeps
1179    /// hot rule-transition checks to a vector lookup after the first visit
1180    /// while the thread-local shared ATN cache still owns the cross-parse
1181    /// computed value.
1182    rule_first_set_cache: Vec<Option<Rc<FirstSet>>>,
1183    /// Per-state expected-symbol cache. `state_expected_symbols` walks every
1184    /// epsilon-reachable consuming transition and shows up as a hot loop in
1185    /// `next_recovery_context` and recovery diagnostics on long inputs.
1186    /// Keying on `state_number` and sharing the result through `Rc` removes
1187    /// repeated DFS plus per-call `BTreeSet` allocations.
1188    state_expected_cache: FxHashMap<usize, Rc<BTreeSet<i32>>>,
1189    /// Same expected-symbol cache as a bitset for generated parser sync.
1190    /// Successful parses only need `contains` and union; keeping that path out
1191    /// of `BTreeSet` avoids tree allocation for every nullable loop/optional
1192    /// check and defers deterministic formatting to diagnostics.
1193    state_expected_token_cache: FxHashMap<usize, Rc<TokenBitSet>>,
1194    /// Per-state cache for whether a return state can finish its owning rule
1195    /// without consuming more input. Generated-parser sync uses this to walk
1196    /// parent prediction contexts for nullable exits without paying repeated
1197    /// epsilon-closure searches on every loop or optional decision.
1198    rule_stop_reach_cache: Vec<Option<bool>>,
1199    /// Per-parser interner for `recovery_symbols` sets. Speculative recursion
1200    /// threads the same epsilon-recovery context through hundreds of follow
1201    /// states; sharing `Rc<BTreeSet<i32>>` instances lets clones reduce to a
1202    /// reference bump and lets the memo key hash by pointer.
1203    recovery_symbols_intern: FxHashMap<Rc<BTreeSet<i32>>, Rc<BTreeSet<i32>>>,
1204    /// Per-decision-state look-1 cache. Built lazily so grammars that rarely
1205    /// touch a given decision state still pay no upfront cost; once cached,
1206    /// the recognizer prunes alternatives whose look-1 cannot accept the
1207    /// current lookahead, letting common SLL decisions reduce to a single
1208    /// transition walk instead of a full speculative fan-out.
1209    decision_lookahead_cache: FxHashMap<usize, Rc<DecisionLookahead>>,
1210    /// Caches the LL(1) alt selection per `(state, lookahead_token)`.
1211    /// Each multi-trans visit asks "given this decision state and this
1212    /// lookahead token, which alt do I commit to?" Hitting this cache
1213    /// turns the question into a hashmap probe instead of re-scanning
1214    /// the decision's per-transition FIRST sets every visit.
1215    ll1_decision_cache: FxHashMap<(usize, i32), Option<usize>>,
1216    /// Predicate results shared by the fast recognizer's clean and recovery
1217    /// attempts. The eligible fast path keeps every runtime-provided input
1218    /// fixed, and custom predicate hooks are required to be replay-safe.
1219    fast_predicate_cache: FxHashMap<(usize, usize, usize), bool>,
1220    /// Cache for whether an ATN state can reach itself without consuming
1221    /// input. Only those states need the recursive recognizer's
1222    /// `(state, token-index)` cycle guard. The companion ATN key lets this
1223    /// grammar-static cache survive parser resets without reusing state
1224    /// coordinates after the parser is driven against a different ATN.
1225    empty_cycle_cache: Vec<Option<bool>>,
1226    empty_cycle_cache_atn: Option<SharedAtnCacheKey>,
1227    /// Probe state for deciding whether clean-pass memo entries are worth
1228    /// storing for the current parse.
1229    clean_memo_mode: CleanMemoMode,
1230    clean_memo_probe_seen: FxHashSet<FastRecognizeKey>,
1231    clean_memo_probe_samples: usize,
1232    clean_memo_probe_repeats: usize,
1233    clean_memo_sparse_samples: usize,
1234    /// Reusable cycle and memo storage for one top-level fast recognition.
1235    fast_recognize_scratch: FastRecognizeTopScratch,
1236    /// Reusable direct-index/hash storage for clean speculative endpoints.
1237    fast_outcome_dedup: FastOutcomeDedupScratch,
1238    /// Empty recovery-symbols singleton used as the default at rule entry and
1239    /// after token consumption.
1240    empty_recovery_symbols: Rc<BTreeSet<i32>>,
1241    /// Whether the fast recognizer's FIRST-set prefilter is enabled. The
1242    /// prefilter trims speculative rule calls whose called rule cannot
1243    /// match the current lookahead, but it also bypasses single-token
1244    /// insertion / deletion recovery that ANTLR runs at the rule's first
1245    /// consuming transition. `parse_atn_rule` flips this off and retries
1246    /// when the first pass produces no clean outcome so the runtime can
1247    /// repair inputs the reference parser would have repaired.
1248    fast_first_set_prefilter: bool,
1249    /// Whether the fast recognizer should explore parser error-recovery paths.
1250    /// Public rule parsing starts with this disabled for the common valid-input
1251    /// path and enables it only for the retry that needs ANTLR-style repairs.
1252    fast_recovery_enabled: bool,
1253    /// Whether the fast recognizer should record terminal-token nodes while
1254    /// speculating. Clean valid-input parsing can reconstruct terminals from
1255    /// selected rule spans after recognition, avoiding many speculative
1256    /// nodes that are thrown away with losing paths.
1257    fast_token_nodes_enabled: bool,
1258    /// Parser-owned append-only storage for speculative recognition output.
1259    /// Each public interpreted-rule entry clears lengths while retaining
1260    /// bounded backing capacities for parser reuse.
1261    recognition_arena: RecognitionArena,
1262    last_recognition_arena_root: NodeSeqId,
1263    last_recognition_arena_diagnostics: DiagnosticSeqId,
1264}
1265
1266/// Rollback marker for speculative generated parser paths.
1267#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1268pub struct GeneratedDiagnosticsCheckpoint {
1269    diagnostics_len: usize,
1270    syntax_errors: usize,
1271    tree: ParseTreeCheckpoint,
1272}
1273
1274/// Storage and reachability counters for the most recent interpreted-rule
1275/// recognition arena.
1276#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
1277pub struct RecognitionArenaStats {
1278    pub total_nodes: usize,
1279    pub live_nodes: usize,
1280    pub dead_nodes: usize,
1281    pub node_capacity: usize,
1282    pub total_links: usize,
1283    pub live_links: usize,
1284    pub dead_links: usize,
1285    pub link_capacity: usize,
1286    pub total_extras: usize,
1287    pub live_extras: usize,
1288    pub dead_extras: usize,
1289    pub extra_capacity: usize,
1290}
1291
1292#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1293struct RuleContextFrame {
1294    rule_index: usize,
1295    invoking_state: isize,
1296}
1297
1298#[derive(Clone, Debug, Eq, PartialEq)]
1299struct RecognizeOutcome {
1300    index: usize,
1301    consumed_eof: bool,
1302    alt_number: usize,
1303    member_values: BTreeMap<usize, i64>,
1304    return_values: BTreeMap<String, i64>,
1305    diagnostics: DiagnosticSeqId,
1306    decisions: Vec<usize>,
1307    actions: Vec<ParserAction>,
1308    nodes: NodeSeqId,
1309}
1310
1311#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1312struct FastRecognizeOutcome {
1313    index: usize,
1314    consumed_eof: bool,
1315    diagnostics: DiagnosticSeqId,
1316    deferred_nodes: FastDeferredNodeId,
1317    /// Head of the speculative parse-tree fragment in the parser-owned arena.
1318    /// Copying an outcome copies this compact ID; prepending appends one
1319    /// `SeqLink` without allocating an individual node or list tail.
1320    nodes: NodeSeqId,
1321}
1322
1323#[derive(Debug, Default)]
1324struct FastRecognizeTopScratch {
1325    visiting: FxHashSet<FastRecognizeKey>,
1326    memo: FxHashMap<FastRecognizeKey, Rc<[FastRecognizeOutcome]>>,
1327}
1328
1329impl FastRecognizeTopScratch {
1330    fn prepare(&mut self, memo_capacity: usize) {
1331        self.visiting.clear();
1332        self.visiting.reserve(FAST_RECOGNIZE_VISITING_CAPACITY);
1333        self.memo.clear();
1334        self.memo.reserve(memo_capacity);
1335    }
1336
1337    fn release_oversized_memo(&mut self) {
1338        self.memo.clear();
1339        if self.memo.capacity() > FAST_RECOGNIZE_MAX_RETAINED_MEMO_CAPACITY {
1340            self.memo = FxHashMap::default();
1341        }
1342    }
1343}
1344
1345fn fast_recognize_memo_capacity(buffered_tokens: usize) -> usize {
1346    buffered_tokens.saturating_mul(8).clamp(
1347        FAST_RECOGNIZE_MIN_MEMO_CAPACITY,
1348        FAST_RECOGNIZE_MAX_MEMO_CAPACITY,
1349    )
1350}
1351
1352#[derive(Debug, Default)]
1353struct FastOutcomeDedupScratch {
1354    dense_words: Vec<u64>,
1355    touched_dense_words: Vec<u32>,
1356    sparse_keys: FxHashSet<(usize, bool)>,
1357}
1358
1359/// Handle into the parser-owned deferred tree rope.
1360///
1361/// The sentinel keeps outcomes and repetition paths compact without an
1362/// `Option` discriminant or per-node reference counting.
1363#[repr(transparent)]
1364#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1365struct FastDeferredNodeId(u32);
1366
1367impl FastDeferredNodeId {
1368    const EMPTY: Self = Self(u32::MAX);
1369
1370    const fn is_empty(self) -> bool {
1371        self.0 == Self::EMPTY.0
1372    }
1373}
1374
1375impl Default for FastDeferredNodeId {
1376    fn default() -> Self {
1377        Self::EMPTY
1378    }
1379}
1380
1381#[repr(transparent)]
1382#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1383struct FastDeferredRuleId(u32);
1384
1385/// One immutable deferred-tree rope record in `RecognitionArena`.
1386#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1387enum FastDeferredNode {
1388    Fragment(NodeSeqId),
1389    Rule(FastDeferredRuleId),
1390    Concat {
1391        prefix: FastDeferredNodeId,
1392        suffix: FastDeferredNodeId,
1393    },
1394}
1395
1396#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1397struct FastDeferredRule {
1398    rule_index: u32,
1399    invoking_state: i32,
1400    start_index: u32,
1401    stop_index: Option<u32>,
1402    deferred_children: FastDeferredNodeId,
1403    children: NodeSeqId,
1404}
1405
1406#[repr(transparent)]
1407#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1408struct RecognizedNodeId(u32);
1409
1410#[repr(transparent)]
1411#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1412struct NodeSeqId(u32);
1413
1414impl NodeSeqId {
1415    const EMPTY: Self = Self(u32::MAX);
1416
1417    const fn is_empty(self) -> bool {
1418        self.0 == Self::EMPTY.0
1419    }
1420}
1421
1422impl Default for NodeSeqId {
1423    fn default() -> Self {
1424        Self::EMPTY
1425    }
1426}
1427
1428#[repr(transparent)]
1429#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1430struct DiagnosticSeqId(u32);
1431
1432impl DiagnosticSeqId {
1433    const EMPTY: Self = Self(u32::MAX);
1434
1435    const fn is_empty(self) -> bool {
1436        self.0 == Self::EMPTY.0
1437    }
1438}
1439
1440impl Default for DiagnosticSeqId {
1441    fn default() -> Self {
1442        Self::EMPTY
1443    }
1444}
1445
1446#[repr(transparent)]
1447#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1448struct RecognitionExtraId(u32);
1449
1450#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
1451struct SeqLink {
1452    head: RecognizedNodeId,
1453    tail: NodeSeqId,
1454}
1455
1456#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
1457struct DiagnosticLink {
1458    head: RecognitionExtraId,
1459    tail: DiagnosticSeqId,
1460}
1461
1462struct ArenaRuleSpec {
1463    rule_index: usize,
1464    invoking_state: isize,
1465    alt_number: usize,
1466    start_index: usize,
1467    stop_index: Option<usize>,
1468    return_values: BTreeMap<String, i64>,
1469    children: NodeSeqId,
1470}
1471
1472/// Compact speculative node record. Common records contain only IDs and
1473/// scalars; missing-token text and generated return values live in `extras`.
1474#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
1475enum ArenaRecognizedNode {
1476    Token {
1477        token: TokenId,
1478    },
1479    ErrorToken {
1480        token: TokenId,
1481    },
1482    MissingToken {
1483        extra: RecognitionExtraId,
1484    },
1485    Rule {
1486        rule_index: u32,
1487        invoking_state: i32,
1488        alt_number: u32,
1489        start_index: u32,
1490        stop_index: Option<u32>,
1491        return_values: Option<RecognitionExtraId>,
1492        children: NodeSeqId,
1493    },
1494    /// Marker emitted at a precedence-rule loop entry where ANTLR would call
1495    /// `pushNewRecursionContext`. Folded into a wrapper rule node before the
1496    /// public rule entry hands the tree to the caller.
1497    LeftRecursiveBoundary {
1498        rule_index: u32,
1499        alt_number: u32,
1500    },
1501}
1502
1503#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
1504enum RecognitionExtra {
1505    MissingToken {
1506        token_type: i32,
1507        at_index: u32,
1508        text: String,
1509    },
1510    ReturnValues(BTreeMap<String, i64>),
1511    Diagnostic(ParserDiagnostic),
1512}
1513
1514#[derive(Debug, Default)]
1515struct RecognitionArena {
1516    nodes: Vec<ArenaRecognizedNode>,
1517    seq_links: Vec<SeqLink>,
1518    diagnostic_links: Vec<DiagnosticLink>,
1519    extras: Vec<RecognitionExtra>,
1520    deferred_nodes: Vec<FastDeferredNode>,
1521    deferred_rules: Vec<FastDeferredRule>,
1522}
1523
1524// Preserve normal parser reuse while preventing one pathological parse from
1525// pinning an arbitrarily large arena for the parser's remaining lifetime.
1526const MAX_RETAINED_RECOGNITION_NODES: usize = 131_072;
1527const MAX_RETAINED_RECOGNITION_SEQUENCE_LINKS: usize = 262_144;
1528const MAX_RETAINED_RECOGNITION_DIAGNOSTIC_LINKS: usize = 65_536;
1529const MAX_RETAINED_RECOGNITION_EXTRAS: usize = 32_768;
1530const MAX_RETAINED_FAST_DEFERRED_NODES: usize = 262_144;
1531const MAX_RETAINED_FAST_DEFERRED_RULES: usize = 131_072;
1532
1533impl RecognitionArena {
1534    fn reset(&mut self) {
1535        reset_arena_vec(&mut self.nodes, MAX_RETAINED_RECOGNITION_NODES);
1536        reset_arena_vec(&mut self.seq_links, MAX_RETAINED_RECOGNITION_SEQUENCE_LINKS);
1537        reset_arena_vec(
1538            &mut self.diagnostic_links,
1539            MAX_RETAINED_RECOGNITION_DIAGNOSTIC_LINKS,
1540        );
1541        reset_arena_vec(&mut self.extras, MAX_RETAINED_RECOGNITION_EXTRAS);
1542        reset_arena_vec(&mut self.deferred_nodes, MAX_RETAINED_FAST_DEFERRED_NODES);
1543        reset_arena_vec(&mut self.deferred_rules, MAX_RETAINED_FAST_DEFERRED_RULES);
1544    }
1545
1546    fn push_node(&mut self, node: ArenaRecognizedNode) -> RecognizedNodeId {
1547        let id = RecognizedNodeId(
1548            u32::try_from(self.nodes.len()).expect("recognition node arena fits in u32"),
1549        );
1550        self.nodes.push(node);
1551        id
1552    }
1553
1554    fn push_extra(&mut self, extra: RecognitionExtra) -> RecognitionExtraId {
1555        let id = RecognitionExtraId(
1556            u32::try_from(self.extras.len()).expect("recognition extra arena fits in u32"),
1557        );
1558        self.extras.push(extra);
1559        id
1560    }
1561
1562    fn prepend(&mut self, tail: NodeSeqId, head: RecognizedNodeId) -> NodeSeqId {
1563        let id = NodeSeqId(
1564            u32::try_from(self.seq_links.len()).expect("node sequence arena fits in u32"),
1565        );
1566        self.seq_links.push(SeqLink { head, tail });
1567        id
1568    }
1569
1570    fn push_deferred_node(&mut self, node: FastDeferredNode) -> FastDeferredNodeId {
1571        let id = FastDeferredNodeId(
1572            u32::try_from(self.deferred_nodes.len()).expect("deferred node arena fits in u32"),
1573        );
1574        self.deferred_nodes.push(node);
1575        id
1576    }
1577
1578    fn push_deferred_rule(&mut self, rule: FastDeferredRule) -> FastDeferredRuleId {
1579        let id = FastDeferredRuleId(
1580            u32::try_from(self.deferred_rules.len()).expect("deferred rule arena fits in u32"),
1581        );
1582        self.deferred_rules.push(rule);
1583        id
1584    }
1585
1586    fn deferred_fragment(&mut self, nodes: NodeSeqId) -> FastDeferredNodeId {
1587        if nodes.is_empty() {
1588            FastDeferredNodeId::EMPTY
1589        } else {
1590            self.push_deferred_node(FastDeferredNode::Fragment(nodes))
1591        }
1592    }
1593
1594    fn deferred_rule_node(&mut self, rule: FastDeferredRule) -> FastDeferredNodeId {
1595        let rule = self.push_deferred_rule(rule);
1596        self.push_deferred_node(FastDeferredNode::Rule(rule))
1597    }
1598
1599    fn concat_deferred_nodes(
1600        &mut self,
1601        prefix: FastDeferredNodeId,
1602        suffix: FastDeferredNodeId,
1603    ) -> FastDeferredNodeId {
1604        if prefix.is_empty() {
1605            return suffix;
1606        }
1607        if suffix.is_empty() {
1608            return prefix;
1609        }
1610        self.push_deferred_node(FastDeferredNode::Concat { prefix, suffix })
1611    }
1612
1613    fn deferred_node(&self, id: FastDeferredNodeId) -> FastDeferredNode {
1614        self.deferred_nodes[id.0 as usize]
1615    }
1616
1617    fn deferred_rule(&self, id: FastDeferredRuleId) -> FastDeferredRule {
1618        self.deferred_rules[id.0 as usize]
1619    }
1620
1621    fn prepend_diagnostic(
1622        &mut self,
1623        tail: DiagnosticSeqId,
1624        diagnostic: ParserDiagnostic,
1625    ) -> DiagnosticSeqId {
1626        let head = self.push_extra(RecognitionExtra::Diagnostic(diagnostic));
1627        self.prepend_diagnostic_id(tail, head)
1628    }
1629
1630    fn prepend_diagnostic_id(
1631        &mut self,
1632        tail: DiagnosticSeqId,
1633        head: RecognitionExtraId,
1634    ) -> DiagnosticSeqId {
1635        let id = DiagnosticSeqId(
1636            u32::try_from(self.diagnostic_links.len())
1637                .expect("diagnostic sequence arena fits in u32"),
1638        );
1639        self.diagnostic_links.push(DiagnosticLink { head, tail });
1640        id
1641    }
1642
1643    fn concat_diagnostics(
1644        &mut self,
1645        prefix: DiagnosticSeqId,
1646        mut suffix: DiagnosticSeqId,
1647    ) -> DiagnosticSeqId {
1648        if prefix.is_empty() {
1649            return suffix;
1650        }
1651        if suffix.is_empty() {
1652            return prefix;
1653        }
1654        let mut reversed = DiagnosticSeqId::EMPTY;
1655        let mut cursor = prefix;
1656        while let Some(link) = self.diagnostic_link(cursor) {
1657            reversed = self.prepend_diagnostic_id(reversed, link.head);
1658            cursor = link.tail;
1659        }
1660        while let Some(link) = self.diagnostic_link(reversed) {
1661            suffix = self.prepend_diagnostic_id(suffix, link.head);
1662            reversed = link.tail;
1663        }
1664        suffix
1665    }
1666
1667    #[cfg(test)]
1668    fn diagnostic_sequence(
1669        &mut self,
1670        diagnostics: impl IntoIterator<Item = ParserDiagnostic>,
1671    ) -> DiagnosticSeqId {
1672        let diagnostics = diagnostics.into_iter().collect::<Vec<_>>();
1673        let mut sequence = DiagnosticSeqId::EMPTY;
1674        for diagnostic in diagnostics.into_iter().rev() {
1675            sequence = self.prepend_diagnostic(sequence, diagnostic);
1676        }
1677        sequence
1678    }
1679
1680    fn node(&self, id: RecognizedNodeId) -> ArenaRecognizedNode {
1681        self.nodes[id.0 as usize]
1682    }
1683
1684    fn extra(&self, id: RecognitionExtraId) -> &RecognitionExtra {
1685        &self.extras[id.0 as usize]
1686    }
1687
1688    fn link(&self, id: NodeSeqId) -> Option<SeqLink> {
1689        (!id.is_empty()).then(|| self.seq_links[id.0 as usize])
1690    }
1691
1692    fn diagnostic_link(&self, id: DiagnosticSeqId) -> Option<DiagnosticLink> {
1693        (!id.is_empty()).then(|| self.diagnostic_links[id.0 as usize])
1694    }
1695
1696    const fn iter(&self, sequence: NodeSeqId) -> NodeSeqIter<'_> {
1697        NodeSeqIter {
1698            arena: self,
1699            cursor: sequence,
1700        }
1701    }
1702
1703    const fn diagnostics(&self, sequence: DiagnosticSeqId) -> DiagnosticSeqIter<'_> {
1704        DiagnosticSeqIter {
1705            arena: self,
1706            cursor: sequence,
1707        }
1708    }
1709
1710    fn diagnostics_len(&self, sequence: DiagnosticSeqId) -> usize {
1711        self.diagnostics(sequence).count()
1712    }
1713
1714    fn diagnostics_recovery_rank(&self, sequence: DiagnosticSeqId) -> usize {
1715        self.diagnostics(sequence)
1716            .filter(|diagnostic| {
1717                diagnostic.message.starts_with("mismatched input ")
1718                    && !diagnostic.message.starts_with("mismatched input '<EOF>' ")
1719            })
1720            .count()
1721    }
1722
1723    fn compare_diagnostics(&self, left: DiagnosticSeqId, right: DiagnosticSeqId) -> Ordering {
1724        self.diagnostics(left).cmp(self.diagnostics(right))
1725    }
1726
1727    fn sequence_len(&self, sequence: NodeSeqId) -> usize {
1728        self.iter(sequence).count()
1729    }
1730
1731    fn sequence_has_left_recursive_boundary(&self, sequence: NodeSeqId) -> bool {
1732        self.iter(sequence).any(|node| match self.node(node) {
1733            ArenaRecognizedNode::LeftRecursiveBoundary { .. } => true,
1734            ArenaRecognizedNode::Rule { children, .. } => {
1735                self.sequence_has_left_recursive_boundary(children)
1736            }
1737            ArenaRecognizedNode::Token { .. }
1738            | ArenaRecognizedNode::ErrorToken { .. }
1739            | ArenaRecognizedNode::MissingToken { .. } => false,
1740        })
1741    }
1742
1743    fn sequence_has_direct_boundary(&self, sequence: NodeSeqId) -> bool {
1744        self.iter(sequence).any(|node| {
1745            matches!(
1746                self.node(node),
1747                ArenaRecognizedNode::LeftRecursiveBoundary { .. }
1748            )
1749        })
1750    }
1751
1752    fn sequence_has_explicit_token(&self, sequence: NodeSeqId) -> bool {
1753        self.iter(sequence).any(|node| {
1754            matches!(
1755                self.node(node),
1756                ArenaRecognizedNode::Token { .. }
1757                    | ArenaRecognizedNode::ErrorToken { .. }
1758                    | ArenaRecognizedNode::MissingToken { .. }
1759            )
1760        })
1761    }
1762
1763    fn node_start_index(&self, node: RecognizedNodeId) -> Option<usize> {
1764        match self.node(node) {
1765            ArenaRecognizedNode::Token { token } | ArenaRecognizedNode::ErrorToken { token } => {
1766                Some(token.index())
1767            }
1768            ArenaRecognizedNode::MissingToken { extra } => {
1769                let RecognitionExtra::MissingToken { at_index, .. } = self.extra(extra) else {
1770                    unreachable!("missing-token node must reference missing-token extra");
1771                };
1772                Some(*at_index as usize)
1773            }
1774            ArenaRecognizedNode::Rule { start_index, .. } => Some(start_index as usize),
1775            ArenaRecognizedNode::LeftRecursiveBoundary { .. } => None,
1776        }
1777    }
1778
1779    fn node_stop_index(&self, node: RecognizedNodeId) -> Option<usize> {
1780        match self.node(node) {
1781            ArenaRecognizedNode::Token { token } | ArenaRecognizedNode::ErrorToken { token } => {
1782                Some(token.index())
1783            }
1784            ArenaRecognizedNode::MissingToken { extra } => {
1785                let RecognitionExtra::MissingToken { at_index, .. } = self.extra(extra) else {
1786                    unreachable!("missing-token node must reference missing-token extra");
1787                };
1788                (*at_index as usize).checked_sub(1)
1789            }
1790            ArenaRecognizedNode::Rule { stop_index, .. } => stop_index.map(|index| index as usize),
1791            ArenaRecognizedNode::LeftRecursiveBoundary { .. } => None,
1792        }
1793    }
1794
1795    fn node_span(&self, node: RecognizedNodeId) -> Option<(usize, Option<usize>)> {
1796        let start = self.node_start_index(node)?;
1797        let stop = self.node_stop_index(node);
1798        Some((start, stop))
1799    }
1800
1801    fn sequence_start_index(&self, sequence: NodeSeqId) -> Option<usize> {
1802        self.iter(sequence)
1803            .find_map(|node| self.node_start_index(node))
1804    }
1805
1806    fn sequence_stop_index(&self, sequence: NodeSeqId) -> Option<usize> {
1807        let mut stop = None;
1808        for node in self.iter(sequence) {
1809            if let Some(index) = self.node_stop_index(node) {
1810                stop = Some(index);
1811            }
1812        }
1813        stop
1814    }
1815
1816    fn sequence_needs_stable_tie(&self, sequence: NodeSeqId) -> bool {
1817        self.iter(sequence)
1818            .any(|node| self.node_needs_stable_tie(node))
1819    }
1820
1821    fn node_needs_stable_tie(&self, node: RecognizedNodeId) -> bool {
1822        match self.node(node) {
1823            ArenaRecognizedNode::Token { .. }
1824            | ArenaRecognizedNode::ErrorToken { .. }
1825            | ArenaRecognizedNode::MissingToken { .. } => false,
1826            ArenaRecognizedNode::LeftRecursiveBoundary { .. } => true,
1827            ArenaRecognizedNode::Rule {
1828                rule_index,
1829                children,
1830                ..
1831            } => self.iter(children).any(|child| {
1832                matches!(
1833                    self.node(child),
1834                    ArenaRecognizedNode::Rule {
1835                        rule_index: child_rule,
1836                        ..
1837                    } if child_rule == rule_index
1838                ) || self.node_needs_stable_tie(child)
1839            }),
1840        }
1841    }
1842
1843    fn compare_sequences(&self, mut left: NodeSeqId, mut right: NodeSeqId) -> Ordering {
1844        loop {
1845            match (self.link(left), self.link(right)) {
1846                (Some(left_link), Some(right_link)) => {
1847                    let order = self.compare_nodes(left_link.head, right_link.head);
1848                    if order != Ordering::Equal {
1849                        return order;
1850                    }
1851                    left = left_link.tail;
1852                    right = right_link.tail;
1853                }
1854                (None, None) => return Ordering::Equal,
1855                (None, Some(_)) => return Ordering::Less,
1856                (Some(_), None) => return Ordering::Greater,
1857            }
1858        }
1859    }
1860
1861    fn compare_nodes(&self, left: RecognizedNodeId, right: RecognizedNodeId) -> Ordering {
1862        let left = self.node(left);
1863        let right = self.node(right);
1864        match (left, right) {
1865            (
1866                ArenaRecognizedNode::Token { token: left },
1867                ArenaRecognizedNode::Token { token: right },
1868            )
1869            | (
1870                ArenaRecognizedNode::ErrorToken { token: left },
1871                ArenaRecognizedNode::ErrorToken { token: right },
1872            ) => left.cmp(&right),
1873            (
1874                ArenaRecognizedNode::MissingToken { extra: left },
1875                ArenaRecognizedNode::MissingToken { extra: right },
1876            ) => self.extra(left).cmp(self.extra(right)),
1877            (
1878                ArenaRecognizedNode::Rule {
1879                    rule_index: left_rule,
1880                    invoking_state: left_invoking,
1881                    alt_number: left_alt,
1882                    start_index: left_start,
1883                    stop_index: left_stop,
1884                    return_values: left_returns,
1885                    children: left_children,
1886                },
1887                ArenaRecognizedNode::Rule {
1888                    rule_index: right_rule,
1889                    invoking_state: right_invoking,
1890                    alt_number: right_alt,
1891                    start_index: right_start,
1892                    stop_index: right_stop,
1893                    return_values: right_returns,
1894                    children: right_children,
1895                },
1896            ) => (left_rule, left_invoking, left_alt, left_start, left_stop)
1897                .cmp(&(
1898                    right_rule,
1899                    right_invoking,
1900                    right_alt,
1901                    right_start,
1902                    right_stop,
1903                ))
1904                .then_with(|| {
1905                    left_returns
1906                        .map(|id| self.extra(id))
1907                        .cmp(&right_returns.map(|id| self.extra(id)))
1908                })
1909                .then_with(|| self.compare_sequences(left_children, right_children)),
1910            (
1911                ArenaRecognizedNode::LeftRecursiveBoundary {
1912                    rule_index: left_rule,
1913                    alt_number: left_alt,
1914                },
1915                ArenaRecognizedNode::LeftRecursiveBoundary {
1916                    rule_index: right_rule,
1917                    alt_number: right_alt,
1918                },
1919            ) => (left_rule, left_alt).cmp(&(right_rule, right_alt)),
1920            (left, right) => recognition_node_kind(&left).cmp(&recognition_node_kind(&right)),
1921        }
1922    }
1923
1924    fn reverse_sequence(&mut self, mut sequence: NodeSeqId) -> NodeSeqId {
1925        let mut reversed = NodeSeqId::EMPTY;
1926        while let Some(link) = self.link(sequence) {
1927            reversed = self.prepend(reversed, link.head);
1928            sequence = link.tail;
1929        }
1930        reversed
1931    }
1932
1933    fn fold_left_recursive_boundaries(&mut self, mut sequence: NodeSeqId) -> NodeSeqId {
1934        if !self.sequence_has_direct_boundary(sequence) {
1935            return sequence;
1936        }
1937        let mut reversed = NodeSeqId::EMPTY;
1938        while let Some(link) = self.link(sequence) {
1939            match self.node(link.head) {
1940                ArenaRecognizedNode::LeftRecursiveBoundary {
1941                    rule_index,
1942                    alt_number,
1943                } => {
1944                    if !reversed.is_empty() {
1945                        let children = self.reverse_sequence(reversed);
1946                        let start_index = self.sequence_start_index(children).unwrap_or_default();
1947                        let stop_index = self.sequence_stop_index(children);
1948                        let rule = self.push_node(ArenaRecognizedNode::Rule {
1949                            rule_index,
1950                            invoking_state: -1,
1951                            alt_number,
1952                            start_index: u32::try_from(start_index)
1953                                .expect("left-recursive start index fits in u32"),
1954                            stop_index: stop_index.map(|index| {
1955                                u32::try_from(index).expect("left-recursive stop index fits in u32")
1956                            }),
1957                            return_values: None,
1958                            children,
1959                        });
1960                        reversed = self.prepend(NodeSeqId::EMPTY, rule);
1961                    }
1962                }
1963                _ => {
1964                    reversed = self.prepend(reversed, link.head);
1965                }
1966            }
1967            sequence = link.tail;
1968        }
1969        self.reverse_sequence(reversed)
1970    }
1971
1972    fn stats(&self, root: NodeSeqId, diagnostics: DiagnosticSeqId) -> RecognitionArenaStats {
1973        let mut live_nodes = vec![false; self.nodes.len()];
1974        let mut live_links = vec![false; self.seq_links.len()];
1975        let mut live_diagnostic_links = vec![false; self.diagnostic_links.len()];
1976        let mut live_extras = vec![false; self.extras.len()];
1977        let mut pending = vec![root];
1978        while let Some(mut sequence) = pending.pop() {
1979            while let Some(link) = self.link(sequence) {
1980                let link_index = sequence.0 as usize;
1981                if live_links[link_index] {
1982                    break;
1983                }
1984                live_links[link_index] = true;
1985                let node_index = link.head.0 as usize;
1986                if !live_nodes[node_index] {
1987                    live_nodes[node_index] = true;
1988                    match self.node(link.head) {
1989                        ArenaRecognizedNode::MissingToken { extra } => {
1990                            live_extras[extra.0 as usize] = true;
1991                        }
1992                        ArenaRecognizedNode::Rule {
1993                            return_values,
1994                            children,
1995                            ..
1996                        } => {
1997                            if let Some(extra) = return_values {
1998                                live_extras[extra.0 as usize] = true;
1999                            }
2000                            pending.push(children);
2001                        }
2002                        ArenaRecognizedNode::Token { .. }
2003                        | ArenaRecognizedNode::ErrorToken { .. }
2004                        | ArenaRecognizedNode::LeftRecursiveBoundary { .. } => {}
2005                    }
2006                }
2007                sequence = link.tail;
2008            }
2009        }
2010        let mut diagnostics = diagnostics;
2011        while let Some(link) = self.diagnostic_link(diagnostics) {
2012            let link_index = diagnostics.0 as usize;
2013            if live_diagnostic_links[link_index] {
2014                break;
2015            }
2016            live_diagnostic_links[link_index] = true;
2017            live_extras[link.head.0 as usize] = true;
2018            diagnostics = link.tail;
2019        }
2020        let live_node_count = live_nodes.into_iter().filter(|live| *live).count();
2021        let live_link_count = live_links.into_iter().filter(|live| *live).count()
2022            + live_diagnostic_links
2023                .into_iter()
2024                .filter(|live| *live)
2025                .count();
2026        let live_extra_count = live_extras.into_iter().filter(|live| *live).count();
2027        let total_links = self.seq_links.len() + self.diagnostic_links.len();
2028        RecognitionArenaStats {
2029            total_nodes: self.nodes.len(),
2030            live_nodes: live_node_count,
2031            dead_nodes: self.nodes.len().saturating_sub(live_node_count),
2032            node_capacity: self.nodes.capacity(),
2033            total_links,
2034            live_links: live_link_count,
2035            dead_links: total_links.saturating_sub(live_link_count),
2036            link_capacity: self.seq_links.capacity() + self.diagnostic_links.capacity(),
2037            total_extras: self.extras.len(),
2038            live_extras: live_extra_count,
2039            dead_extras: self.extras.len().saturating_sub(live_extra_count),
2040            extra_capacity: self.extras.capacity(),
2041        }
2042    }
2043}
2044
2045fn reset_arena_vec<T>(storage: &mut Vec<T>, max_retained_capacity: usize) {
2046    if storage.capacity() > max_retained_capacity {
2047        *storage = Vec::new();
2048    } else {
2049        storage.clear();
2050    }
2051}
2052
2053const fn recognition_node_kind(node: &ArenaRecognizedNode) -> u8 {
2054    match node {
2055        ArenaRecognizedNode::Token { .. } => 0,
2056        ArenaRecognizedNode::ErrorToken { .. } => 1,
2057        ArenaRecognizedNode::MissingToken { .. } => 2,
2058        ArenaRecognizedNode::Rule { .. } => 3,
2059        ArenaRecognizedNode::LeftRecursiveBoundary { .. } => 4,
2060    }
2061}
2062
2063struct NodeSeqIter<'a> {
2064    arena: &'a RecognitionArena,
2065    cursor: NodeSeqId,
2066}
2067
2068impl Iterator for NodeSeqIter<'_> {
2069    type Item = RecognizedNodeId;
2070
2071    fn next(&mut self) -> Option<Self::Item> {
2072        let link = self.arena.link(self.cursor)?;
2073        self.cursor = link.tail;
2074        Some(link.head)
2075    }
2076}
2077
2078struct DiagnosticSeqIter<'a> {
2079    arena: &'a RecognitionArena,
2080    cursor: DiagnosticSeqId,
2081}
2082
2083impl<'a> Iterator for DiagnosticSeqIter<'a> {
2084    type Item = &'a ParserDiagnostic;
2085
2086    fn next(&mut self) -> Option<Self::Item> {
2087        let link = self.arena.diagnostic_link(self.cursor)?;
2088        self.cursor = link.tail;
2089        let RecognitionExtra::Diagnostic(diagnostic) = self.arena.extra(link.head) else {
2090            unreachable!("diagnostic link must reference diagnostic extra");
2091        };
2092        Some(diagnostic)
2093    }
2094}
2095
2096#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
2097struct ParserDiagnostic {
2098    line: usize,
2099    column: usize,
2100    message: String,
2101}
2102
2103#[derive(Clone, Debug, Default, Eq, PartialEq)]
2104struct ExpectedTokens {
2105    index: Option<usize>,
2106    symbols: BTreeSet<i32>,
2107    no_viable: Option<NoViableAlternative>,
2108}
2109
2110#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2111struct NoViableAlternative {
2112    start_index: usize,
2113    error_index: usize,
2114}
2115
2116impl ExpectedTokens {
2117    /// Records the expected symbols for the farthest token index reached by any
2118    /// failed ATN path.
2119    fn record_transition(
2120        &mut self,
2121        index: usize,
2122        transition: ParserTransition<'_>,
2123        max_token_type: i32,
2124    ) {
2125        let symbols = transition_expected_symbols(transition, max_token_type);
2126        match self.index {
2127            Some(current) if index < current => {}
2128            Some(current) if index == current => self.symbols.extend(symbols),
2129            _ => {
2130                self.index = Some(index);
2131                self.symbols = symbols;
2132            }
2133        }
2134    }
2135
2136    /// Records an ambiguous decision that failed after consuming a shared
2137    /// prefix, which ANTLR reports as `no viable alternative`.
2138    const fn record_no_viable(&mut self, start_index: usize, error_index: usize) {
2139        match self.no_viable {
2140            Some(current) if error_index < current.error_index => {}
2141            _ => {
2142                self.no_viable = Some(NoViableAlternative {
2143                    start_index,
2144                    error_index,
2145                });
2146            }
2147        }
2148    }
2149}
2150
2151/// Compact token-type set for parser-internal FIRST/lookahead caches.
2152///
2153/// Public diagnostics still use `BTreeSet<i32>` for deterministic formatting,
2154/// but the hot recognizer path mostly needs `contains` and set union over
2155/// small token ids. A bitset avoids tree traversal and per-symbol allocation
2156/// while keeping conversion to `BTreeSet` at recovery/reporting boundaries.
2157#[derive(Clone, Debug, Default, Eq, PartialEq)]
2158struct TokenBitSet {
2159    words: Vec<u64>,
2160}
2161
2162impl TokenBitSet {
2163    fn insert(&mut self, symbol: i32) {
2164        let Some(slot) = token_bit_slot(symbol) else {
2165            return;
2166        };
2167        let word = slot / u64::BITS as usize;
2168        if word >= self.words.len() {
2169            self.words.resize(word + 1, 0);
2170        }
2171        self.words[word] |= 1_u64 << (slot % u64::BITS as usize);
2172    }
2173
2174    fn extend_range(&mut self, start: i32, stop: i32) {
2175        let (start, stop) = if start <= stop {
2176            (start, stop)
2177        } else {
2178            (stop, start)
2179        };
2180        if start <= TOKEN_EOF && stop >= TOKEN_EOF {
2181            self.insert(TOKEN_EOF);
2182        }
2183        let positive_start = start.max(1);
2184        if positive_start > stop {
2185            return;
2186        }
2187        let Some(start_slot) = token_bit_slot(positive_start) else {
2188            return;
2189        };
2190        let Some(stop_slot) = token_bit_slot(stop) else {
2191            return;
2192        };
2193        self.extend_slot_range(start_slot, stop_slot);
2194    }
2195
2196    fn extend_slot_range(&mut self, start_slot: usize, stop_slot: usize) {
2197        if start_slot > stop_slot {
2198            return;
2199        }
2200        let start_word = start_slot / u64::BITS as usize;
2201        let stop_word = stop_slot / u64::BITS as usize;
2202        if stop_word >= self.words.len() {
2203            self.words.resize(stop_word + 1, 0);
2204        }
2205        let start_offset = start_slot % u64::BITS as usize;
2206        let stop_offset = stop_slot % u64::BITS as usize;
2207        if start_word == stop_word {
2208            self.words[start_word] |=
2209                (!0_u64 << start_offset) & (!0_u64 >> (u64::BITS as usize - 1 - stop_offset));
2210            return;
2211        }
2212        self.words[start_word] |= !0_u64 << start_offset;
2213        for word in &mut self.words[(start_word + 1)..stop_word] {
2214            *word = !0_u64;
2215        }
2216        self.words[stop_word] |= !0_u64 >> (u64::BITS as usize - 1 - stop_offset);
2217    }
2218
2219    fn extend_iter(&mut self, symbols: impl IntoIterator<Item = i32>) {
2220        for symbol in symbols {
2221            self.insert(symbol);
2222        }
2223    }
2224
2225    fn extend_from(&mut self, other: &Self) {
2226        if other.words.len() > self.words.len() {
2227            self.words.resize(other.words.len(), 0);
2228        }
2229        for (left, right) in self.words.iter_mut().zip(&other.words) {
2230            *left |= *right;
2231        }
2232    }
2233
2234    fn contains(&self, symbol: i32) -> bool {
2235        let Some(slot) = token_bit_slot(symbol) else {
2236            return false;
2237        };
2238        let word = slot / u64::BITS as usize;
2239        self.words
2240            .get(word)
2241            .is_some_and(|bits| bits & (1_u64 << (slot % u64::BITS as usize)) != 0)
2242    }
2243
2244    fn is_empty(&self) -> bool {
2245        self.words.iter().all(|word| *word == 0)
2246    }
2247
2248    fn symbols(&self) -> impl Iterator<Item = i32> + '_ {
2249        self.words
2250            .iter()
2251            .copied()
2252            .enumerate()
2253            .flat_map(|(word_index, mut bits)| {
2254                std::iter::from_fn(move || {
2255                    while bits != 0 {
2256                        let bit = bits.trailing_zeros() as usize;
2257                        bits &= bits - 1;
2258                        if let Some(symbol) =
2259                            token_bit_symbol(word_index * u64::BITS as usize + bit)
2260                        {
2261                            return Some(symbol);
2262                        }
2263                    }
2264                    None
2265                })
2266            })
2267    }
2268
2269    fn extend_btree_set(&self, target: &mut BTreeSet<i32>) {
2270        target.extend(self.symbols());
2271    }
2272
2273    fn to_btree_set(&self) -> BTreeSet<i32> {
2274        let mut out = BTreeSet::new();
2275        self.extend_btree_set(&mut out);
2276        out
2277    }
2278}
2279
2280fn token_bit_slot(symbol: i32) -> Option<usize> {
2281    if symbol == TOKEN_EOF {
2282        Some(0)
2283    } else if symbol > 0 {
2284        usize::try_from(symbol).ok()
2285    } else {
2286        None
2287    }
2288}
2289
2290fn token_bit_symbol(slot: usize) -> Option<i32> {
2291    if slot == 0 {
2292        Some(TOKEN_EOF)
2293    } else {
2294        i32::try_from(slot).ok()
2295    }
2296}
2297
2298/// Converts one consuming transition into the token types that would satisfy it
2299/// for diagnostic reporting.
2300fn transition_expected_symbols(
2301    transition: ParserTransition<'_>,
2302    max_token_type: i32,
2303) -> BTreeSet<i32> {
2304    let mut symbols = BTreeSet::new();
2305    match &transition.data() {
2306        Transition::Atom { label, .. } => {
2307            symbols.insert(*label);
2308        }
2309        Transition::Range { start, stop, .. } => {
2310            symbols.extend(*start..=*stop);
2311        }
2312        Transition::Set { set, .. } => {
2313            for (start, stop) in set.ranges() {
2314                symbols.extend(start..=stop);
2315            }
2316        }
2317        Transition::NotSet { set, .. } => {
2318            symbols.extend((1..=max_token_type).filter(|symbol| !set.contains(*symbol)));
2319        }
2320        Transition::Wildcard { .. } => {
2321            symbols.extend(1..=max_token_type);
2322        }
2323        Transition::Epsilon { .. }
2324        | Transition::Rule { .. }
2325        | Transition::Predicate { .. }
2326        | Transition::Action { .. }
2327        | Transition::Precedence { .. } => {}
2328    }
2329    symbols
2330}
2331
2332fn transition_expected_token_set(
2333    transition: ParserTransition<'_>,
2334    max_token_type: i32,
2335) -> TokenBitSet {
2336    let mut symbols = TokenBitSet::default();
2337    match &transition.data() {
2338        Transition::Atom { label, .. } => {
2339            symbols.insert(*label);
2340        }
2341        Transition::Range { start, stop, .. } => {
2342            symbols.extend_range(*start, *stop);
2343        }
2344        Transition::Set { set, .. } => {
2345            for (start, stop) in set.ranges() {
2346                symbols.extend_range(start, stop);
2347            }
2348        }
2349        Transition::NotSet { set, .. } => {
2350            symbols.extend_iter((1..=max_token_type).filter(|symbol| !set.contains(*symbol)));
2351        }
2352        Transition::Wildcard { .. } => {
2353            symbols.extend_range(1, max_token_type);
2354        }
2355        Transition::Epsilon { .. }
2356        | Transition::Rule { .. }
2357        | Transition::Predicate { .. }
2358        | Transition::Action { .. }
2359        | Transition::Precedence { .. } => {}
2360    }
2361    symbols
2362}
2363
2364/// Returns the consuming-token expectations reachable from an ATN state through
2365/// epsilon transitions. Recovery diagnostics need this closure so alternatives
2366/// and loop exits report the same expectation set ANTLR users see.
2367fn state_expected_symbols(atn: &Atn, state_number: usize) -> BTreeSet<i32> {
2368    let mut symbols = BTreeSet::new();
2369    let mut stack = vec![state_number];
2370    let mut visited = BTreeSet::new();
2371    while let Some(current) = stack.pop() {
2372        if !visited.insert(current) {
2373            continue;
2374        }
2375        let Some(state) = atn.state(current) else {
2376            continue;
2377        };
2378        for transition in &state.transitions() {
2379            let transition_symbols = transition_expected_symbols(transition, atn.max_token_type());
2380            if transition_symbols.is_empty() {
2381                if transition.is_epsilon() {
2382                    stack.push(transition.target());
2383                }
2384            } else {
2385                symbols.extend(transition_symbols);
2386            }
2387        }
2388    }
2389    symbols
2390}
2391
2392fn state_expected_token_set(atn: &Atn, state_number: usize) -> TokenBitSet {
2393    let mut symbols = TokenBitSet::default();
2394    let mut stack = vec![state_number];
2395    let mut visited = BTreeSet::new();
2396    while let Some(current) = stack.pop() {
2397        if !visited.insert(current) {
2398            continue;
2399        }
2400        let Some(state) = atn.state(current) else {
2401            continue;
2402        };
2403        for transition in &state.transitions() {
2404            let transition_symbols =
2405                transition_expected_token_set(transition, atn.max_token_type());
2406            if transition_symbols.is_empty() {
2407                if transition.is_epsilon() {
2408                    stack.push(transition.target());
2409                }
2410            } else {
2411                symbols.extend_from(&transition_symbols);
2412            }
2413        }
2414    }
2415    symbols
2416}
2417
2418fn state_can_reach_rule_stop(atn: &Atn, state_number: usize) -> bool {
2419    let Some(rule_index) = atn.state(state_number).and_then(AtnState::rule_index) else {
2420        return false;
2421    };
2422    let Some(stop_state) = atn.rule_to_stop_state().get(rule_index) else {
2423        return false;
2424    };
2425    epsilon_reaches_state(atn, state_number, stop_state)
2426}
2427
2428fn epsilon_reaches_state(atn: &Atn, start: usize, target: usize) -> bool {
2429    let mut stack = vec![start];
2430    let mut visited = BTreeSet::new();
2431    while let Some(current) = stack.pop() {
2432        if current == target {
2433            return true;
2434        }
2435        if !visited.insert(current) {
2436            continue;
2437        }
2438        let Some(state) = atn.state(current) else {
2439            continue;
2440        };
2441        stack.extend(
2442            state
2443                .transitions()
2444                .iter()
2445                .filter(|transition| transition.is_epsilon())
2446                .map(ParserTransition::target),
2447        );
2448    }
2449    false
2450}
2451
2452/// FIRST set for a rule entry plus whether the rule is nullable.
2453///
2454/// Walks epsilon, predicate, action, and rule-call transitions until it finds
2455/// a consuming transition or reaches the rule's stop state. Used by the fast
2456/// recognizer to skip rule alternatives whose first-consumed token cannot
2457/// possibly match the current lookahead.
2458#[derive(Clone, Debug, Default, Eq, PartialEq)]
2459struct FirstSet {
2460    symbols: TokenBitSet,
2461    nullable: bool,
2462}
2463
2464/// Per-parser cache of FIRST sets computed during recognition. The fast path
2465/// consults this on every speculative `Transition::Rule` encounter, so the
2466/// computation must amortize across all of those calls — the FIRST set is a
2467/// pure function of the ATN, not of the input position. Cached entries are
2468/// shared via `Rc` so the recognizer never deep-copies the underlying
2469/// `BTreeSet<i32>`.
2470type FirstSetCache = FxHashMap<(usize, usize), Rc<FirstSet>>;
2471
2472// Thread-local FIRST-set caches keyed by the ATN pointer. The FIRST set
2473// and decision-lookahead entries are purely functions of the grammar's
2474// ATN, so caching across parses lets repeated parsing of the same grammar
2475// (the common case for a CLI tool or language server) avoid redoing the
2476// closure work. Generated parsers hand us a `&'static Atn` whose address
2477// is stable, which is what we hash on.
2478type DecisionLookaheadCache = FxHashMap<usize, Rc<DecisionLookahead>>;
2479
2480#[derive(Debug, Default)]
2481struct LeftRecursiveOperatorLookahead {
2482    /// Operator alts whose token-prefix is fully matched by this one symbol
2483    /// (then only epsilons/actions remain before the recursive RHS call).
2484    /// Safe for one-token loop-enter fast path.
2485    single_token: TokenBitSet,
2486    /// Operator alts that start with this symbol but still require more tokens
2487    /// before the operand. Must not force enter from one-token lookahead when a
2488    /// shorter operator shares the prefix; `StarLoopEntry` adaptive prediction
2489    /// has to weigh the exit alt as well.
2490    multi_token_prefix: TokenBitSet,
2491    predicate_dependent: TokenBitSet,
2492}
2493
2494#[derive(Default)]
2495struct SharedAtnCache {
2496    first_set: FirstSetCache,
2497    decision_lookahead: DecisionLookaheadCache,
2498    left_recursive_operator_lookahead: FxHashMap<(usize, i32), Rc<LeftRecursiveOperatorLookahead>>,
2499    state_before_stop_lookahead: FxHashMap<(usize, usize), Rc<StateBeforeStopLookahead>>,
2500    state_expected_tokens: FxHashMap<usize, Rc<TokenBitSet>>,
2501    rule_stop_reach: FxHashMap<usize, bool>,
2502    observable_action_transitions: Option<bool>,
2503    predicate_transitions: Option<bool>,
2504}
2505
2506thread_local! {
2507    static SHARED_ATN_CACHES: RefCell<FxHashMap<SharedAtnCacheKey, SharedAtnCache>> =
2508        RefCell::new(FxHashMap::default());
2509}
2510
2511/// Compound key for `SHARED_ATN_CACHES`.
2512///
2513/// Generated parsers feed us a `&'static Atn` from a `OnceLock<Atn>`, so the
2514/// pointer identifies one grammar for the program's lifetime. For the
2515/// non-`'static` case (a dropped `Atn` whose allocation is later reused),
2516/// the secondary fields below catch the pointer collision: a new grammar
2517/// would need to match all of `(states ptr, states len, max_token_type)` to
2518/// be mistaken for the dropped one. That combination changing under us
2519/// without a rebuild is implausible enough to treat as a bug; bundling them
2520/// into the key is otherwise a few extra bytes per lookup.
2521#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
2522struct SharedAtnCacheKey {
2523    atn: usize,
2524    states: usize,
2525    state_count: usize,
2526    max_token_type: i32,
2527}
2528
2529impl SharedAtnCacheKey {
2530    fn for_atn(atn: &Atn) -> Self {
2531        let (states, state_count) = atn.storage_identity();
2532        Self {
2533            atn: std::ptr::from_ref::<Atn>(atn) as usize,
2534            states,
2535            state_count,
2536            max_token_type: atn.max_token_type(),
2537        }
2538    }
2539}
2540
2541fn with_shared_first_set_cache<R>(atn: &Atn, f: impl FnOnce(&mut FirstSetCache) -> R) -> R {
2542    SHARED_ATN_CACHES.with(|cell| {
2543        let key = SharedAtnCacheKey::for_atn(atn);
2544        let mut map = cell.borrow_mut();
2545        let cache = map.entry(key).or_default();
2546        f(&mut cache.first_set)
2547    })
2548}
2549
2550fn with_shared_atn_caches<R>(atn: &Atn, f: impl FnOnce(&mut SharedAtnCache) -> R) -> R {
2551    SHARED_ATN_CACHES.with(|cell| {
2552        let key = SharedAtnCacheKey::for_atn(atn);
2553        let mut map = cell.borrow_mut();
2554        let cache = map.entry(key).or_default();
2555        f(cache)
2556    })
2557}
2558
2559/// Per-decision-state cached look-1 sets for each outgoing transition.
2560///
2561/// At a multi-alternative state, the recognizer would otherwise speculatively
2562/// walk every alternative even when only one can possibly accept the current
2563/// lookahead. Caching the look-1 set per transition lets us prune the
2564/// non-viable transitions before recursing — the same SLL prediction trick
2565/// the reference ANTLR runtime uses, just expressed as a `(state, lookahead)`
2566/// filter rather than a full DFA.
2567#[derive(Debug, Default)]
2568struct DecisionLookahead {
2569    transitions: Vec<TransitionLookSet>,
2570}
2571
2572/// Look-1 information for one outgoing transition.
2573///
2574/// `nullable` mirrors `FirstSet::nullable` and is true when the transition
2575/// can reach the rule stop without consuming a token (e.g. an empty alt).
2576/// Nullable transitions cannot be pruned: they may still be the right path
2577/// when the lookahead consumes nothing further inside the current rule.
2578#[derive(Clone, Debug, Default)]
2579struct TransitionLookSet {
2580    symbols: TokenBitSet,
2581    nullable: bool,
2582}
2583
2584/// Mutable bookkeeping shared across one FIRST-set computation. Bundling the
2585/// rarely-touched fields keeps the recursive helpers below the function-arity
2586/// lint and lets every nested call thread the same cache and cycle guards.
2587struct FirstSetCtx<'a> {
2588    cache: &'a mut FirstSetCache,
2589    in_progress: BTreeSet<(usize, usize)>,
2590    hit_cycle: bool,
2591}
2592
2593/// Returns the FIRST set for the (rule entry, rule stop) pair, populating the
2594/// shared cache and tolerating recursive nullable rule chains. Mutually
2595/// recursive rules cannot stack-overflow because callers in flight are tracked
2596/// in `ctx.in_progress`; revisits return without recursing, and the partial
2597/// result is cached only when no cycle was detected during its computation.
2598///
2599/// On a cache hit the returned `Rc` is shared with the recognizer so subsequent
2600/// rule-call probes only pay a reference bump.
2601fn rule_first_set(
2602    atn: &Atn,
2603    target: usize,
2604    rule_stop_state: usize,
2605    cache: &mut FirstSetCache,
2606) -> Rc<FirstSet> {
2607    if let Some(cached) = cache.get(&(target, rule_stop_state)) {
2608        return Rc::clone(cached);
2609    }
2610    let mut ctx = FirstSetCtx {
2611        cache,
2612        in_progress: BTreeSet::new(),
2613        hit_cycle: false,
2614    };
2615    rule_first_set_cached(atn, target, rule_stop_state, &mut ctx)
2616}
2617
2618fn rule_first_set_cached(
2619    atn: &Atn,
2620    target: usize,
2621    rule_stop_state: usize,
2622    ctx: &mut FirstSetCtx<'_>,
2623) -> Rc<FirstSet> {
2624    let key = (target, rule_stop_state);
2625    if let Some(cached) = ctx.cache.get(&key) {
2626        return Rc::clone(cached);
2627    }
2628    if !ctx.in_progress.insert(key) {
2629        // Cycle: a caller above is already computing this entry. Return an
2630        // empty FIRST set; that caller's traversal supplies the contributions
2631        // from the rule's other alternatives.
2632        return Rc::new(FirstSet::default());
2633    }
2634    let saved_hit_cycle = ctx.hit_cycle;
2635    ctx.hit_cycle = false;
2636    let mut first = FirstSet::default();
2637    let mut visited = BTreeSet::new();
2638    rule_first_set_inner(atn, target, rule_stop_state, ctx, &mut visited, &mut first);
2639    ctx.in_progress.remove(&key);
2640    let entry = Rc::new(first);
2641    if !ctx.hit_cycle {
2642        ctx.cache.insert(key, Rc::clone(&entry));
2643    }
2644    ctx.hit_cycle = saved_hit_cycle || ctx.hit_cycle;
2645    entry
2646}
2647
2648/// Returns the look-1 set for traversing `transition` while still inside the
2649/// current `rule_stop_state`. Used by the multi-alternative prefilter, which
2650/// prunes transitions whose look-1 cannot accept the current lookahead.
2651fn transition_first_set(
2652    atn: &Atn,
2653    transition: ParserTransition<'_>,
2654    rule_stop_state: usize,
2655    cache: &mut FirstSetCache,
2656) -> TransitionLookSet {
2657    match &transition.data() {
2658        Transition::Atom { label, .. } => {
2659            let mut symbols = TokenBitSet::default();
2660            symbols.insert(*label);
2661            TransitionLookSet {
2662                symbols,
2663                nullable: false,
2664            }
2665        }
2666        Transition::Range { start, stop, .. } => {
2667            let mut symbols = TokenBitSet::default();
2668            symbols.extend_range(*start, *stop);
2669            TransitionLookSet {
2670                symbols,
2671                nullable: false,
2672            }
2673        }
2674        Transition::Set { set, .. } => {
2675            let mut symbols = TokenBitSet::default();
2676            for (start, stop) in set.ranges() {
2677                symbols.extend_range(start, stop);
2678            }
2679            TransitionLookSet {
2680                symbols,
2681                nullable: false,
2682            }
2683        }
2684        Transition::NotSet { set, .. } => {
2685            let max = atn.max_token_type();
2686            let mut symbols = TokenBitSet::default();
2687            symbols.extend_iter((1..=max).filter(|symbol| !set.contains(*symbol)));
2688            TransitionLookSet {
2689                symbols,
2690                nullable: false,
2691            }
2692        }
2693        Transition::Wildcard { .. } => {
2694            let mut symbols = TokenBitSet::default();
2695            symbols.extend_range(1, atn.max_token_type());
2696            TransitionLookSet {
2697                symbols,
2698                nullable: false,
2699            }
2700        }
2701        Transition::Epsilon { target }
2702        | Transition::Action { target, .. }
2703        | Transition::Predicate { target, .. }
2704        | Transition::Precedence { target, .. } => {
2705            // Walk the closure starting at `target` until a consuming transition
2706            // is reached or the rule stop state is hit.
2707            let first = rule_first_set(atn, *target, rule_stop_state, cache);
2708            TransitionLookSet {
2709                symbols: first.symbols.clone(),
2710                nullable: first.nullable,
2711            }
2712        }
2713        Transition::Rule {
2714            target,
2715            rule_index,
2716            follow_state,
2717            ..
2718        } => {
2719            let Some(child_stop) = atn.rule_to_stop_state().get(*rule_index) else {
2720                return TransitionLookSet::default();
2721            };
2722            let child = rule_first_set(atn, *target, child_stop, cache);
2723            let mut symbols = child.symbols.clone();
2724            let nullable = if child.nullable {
2725                let follow = rule_first_set(atn, *follow_state, rule_stop_state, cache);
2726                symbols.extend_from(&follow.symbols);
2727                follow.nullable
2728            } else {
2729                false
2730            };
2731            TransitionLookSet { symbols, nullable }
2732        }
2733    }
2734}
2735
2736/// Reports whether `transition` can be pruned at a multi-alt state because
2737/// its cached look-1 cannot accept the current lookahead.
2738///
2739/// Pruning runs only for non-consuming transitions (Epsilon/Action/Predicate/
2740/// Rule/Precedence) so consuming transitions still reach the
2741/// `matches`+recovery path that surfaces single-token deletion / insertion
2742/// repairs and ANTLR-compatible expected-token sets. When a non-consuming
2743/// transition is pruned, its FIRST set is folded into `expected` so failed
2744/// parses produce the same `mismatched input ... expecting ...` diagnostic
2745/// the no-prefilter baseline would emit.
2746/// Returns the unique alt index (0-based) when `symbol` falls into exactly
2747/// one transition's FIRST set and no transition is nullable. Used as an
2748/// LL(1) commit point: when prediction is unambiguous from the lookahead
2749/// alone, the recursive recognizer can skip every other alt without paying
2750/// for the per-transition filter probe.
2751///
2752/// `None` signals the caller to fall back to per-transition lookahead
2753/// filtering. Returning `Some` for an alt whose transition cannot actually
2754/// match would prune the only viable parse path; this is why we require
2755/// strict disjointness *and* no nullable transitions in the decision.
2756fn ll1_unique_alt(entry: &DecisionLookahead, symbol: i32) -> Option<usize> {
2757    let mut chosen: Option<usize> = None;
2758    for (index, transition) in entry.transitions.iter().enumerate() {
2759        if transition.nullable {
2760            return None;
2761        }
2762        if transition.symbols.contains(symbol) {
2763            if chosen.is_some() {
2764                return None;
2765            }
2766            chosen = Some(index);
2767        }
2768    }
2769    chosen
2770}
2771
2772/// Returns the unique greedy alt index (0-based) selected by the current
2773/// lookahead.
2774///
2775/// The shortcut is intentionally conservative around nullable exits. If the
2776/// current symbol can start a consuming alternative and an empty alternative is
2777/// also present, one-token lookahead is not enough to know whether the symbol
2778/// belongs to the current construct or to its caller's follow set. `None`
2779/// signals the caller to fall back to adaptive prediction.
2780fn ll1_greedy_alt(entry: &DecisionLookahead, symbol: i32, non_greedy: bool) -> Option<usize> {
2781    let mut matching_non_nullable_alt = None;
2782    let mut nullable_alt = None;
2783    for (index, transition) in entry.transitions.iter().enumerate() {
2784        if transition.nullable {
2785            if nullable_alt.is_some() {
2786                return None;
2787            }
2788            nullable_alt = Some(index);
2789        }
2790        if transition.symbols.contains(symbol) {
2791            if transition.nullable {
2792                continue;
2793            }
2794            if matching_non_nullable_alt.is_some() {
2795                return None;
2796            }
2797            matching_non_nullable_alt = Some(index);
2798        }
2799    }
2800    if matching_non_nullable_alt.is_some() && nullable_alt.is_some() {
2801        return None;
2802    }
2803    if non_greedy {
2804        nullable_alt.or(matching_non_nullable_alt)
2805    } else {
2806        matching_non_nullable_alt.or(nullable_alt)
2807    }
2808}
2809
2810fn should_skip_via_lookahead(
2811    transition_kind: ParserTransitionKind,
2812    transition_index: usize,
2813    lookahead_filter: Option<&(i32, Rc<DecisionLookahead>)>,
2814    index: usize,
2815    record_expected: bool,
2816    expected: &mut ExpectedTokens,
2817) -> bool {
2818    let prune_non_consuming = matches!(
2819        transition_kind,
2820        ParserTransitionKind::Epsilon
2821            | ParserTransitionKind::Action
2822            | ParserTransitionKind::Predicate
2823            | ParserTransitionKind::Rule
2824            | ParserTransitionKind::Precedence
2825    );
2826    if !prune_non_consuming {
2827        return false;
2828    }
2829    let Some((symbol, entry)) = lookahead_filter else {
2830        return false;
2831    };
2832    let Some(set) = entry.transitions.get(transition_index) else {
2833        return false;
2834    };
2835    if set.symbols.contains(*symbol) || set.nullable {
2836        return false;
2837    }
2838    if record_expected && !set.symbols.is_empty() {
2839        record_pruned_transition_expected(set, index, expected);
2840    }
2841    true
2842}
2843
2844fn should_skip_rule_via_first_set(
2845    first: &FirstSet,
2846    symbol: i32,
2847    record_expected: bool,
2848    index: usize,
2849    expected: &mut ExpectedTokens,
2850) -> bool {
2851    if first.nullable || first.symbols.contains(symbol) {
2852        return false;
2853    }
2854    if record_expected && !first.symbols.is_empty() {
2855        record_token_bit_expected(&first.symbols, index, expected);
2856    }
2857    true
2858}
2859
2860fn record_token_bit_expected(symbols: &TokenBitSet, index: usize, expected: &mut ExpectedTokens) {
2861    match expected.index {
2862        Some(current) if index < current => {}
2863        Some(current) if index == current => {
2864            symbols.extend_btree_set(&mut expected.symbols);
2865        }
2866        _ => {
2867            expected.index = Some(index);
2868            expected.symbols = symbols.to_btree_set();
2869        }
2870    }
2871}
2872
2873/// Folds a pruned transition's FIRST set into the farthest-expected accumulator.
2874fn record_pruned_transition_expected(
2875    set: &TransitionLookSet,
2876    index: usize,
2877    expected: &mut ExpectedTokens,
2878) {
2879    match expected.index {
2880        Some(current) if index < current => {}
2881        Some(current) if index == current => {
2882            set.symbols.extend_btree_set(&mut expected.symbols);
2883        }
2884        _ => {
2885            expected.index = Some(index);
2886            expected.symbols = set.symbols.to_btree_set();
2887        }
2888    }
2889}
2890
2891fn rule_first_set_inner(
2892    atn: &Atn,
2893    state_number: usize,
2894    rule_stop_state: usize,
2895    ctx: &mut FirstSetCtx<'_>,
2896    visited: &mut BTreeSet<usize>,
2897    first: &mut FirstSet,
2898) {
2899    if !visited.insert(state_number) {
2900        return;
2901    }
2902    if state_number == rule_stop_state {
2903        first.nullable = true;
2904        return;
2905    }
2906    let Some(state) = atn.state(state_number) else {
2907        return;
2908    };
2909    for transition in &state.transitions() {
2910        let transition_symbols = transition_expected_symbols(transition, atn.max_token_type());
2911        if !transition_symbols.is_empty() {
2912            first.symbols.extend_iter(transition_symbols);
2913            continue;
2914        }
2915        match &transition.data() {
2916            Transition::Epsilon { target }
2917            | Transition::Action { target, .. }
2918            | Transition::Predicate { target, .. }
2919            | Transition::Precedence { target, .. } => {
2920                rule_first_set_inner(atn, *target, rule_stop_state, ctx, visited, first);
2921            }
2922            Transition::Rule {
2923                target,
2924                rule_index,
2925                follow_state,
2926                ..
2927            } => {
2928                let Some(child_stop) = atn.rule_to_stop_state().get(*rule_index) else {
2929                    continue;
2930                };
2931                let child_key = (*target, child_stop);
2932                if ctx.in_progress.contains(&child_key) && !ctx.cache.contains_key(&child_key) {
2933                    ctx.hit_cycle = true;
2934                }
2935                let child = rule_first_set_cached(atn, *target, child_stop, ctx);
2936                first.symbols.extend_from(&child.symbols);
2937                if child.nullable {
2938                    rule_first_set_inner(atn, *follow_state, rule_stop_state, ctx, visited, first);
2939                }
2940            }
2941            Transition::Atom { .. }
2942            | Transition::Range { .. }
2943            | Transition::Set { .. }
2944            | Transition::NotSet { .. }
2945            | Transition::Wildcard { .. } => {}
2946        }
2947    }
2948}
2949
2950/// Returns token types that can resume parsing from `state_number` after a
2951/// failed child rule, following rule calls as well as epsilon transitions.
2952fn state_sync_symbols(atn: &Atn, state_number: usize, stop_state: usize) -> BTreeSet<i32> {
2953    let mut symbols = BTreeSet::new();
2954    state_sync_symbols_inner(
2955        atn,
2956        state_number,
2957        stop_state,
2958        &mut BTreeSet::new(),
2959        &mut symbols,
2960    );
2961    symbols
2962}
2963
2964/// Walks epsilon-like continuations from a parent follow state until it finds
2965/// consuming tokens that can anchor recovery, or EOF if the parent rule can end.
2966fn state_sync_symbols_inner(
2967    atn: &Atn,
2968    state_number: usize,
2969    stop_state: usize,
2970    visited: &mut BTreeSet<usize>,
2971    symbols: &mut BTreeSet<i32>,
2972) {
2973    if !visited.insert(state_number) {
2974        return;
2975    }
2976    if state_number == stop_state {
2977        symbols.insert(TOKEN_EOF);
2978        return;
2979    }
2980    let Some(state) = atn.state(state_number) else {
2981        return;
2982    };
2983    for transition in &state.transitions() {
2984        let transition_symbols = transition_expected_symbols(transition, atn.max_token_type());
2985        if transition_symbols.is_empty() {
2986            match &transition.data() {
2987                Transition::Rule { target, .. }
2988                | Transition::Epsilon { target }
2989                | Transition::Action { target, .. }
2990                | Transition::Predicate { target, .. }
2991                | Transition::Precedence { target, .. } => {
2992                    state_sync_symbols_inner(atn, *target, stop_state, visited, symbols);
2993                }
2994                Transition::Atom { .. }
2995                | Transition::Range { .. }
2996                | Transition::Set { .. }
2997                | Transition::NotSet { .. }
2998                | Transition::Wildcard { .. } => {}
2999            }
3000        } else {
3001            symbols.extend(transition_symbols);
3002        }
3003    }
3004}
3005
3006#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
3007struct OperatorSymbolReachability {
3008    /// One token completes an unconditional operator token-prefix.
3009    single_token: bool,
3010    /// An unconditional operator path requires more tokens before its operand.
3011    multi_token: bool,
3012    /// At least one matching operator path depends on a semantic predicate.
3013    predicate_dependent: bool,
3014}
3015
3016impl OperatorSymbolReachability {
3017    const ADAPTIVE_FALLBACK: Self = Self {
3018        single_token: false,
3019        multi_token: false,
3020        predicate_dependent: true,
3021    };
3022
3023    const fn single_token(predicate_dependent: bool) -> Self {
3024        if predicate_dependent {
3025            Self {
3026                single_token: false,
3027                multi_token: false,
3028                predicate_dependent: true,
3029            }
3030        } else {
3031            Self {
3032                single_token: true,
3033                multi_token: false,
3034                predicate_dependent: false,
3035            }
3036        }
3037    }
3038
3039    const fn multi_token(predicate_dependent: bool) -> Self {
3040        if predicate_dependent {
3041            Self {
3042                single_token: false,
3043                multi_token: false,
3044                predicate_dependent: true,
3045            }
3046        } else {
3047            Self {
3048                single_token: false,
3049                multi_token: true,
3050                predicate_dependent: false,
3051            }
3052        }
3053    }
3054
3055    const fn union(self, other: Self) -> Self {
3056        Self {
3057            single_token: self.single_token || other.single_token,
3058            multi_token: self.multi_token || other.multi_token,
3059            predicate_dependent: self.predicate_dependent || other.predicate_dependent,
3060        }
3061    }
3062}
3063
3064#[derive(Clone, Copy)]
3065struct OperatorReachabilityRequest {
3066    symbol: i32,
3067    precedence: i32,
3068    predicate_dependent: bool,
3069    operator_rule_index: usize,
3070}
3071
3072#[derive(Clone, Copy, Debug)]
3073struct OperatorRuleContinuation {
3074    stop_state: usize,
3075    follow_state: usize,
3076    return_precedence: i32,
3077}
3078
3079struct NullablePrecedenceCtx {
3080    cache: FxHashMap<(usize, usize, i32, bool), bool>,
3081    in_progress: BTreeSet<(usize, usize, i32, bool)>,
3082    hit_cycle: bool,
3083}
3084
3085fn state_is_nullable_with_precedence(
3086    atn: &Atn,
3087    state_number: usize,
3088    stop_state_number: usize,
3089    precedence: i32,
3090    allow_predicates: bool,
3091    ctx: &mut NullablePrecedenceCtx,
3092) -> bool {
3093    let saved_hit_cycle = ctx.hit_cycle;
3094    ctx.hit_cycle = false;
3095    let nullable = state_is_nullable_with_precedence_cached(
3096        atn,
3097        state_number,
3098        stop_state_number,
3099        precedence,
3100        allow_predicates,
3101        ctx,
3102    );
3103    ctx.hit_cycle = saved_hit_cycle;
3104    nullable
3105}
3106
3107fn state_is_nullable_with_precedence_cached(
3108    atn: &Atn,
3109    state_number: usize,
3110    stop_state_number: usize,
3111    precedence: i32,
3112    allow_predicates: bool,
3113    ctx: &mut NullablePrecedenceCtx,
3114) -> bool {
3115    if state_number == stop_state_number {
3116        return true;
3117    }
3118    let key = (
3119        state_number,
3120        stop_state_number,
3121        precedence,
3122        allow_predicates,
3123    );
3124    if let Some(cached) = ctx.cache.get(&key) {
3125        return *cached;
3126    }
3127    if !ctx.in_progress.insert(key) {
3128        ctx.hit_cycle = true;
3129        return false;
3130    }
3131    let saved_hit_cycle = ctx.hit_cycle;
3132    ctx.hit_cycle = false;
3133    let nullable = atn.state(state_number).is_some_and(|state| {
3134        state
3135            .transitions()
3136            .iter()
3137            .any(|transition| match &transition.data() {
3138                Transition::Rule {
3139                    target,
3140                    rule_index,
3141                    follow_state,
3142                    precedence: rule_precedence,
3143                } => {
3144                    let Some(child_stop) = atn.rule_to_stop_state().get(*rule_index) else {
3145                        return false;
3146                    };
3147                    state_is_nullable_with_precedence_cached(
3148                        atn,
3149                        *target,
3150                        child_stop,
3151                        *rule_precedence,
3152                        allow_predicates,
3153                        ctx,
3154                    ) && state_is_nullable_with_precedence_cached(
3155                        atn,
3156                        *follow_state,
3157                        stop_state_number,
3158                        precedence,
3159                        allow_predicates,
3160                        ctx,
3161                    )
3162                }
3163                Transition::Epsilon { target } | Transition::Action { target, .. } => {
3164                    state_is_nullable_with_precedence_cached(
3165                        atn,
3166                        *target,
3167                        stop_state_number,
3168                        precedence,
3169                        allow_predicates,
3170                        ctx,
3171                    )
3172                }
3173                Transition::Predicate { target, .. } if allow_predicates => {
3174                    state_is_nullable_with_precedence_cached(
3175                        atn,
3176                        *target,
3177                        stop_state_number,
3178                        precedence,
3179                        allow_predicates,
3180                        ctx,
3181                    )
3182                }
3183                Transition::Precedence {
3184                    target,
3185                    precedence: transition_precedence,
3186                } if *transition_precedence >= precedence => {
3187                    state_is_nullable_with_precedence_cached(
3188                        atn,
3189                        *target,
3190                        stop_state_number,
3191                        precedence,
3192                        allow_predicates,
3193                        ctx,
3194                    )
3195                }
3196                Transition::Atom { .. }
3197                | Transition::Range { .. }
3198                | Transition::Set { .. }
3199                | Transition::NotSet { .. }
3200                | Transition::Wildcard { .. }
3201                | Transition::Predicate { .. }
3202                | Transition::Precedence { .. } => false,
3203            })
3204    });
3205    ctx.in_progress.remove(&key);
3206    if !ctx.hit_cycle {
3207        ctx.cache.insert(key, nullable);
3208    }
3209    ctx.hit_cycle = saved_hit_cycle || ctx.hit_cycle;
3210    nullable
3211}
3212
3213/// Classifies what remains after the operator's first token is matched.
3214fn state_operator_token_prefix_reachability(
3215    atn: &Atn,
3216    state_number: usize,
3217    request: OperatorReachabilityRequest,
3218    continuations: &[OperatorRuleContinuation],
3219    visited: &mut BTreeSet<(usize, i32, bool)>,
3220) -> OperatorSymbolReachability {
3221    let key = (
3222        state_number,
3223        request.precedence,
3224        request.predicate_dependent,
3225    );
3226    if !visited.insert(key) {
3227        // Recursive helper rules can grow the return stack without consuming
3228        // input. Delegate cycles to adaptive prediction instead of forcing a
3229        // potentially incomplete one-token answer.
3230        return OperatorSymbolReachability::ADAPTIVE_FALLBACK;
3231    }
3232    if let Some((continuation, remaining)) = continuations.split_last()
3233        && state_number == continuation.stop_state
3234    {
3235        let result = state_operator_token_prefix_reachability(
3236            atn,
3237            continuation.follow_state,
3238            OperatorReachabilityRequest {
3239                precedence: continuation.return_precedence,
3240                ..request
3241            },
3242            remaining,
3243            visited,
3244        );
3245        visited.remove(&key);
3246        return result;
3247    }
3248    let Some(state) = atn.state(state_number) else {
3249        visited.remove(&key);
3250        return OperatorSymbolReachability::default();
3251    };
3252    let completes_operator = match state.kind() {
3253        AtnStateKind::RuleStop => continuations.is_empty(),
3254        AtnStateKind::StarLoopBack
3255        | AtnStateKind::StarLoopEntry
3256        | AtnStateKind::PlusLoopBack
3257        | AtnStateKind::LoopEnd => state.rule_index() == Some(request.operator_rule_index),
3258        _ => false,
3259    };
3260    if completes_operator {
3261        visited.remove(&key);
3262        return OperatorSymbolReachability::single_token(request.predicate_dependent);
3263    }
3264    let mut reachability = OperatorSymbolReachability::default();
3265    for transition in &state.transitions() {
3266        let transition_reachability = match &transition.data() {
3267            Transition::Rule { rule_index, .. } if *rule_index == request.operator_rule_index => {
3268                OperatorSymbolReachability::single_token(request.predicate_dependent)
3269            }
3270            Transition::Rule {
3271                target,
3272                rule_index,
3273                follow_state,
3274                precedence: rule_precedence,
3275            } => {
3276                let Some(child_stop) = atn.rule_to_stop_state().get(*rule_index) else {
3277                    continue;
3278                };
3279                let mut nested = continuations.to_vec();
3280                nested.push(OperatorRuleContinuation {
3281                    stop_state: child_stop,
3282                    follow_state: *follow_state,
3283                    return_precedence: request.precedence,
3284                });
3285                state_operator_token_prefix_reachability(
3286                    atn,
3287                    *target,
3288                    OperatorReachabilityRequest {
3289                        precedence: *rule_precedence,
3290                        ..request
3291                    },
3292                    &nested,
3293                    visited,
3294                )
3295            }
3296            Transition::Epsilon { target } | Transition::Action { target, .. } => {
3297                state_operator_token_prefix_reachability(
3298                    atn,
3299                    *target,
3300                    request,
3301                    continuations,
3302                    visited,
3303                )
3304            }
3305            Transition::Precedence {
3306                target,
3307                precedence: transition_precedence,
3308            } => {
3309                if *transition_precedence < request.precedence {
3310                    OperatorSymbolReachability::default()
3311                } else {
3312                    state_operator_token_prefix_reachability(
3313                        atn,
3314                        *target,
3315                        request,
3316                        continuations,
3317                        visited,
3318                    )
3319                }
3320            }
3321            Transition::Predicate { target, .. } => state_operator_token_prefix_reachability(
3322                atn,
3323                *target,
3324                OperatorReachabilityRequest {
3325                    predicate_dependent: true,
3326                    ..request
3327                },
3328                continuations,
3329                visited,
3330            ),
3331            Transition::Atom { .. }
3332            | Transition::Range { .. }
3333            | Transition::Set { .. }
3334            | Transition::NotSet { .. }
3335            | Transition::Wildcard { .. } => {
3336                OperatorSymbolReachability::multi_token(request.predicate_dependent)
3337            }
3338        };
3339        reachability = reachability.union(transition_reachability);
3340    }
3341    visited.remove(&key);
3342    reachability
3343}
3344
3345fn state_can_reach_symbol_with_precedence(
3346    atn: &Atn,
3347    state_number: usize,
3348    request: OperatorReachabilityRequest,
3349    nullable_ctx: &mut NullablePrecedenceCtx,
3350    continuations: &mut Vec<OperatorRuleContinuation>,
3351    visited: &mut BTreeSet<(usize, i32, bool)>,
3352) -> OperatorSymbolReachability {
3353    let key = (
3354        state_number,
3355        request.precedence,
3356        request.predicate_dependent,
3357    );
3358    if !visited.insert(key) {
3359        return OperatorSymbolReachability::ADAPTIVE_FALLBACK;
3360    }
3361    let Some(state) = atn.state(state_number) else {
3362        visited.remove(&key);
3363        return OperatorSymbolReachability::default();
3364    };
3365    let mut reachability = OperatorSymbolReachability::default();
3366    for transition in &state.transitions() {
3367        if transition.matches(request.symbol, 1, atn.max_token_type()) {
3368            reachability = reachability.union(state_operator_token_prefix_reachability(
3369                atn,
3370                transition.target(),
3371                request,
3372                continuations,
3373                &mut BTreeSet::new(),
3374            ));
3375            continue;
3376        }
3377        let transition_reachability = match &transition.data() {
3378            Transition::Rule {
3379                target,
3380                rule_index,
3381                follow_state,
3382                precedence: rule_precedence,
3383            } => {
3384                let Some(child_stop) = atn.rule_to_stop_state().get(*rule_index) else {
3385                    continue;
3386                };
3387                continuations.push(OperatorRuleContinuation {
3388                    stop_state: child_stop,
3389                    follow_state: *follow_state,
3390                    return_precedence: request.precedence,
3391                });
3392                let mut result = state_can_reach_symbol_with_precedence(
3393                    atn,
3394                    *target,
3395                    OperatorReachabilityRequest {
3396                        precedence: *rule_precedence,
3397                        ..request
3398                    },
3399                    nullable_ctx,
3400                    continuations,
3401                    visited,
3402                );
3403                continuations.pop();
3404                if state_is_nullable_with_precedence(
3405                    atn,
3406                    *target,
3407                    child_stop,
3408                    *rule_precedence,
3409                    true,
3410                    nullable_ctx,
3411                ) {
3412                    let child_predicate_dependent = request.predicate_dependent
3413                        || !state_is_nullable_with_precedence(
3414                            atn,
3415                            *target,
3416                            child_stop,
3417                            *rule_precedence,
3418                            false,
3419                            nullable_ctx,
3420                        );
3421                    result = result.union(state_can_reach_symbol_with_precedence(
3422                        atn,
3423                        *follow_state,
3424                        OperatorReachabilityRequest {
3425                            predicate_dependent: child_predicate_dependent,
3426                            ..request
3427                        },
3428                        nullable_ctx,
3429                        continuations,
3430                        visited,
3431                    ));
3432                }
3433                result
3434            }
3435            Transition::Epsilon { target }
3436            | Transition::Action { target, .. }
3437            | Transition::Precedence { target, .. } => {
3438                if matches!(
3439                    &transition.data(),
3440                    Transition::Precedence {
3441                        precedence: transition_precedence,
3442                        ..
3443                    } if *transition_precedence < request.precedence
3444                ) {
3445                    continue;
3446                }
3447                state_can_reach_symbol_with_precedence(
3448                    atn,
3449                    *target,
3450                    request,
3451                    nullable_ctx,
3452                    continuations,
3453                    visited,
3454                )
3455            }
3456            Transition::Predicate { target, .. } => state_can_reach_symbol_with_precedence(
3457                atn,
3458                *target,
3459                OperatorReachabilityRequest {
3460                    predicate_dependent: true,
3461                    ..request
3462                },
3463                nullable_ctx,
3464                continuations,
3465                visited,
3466            ),
3467            Transition::Atom { .. }
3468            | Transition::Range { .. }
3469            | Transition::Set { .. }
3470            | Transition::NotSet { .. }
3471            | Transition::Wildcard { .. } => OperatorSymbolReachability::default(),
3472        };
3473        reachability = reachability.union(transition_reachability);
3474    }
3475    visited.remove(&key);
3476    reachability
3477}
3478
3479fn left_recursive_operator_lookahead(
3480    atn: &Atn,
3481    state_number: usize,
3482    precedence: i32,
3483) -> LeftRecursiveOperatorLookahead {
3484    let Some(state) = atn.state(state_number) else {
3485        return LeftRecursiveOperatorLookahead::default();
3486    };
3487    let Some(operator_rule_index) = state.rule_index() else {
3488        return LeftRecursiveOperatorLookahead::default();
3489    };
3490    let mut lookahead = LeftRecursiveOperatorLookahead::default();
3491    let mut nullable_ctx = NullablePrecedenceCtx {
3492        cache: FxHashMap::default(),
3493        in_progress: BTreeSet::new(),
3494        hit_cycle: false,
3495    };
3496    for transition in &state.transitions() {
3497        let target = transition.target();
3498        if atn
3499            .state(target)
3500            .is_some_and(|state| state.kind() == AtnStateKind::LoopEnd)
3501        {
3502            continue;
3503        }
3504        for symbol in 1..=atn.max_token_type() {
3505            let reachability = state_can_reach_symbol_with_precedence(
3506                atn,
3507                target,
3508                OperatorReachabilityRequest {
3509                    symbol,
3510                    precedence,
3511                    predicate_dependent: false,
3512                    operator_rule_index,
3513                },
3514                &mut nullable_ctx,
3515                &mut Vec::new(),
3516                &mut BTreeSet::new(),
3517            );
3518            if reachability.single_token {
3519                lookahead.single_token.insert(symbol);
3520            }
3521            if reachability.multi_token {
3522                lookahead.multi_token_prefix.insert(symbol);
3523            }
3524            if reachability.predicate_dependent {
3525                lookahead.predicate_dependent.insert(symbol);
3526            }
3527        }
3528    }
3529    lookahead
3530}
3531
3532#[derive(Debug, Default)]
3533struct StateBeforeStopLookahead {
3534    symbols: TokenBitSet,
3535    reaches_context_boundary: bool,
3536}
3537
3538fn state_before_stop_lookahead(
3539    atn: &Atn,
3540    state_number: usize,
3541    stop_state_number: usize,
3542) -> Rc<StateBeforeStopLookahead> {
3543    with_shared_atn_caches(atn, |cache| {
3544        let key = (state_number, stop_state_number);
3545        if let Some(cached) = cache.state_before_stop_lookahead.get(&key) {
3546            return Rc::clone(cached);
3547        }
3548        let mut lookahead = StateBeforeStopLookahead::default();
3549        state_before_stop_lookahead_inner(
3550            atn,
3551            state_number,
3552            stop_state_number,
3553            &mut BTreeSet::new(),
3554            &mut cache.first_set,
3555            &mut lookahead,
3556        );
3557        let lookahead = Rc::new(lookahead);
3558        cache
3559            .state_before_stop_lookahead
3560            .insert(key, Rc::clone(&lookahead));
3561        lookahead
3562    })
3563}
3564
3565fn state_before_stop_lookahead_inner(
3566    atn: &Atn,
3567    state_number: usize,
3568    stop_state_number: usize,
3569    visited: &mut BTreeSet<usize>,
3570    first_set_cache: &mut FirstSetCache,
3571    lookahead: &mut StateBeforeStopLookahead,
3572) {
3573    if state_number == stop_state_number {
3574        lookahead.reaches_context_boundary = true;
3575        return;
3576    }
3577    if !visited.insert(state_number) {
3578        return;
3579    }
3580    let Some(state) = atn.state(state_number) else {
3581        return;
3582    };
3583    if state.kind() == AtnStateKind::RuleStop {
3584        lookahead.reaches_context_boundary = true;
3585        return;
3586    }
3587    for transition in &state.transitions() {
3588        match &transition.data() {
3589            Transition::Epsilon { target }
3590            | Transition::Action { target, .. }
3591            | Transition::Predicate { target, .. }
3592            | Transition::Precedence { target, .. } => {
3593                state_before_stop_lookahead_inner(
3594                    atn,
3595                    *target,
3596                    stop_state_number,
3597                    visited,
3598                    first_set_cache,
3599                    lookahead,
3600                );
3601            }
3602            Transition::Rule {
3603                target,
3604                rule_index,
3605                follow_state,
3606                ..
3607            } => {
3608                let Some(child_stop) = atn.rule_to_stop_state().get(*rule_index) else {
3609                    continue;
3610                };
3611                let child = rule_first_set(atn, *target, child_stop, first_set_cache);
3612                lookahead.symbols.extend_from(&child.symbols);
3613                if child.nullable {
3614                    state_before_stop_lookahead_inner(
3615                        atn,
3616                        *follow_state,
3617                        stop_state_number,
3618                        visited,
3619                        first_set_cache,
3620                        lookahead,
3621                    );
3622                }
3623            }
3624            Transition::Atom { .. }
3625            | Transition::Range { .. }
3626            | Transition::Set { .. }
3627            | Transition::NotSet { .. }
3628            | Transition::Wildcard { .. } => {
3629                lookahead.symbols.extend_iter(transition_expected_symbols(
3630                    transition,
3631                    atn.max_token_type(),
3632                ));
3633            }
3634        }
3635    }
3636}
3637
3638fn caller_context_can_match_symbol_before_state(
3639    atn: &Atn,
3640    return_states: impl DoubleEndedIterator<Item = usize>,
3641    stop_state_number: usize,
3642    symbol: i32,
3643) -> bool {
3644    for return_state in return_states.rev() {
3645        let lookahead = state_before_stop_lookahead(atn, return_state, stop_state_number);
3646        if lookahead.symbols.contains(symbol) {
3647            return true;
3648        }
3649        if !lookahead.reaches_context_boundary {
3650            return false;
3651        }
3652    }
3653    false
3654}
3655
3656/// Carries recovery expectations and their restart state through epsilon-only
3657/// paths. ANTLR can report and repair at the decision state even when the
3658/// failed consuming transition is nested under block or loop epsilon edges.
3659fn next_recovery_context(
3660    atn: &Atn,
3661    state: AtnState<'_>,
3662    inherited: &BTreeSet<i32>,
3663    inherited_state: Option<usize>,
3664) -> (BTreeSet<i32>, Option<usize>) {
3665    let state_symbols = state_expected_symbols(atn, state.state_number());
3666    if state.transitions().len() > 1 && !state_symbols.is_empty() {
3667        let mut symbols = state_symbols;
3668        symbols.extend(inherited.iter().copied());
3669        return (symbols, Some(state.state_number()));
3670    }
3671    (inherited.clone(), inherited_state)
3672}
3673
3674fn recovery_expected_symbols(
3675    atn: &Atn,
3676    state_number: usize,
3677    inherited: &BTreeSet<i32>,
3678) -> BTreeSet<i32> {
3679    let mut symbols = state_expected_symbols(atn, state_number);
3680    symbols.extend(inherited.iter().copied());
3681    symbols
3682}
3683
3684/// Fast-recognizer variant of [`next_recovery_context`] that reuses the
3685/// parser's cached state-expected-symbols sets and the inherited `Rc`
3686/// without copying when the state cannot widen recovery.
3687fn fast_next_recovery_context<S, H>(
3688    parser: &mut BaseParser<S, H>,
3689    atn: &Atn,
3690    state: AtnState<'_>,
3691    inherited: &Rc<BTreeSet<i32>>,
3692    inherited_state: Option<usize>,
3693) -> (Rc<BTreeSet<i32>>, Option<usize>)
3694where
3695    S: TokenSource,
3696    H: SemanticHooks,
3697{
3698    if state.transitions().len() <= 1 {
3699        return (Rc::clone(inherited), inherited_state);
3700    }
3701    let state_symbols = parser.cached_state_expected_symbols(atn, state.state_number());
3702    if state_symbols.is_empty() {
3703        return (Rc::clone(inherited), inherited_state);
3704    }
3705    if inherited.is_empty() {
3706        return (state_symbols, Some(state.state_number()));
3707    }
3708    if Rc::ptr_eq(&state_symbols, inherited) {
3709        return (state_symbols, Some(state.state_number()));
3710    }
3711    let mut combined = (*state_symbols).clone();
3712    combined.extend(inherited.iter().copied());
3713    (
3714        parser.intern_recovery_symbols(combined),
3715        Some(state.state_number()),
3716    )
3717}
3718
3719/// Fast-recognizer variant of [`recovery_expected_symbols`] that reuses the
3720/// cached state-expected-symbols and avoids cloning when no widening is
3721/// needed.
3722fn fast_recovery_expected_symbols<S, H>(
3723    parser: &mut BaseParser<S, H>,
3724    atn: &Atn,
3725    state_number: usize,
3726    inherited: &Rc<BTreeSet<i32>>,
3727) -> Rc<BTreeSet<i32>>
3728where
3729    S: TokenSource,
3730    H: SemanticHooks,
3731{
3732    let cached = parser.cached_state_expected_symbols(atn, state_number);
3733    if inherited.is_empty() {
3734        return cached;
3735    }
3736    if cached.is_empty() {
3737        return Rc::clone(inherited);
3738    }
3739    if Rc::ptr_eq(&cached, inherited) {
3740        return cached;
3741    }
3742    let mut combined = (*cached).clone();
3743    combined.extend(inherited.iter().copied());
3744    parser.intern_recovery_symbols(combined)
3745}
3746
3747struct ParserTableSemCtx<'a> {
3748    member_values: &'a mut BTreeMap<usize, i64>,
3749    return_values: &'a mut BTreeMap<String, i64>,
3750}
3751
3752impl semir::PredContext for ParserTableSemCtx<'_> {
3753    type TokenText<'a>
3754        = &'a str
3755    where
3756        Self: 'a;
3757
3758    fn la(&mut self, _offset: isize) -> i64 {
3759        i64::from(TOKEN_EOF)
3760    }
3761
3762    fn token_text(&mut self, _offset: isize) -> Option<Self::TokenText<'_>> {
3763        None
3764    }
3765
3766    fn token_index_adjacent(&mut self) -> bool {
3767        false
3768    }
3769
3770    fn ctx_rule_text(&self, _rule_index: usize) -> Option<String> {
3771        None
3772    }
3773
3774    fn member(&self, member: usize) -> Option<i64> {
3775        Some(self.member_values.get(&member).copied().unwrap_or_default())
3776    }
3777
3778    fn local_arg(&self) -> Option<i64> {
3779        None
3780    }
3781
3782    fn column(&self) -> Option<i64> {
3783        None
3784    }
3785
3786    fn token_start_column(&self) -> Option<i64> {
3787        None
3788    }
3789
3790    fn token_text_so_far(&self) -> Option<String> {
3791        None
3792    }
3793
3794    fn hook(&mut self, _hook: HookId) -> bool {
3795        false
3796    }
3797}
3798
3799impl semir::ActContext for ParserTableSemCtx<'_> {
3800    fn set_member(&mut self, member: usize, value: i64) {
3801        self.member_values.insert(member, value);
3802    }
3803
3804    fn set_return(&mut self, name: &str, value: i64) {
3805        self.return_values.insert(name.to_owned(), value);
3806    }
3807
3808    fn action_hook(&mut self, _hook: HookId) {}
3809}
3810
3811/// Applies generated integer-member side effects to one speculative path.
3812fn apply_member_actions(
3813    source_state: usize,
3814    actions: &[ParserMemberAction],
3815    semantics: Option<&ParserSemantics>,
3816    values: &mut BTreeMap<usize, i64>,
3817) {
3818    for action in actions
3819        .iter()
3820        .filter(|action| action.source_state == source_state)
3821    {
3822        *values.entry(action.member).or_default() += action.delta;
3823    }
3824    let Some(semantics) = semantics else {
3825        return;
3826    };
3827    let mut return_values = BTreeMap::new();
3828    let mut ctx = ParserTableSemCtx {
3829        member_values: values,
3830        return_values: &mut return_values,
3831    };
3832    for action in semantics
3833        .actions
3834        .iter()
3835        .filter(|action| action.source_state == source_state && action.speculative)
3836    {
3837        semir::exec_stmt(&semantics.ir, action.stmt, &mut ctx);
3838    }
3839}
3840
3841/// Returns the speculative member state after replaying one ATN action state.
3842fn member_values_after_action(
3843    source_state: usize,
3844    actions: &[ParserMemberAction],
3845    semantics: Option<&ParserSemantics>,
3846    values: &BTreeMap<usize, i64>,
3847) -> BTreeMap<usize, i64> {
3848    let mut values = values.clone();
3849    apply_member_actions(source_state, actions, semantics, &mut values);
3850    values
3851}
3852
3853/// Returns the speculative rule-return state after replaying one ATN action.
3854fn return_values_after_action(
3855    source_state: usize,
3856    rule_index: usize,
3857    actions: &[ParserReturnAction],
3858    semantics: Option<&ParserSemantics>,
3859    values: &BTreeMap<String, i64>,
3860) -> BTreeMap<String, i64> {
3861    let mut values = values.clone();
3862    for action in actions
3863        .iter()
3864        .filter(|action| action.source_state == source_state && action.rule_index == rule_index)
3865    {
3866        values.insert(action.name.to_owned(), action.value);
3867    }
3868    if let Some(semantics) = semantics {
3869        let mut member_values = BTreeMap::new();
3870        let mut ctx = ParserTableSemCtx {
3871            member_values: &mut member_values,
3872            return_values: &mut values,
3873        };
3874        for action in semantics.actions.iter().filter(|action| {
3875            action.source_state == source_state
3876                && action.rule_index == rule_index
3877                && !action.speculative
3878        }) {
3879            semir::exec_stmt(&semantics.ir, action.stmt, &mut ctx);
3880        }
3881    }
3882    values
3883}
3884
3885/// Resolves the integer argument visible to a child rule invocation.
3886fn rule_local_int_arg(
3887    rule_args: &[ParserRuleArg],
3888    source_state: usize,
3889    rule_index: usize,
3890    local_int_arg: Option<(usize, i64)>,
3891) -> Option<(usize, i64)> {
3892    rule_args
3893        .iter()
3894        .find(|arg| arg.source_state == source_state && arg.rule_index == rule_index)
3895        .map(|arg| {
3896            let value = if arg.inherit_local {
3897                local_int_arg.map_or(arg.value, |(_, value)| value)
3898            } else {
3899                arg.value
3900            };
3901            (rule_index, value)
3902        })
3903}
3904
3905/// Builds the terminal recognition outcome for a path that reached its stop
3906/// state.
3907fn stop_outcome(
3908    index: usize,
3909    consumed_eof: bool,
3910    rule_alt_number: usize,
3911    member_values: BTreeMap<usize, i64>,
3912    return_values: BTreeMap<String, i64>,
3913) -> Vec<RecognizeOutcome> {
3914    vec![RecognizeOutcome {
3915        index,
3916        consumed_eof,
3917        alt_number: rule_alt_number,
3918        member_values,
3919        return_values,
3920        diagnostics: DiagnosticSeqId::EMPTY,
3921        decisions: Vec::new(),
3922        actions: Vec::new(),
3923        nodes: NodeSeqId::EMPTY,
3924    }]
3925}
3926
3927fn atn_has_observable_action_transitions(atn: &Atn) -> bool {
3928    with_shared_atn_caches(atn, |cache| {
3929        *cache.observable_action_transitions.get_or_insert_with(|| {
3930            atn.states().any(|state| {
3931                state.transitions().iter().any(|transition| {
3932                    matches!(
3933                        &transition.data(),
3934                        Transition::Action {
3935                            action_index: Some(_),
3936                            ..
3937                        }
3938                    )
3939                })
3940            })
3941        })
3942    })
3943}
3944
3945fn atn_has_predicate_transitions(atn: &Atn) -> bool {
3946    with_shared_atn_caches(atn, |cache| {
3947        *cache.predicate_transitions.get_or_insert_with(|| {
3948            atn.states().any(|state| {
3949                state
3950                    .transitions()
3951                    .iter()
3952                    .any(|transition| matches!(&transition.data(), Transition::Predicate { .. }))
3953            })
3954        })
3955    })
3956}
3957
3958/// Reports whether predicates are the only observable semantics the fast
3959/// recognizer must preserve. Without path-local actions, arguments, or return
3960/// state, repeated evaluation at one coordinate and input index receives the
3961/// same runtime context.
3962fn can_use_fast_predicate_recognizer(atn: &Atn, options: &ParserRuntimeOptions<'_>) -> bool {
3963    options.init_action_rules.is_empty()
3964        && !options.track_alt_numbers
3965        && !options.track_context_alt_numbers
3966        && options
3967            .predicates
3968            .iter()
3969            .all(|(_, _, predicate)| predicate.failure_message().is_none())
3970        && options.semantics.is_none_or(|semantics| {
3971            semantics.actions.is_empty()
3972                && semantics
3973                    .predicates
3974                    .iter()
3975                    .all(|predicate| predicate.failure_message.is_none())
3976        })
3977        && options.rule_args.is_empty()
3978        && options.member_actions.is_empty()
3979        && options.return_actions.is_empty()
3980        && !atn_has_observable_action_transitions(atn)
3981}
3982
3983#[derive(Clone, Debug, Eq, PartialEq)]
3984struct RecognizeRequest<'a> {
3985    state_number: usize,
3986    stop_state: usize,
3987    index: usize,
3988    rule_start_index: usize,
3989    decision_start_index: Option<usize>,
3990    init_action_rules: &'a BTreeSet<usize>,
3991    predicates: &'a [(usize, usize, ParserPredicate)],
3992    semantics: Option<&'a ParserSemantics>,
3993    rule_args: &'a [ParserRuleArg],
3994    member_actions: &'a [ParserMemberAction],
3995    return_actions: &'a [ParserReturnAction],
3996    local_int_arg: Option<(usize, i64)>,
3997    member_values: BTreeMap<usize, i64>,
3998    return_values: BTreeMap<String, i64>,
3999    rule_alt_number: usize,
4000    track_alt_numbers: bool,
4001    consumed_eof: bool,
4002    committed_decision: bool,
4003    /// Current left-recursive precedence threshold, matching ANTLR's
4004    /// `precpred(_ctx, k)` check for generated precedence rules.
4005    precedence: i32,
4006    depth: usize,
4007    recovery_symbols: BTreeSet<i32>,
4008    recovery_state: Option<usize>,
4009}
4010
4011#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
4012struct RecognizeKey {
4013    state_number: usize,
4014    stop_state: usize,
4015    index: usize,
4016    rule_start_index: usize,
4017    decision_start_index: Option<usize>,
4018    local_int_arg: Option<(usize, i64)>,
4019    member_values: BTreeMap<usize, i64>,
4020    return_values: BTreeMap<String, i64>,
4021    rule_alt_number: usize,
4022    track_alt_numbers: bool,
4023    consumed_eof: bool,
4024    committed_decision: bool,
4025    precedence: i32,
4026    recovery_symbols: BTreeSet<i32>,
4027    recovery_state: Option<usize>,
4028}
4029
4030#[derive(Clone, Debug, Eq, PartialEq)]
4031struct EpsilonActionStep {
4032    source_state: usize,
4033    target: usize,
4034    action_rule_index: Option<usize>,
4035    left_recursive_boundary: Option<usize>,
4036    decision: Option<usize>,
4037    decision_start_index: Option<usize>,
4038    alt_number: usize,
4039    recovery_symbols: BTreeSet<i32>,
4040    recovery_state: Option<usize>,
4041}
4042
4043struct RecognizeScratch<'a> {
4044    visiting: &'a mut BTreeSet<RecognizeKey>,
4045    memo: &'a mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
4046    expected: &'a mut ExpectedTokens,
4047}
4048
4049#[derive(Clone, Debug, Eq, PartialEq)]
4050struct FastRecognizeRequest {
4051    state_number: usize,
4052    stop_state: usize,
4053    index: usize,
4054    rule_start_index: usize,
4055    decision_start_index: Option<usize>,
4056    precedence: i32,
4057    depth: usize,
4058    recovery_symbols: Rc<BTreeSet<i32>>,
4059    recovery_state: Option<usize>,
4060}
4061
4062#[derive(Clone, Copy, Debug, Eq, PartialEq)]
4063struct FastRecognizeTopRequest {
4064    start_state: usize,
4065    stop_state: usize,
4066    start_index: usize,
4067    precedence: i32,
4068    caller_follow_state: Option<usize>,
4069}
4070
4071#[derive(Clone, Copy, Debug)]
4072struct FastPredicateContext<'a> {
4073    predicates: &'a [(usize, usize, ParserPredicate)],
4074    semantics: Option<&'a ParserSemantics>,
4075    member_values: &'a BTreeMap<usize, i64>,
4076}
4077
4078struct FastRecognizeScratch<'a, 'b> {
4079    predicate_context: Option<FastPredicateContext<'a>>,
4080    visiting: &'b mut FxHashSet<FastRecognizeKey>,
4081    memo: &'b mut FxHashMap<FastRecognizeKey, Rc<[FastRecognizeOutcome]>>,
4082    expected: &'b mut ExpectedTokens,
4083    native_depth: usize,
4084}
4085
4086#[derive(Clone, Copy, Debug)]
4087struct FastRepetitionShape {
4088    enter_target: usize,
4089    exit_target: usize,
4090    body_stop_state: usize,
4091    enter_transition_index: usize,
4092    exit_transition_index: usize,
4093}
4094
4095#[derive(Clone, Copy, Debug)]
4096struct FastRepetitionPath {
4097    index: usize,
4098    deferred_nodes: FastDeferredNodeId,
4099    diagnostics: DiagnosticSeqId,
4100    consumed_eof: bool,
4101}
4102
4103enum FastRepetitionWork {
4104    Enter(FastRepetitionPath),
4105    Exit(FastRepetitionPath),
4106}
4107
4108/// Dense entered/exited coordinate sets for one repetition walk.
4109///
4110/// The start coordinate stays inline so short loops avoid a heap allocation;
4111/// later token indexes use one byte each instead of two hash-table entries.
4112struct FastRepetitionCoordinates {
4113    base_index: usize,
4114    base_state: u8,
4115    later_states: Vec<u8>,
4116}
4117
4118impl FastRepetitionCoordinates {
4119    const ENTERED: u8 = 0;
4120    const EXITED: u8 = 2;
4121
4122    const fn new(base_index: usize) -> Self {
4123        Self {
4124            base_index,
4125            base_state: 0,
4126            later_states: Vec::new(),
4127        }
4128    }
4129
4130    fn insert_entered(&mut self, path: FastRepetitionPath) -> bool {
4131        self.insert(path.index, path.consumed_eof, Self::ENTERED)
4132    }
4133
4134    fn insert_exited(&mut self, path: FastRepetitionPath) -> bool {
4135        self.insert(path.index, path.consumed_eof, Self::EXITED)
4136    }
4137
4138    fn insert(&mut self, index: usize, consumed_eof: bool, base_bit: u8) -> bool {
4139        let Some(offset) = index.checked_sub(self.base_index) else {
4140            return false;
4141        };
4142        let state = if offset == 0 {
4143            &mut self.base_state
4144        } else {
4145            if self.later_states.len() < offset {
4146                self.later_states.resize(offset, 0);
4147            }
4148            &mut self.later_states[offset - 1]
4149        };
4150        let bit = 1 << (base_bit + u8::from(consumed_eof));
4151        let is_new = *state & bit == 0;
4152        *state |= bit;
4153        is_new
4154    }
4155}
4156
4157fn fast_repetition_shape(atn: &Atn, state: AtnState<'_>) -> Option<FastRepetitionShape> {
4158    if state.precedence_rule_decision()
4159        || !matches!(
4160            state.kind(),
4161            AtnStateKind::StarLoopEntry | AtnStateKind::PlusLoopBack
4162        )
4163        || state.transitions().len() != 2
4164    {
4165        return None;
4166    }
4167    let mut enter = None;
4168    let mut exit = None;
4169    for (index, transition) in state.transitions().iter().enumerate() {
4170        if transition.kind() != ParserTransitionKind::Epsilon {
4171            return None;
4172        }
4173        let target = transition.target();
4174        if atn
4175            .state(target)
4176            .is_some_and(|target_state| target_state.kind() == AtnStateKind::LoopEnd)
4177        {
4178            if exit.replace((index, target)).is_some() {
4179                return None;
4180            }
4181        } else if enter.replace((index, target)).is_some() {
4182            return None;
4183        }
4184    }
4185    let (enter_transition_index, enter_target) = enter?;
4186    let (exit_transition_index, exit_target) = exit?;
4187    let body_stop_state = if state.kind() == AtnStateKind::StarLoopEntry {
4188        atn.state(exit_target)?.loop_back_state()?
4189    } else {
4190        state.state_number()
4191    };
4192    Some(FastRepetitionShape {
4193        enter_target,
4194        exit_target,
4195        body_stop_state,
4196        enter_transition_index,
4197        exit_transition_index,
4198    })
4199}
4200
4201fn push_fast_repetition_work(
4202    work: &mut Vec<FastRepetitionWork>,
4203    shape: FastRepetitionShape,
4204    path: FastRepetitionPath,
4205    lookahead: Option<&DecisionLookahead>,
4206    symbol: i32,
4207) {
4208    // Match the normal recognizer's FIRST-set pruning before queueing work.
4209    // Ambiguous body paths still share the coordinate bitmap below.
4210    let transition_is_viable = |transition_index: usize| {
4211        let Some(entry) = lookahead else {
4212            return true;
4213        };
4214        let Some(transition) = entry.transitions.get(transition_index) else {
4215            return true;
4216        };
4217        transition.nullable || transition.symbols.contains(symbol)
4218    };
4219    let enter_is_viable = transition_is_viable(shape.enter_transition_index);
4220    let exit_is_viable = transition_is_viable(shape.exit_transition_index);
4221    if shape.enter_transition_index < shape.exit_transition_index {
4222        if exit_is_viable {
4223            work.push(FastRepetitionWork::Exit(path));
4224        }
4225        if enter_is_viable {
4226            work.push(FastRepetitionWork::Enter(path));
4227        }
4228    } else {
4229        if enter_is_viable {
4230            work.push(FastRepetitionWork::Enter(path));
4231        }
4232        if exit_is_viable {
4233            work.push(FastRepetitionWork::Exit(path));
4234        }
4235    }
4236}
4237
4238/// Memo key for the fast recognizer. `recovery_symbols` must come from
4239/// `intern_recovery_symbols` or `empty_recovery_symbols` before it reaches this
4240/// key, so equal sets share one allocation and the key can store that
4241/// allocation's address instead of cloning an `Rc` and walking the full
4242/// `BTreeSet`. Bypassing the interner would turn content-equal recovery sets
4243/// into distinct cache coordinates.
4244#[derive(Clone, Debug)]
4245struct FastRecognizeKey {
4246    state_number: usize,
4247    stop_state: usize,
4248    index: usize,
4249    rule_start_index: usize,
4250    decision_start_index: Option<usize>,
4251    precedence: i32,
4252    recovery_symbols_id: usize,
4253    recovery_state: Option<usize>,
4254}
4255
4256impl PartialEq for FastRecognizeKey {
4257    fn eq(&self, other: &Self) -> bool {
4258        if self.state_number != other.state_number
4259            || self.stop_state != other.stop_state
4260            || self.index != other.index
4261            || self.rule_start_index != other.rule_start_index
4262            || self.decision_start_index != other.decision_start_index
4263            || self.precedence != other.precedence
4264            || self.recovery_state != other.recovery_state
4265            || self.recovery_symbols_id != other.recovery_symbols_id
4266        {
4267            return false;
4268        }
4269        true
4270    }
4271}
4272
4273impl Eq for FastRecognizeKey {}
4274
4275impl Hash for FastRecognizeKey {
4276    fn hash<H: Hasher>(&self, hasher: &mut H) {
4277        self.state_number.hash(hasher);
4278        self.stop_state.hash(hasher);
4279        self.index.hash(hasher);
4280        self.rule_start_index.hash(hasher);
4281        self.decision_start_index.hash(hasher);
4282        self.precedence.hash(hasher);
4283        self.recovery_state.hash(hasher);
4284        self.recovery_symbols_id.hash(hasher);
4285    }
4286}
4287
4288struct FastRecoveryRequest<'a, 'b> {
4289    atn: &'a Atn,
4290    transition: ParserTransition<'a>,
4291    expected_symbols: Rc<BTreeSet<i32>>,
4292    target: usize,
4293    request: FastRecognizeRequest,
4294    visiting: &'b mut FxHashSet<FastRecognizeKey>,
4295    memo: &'b mut FxHashMap<FastRecognizeKey, Rc<[FastRecognizeOutcome]>>,
4296    expected: &'b mut ExpectedTokens,
4297}
4298
4299struct FastCurrentTokenDeletionRequest<'a, 'b> {
4300    atn: &'a Atn,
4301    expected_symbols: Rc<BTreeSet<i32>>,
4302    request: FastRecognizeRequest,
4303    visiting: &'b mut FxHashSet<FastRecognizeKey>,
4304    memo: &'b mut FxHashMap<FastRecognizeKey, Rc<[FastRecognizeOutcome]>>,
4305    expected: &'b mut ExpectedTokens,
4306}
4307
4308#[derive(Clone, Copy)]
4309struct FastChildRuleFailureRecoveryRequest<'a> {
4310    atn: &'a Atn,
4311    rule_index: usize,
4312    start_index: usize,
4313    follow_state: usize,
4314    stop_state: usize,
4315    expected: &'a ExpectedTokens,
4316}
4317
4318struct RecoveryRequest<'a, 'b> {
4319    atn: &'a Atn,
4320    transition: ParserTransition<'a>,
4321    expected_symbols: BTreeSet<i32>,
4322    target: usize,
4323    request: RecognizeRequest<'a>,
4324    visiting: &'b mut BTreeSet<RecognizeKey>,
4325    memo: &'b mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
4326    expected: &'b mut ExpectedTokens,
4327}
4328
4329struct CurrentTokenDeletionRequest<'a, 'b> {
4330    atn: &'a Atn,
4331    expected_symbols: BTreeSet<i32>,
4332    request: RecognizeRequest<'a>,
4333    visiting: &'b mut BTreeSet<RecognizeKey>,
4334    memo: &'b mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
4335    expected: &'b mut ExpectedTokens,
4336}
4337
4338/// Carries the state needed after the normal token-recovery strategies fail
4339/// for a consuming transition.
4340struct ConsumingFailureFallback<'a> {
4341    atn: &'a Atn,
4342    target: usize,
4343    request: RecognizeRequest<'a>,
4344    symbol: i32,
4345    expected_symbols: BTreeSet<i32>,
4346    decision_start_index: Option<usize>,
4347    decision: Option<usize>,
4348}
4349
4350/// Captures the parent-rule context needed when a called rule fails before it
4351/// can produce a normal outcome.
4352struct ChildRuleFailureRecovery<'a> {
4353    atn: &'a Atn,
4354    rule_index: usize,
4355    start_index: usize,
4356    follow_state: usize,
4357    stop_state: usize,
4358    member_values: BTreeMap<usize, i64>,
4359    expected: &'a ExpectedTokens,
4360}
4361
4362/// Bundles the context needed to evaluate one semantic predicate transition.
4363#[derive(Clone, Copy, Debug)]
4364struct PredicateEval<'a> {
4365    index: usize,
4366    rule_index: usize,
4367    pred_index: usize,
4368    predicates: &'a [(usize, usize, ParserPredicate)],
4369    semantics: Option<&'a ParserSemantics>,
4370    context: Option<&'a ParserRuleContext>,
4371    local_int_arg: Option<(usize, i64)>,
4372    member_values: &'a BTreeMap<usize, i64>,
4373}
4374
4375#[derive(Clone, Copy, Debug)]
4376struct ParserSemanticHookRequest<'a> {
4377    index: usize,
4378    rule_index: usize,
4379    pred_index: usize,
4380    context: Option<&'a ParserRuleContext>,
4381    local_int_arg: Option<(usize, i64)>,
4382    member_values: &'a BTreeMap<usize, i64>,
4383}
4384
4385/// Predicate-evaluation context over the recognizer's speculative state.
4386///
4387/// This sits in the prediction hot loop, so everything is borrowed: member
4388/// state read-only from the current speculative path and the rule name
4389/// straight from recognizer metadata. Predicates are pure by construction
4390/// ([`semir::PExpr`] has no mutating node); statement execution uses
4391/// [`ParserTableSemCtx`] (speculative member/return replay) and
4392/// [`BaseParser::parser_action_hook`] (committed action hooks) instead.
4393struct ParserSemIrCtx<'a, S, H>
4394where
4395    S: TokenSource,
4396    H: SemanticHooks,
4397{
4398    input: &'a mut CommonTokenStream<S>,
4399    tree_storage: &'a ParseTreeStorage,
4400    semantic_hooks: &'a mut H,
4401    rule_index: usize,
4402    coordinate_index: usize,
4403    rule_name: Option<&'a str>,
4404    context: Option<&'a ParserRuleContext>,
4405    local_int_arg: Option<(usize, i64)>,
4406    member_values: &'a BTreeMap<usize, i64>,
4407    invoked_predicates: &'a mut Vec<(usize, usize)>,
4408    /// Policy applied when a [`semir::PExpr::Hook`] node's user hook declines
4409    /// (`None`); keeps the fail-loud fallback chain identical to the legacy
4410    /// table path instead of coercing the miss to `false`.
4411    unknown_predicate_policy: UnknownSemanticPolicy,
4412    unknown_predicate_hits: &'a mut Vec<(usize, usize)>,
4413}
4414
4415impl<S, H> semir::PredContext for ParserSemIrCtx<'_, S, H>
4416where
4417    S: TokenSource,
4418    H: SemanticHooks,
4419{
4420    type TokenText<'a>
4421        = TokenView<'a>
4422    where
4423        Self: 'a;
4424
4425    fn la(&mut self, offset: isize) -> i64 {
4426        i64::from(self.input.la(offset))
4427    }
4428
4429    fn token_text(&mut self, offset: isize) -> Option<Self::TokenText<'_>> {
4430        self.input.lt(offset)
4431    }
4432
4433    fn token_index_adjacent(&mut self) -> bool {
4434        let Some(first) = self.input.lt_id(-2).map(TokenId::index) else {
4435            return false;
4436        };
4437        let Some(second) = self.input.lt_id(-1).map(TokenId::index) else {
4438            return false;
4439        };
4440        first + 1 == second
4441    }
4442
4443    fn ctx_rule_text(&self, rule_index: usize) -> Option<String> {
4444        self.context.and_then(|context| {
4445            context
4446                .child_rules(self.tree_storage, self.input.token_store(), rule_index)
4447                .next()
4448                .map(crate::tree::RuleNodeView::text)
4449        })
4450    }
4451
4452    fn member(&self, member: usize) -> Option<i64> {
4453        Some(self.member_values.get(&member).copied().unwrap_or_default())
4454    }
4455
4456    fn local_arg(&self) -> Option<i64> {
4457        self.local_int_arg.map(|(_, value)| value)
4458    }
4459
4460    fn column(&self) -> Option<i64> {
4461        None
4462    }
4463
4464    fn token_start_column(&self) -> Option<i64> {
4465        None
4466    }
4467
4468    fn token_text_so_far(&self) -> Option<String> {
4469        None
4470    }
4471
4472    fn hook(&mut self, _hook: HookId) -> bool {
4473        let mut ctx = ParserSemCtx {
4474            input: &mut *self.input,
4475            tree_storage: self.tree_storage,
4476            rule_index: self.rule_index,
4477            coordinate_index: self.coordinate_index,
4478            rule_name: self.rule_name.map(str::to_owned),
4479            context: self.context,
4480            tree: None,
4481            local_int_arg: self.local_int_arg,
4482            member_values: self.member_values,
4483            action: None,
4484        };
4485        match self
4486            .semantic_hooks
4487            .sempred(&mut ctx, self.rule_index, self.coordinate_index)
4488        {
4489            Some(result) => result,
4490            // No hook answered this coordinate: fall through to the configured
4491            // policy instead of silently rejecting the alternative, matching the
4492            // legacy table path's dispatch chain (hook → policy).
4493            None => apply_unknown_predicate_policy(
4494                self.unknown_predicate_policy,
4495                self.rule_index,
4496                self.coordinate_index,
4497                self.unknown_predicate_hits,
4498            ),
4499        }
4500    }
4501
4502    fn trace_bool(&mut self, value: bool) -> bool {
4503        let key = (self.rule_index, self.coordinate_index);
4504        if !self.invoked_predicates.contains(&key) {
4505            self.invoked_predicates.push(key);
4506            use std::io::Write as _;
4507            let mut stdout = std::io::stdout().lock();
4508            let _ = writeln!(stdout, "eval={value}");
4509        }
4510        value
4511    }
4512}
4513
4514/// Captures predicate-failure recovery metadata for fail-option predicates.
4515struct PredicateFailureRecovery<'a> {
4516    rule_index: usize,
4517    index: usize,
4518    message: &'a str,
4519    member_values: BTreeMap<usize, i64>,
4520    return_values: BTreeMap<String, i64>,
4521    rule_alt_number: usize,
4522}
4523
4524#[derive(Debug)]
4525enum DirectAdaptiveParseControl {
4526    Fallback(DirectAdaptiveFallback),
4527}
4528
4529#[derive(Clone, Copy, Debug, Eq, PartialEq)]
4530enum DirectAdaptiveFallback {
4531    Action,
4532    InvalidAlt,
4533    LeftRecursiveBoundary,
4534    MissingAtn,
4535    NoTransition,
4536    Predicate,
4537    Prediction,
4538    Precedence,
4539    RuleStop,
4540    SemanticContext,
4541    StepLimit,
4542    TokenMismatch,
4543    UnknownDecision,
4544}
4545
4546type DirectAdaptiveParseResult<T> = Result<T, DirectAdaptiveParseControl>;
4547
4548struct DirectAdaptiveParser<'atn, 'sim, S, H = NoSemanticHooks>
4549where
4550    S: TokenSource,
4551    H: SemanticHooks,
4552{
4553    parser: &'sim mut BaseParser<S, H>,
4554    atn: &'atn Atn,
4555    simulator: &'sim mut ParserAtnSimulator<'atn>,
4556    decision_by_state: Vec<Option<usize>>,
4557    steps: usize,
4558}
4559
4560/// Outcome of a generated token / set / not-set match that may recover.
4561///
4562/// Generated parsers append `children` to the current rule context. `consumed_eof`
4563/// reports whether the match actually consumed a real EOF terminal — it is true
4564/// only on a successful match (or single-token deletion that lands on EOF), and
4565/// always false on single-token insertion, which synthesizes a missing token and
4566/// consumes nothing. Generated code feeds this into `finish_rule`'s
4567/// `consumed_eof`, so the rule stop token is recorded as EOF only when EOF was
4568/// truly matched, matching ANTLR's `matchedEOF` semantics.
4569#[derive(Clone, Debug, Eq, PartialEq)]
4570pub struct GeneratedMatch {
4571    children: GeneratedMatchChildren,
4572    consumed_eof: bool,
4573}
4574
4575#[derive(Clone, Copy)]
4576enum GeneratedExpectedSymbols<'a> {
4577    Tree(&'a BTreeSet<i32>),
4578    TokenSet(ParserIntervalSet<'a>),
4579    TokenSetComplement {
4580        set: ParserIntervalSet<'a>,
4581        min_vocabulary: i32,
4582        max_vocabulary: i32,
4583    },
4584}
4585
4586impl GeneratedExpectedSymbols<'_> {
4587    fn is_empty(self) -> bool {
4588        match self {
4589            Self::Tree(symbols) => symbols.is_empty(),
4590            Self::TokenSet(set) => set.is_empty(),
4591            Self::TokenSetComplement {
4592                set,
4593                min_vocabulary,
4594                max_vocabulary,
4595            } => (min_vocabulary..=max_vocabulary).all(|symbol| set.contains(symbol)),
4596        }
4597    }
4598
4599    fn first(self) -> Option<i32> {
4600        match self {
4601            Self::Tree(symbols) => symbols.iter().next().copied(),
4602            Self::TokenSet(set) => set.ranges().next().map(|(start, _)| start),
4603            Self::TokenSetComplement {
4604                set,
4605                min_vocabulary,
4606                max_vocabulary,
4607            } => (min_vocabulary..=max_vocabulary).find(|symbol| !set.contains(*symbol)),
4608        }
4609    }
4610
4611    fn display(self, vocabulary: &Vocabulary) -> String {
4612        match self {
4613            Self::Tree(symbols) => expected_symbols_display(symbols, vocabulary),
4614            Self::TokenSet(set) => expected_symbols_display_iter(
4615                set.ranges().flat_map(|(start, stop)| start..=stop),
4616                vocabulary,
4617            ),
4618            Self::TokenSetComplement {
4619                set,
4620                min_vocabulary,
4621                max_vocabulary,
4622            } => expected_symbols_display_iter(
4623                (min_vocabulary..=max_vocabulary).filter(|symbol| !set.contains(*symbol)),
4624                vocabulary,
4625            ),
4626        }
4627    }
4628}
4629
4630#[derive(Clone, Debug, Eq, PartialEq)]
4631enum GeneratedMatchChildren {
4632    One(ParseTree),
4633    Many(Vec<ParseTree>),
4634}
4635
4636struct GeneratedMatchChildrenIntoIter {
4637    one: Option<ParseTree>,
4638    many: Option<std::vec::IntoIter<ParseTree>>,
4639}
4640
4641impl Iterator for GeneratedMatchChildrenIntoIter {
4642    type Item = ParseTree;
4643
4644    fn next(&mut self) -> Option<Self::Item> {
4645        self.one
4646            .take()
4647            .or_else(|| self.many.as_mut().and_then(Iterator::next))
4648    }
4649}
4650
4651impl GeneratedMatch {
4652    /// Parse-tree children produced by the match (the matched terminal, an
4653    /// error node plus deleted-then-matched terminal, or a single missing-token
4654    /// error node).
4655    #[must_use]
4656    pub fn children(&self) -> &[ParseTree] {
4657        match &self.children {
4658            GeneratedMatchChildren::One(child) => std::slice::from_ref(child),
4659            GeneratedMatchChildren::Many(children) => children,
4660        }
4661    }
4662
4663    /// Consumes the result, returning the children for appending to the rule
4664    /// context.
4665    #[must_use]
4666    pub fn into_children(self) -> Vec<ParseTree> {
4667        match self.children {
4668            GeneratedMatchChildren::One(child) => vec![child],
4669            GeneratedMatchChildren::Many(children) => children,
4670        }
4671    }
4672
4673    /// Consumes the match without allocating for the common single-child case.
4674    pub fn into_child_iter(self) -> impl Iterator<Item = ParseTree> {
4675        match self.children {
4676            GeneratedMatchChildren::One(child) => GeneratedMatchChildrenIntoIter {
4677                one: Some(child),
4678                many: None,
4679            },
4680            GeneratedMatchChildren::Many(children) => GeneratedMatchChildrenIntoIter {
4681                one: None,
4682                many: Some(children.into_iter()),
4683            },
4684        }
4685    }
4686
4687    /// Whether a real EOF terminal was consumed by this match.
4688    #[must_use]
4689    pub const fn consumed_eof(&self) -> bool {
4690        self.consumed_eof
4691    }
4692}
4693
4694impl<S> BaseParser<S, NoSemanticHooks>
4695where
4696    S: TokenSource,
4697{
4698    /// Creates a parser base over a buffered token stream and recognizer
4699    /// metadata.
4700    pub fn new(input: CommonTokenStream<S>, data: RecognizerData) -> Self {
4701        Self::with_semantic_hooks(input, data, NoSemanticHooks)
4702    }
4703}
4704
4705impl<S, H> BaseParser<S, H>
4706where
4707    S: TokenSource,
4708    H: SemanticHooks,
4709{
4710    /// Creates a parser base with caller-owned semantic hooks.
4711    pub fn with_semantic_hooks(
4712        input: CommonTokenStream<S>,
4713        data: RecognizerData,
4714        semantic_hooks: H,
4715    ) -> Self {
4716        Self {
4717            input,
4718            tree: ParseTreeStorage::new(),
4719            data,
4720            semantic_hooks,
4721            decision_override_generation: 0,
4722            build_parse_trees: true,
4723            syntax_errors: 0,
4724            report_diagnostic_errors: false,
4725            prediction_mode: PredictionMode::Ll,
4726            prediction_diagnostics: Vec::new(),
4727            reported_prediction_diagnostics: BTreeSet::new(),
4728            generated_parser_diagnostics: Vec::new(),
4729            generated_sync_expected: None,
4730            generated_recovery_error_index: None,
4731            generated_recovery_error_states: BTreeSet::new(),
4732            int_members: BTreeMap::new(),
4733            rule_context_stack: Vec::new(),
4734            rule_context_version: 0,
4735            left_recursive_caller_overlap_cache: std::array::from_fn(|_| None),
4736            pending_invoking_states: Vec::new(),
4737            precedence_stack: vec![0],
4738            invoked_predicates: Vec::new(),
4739            bail_on_error: false,
4740            unknown_predicate_policy: UnknownSemanticPolicy::default(),
4741            unknown_predicate_hits: Vec::new(),
4742            unhandled_action_hits: Vec::new(),
4743            rule_first_set_cache: Vec::new(),
4744            state_expected_cache: FxHashMap::default(),
4745            state_expected_token_cache: FxHashMap::default(),
4746            rule_stop_reach_cache: Vec::new(),
4747            recovery_symbols_intern: FxHashMap::default(),
4748            decision_lookahead_cache: FxHashMap::default(),
4749            ll1_decision_cache: FxHashMap::default(),
4750            fast_predicate_cache: FxHashMap::default(),
4751            empty_cycle_cache: Vec::new(),
4752            empty_cycle_cache_atn: None,
4753            clean_memo_mode: CleanMemoMode::Probe,
4754            clean_memo_probe_seen: FxHashSet::default(),
4755            clean_memo_probe_samples: 0,
4756            clean_memo_probe_repeats: 0,
4757            clean_memo_sparse_samples: 0,
4758            fast_recognize_scratch: FastRecognizeTopScratch::default(),
4759            fast_outcome_dedup: FastOutcomeDedupScratch::default(),
4760            empty_recovery_symbols: Rc::new(BTreeSet::new()),
4761            fast_first_set_prefilter: true,
4762            fast_recovery_enabled: true,
4763            fast_token_nodes_enabled: true,
4764            recognition_arena: RecognitionArena::default(),
4765            last_recognition_arena_root: NodeSeqId::EMPTY,
4766            last_recognition_arena_diagnostics: DiagnosticSeqId::EMPTY,
4767        }
4768    }
4769
4770    pub const fn input(&mut self) -> &mut CommonTokenStream<S> {
4771        &mut self.input
4772    }
4773
4774    /// Fully resets parser-owned state and rewinds the current token stream.
4775    ///
4776    /// Parser configuration, semantic hooks, learned DFA tables, and
4777    /// grammar-owned member values are retained.
4778    pub fn reset(&mut self) {
4779        self.input.seek(0);
4780        self.tree.reset();
4781        self.data.set_state(-1);
4782        self.syntax_errors = 0;
4783        self.prediction_diagnostics.clear();
4784        self.reported_prediction_diagnostics.clear();
4785        self.generated_parser_diagnostics.clear();
4786        self.generated_sync_expected = None;
4787        self.reset_generated_recovery_state();
4788        self.rule_context_stack.clear();
4789        self.advance_rule_context_version();
4790        self.left_recursive_caller_overlap_cache = std::array::from_fn(|_| None);
4791        self.pending_invoking_states.clear();
4792        self.precedence_stack.clear();
4793        self.precedence_stack.push(0);
4794        self.invoked_predicates.clear();
4795        self.decision_override_generation = 0;
4796        self.unknown_predicate_hits.clear();
4797        self.unhandled_action_hits.clear();
4798        self.reset_per_parse_caches();
4799        self.fast_first_set_prefilter = true;
4800        self.fast_recovery_enabled = true;
4801        self.fast_token_nodes_enabled = self.build_parse_trees;
4802        self.reset_recognition_arena();
4803    }
4804
4805    /// Replaces the buffered token stream and fully resets this parser.
4806    pub fn set_token_stream(&mut self, input: CommonTokenStream<S>) {
4807        self.input = input;
4808        self.reset();
4809    }
4810
4811    /// Installs the policy for predicate coordinates that no translated table
4812    /// entry or user hook resolves.
4813    ///
4814    /// The interpreter fallback sets this per parse from [`ParserRuntimeOptions`],
4815    /// but generated recursive-descent rules evaluate predicates directly
4816    /// (`parser_semantic_ir_predicate_matches_with_context_and_local`) without
4817    /// going through those options. Generated parser constructors call this so
4818    /// the generated-direct path honors `--sem-unknown` too, instead of leaving
4819    /// the field at its `AssumeTrue` default and silently accepting an
4820    /// unimplemented hook predicate.
4821    pub const fn set_unknown_predicate_policy(&mut self, policy: UnknownSemanticPolicy) {
4822        self.unknown_predicate_policy = policy;
4823    }
4824
4825    /// Reports any unknown predicate coordinate the generated-direct path
4826    /// recorded under [`UnknownSemanticPolicy::Error`], as an
4827    /// [`AntlrError::Unsupported`]. Generated parser entry points call this
4828    /// after a rule completes so the fail-loud policy surfaces on the
4829    /// generated path the same way the interpreter entry surfaces it.
4830    #[must_use]
4831    pub fn take_unknown_semantic_error(&mut self) -> Option<AntlrError> {
4832        let error = self.unknown_semantic_error();
4833        self.unknown_predicate_hits.clear();
4834        self.unhandled_action_hits.clear();
4835        error
4836    }
4837
4838    /// Drops any fail-loud semantic coordinates recorded by a previous parse.
4839    ///
4840    /// Generated parsers call this at the true top-level entry so a parser
4841    /// reused after a fail-loud (or recovered) parse starts clean, without
4842    /// clearing hits mid-parse where a generated parent still needs a child's
4843    /// recorded coordinate to survive to the top-level boundary.
4844    pub fn reset_unknown_semantic_hits(&mut self) {
4845        self.unknown_predicate_hits.clear();
4846        self.unhandled_action_hits.clear();
4847    }
4848
4849    /// Returns the token stream owned by this parser.
4850    #[must_use]
4851    pub const fn token_stream(&self) -> &CommonTokenStream<S> {
4852        &self.input
4853    }
4854
4855    /// Returns the token stream for source replacement or in-place re-feeding.
4856    #[must_use]
4857    pub const fn token_stream_mut(&mut self) -> &mut CommonTokenStream<S> {
4858        &mut self.input
4859    }
4860
4861    /// Returns the canonical token store referenced by parse trees.
4862    #[must_use]
4863    pub const fn token_store(&self) -> &TokenStore {
4864        self.input.token_store()
4865    }
4866
4867    /// Returns the flat CST storage populated by completed rules.
4868    #[must_use]
4869    pub const fn parse_tree_storage(&self) -> &ParseTreeStorage {
4870        &self.tree
4871    }
4872
4873    /// Resolves a compact parse-tree ID into a borrowing node view.
4874    #[must_use]
4875    pub fn node(&self, id: NodeId) -> Node<'_> {
4876        self.tree
4877            .node(self.input.token_store(), id)
4878            .expect("parser-produced node ID should remain valid")
4879    }
4880
4881    /// Consumes this parser and returns its token stream.
4882    #[must_use]
4883    pub fn into_token_stream(self) -> CommonTokenStream<S> {
4884        self.input
4885    }
4886
4887    /// Consumes this parser and returns its canonical token store.
4888    #[must_use]
4889    pub fn into_token_store(self) -> TokenStore {
4890        self.input.into_token_store()
4891    }
4892
4893    /// Consumes the parser and pairs its token store and flat CST with `root`.
4894    #[must_use]
4895    pub fn into_parsed_file(self, root: NodeId) -> ParsedFile {
4896        ParsedFile::new(self.input.into_token_store(), self.tree, root)
4897    }
4898
4899    /// Returns the number of parser syntax errors recorded by committed parse
4900    /// paths so far.
4901    pub const fn number_of_syntax_errors(&self) -> usize {
4902        self.syntax_errors
4903    }
4904
4905    /// Computes reachability and retained-capacity counters for the most recent
4906    /// interpreted-rule recognition arena.
4907    ///
4908    /// The reachability scan is linear in the arena size and is deferred until
4909    /// this instrumentation method is called.
4910    #[must_use]
4911    pub fn recognition_arena_stats(&self) -> RecognitionArenaStats {
4912        self.recognition_arena.stats(
4913            self.last_recognition_arena_root,
4914            self.last_recognition_arena_diagnostics,
4915        )
4916    }
4917
4918    /// Records a syntax error that generated parser code returns as fatal before
4919    /// it can recover into the current rule context.
4920    pub const fn record_generated_syntax_error(&mut self) {
4921        self.record_syntax_errors(1);
4922    }
4923
4924    const fn record_syntax_errors(&mut self, count: usize) {
4925        self.syntax_errors = self.syntax_errors.saturating_add(count);
4926    }
4927
4928    /// Emits diagnostics buffered by the token stream while generated parser
4929    /// code was fetching lexer tokens directly.
4930    pub fn report_token_source_errors(&mut self) {
4931        let errors = self.input.drain_source_errors();
4932        self.dispatch_token_source_errors(&errors);
4933    }
4934
4935    /// Captures generated-parser diagnostics and syntax-error count before a
4936    /// speculative generated rule path.
4937    pub const fn generated_diagnostics_checkpoint(&self) -> GeneratedDiagnosticsCheckpoint {
4938        GeneratedDiagnosticsCheckpoint {
4939            diagnostics_len: self.generated_parser_diagnostics.len(),
4940            syntax_errors: self.syntax_errors,
4941            tree: self.tree.checkpoint(),
4942        }
4943    }
4944
4945    /// Restores generated-parser diagnostics after a speculative rule path failed.
4946    pub fn restore_generated_diagnostics(&mut self, marker: GeneratedDiagnosticsCheckpoint) {
4947        self.generated_parser_diagnostics
4948            .truncate(marker.diagnostics_len);
4949        self.syntax_errors = marker.syntax_errors;
4950        self.generated_sync_expected = None;
4951        self.tree.rollback(marker.tree);
4952    }
4953
4954    /// Emits diagnostics recorded by committed generated parser recovery.
4955    pub fn report_generated_parser_diagnostics(&mut self) {
4956        let parser_diagnostics = std::mem::take(&mut self.generated_parser_diagnostics);
4957        let token_errors = self.input.drain_source_errors();
4958        self.dispatch_generated_diagnostics(&parser_diagnostics, &token_errors);
4959    }
4960
4961    fn dispatch_parser_diagnostic(&self, diagnostic: &ParserDiagnostic) {
4962        self.notify_error_listeners(
4963            diagnostic.line,
4964            diagnostic.column,
4965            &diagnostic.message,
4966            None,
4967        );
4968    }
4969
4970    fn dispatch_parser_diagnostics<'a>(
4971        &self,
4972        diagnostics: impl IntoIterator<Item = &'a ParserDiagnostic>,
4973    ) {
4974        for diagnostic in diagnostics {
4975            self.dispatch_parser_diagnostic(diagnostic);
4976        }
4977    }
4978
4979    fn dispatch_token_source_error(&self, source_error: &TokenSourceError) {
4980        if self.input.token_source().report_error(source_error) {
4981            return;
4982        }
4983        self.notify_error_listeners(
4984            source_error.line,
4985            source_error.column,
4986            &source_error.message,
4987            None,
4988        );
4989    }
4990
4991    fn dispatch_token_source_errors(&self, errors: &[TokenSourceError]) {
4992        for error in errors {
4993            self.dispatch_token_source_error(error);
4994        }
4995    }
4996
4997    /// Dispatches generated parser and lexer diagnostics in the same
4998    /// source-position order as ANTLR's lazy token stream reports them.
4999    fn dispatch_generated_diagnostics(
5000        &self,
5001        parser_diagnostics: &[ParserDiagnostic],
5002        token_errors: &[TokenSourceError],
5003    ) {
5004        // Parser diagnostics keep their event order: Java's console and
5005        // DiagnosticErrorListener print reports as prediction produces them,
5006        // so reportAttemptingFullContext precedes reportContextSensitivity
5007        // even though the latter's position is earlier. Buffered token-source
5008        // errors interleave by source position and win ties.
5009        let mut token_iter = token_errors.iter().peekable();
5010        for diagnostic in parser_diagnostics {
5011            while let Some(error) = token_iter.peek() {
5012                if (error.line, error.column) <= (diagnostic.line, diagnostic.column) {
5013                    self.dispatch_token_source_error(error);
5014                    token_iter.next();
5015                } else {
5016                    break;
5017                }
5018            }
5019            self.dispatch_parser_diagnostic(diagnostic);
5020        }
5021        for error in token_iter {
5022            self.dispatch_token_source_error(error);
5023        }
5024    }
5025
5026    /// Buffers ANTLR-style ambiguity diagnostics discovered by generated
5027    /// decision code.
5028    pub fn record_generated_ambiguity_diagnostic(
5029        &mut self,
5030        atn: &Atn,
5031        state_number: usize,
5032        start_index: usize,
5033        stop_index: usize,
5034        alts: &[usize],
5035    ) {
5036        if !self.report_diagnostic_errors || alts.len() < 2 {
5037            return;
5038        }
5039        let Some(decision) = atn
5040            .decision_to_state()
5041            .iter()
5042            .position(|candidate| candidate == state_number)
5043        else {
5044            return;
5045        };
5046        let Some(rule_index) = atn.state(state_number).and_then(AtnState::rule_index) else {
5047            return;
5048        };
5049        let rule_name = self
5050            .rule_names()
5051            .get(rule_index)
5052            .map_or_else(|| "<unknown>".to_owned(), Clone::clone);
5053        let input = display_input_text(&self.input.text(start_index, stop_index));
5054        let alts = alts
5055            .iter()
5056            .map(usize::to_string)
5057            .collect::<Vec<_>>()
5058            .join(", ");
5059        let key = (decision, start_index, format!("{alts}:{input}"));
5060        if !self.reported_prediction_diagnostics.insert(key) {
5061            return;
5062        }
5063        let start_diagnostic = diagnostic_for_token(
5064            self.token_at(start_index),
5065            format!("reportAttemptingFullContext d={decision} ({rule_name}), input='{input}'"),
5066        );
5067        let stop_diagnostic = diagnostic_for_token(
5068            self.token_at(stop_index),
5069            format!(
5070                "reportAmbiguity d={decision} ({rule_name}): ambigAlts={{{alts}}}, input='{input}'"
5071            ),
5072        );
5073        self.generated_parser_diagnostics.push(start_diagnostic);
5074        self.generated_parser_diagnostics.push(stop_diagnostic);
5075    }
5076
5077    /// Buffers ANTLR-style diagnostic-listener messages produced by generated
5078    /// parser calls to the adaptive simulator.
5079    pub fn record_generated_prediction_diagnostic(
5080        &mut self,
5081        atn: &Atn,
5082        state_number: usize,
5083        prediction: &ParserAtnPrediction,
5084    ) {
5085        let Some(diagnostic) = &prediction.diagnostic else {
5086            return;
5087        };
5088        if !self.report_diagnostic_errors || diagnostic.conflicting_alts.len() < 2 {
5089            return;
5090        }
5091        let Some(decision) = atn
5092            .decision_to_state()
5093            .iter()
5094            .position(|candidate| candidate == state_number)
5095        else {
5096            return;
5097        };
5098        let Some(rule_index) = atn.state(state_number).and_then(AtnState::rule_index) else {
5099            return;
5100        };
5101        let rule_name = self
5102            .rule_names()
5103            .get(rule_index)
5104            .map_or_else(|| "<unknown>".to_owned(), Clone::clone);
5105        let attempt_input = display_input_text(
5106            &self
5107                .input
5108                .text(diagnostic.start_index, diagnostic.sll_stop_index),
5109        );
5110        let result_input = display_input_text(
5111            &self
5112                .input
5113                .text(diagnostic.start_index, diagnostic.ll_stop_index),
5114        );
5115        let alts = diagnostic
5116            .conflicting_alts
5117            .iter()
5118            .map(usize::to_string)
5119            .collect::<Vec<_>>()
5120            .join(", ");
5121        let key = (
5122            decision,
5123            diagnostic.start_index,
5124            format!(
5125                "{:?}:{alts}:{attempt_input}:{result_input}",
5126                diagnostic.kind
5127            ),
5128        );
5129        if !self.reported_prediction_diagnostics.insert(key) {
5130            return;
5131        }
5132        let attempt_diagnostic = diagnostic_for_token(
5133            self.token_at(diagnostic.sll_stop_index),
5134            format!(
5135                "reportAttemptingFullContext d={decision} ({rule_name}), input='{attempt_input}'"
5136            ),
5137        );
5138        self.generated_parser_diagnostics.push(attempt_diagnostic);
5139        let message = match diagnostic.kind {
5140            ParserAtnPredictionDiagnosticKind::Ambiguity => {
5141                // Java's DiagnosticErrorListener is exactOnly by default:
5142                // non-exact ambiguities (default LL mode stopping at the
5143                // first resolvable conflict) report the attempt above but
5144                // suppress the ambiguity line itself.
5145                if !diagnostic.exact {
5146                    return;
5147                }
5148                format!(
5149                    "reportAmbiguity d={decision} ({rule_name}): ambigAlts={{{alts}}}, input='{result_input}'"
5150                )
5151            }
5152            ParserAtnPredictionDiagnosticKind::ContextSensitivity => {
5153                format!(
5154                    "reportContextSensitivity d={decision} ({rule_name}), input='{result_input}'"
5155                )
5156            }
5157        };
5158        let result_diagnostic =
5159            diagnostic_for_token(self.token_at(diagnostic.ll_stop_index), message);
5160        self.generated_parser_diagnostics.push(result_diagnostic);
5161    }
5162
5163    pub fn la(&self, offset: isize) -> i32 {
5164        self.input.la_token(offset)
5165    }
5166
5167    pub fn consume(&mut self) {
5168        IntStream::consume(&mut self.input);
5169    }
5170
5171    /// Sets a generated integer member value used by target-template tests.
5172    pub fn set_int_member(&mut self, member: usize, value: i64) {
5173        self.int_members.insert(member, value);
5174    }
5175
5176    /// Reads a generated integer member value.
5177    pub fn int_member(&self, member: usize) -> Option<i64> {
5178        self.int_members.get(&member).copied()
5179    }
5180
5181    /// Captures generated integer members before speculative generated parser
5182    /// execution.
5183    pub fn int_members_checkpoint(&self) -> BTreeMap<usize, i64> {
5184        self.int_members.clone()
5185    }
5186
5187    /// Restores generated integer members after generated parser fallback.
5188    pub fn restore_int_members(&mut self, members: BTreeMap<usize, i64>) {
5189        self.int_members = members;
5190    }
5191
5192    /// Adds `delta` to a generated integer member and returns the new value.
5193    pub fn add_int_member(&mut self, member: usize, delta: i64) -> i64 {
5194        let value = self.int_members.entry(member).or_default();
5195        *value += delta;
5196        *value
5197    }
5198
5199    fn token_type_for_id(&self, id: TokenId) -> i32 {
5200        self.input.token_store().token_type(id).unwrap_or(TOKEN_EOF)
5201    }
5202
5203    fn terminal_tree(&mut self, id: TokenId) -> ParseTree {
5204        if self.build_parse_trees {
5205            self.tree.terminal(id)
5206        } else {
5207            NodeId::placeholder()
5208        }
5209    }
5210
5211    fn error_tree(&mut self, id: TokenId) -> ParseTree {
5212        if self.build_parse_trees {
5213            self.tree.error(id)
5214        } else {
5215            NodeId::placeholder()
5216        }
5217    }
5218
5219    const fn set_context_start(&self, context: &mut ParserRuleContext, id: TokenId) {
5220        context.set_start_id(id);
5221    }
5222
5223    const fn set_context_stop(&self, context: &mut ParserRuleContext, id: TokenId) {
5224        context.set_stop_id(id);
5225    }
5226
5227    fn insert_synthetic_token(
5228        &mut self,
5229        token_type: i32,
5230        text: String,
5231        line: usize,
5232        column: usize,
5233    ) -> Result<TokenId, AntlrError> {
5234        self.input
5235            .insert(
5236                TokenSpec::explicit(token_type, text)
5237                    .with_span(usize::MAX, usize::MAX)
5238                    .with_byte_span(0, 0)
5239                    .with_position(line, column),
5240            )
5241            .map_err(|error| AntlrError::Unsupported(error.to_string()))
5242    }
5243
5244    /// Matches and consumes the current token when it has the expected token
5245    /// type.
5246    ///
5247    /// On success the consumed token is wrapped as a terminal parse-tree node.
5248    /// On mismatch the error carries vocabulary display names so diagnostics are
5249    /// stable across literal and symbolic token naming.
5250    pub fn match_token(&mut self, token_type: i32) -> Result<ParseTree, AntlrError> {
5251        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
5252            line: 0,
5253            column: 0,
5254            message: "missing current token".to_owned(),
5255        })?;
5256        let current_type = self.token_type_for_id(current);
5257        if current_type == token_type {
5258            self.reset_generated_recovery_state();
5259            self.consume();
5260            Ok(self.terminal_tree(current))
5261        } else {
5262            Err(AntlrError::MismatchedInput {
5263                expected: self.vocabulary().display_name(token_type),
5264                found: self.vocabulary().display_name(current_type),
5265            })
5266        }
5267    }
5268
5269    /// Matches a token from generated recursive-descent code, including ANTLR's
5270    /// single-token insertion recovery when the active rule context can legally
5271    /// continue at the current input symbol.
5272    pub fn match_token_recovering(
5273        &mut self,
5274        token_type: i32,
5275        follow_state: usize,
5276        atn: &Atn,
5277    ) -> Result<GeneratedMatch, AntlrError> {
5278        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
5279            line: 0,
5280            column: 0,
5281            message: "missing current token".to_owned(),
5282        })?;
5283        let current_type = self.token_type_for_id(current);
5284        if current_type == token_type {
5285            self.generated_sync_expected = None;
5286            self.reset_generated_recovery_state();
5287            let consumed_eof = current_type == TOKEN_EOF;
5288            self.consume();
5289            return Ok(GeneratedMatch {
5290                children: GeneratedMatchChildren::One(self.terminal_tree(current)),
5291                consumed_eof,
5292            });
5293        }
5294        let mut expected_symbols = BTreeSet::new();
5295        expected_symbols.insert(token_type);
5296        self.recover_generated_match(
5297            current,
5298            GeneratedExpectedSymbols::Tree(&expected_symbols),
5299            follow_state,
5300            atn,
5301            |symbol| symbol == token_type,
5302        )
5303    }
5304
5305    pub fn match_set_recovering(
5306        &mut self,
5307        intervals: &[(i32, i32)],
5308        follow_state: usize,
5309        atn: &Atn,
5310    ) -> Result<GeneratedMatch, AntlrError> {
5311        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
5312            line: 0,
5313            column: 0,
5314            message: "missing current token".to_owned(),
5315        })?;
5316        let current_type = self.token_type_for_id(current);
5317        if interval_set_contains(intervals, current_type) {
5318            self.generated_sync_expected = None;
5319            self.reset_generated_recovery_state();
5320            let consumed_eof = current_type == TOKEN_EOF;
5321            self.consume();
5322            return Ok(GeneratedMatch {
5323                children: GeneratedMatchChildren::One(self.terminal_tree(current)),
5324                consumed_eof,
5325            });
5326        }
5327        let expected_symbols = interval_symbols(intervals);
5328        self.recover_generated_match(
5329            current,
5330            GeneratedExpectedSymbols::Tree(&expected_symbols),
5331            follow_state,
5332            atn,
5333            |symbol| interval_set_contains(intervals, symbol),
5334        )
5335    }
5336
5337    pub fn match_token_set_recovering(
5338        &mut self,
5339        set: ParserIntervalSet<'_>,
5340        follow_state: usize,
5341        atn: &Atn,
5342    ) -> Result<GeneratedMatch, AntlrError> {
5343        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
5344            line: 0,
5345            column: 0,
5346            message: "missing current token".to_owned(),
5347        })?;
5348        let current_type = self.token_type_for_id(current);
5349        if set.contains(current_type) {
5350            self.generated_sync_expected = None;
5351            self.reset_generated_recovery_state();
5352            let consumed_eof = current_type == TOKEN_EOF;
5353            self.consume();
5354            return Ok(GeneratedMatch {
5355                children: GeneratedMatchChildren::One(self.terminal_tree(current)),
5356                consumed_eof,
5357            });
5358        }
5359        self.recover_generated_match(
5360            current,
5361            GeneratedExpectedSymbols::TokenSet(set),
5362            follow_state,
5363            atn,
5364            |symbol| set.contains(symbol),
5365        )
5366    }
5367
5368    pub fn match_not_set_recovering(
5369        &mut self,
5370        intervals: &[(i32, i32)],
5371        min_vocabulary: i32,
5372        max_vocabulary: i32,
5373        follow_state: usize,
5374        atn: &Atn,
5375    ) -> Result<GeneratedMatch, AntlrError> {
5376        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
5377            line: 0,
5378            column: 0,
5379            message: "missing current token".to_owned(),
5380        })?;
5381        let current_type = self.token_type_for_id(current);
5382        if (min_vocabulary..=max_vocabulary).contains(&current_type)
5383            && !interval_set_contains(intervals, current_type)
5384        {
5385            self.generated_sync_expected = None;
5386            self.reset_generated_recovery_state();
5387            let consumed_eof = current_type == TOKEN_EOF;
5388            self.consume();
5389            return Ok(GeneratedMatch {
5390                children: GeneratedMatchChildren::One(self.terminal_tree(current)),
5391                consumed_eof,
5392            });
5393        }
5394        let expected_symbols =
5395            interval_complement_symbols(intervals, min_vocabulary, max_vocabulary);
5396        self.recover_generated_match(
5397            current,
5398            GeneratedExpectedSymbols::Tree(&expected_symbols),
5399            follow_state,
5400            atn,
5401            |symbol| {
5402                (min_vocabulary..=max_vocabulary).contains(&symbol)
5403                    && !interval_set_contains(intervals, symbol)
5404            },
5405        )
5406    }
5407
5408    pub fn match_not_token_set_recovering(
5409        &mut self,
5410        set: ParserIntervalSet<'_>,
5411        min_vocabulary: i32,
5412        max_vocabulary: i32,
5413        follow_state: usize,
5414        atn: &Atn,
5415    ) -> Result<GeneratedMatch, AntlrError> {
5416        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
5417            line: 0,
5418            column: 0,
5419            message: "missing current token".to_owned(),
5420        })?;
5421        let current_type = self.token_type_for_id(current);
5422        if (min_vocabulary..=max_vocabulary).contains(&current_type) && !set.contains(current_type)
5423        {
5424            self.generated_sync_expected = None;
5425            self.reset_generated_recovery_state();
5426            let consumed_eof = current_type == TOKEN_EOF;
5427            self.consume();
5428            return Ok(GeneratedMatch {
5429                children: GeneratedMatchChildren::One(self.terminal_tree(current)),
5430                consumed_eof,
5431            });
5432        }
5433        self.recover_generated_match(
5434            current,
5435            GeneratedExpectedSymbols::TokenSetComplement {
5436                set,
5437                min_vocabulary,
5438                max_vocabulary,
5439            },
5440            follow_state,
5441            atn,
5442            |symbol| (min_vocabulary..=max_vocabulary).contains(&symbol) && !set.contains(symbol),
5443        )
5444    }
5445
5446    fn recover_generated_match(
5447        &mut self,
5448        current: TokenId,
5449        expected_symbols: GeneratedExpectedSymbols<'_>,
5450        follow_state: usize,
5451        atn: &Atn,
5452        matches: impl Fn(i32) -> bool,
5453    ) -> Result<GeneratedMatch, AntlrError> {
5454        let expected_display = expected_symbols.display(self.vocabulary());
5455        let (current_type, current_line, current_column, current_display) = {
5456            let token = self
5457                .input
5458                .token_view(current)
5459                .expect("current token ID should be valid");
5460            (
5461                token.token_type(),
5462                token.line(),
5463                token.column(),
5464                token_input_display(&token),
5465            )
5466        };
5467        if self.bail_on_error {
5468            return Err(AntlrError::ParserError {
5469                line: current_line,
5470                column: current_column,
5471                message: format!("mismatched input {current_display} expecting {expected_display}"),
5472            });
5473        }
5474        if current_type != TOKEN_EOF
5475            && let Some(next) = self.input.lt_id(2)
5476            && matches(self.token_type_for_id(next))
5477        {
5478            let message =
5479                format!("extraneous input {current_display} expecting {expected_display}");
5480            self.push_generated_parser_diagnostic(ParserDiagnostic {
5481                line: current_line,
5482                column: current_column,
5483                message,
5484            });
5485            self.record_syntax_errors(1);
5486            self.generated_sync_expected = None;
5487            // Single-token deletion: skip `current`, then accept `next`. The
5488            // accepted token can be EOF only if it is a real EOF terminal.
5489            let consumed_eof = self.token_type_for_id(next) == TOKEN_EOF;
5490            self.consume();
5491            self.consume();
5492            self.reset_generated_recovery_state();
5493            return Ok(GeneratedMatch {
5494                children: GeneratedMatchChildren::Many(vec![
5495                    self.error_tree(current),
5496                    self.terminal_tree(next),
5497                ]),
5498                consumed_eof,
5499            });
5500        }
5501        let follow_symbols = self.generated_recovery_follow_symbols(atn, follow_state);
5502        // ANTLR's `singleTokenInsertion` inserts a missing token when the state
5503        // *after* the current element can consume the current symbol. At EOF that
5504        // only holds when the follow state EXPLICITLY expects EOF (e.g. an `EOF`
5505        // terminal follows in the rule, as in `r: . EOF;` or `r: ID EOF;`), not
5506        // when EOF merely leaks in from the empty enclosing context (as in
5507        // `start: ID+;` on empty input — antlr#6 `InvalidEmptyInput`, which must
5508        // stay a `mismatched input` error). `follow_symbols` mixes both sources,
5509        // so consult the follow state's OWN expected set for the explicit case.
5510        let follow_explicitly_expects_eof = current_type == TOKEN_EOF
5511            && self
5512                .cached_state_expected_symbols(atn, follow_state)
5513                .contains(&TOKEN_EOF);
5514        if follow_symbols.contains(&current_type)
5515            && (current_type != TOKEN_EOF
5516                || self.rule_context_stack.len() > 1
5517                || expected_symbols.is_empty()
5518                || follow_explicitly_expects_eof)
5519        {
5520            let message = format!("missing {expected_display} at {current_display}");
5521            self.push_generated_parser_diagnostic(ParserDiagnostic {
5522                line: current_line,
5523                column: current_column,
5524                message,
5525            });
5526            self.record_syntax_errors(1);
5527            self.generated_sync_expected = None;
5528            let token_type = expected_symbols.first().unwrap_or(TOKEN_EOF);
5529            let missing_display = expected_symbol_display(token_type, self.vocabulary());
5530            let token = self.insert_synthetic_token(
5531                token_type,
5532                format!("<missing {missing_display}>"),
5533                current_line,
5534                current_column,
5535            )?;
5536            // Single-token insertion synthesizes a missing token and consumes
5537            // nothing, so no EOF terminal is consumed even when the lookahead is
5538            // EOF. Reporting consumed_eof=false here is what keeps `finish_rule`
5539            // from recording EOF as the rule stop on this recovery path.
5540            return Ok(GeneratedMatch {
5541                children: GeneratedMatchChildren::One(self.error_tree(token)),
5542                consumed_eof: false,
5543            });
5544        }
5545        let mismatch_expected_display = self
5546            .generated_sync_expected
5547            .take()
5548            .map_or(expected_display, |symbols| {
5549                expected_symbols_display_iter(symbols.symbols(), self.vocabulary())
5550            });
5551        Err(AntlrError::ParserError {
5552            line: current_line,
5553            column: current_column,
5554            message: format!(
5555                "mismatched input {current_display} expecting {mismatch_expected_display}"
5556            ),
5557        })
5558    }
5559
5560    fn generated_recovery_follow_symbols(
5561        &mut self,
5562        atn: &Atn,
5563        follow_state: usize,
5564    ) -> BTreeSet<i32> {
5565        let mut follow = self
5566            .cached_state_expected_symbols(atn, follow_state)
5567            .as_ref()
5568            .clone();
5569        if self.cached_state_can_reach_rule_stop(atn, follow_state) {
5570            follow.extend(self.context_expected_symbols(atn));
5571        }
5572        follow
5573    }
5574
5575    pub fn match_eof(&mut self) -> Result<ParseTree, AntlrError> {
5576        self.match_token(TOKEN_EOF)
5577    }
5578
5579    pub fn match_set(&mut self, intervals: &[(i32, i32)]) -> Result<ParseTree, AntlrError> {
5580        self.match_interval_condition(intervals, |symbol| interval_set_contains(intervals, symbol))
5581    }
5582
5583    pub fn match_not_set(
5584        &mut self,
5585        intervals: &[(i32, i32)],
5586        min_vocabulary: i32,
5587        max_vocabulary: i32,
5588    ) -> Result<ParseTree, AntlrError> {
5589        self.match_interval_condition(intervals, |symbol| {
5590            (min_vocabulary..=max_vocabulary).contains(&symbol)
5591                && !interval_set_contains(intervals, symbol)
5592        })
5593    }
5594
5595    fn match_interval_condition(
5596        &mut self,
5597        intervals: &[(i32, i32)],
5598        matches: impl FnOnce(i32) -> bool,
5599    ) -> Result<ParseTree, AntlrError> {
5600        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
5601            line: 0,
5602            column: 0,
5603            message: "missing current token".to_owned(),
5604        })?;
5605        let current_type = self.token_type_for_id(current);
5606        if matches(current_type) {
5607            self.reset_generated_recovery_state();
5608            self.consume();
5609            Ok(self.terminal_tree(current))
5610        } else {
5611            Err(AntlrError::MismatchedInput {
5612                expected: self.interval_display(intervals),
5613                found: self.vocabulary().display_name(current_type),
5614            })
5615        }
5616    }
5617
5618    fn interval_display(&self, intervals: &[(i32, i32)]) -> String {
5619        let values = intervals
5620            .iter()
5621            .map(|(start, stop)| {
5622                if start == stop {
5623                    self.vocabulary().display_name(*start)
5624                } else {
5625                    format!(
5626                        "{}..{}",
5627                        self.vocabulary().display_name(*start),
5628                        self.vocabulary().display_name(*stop)
5629                    )
5630                }
5631            })
5632            .collect::<Vec<_>>()
5633            .join(", ");
5634        format!("{{{values}}}")
5635    }
5636
5637    pub fn rule_node(&mut self, context: ParserRuleContext) -> ParseTree {
5638        if self.build_parse_trees {
5639            self.tree.finish_rule(context)
5640        } else {
5641            NodeId::placeholder()
5642        }
5643    }
5644
5645    /// Enters a generated parser rule and returns the context object the
5646    /// generated method should populate.
5647    pub fn enter_rule(&mut self, state: isize, rule_index: usize) -> ParserRuleContext {
5648        self.set_state(state);
5649        let invoking_state = self.pending_invoking_states.pop().unwrap_or(state);
5650        self.rule_context_stack.push(RuleContextFrame {
5651            rule_index,
5652            invoking_state,
5653        });
5654        self.advance_rule_context_version();
5655        let start_index = self.current_visible_index();
5656        let mut context = ParserRuleContext::new(rule_index, invoking_state);
5657        if let Some(token) = self.token_id_at(start_index) {
5658            self.set_context_start(&mut context, token);
5659        }
5660        context
5661    }
5662
5663    /// Records the ATN source state for the next generated rule invocation.
5664    ///
5665    /// ANTLR's full-context prediction reconstructs caller follow states from
5666    /// each active rule context's invoking state. Generated Rust rule methods are
5667    /// plain functions, so the caller supplies that ATN state just before making a
5668    /// rule call; `enter_rule` consumes it when the callee starts.
5669    pub fn push_invoking_state(&mut self, invoking_state: isize) -> usize {
5670        let marker = self.pending_invoking_states.len();
5671        self.pending_invoking_states.push(invoking_state);
5672        marker
5673    }
5674
5675    /// Discards an invoking-state marker if the callee did not consume it.
5676    pub fn discard_invoking_state(&mut self, marker: usize) {
5677        self.pending_invoking_states.truncate(marker);
5678    }
5679
5680    /// Exits the current generated parser rule.
5681    pub fn exit_rule(&mut self) {
5682        self.rule_context_stack.pop();
5683        self.advance_rule_context_version();
5684    }
5685
5686    /// Returns caller follow states for interning in a parser ATN simulator's
5687    /// prediction store. States are yielded outermost to innermost.
5688    pub fn prediction_context_return_states<'a>(
5689        &'a self,
5690        atn: &'a Atn,
5691    ) -> impl DoubleEndedIterator<Item = usize> + 'a {
5692        self.rule_context_stack.iter().skip(1).filter_map(|frame| {
5693            let Ok(state_number) = usize::try_from(frame.invoking_state) else {
5694                return None;
5695            };
5696            let Some(Transition::Rule { follow_state, .. }) = atn
5697                .state(state_number)
5698                .and_then(|state| state.transitions().first())
5699                .map(ParserTransition::data)
5700            else {
5701                return None;
5702            };
5703            Some(follow_state)
5704        })
5705    }
5706
5707    /// Returns a generation that changes whenever the active rule stack changes.
5708    ///
5709    /// A parser ATN simulator uses this to reuse an interned outer prediction
5710    /// context while generated predictions remain in the same rule context.
5711    pub const fn rule_context_version(&self) -> usize {
5712        self.rule_context_version
5713    }
5714
5715    const fn advance_rule_context_version(&mut self) {
5716        self.rule_context_version = self.rule_context_version.wrapping_add(1);
5717    }
5718
5719    /// Adds a generated parser child only when parse-tree construction is
5720    /// enabled. The match is recorded on the context either way (via `add_child`,
5721    /// or `note_matched_child` when trees are off) so generated recovery can tell
5722    /// whether the rule has matched anything yet without depending on `children`.
5723    pub fn add_parse_child(&mut self, context: &mut ParserRuleContext, child: ParseTree) {
5724        if self.build_parse_trees {
5725            self.tree.add_child(context, child);
5726        } else {
5727            context.note_matched_child();
5728        }
5729    }
5730
5731    fn release_tree_scratch_if_idle(&mut self) {
5732        if self.rule_context_stack.is_empty() {
5733            self.tree.release_scratch();
5734        }
5735    }
5736
5737    /// Finishes a generated parser rule and returns its parse-tree node.
5738    pub fn finish_rule(&mut self, mut context: ParserRuleContext, consumed_eof: bool) -> ParseTree {
5739        let stop_index = self.rule_stop_token_index(self.input.index(), consumed_eof);
5740        if let Some(token) = stop_index.and_then(|index| self.token_id_at(index)) {
5741            self.set_context_stop(&mut context, token);
5742        }
5743        let node = self.rule_node(context);
5744        self.exit_rule();
5745        self.release_tree_scratch_if_idle();
5746        node
5747    }
5748
5749    /// Recovers a generated rule catch block after a committed mismatch.
5750    ///
5751    /// ANTLR's generated parsers catch recognition errors inside each rule,
5752    /// report the original error, then consume unexpected tokens until the
5753    /// caller's recovery set can resume. Tokens consumed during recovery become
5754    /// error nodes in the current rule context.
5755    pub fn recover_generated_rule(
5756        &mut self,
5757        context: &mut ParserRuleContext,
5758        atn: &Atn,
5759        error: AntlrError,
5760    ) {
5761        let diagnostic = self.generated_rule_error_diagnostic(error);
5762        self.push_generated_parser_diagnostic(diagnostic);
5763        self.generated_sync_expected = None;
5764        let error_index = self.input.index();
5765        let error_state = self.data.state();
5766        // Match ANTLR's lastErrorIndex/lastErrorStates failsafe: a recovery
5767        // token can also be in the caller's follow set, leaving the cursor
5768        // unchanged and allowing generated outer decisions to revisit the same
5769        // failed state forever.
5770        if self.generated_recovery_error_index == Some(error_index)
5771            && self.generated_recovery_error_states.contains(&error_state)
5772            && self.la(1) != TOKEN_EOF
5773            && let Some(token) = self.input.lt_id(1)
5774        {
5775            self.consume();
5776            let child = self.error_tree(token);
5777            self.add_parse_child(context, child);
5778        }
5779        let recovery_index = self.input.index();
5780        if self.generated_recovery_error_index != Some(recovery_index) {
5781            self.generated_recovery_error_index = Some(recovery_index);
5782            self.generated_recovery_error_states.clear();
5783        }
5784        self.generated_recovery_error_states.insert(error_state);
5785        let recovery_symbols = self.context_expected_symbols(atn);
5786        loop {
5787            let symbol = self.la(1);
5788            if symbol == TOKEN_EOF || recovery_symbols.contains(&symbol) {
5789                break;
5790            }
5791            let Some(token) = self.input.lt_id(1) else {
5792                break;
5793            };
5794            self.consume();
5795            let child = self.error_tree(token);
5796            self.add_parse_child(context, child);
5797        }
5798        self.record_syntax_errors(1);
5799    }
5800
5801    fn reset_generated_recovery_state(&mut self) {
5802        if self.generated_recovery_error_index.is_some() {
5803            self.generated_recovery_error_index = None;
5804            self.generated_recovery_error_states.clear();
5805        }
5806    }
5807
5808    fn push_generated_parser_diagnostic(&mut self, diagnostic: ParserDiagnostic) {
5809        if self
5810            .generated_parser_diagnostics
5811            .iter()
5812            .any(|existing| existing == &diagnostic)
5813        {
5814            return;
5815        }
5816        self.generated_parser_diagnostics.push(diagnostic);
5817    }
5818
5819    fn generated_rule_error_diagnostic(&self, error: AntlrError) -> ParserDiagnostic {
5820        match error {
5821            AntlrError::ParserError {
5822                line,
5823                column,
5824                message,
5825            } => ParserDiagnostic {
5826                line,
5827                column,
5828                message,
5829            },
5830            AntlrError::MismatchedInput { expected, found } => diagnostic_for_token(
5831                self.input.lt(1),
5832                format!("mismatched input {found} expecting {expected}"),
5833            ),
5834            AntlrError::NoViableAlternative { input } => diagnostic_for_token(
5835                self.input.lt(1),
5836                format!("no viable alternative at input {input}"),
5837            ),
5838            AntlrError::LexerError {
5839                line,
5840                column,
5841                message,
5842            } => ParserDiagnostic {
5843                line,
5844                column,
5845                message,
5846            },
5847            AntlrError::Unsupported(message) => diagnostic_for_token(self.input.lt(1), message),
5848        }
5849    }
5850
5851    /// Finishes a generated left-recursive parser rule and returns its parse-tree node.
5852    pub fn finish_recursion_rule(
5853        &mut self,
5854        mut context: ParserRuleContext,
5855        consumed_eof: bool,
5856    ) -> ParseTree {
5857        let stop_index = self.rule_stop_token_index(self.input.index(), consumed_eof);
5858        if let Some(token) = stop_index.and_then(|index| self.token_id_at(index)) {
5859            self.set_context_stop(&mut context, token);
5860        }
5861        let node = self.rule_node(context);
5862        self.unroll_recursion_context();
5863        self.release_tree_scratch_if_idle();
5864        node
5865    }
5866
5867    /// Enters a generated left-recursive rule at `precedence`.
5868    pub fn enter_recursion_rule(
5869        &mut self,
5870        state: isize,
5871        rule_index: usize,
5872        precedence: i32,
5873    ) -> ParserRuleContext {
5874        self.precedence_stack.push(precedence);
5875        self.enter_rule(state, rule_index)
5876    }
5877
5878    /// Replaces the current context while expanding a left-recursive rule.
5879    pub fn push_new_recursion_context(
5880        &mut self,
5881        state: isize,
5882        rule_index: usize,
5883    ) -> ParserRuleContext {
5884        self.set_state(state);
5885        ParserRuleContext::new(rule_index, state)
5886    }
5887
5888    /// Wraps the previous left-recursive context before parsing the next
5889    /// recursive operator alternative.
5890    pub fn push_new_recursion_context_with_previous(
5891        &mut self,
5892        state: isize,
5893        rule_index: usize,
5894        current: &mut ParserRuleContext,
5895    ) {
5896        self.set_state(state);
5897        if let Some(stop) = self
5898            .rule_stop_token_index(self.input.index(), false)
5899            .and_then(|index| self.token_id_at(index))
5900        {
5901            self.set_context_stop(current, stop);
5902        }
5903        let invoking_state = current.invoking_state();
5904        let start = current.start_id();
5905        let mut replacement = ParserRuleContext::new(rule_index, invoking_state);
5906        if start.is_some() {
5907            replacement.set_start_from_context(current);
5908        }
5909        let previous = std::mem::replace(current, replacement);
5910        if self.build_parse_trees {
5911            let previous = self.rule_node(previous);
5912            self.tree.add_child(current, previous);
5913        }
5914    }
5915
5916    /// Leaves a generated left-recursive rule.
5917    pub fn unroll_recursion_context(&mut self) {
5918        if self.precedence_stack.len() > 1 {
5919            self.precedence_stack.pop();
5920        }
5921        self.exit_rule();
5922    }
5923
5924    /// Predicts a generated left-recursive loop from one-token lookahead.
5925    ///
5926    /// `Some(true)` enters the operator alternative, `Some(false)` exits, and
5927    /// `None` means caller overlap, a dangerous multi-token prefix, or an
5928    /// unresolved semantic predicate requires full `StarLoopEntry` adaptive
5929    /// prediction (which includes the exit alt and precedence filtering).
5930    ///
5931    /// Single-token operators and multi-token prefixes that do not shadow a
5932    /// lower-precedence single-token operator keep the one-token enter fast path.
5933    ///
5934    /// Multi-token prefixes that **do** shadow a lower-precedence single-token
5935    /// operator must not force enter; the adaptive decision may need to select
5936    /// the loop exit instead.
5937    pub fn left_recursive_loop_enter_prediction(
5938        &mut self,
5939        atn: &Atn,
5940        state_number: usize,
5941        precedence: i32,
5942    ) -> Option<bool> {
5943        let symbol = self.la(1);
5944        if symbol == TOKEN_EOF {
5945            return Some(false);
5946        }
5947        let operator_lookahead =
5948            Self::cached_left_recursive_operator_lookahead(atn, state_number, precedence);
5949        let can_single = operator_lookahead.single_token.contains(symbol);
5950        let can_multi = operator_lookahead.multi_token_prefix.contains(symbol);
5951        let can_predicate = operator_lookahead.predicate_dependent.contains(symbol);
5952        if !can_single && !can_multi && !can_predicate {
5953            return Some(false);
5954        }
5955        if can_predicate && !can_single {
5956            return None;
5957        }
5958        // Multi-token-only at this precedence, but the same symbol is a
5959        // single-token operator at precedence 0: defer so exit can win when the
5960        // multi-token sequence does not actually match (e.g. `>` vs `>>`).
5961        if !can_single && can_multi && precedence > 0 {
5962            let baseline = Self::cached_left_recursive_operator_lookahead(atn, state_number, 0);
5963            if baseline.single_token.contains(symbol) {
5964                return None;
5965            }
5966        }
5967        let atn_key = SharedAtnCacheKey::for_atn(atn);
5968        let cached_overlap = self
5969            .left_recursive_caller_overlap_cache
5970            .iter()
5971            .flatten()
5972            .find(|entry| {
5973                entry.atn_key == atn_key
5974                    && entry.state_number == state_number
5975                    && entry.symbol == symbol
5976                    && entry.context_version == self.rule_context_version
5977            })
5978            .map(|entry| entry.overlaps);
5979        let caller_overlaps = cached_overlap.unwrap_or_else(|| {
5980            let overlaps = caller_context_can_match_symbol_before_state(
5981                atn,
5982                self.prediction_context_return_states(atn),
5983                state_number,
5984                symbol,
5985            );
5986            if let Some(slot) = self
5987                .left_recursive_caller_overlap_cache
5988                .iter_mut()
5989                .find(|slot| slot.is_none())
5990            {
5991                *slot = Some(LeftRecursiveCallerOverlap {
5992                    atn_key,
5993                    state_number,
5994                    symbol,
5995                    context_version: self.rule_context_version,
5996                    overlaps,
5997                });
5998            }
5999            overlaps
6000        });
6001        if caller_overlaps {
6002            return None;
6003        }
6004        Some(true)
6005    }
6006
6007    fn cached_left_recursive_operator_lookahead(
6008        atn: &Atn,
6009        state_number: usize,
6010        precedence: i32,
6011    ) -> Rc<LeftRecursiveOperatorLookahead> {
6012        with_shared_atn_caches(atn, |cache| {
6013            let key = (state_number, precedence);
6014            if let Some(cached) = cache.left_recursive_operator_lookahead.get(&key) {
6015                return Rc::clone(cached);
6016            }
6017            let lookahead = Rc::new(left_recursive_operator_lookahead(
6018                atn,
6019                state_number,
6020                precedence,
6021            ));
6022            cache
6023                .left_recursive_operator_lookahead
6024                .insert(key, Rc::clone(&lookahead));
6025            lookahead
6026        })
6027    }
6028
6029    /// Checks whether a generated left-recursive loop can unambiguously enter
6030    /// its operator alternative from one-token lookahead.
6031    pub fn left_recursive_loop_enter_matches(
6032        &mut self,
6033        atn: &Atn,
6034        state_number: usize,
6035        precedence: i32,
6036    ) -> bool {
6037        self.left_recursive_loop_enter_prediction(atn, state_number, precedence) == Some(true)
6038    }
6039
6040    /// Implements generated `precpred(_ctx, k)` checks.
6041    pub fn precpred(&self, precedence: i32) -> bool {
6042        precedence >= self.precedence_stack.last().copied().unwrap_or_default()
6043    }
6044
6045    /// Evaluates a generated parser semantic predicate at the current input
6046    /// position.
6047    pub fn parser_semantic_predicate_matches(
6048        &mut self,
6049        predicates: &[(usize, usize, ParserPredicate)],
6050        rule_index: usize,
6051        pred_index: usize,
6052    ) -> bool {
6053        self.parser_semantic_predicate_matches_inner(predicates, rule_index, pred_index, None)
6054    }
6055
6056    /// Evaluates a generated parser semantic predicate with the current integer
6057    /// rule argument exposed as `$_p`/`$i` metadata where applicable.
6058    pub fn parser_semantic_predicate_matches_with_local(
6059        &mut self,
6060        predicates: &[(usize, usize, ParserPredicate)],
6061        rule_index: usize,
6062        pred_index: usize,
6063        local_int_arg: i32,
6064    ) -> bool {
6065        self.parser_semantic_predicate_matches_inner(
6066            predicates,
6067            rule_index,
6068            pred_index,
6069            Some((rule_index, i64::from(local_int_arg))),
6070        )
6071    }
6072
6073    fn parser_semantic_predicate_matches_inner(
6074        &mut self,
6075        predicates: &[(usize, usize, ParserPredicate)],
6076        rule_index: usize,
6077        pred_index: usize,
6078        local_int_arg: Option<(usize, i64)>,
6079    ) -> bool {
6080        let index = self.input.index();
6081        let member_values = self.int_members.clone();
6082        self.parser_predicate_matches(PredicateEval {
6083            index,
6084            rule_index,
6085            pred_index,
6086            predicates,
6087            semantics: None,
6088            context: None,
6089            local_int_arg,
6090            member_values: &member_values,
6091        })
6092    }
6093
6094    /// Evaluates a generated parser semantic predicate with access to the
6095    /// current generated rule context.
6096    pub fn parser_semantic_predicate_matches_with_context_and_local(
6097        &mut self,
6098        predicates: &[(usize, usize, ParserPredicate)],
6099        rule_index: usize,
6100        pred_index: usize,
6101        context: &ParserRuleContext,
6102        local_int_arg: i32,
6103    ) -> bool {
6104        let index = self.input.index();
6105        let member_values = self.int_members.clone();
6106        self.parser_predicate_matches(PredicateEval {
6107            index,
6108            rule_index,
6109            pred_index,
6110            predicates,
6111            semantics: None,
6112            context: Some(context),
6113            local_int_arg: Some((rule_index, i64::from(local_int_arg))),
6114            member_values: &member_values,
6115        })
6116    }
6117
6118    /// Evaluates a generated `SemIR` parser predicate with access to the current
6119    /// generated rule context.
6120    pub fn parser_semantic_ir_predicate_matches_with_context_and_local(
6121        &mut self,
6122        semantics: &ParserSemantics,
6123        rule_index: usize,
6124        pred_index: usize,
6125        context: &ParserRuleContext,
6126        local_int_arg: i32,
6127    ) -> bool {
6128        let index = self.input.index();
6129        let member_values = self.int_members.clone();
6130        self.parser_predicate_matches(PredicateEval {
6131            index,
6132            rule_index,
6133            pred_index,
6134            predicates: &[],
6135            semantics: Some(semantics),
6136            context: Some(context),
6137            local_int_arg: Some((rule_index, i64::from(local_int_arg))),
6138            member_values: &member_values,
6139        })
6140    }
6141
6142    /// Returns a generated fail-option message for a parser semantic
6143    /// predicate coordinate.
6144    pub fn parser_semantic_predicate_failure_message(
6145        &self,
6146        rule_index: usize,
6147        pred_index: usize,
6148        predicates: &[(usize, usize, ParserPredicate)],
6149    ) -> Option<&'static str> {
6150        self.parser_predicate_failure_message(rule_index, pred_index, predicates)
6151    }
6152
6153    /// Matches any non-EOF token.
6154    pub fn match_wildcard(&mut self) -> Result<ParseTree, AntlrError> {
6155        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
6156            line: 0,
6157            column: 0,
6158            message: "missing current token".to_owned(),
6159        })?;
6160        if self.token_type_for_id(current) == TOKEN_EOF {
6161            return Err(AntlrError::MismatchedInput {
6162                expected: "wildcard".to_owned(),
6163                found: self.vocabulary().display_name(TOKEN_EOF),
6164            });
6165        }
6166        self.reset_generated_recovery_state();
6167        self.consume();
6168        Ok(self.terminal_tree(current))
6169    }
6170
6171    /// Generated parser synchronization hook. The current interpreter owns
6172    /// recovery; direct generated methods can call this as a no-op until the
6173    /// generated recovery strategy is expanded.
6174    #[allow(clippy::unnecessary_wraps)]
6175    pub fn sync(&mut self, state: isize) -> Result<(), AntlrError> {
6176        self.set_state(state);
6177        Ok(())
6178    }
6179
6180    /// Synchronizes a generated parser decision against the ATN lookahead set.
6181    ///
6182    /// ANTLR generated parsers call the error strategy before optional and loop
6183    /// decisions. When the current token cannot start any alternative, follow a
6184    /// nullable exit, or be deleted before a later synchronization token, the
6185    /// generated Rust method reports that decision-level mismatch instead of
6186    /// descending into a child rule that cannot start at the current token.
6187    pub fn sync_decision(
6188        &mut self,
6189        atn: &Atn,
6190        state_number: usize,
6191        current_context_empty: bool,
6192        loop_back: bool,
6193    ) -> Result<Vec<ParseTree>, AntlrError> {
6194        self.set_state(isize::try_from(state_number).unwrap_or(isize::MAX));
6195        self.generated_sync_expected = None;
6196        let Some(state) = atn.state(state_number) else {
6197            return Ok(Vec::new());
6198        };
6199        let Some(rule_index) = state.rule_index() else {
6200            return Ok(Vec::new());
6201        };
6202        let Some(rule_stop) = atn.rule_to_stop_state().get(rule_index) else {
6203            return Ok(Vec::new());
6204        };
6205        let entry = self.cached_decision_lookahead(atn, state, rule_stop);
6206        let symbol = self.la(1);
6207        let mut has_expected_symbols = false;
6208        let mut nullable = false;
6209        // Whether EOF is an EXPLICIT expected token of this decision (a real `EOF`
6210        // reference in the grammar, e.g. `A* EOF`), as opposed to merely the
6211        // implicit rule-follow that a nullable exit inherits (e.g. a start rule's
6212        // end). Only an explicit EOF makes a token-before-EOF genuinely extraneous
6213        // and worth deleting; an implicit-follow EOF means the loop should simply
6214        // exit and leave the token for the (absent) caller — matching ANTLR, which
6215        // exits the loop via prediction rather than consuming up to a synthetic EOF.
6216        let mut explicit_eof_expected = false;
6217        for transition in &entry.transitions {
6218            if transition.symbols.contains(symbol) {
6219                return Ok(Vec::new());
6220            }
6221            has_expected_symbols |= !transition.symbols.is_empty();
6222            nullable |= transition.nullable;
6223            explicit_eof_expected |= transition.symbols.contains(TOKEN_EOF);
6224        }
6225        // Happy path: a nullable decision exits when the symbol is in the
6226        // rule-stack follow set. Answer the membership question with an
6227        // early-exit walk; the full union below is only needed for the
6228        // mismatch/deletion diagnostics.
6229        if nullable && self.context_expected_contains(atn, symbol) {
6230            return Ok(Vec::new());
6231        }
6232        let context_expected = nullable.then(|| self.context_expected_token_set(atn));
6233        if !has_expected_symbols && context_expected.as_ref().is_none_or(TokenBitSet::is_empty) {
6234            return Ok(Vec::new());
6235        }
6236        let mut expected = TokenBitSet::default();
6237        for transition in &entry.transitions {
6238            expected.extend_from(&transition.symbols);
6239        }
6240        if let Some(context_expected) = context_expected {
6241            expected.extend_from(&context_expected);
6242        }
6243        let can_delete_in_place =
6244            !(nullable && current_context_empty && self.rule_context_stack.len() > 1);
6245        // ANTLR's `DefaultErrorStrategy.sync` recovers differently by decision kind:
6246        // a loop-BACK sync (STAR_LOOP_BACK / PLUS_LOOP_BACK — reached only after at
6247        // least one iteration) does `consumeUntil` the follow set — multi-token
6248        // deletion, one error per skipped token across iterations; a loop ENTRY
6249        // (STAR_LOOP_ENTRY) and a plain optional/block entry (BLOCK_START /
6250        // *-block / +-block starts) do `singleTokenDeletion` — delete the one
6251        // unexpected token only when LA(2) is expected, otherwise report a mismatch
6252        // and leave recovery to the rule.
6253        //
6254        // The generated loop always presents the loop-ENTRY state to this method on
6255        // every pass, so `state.kind()` cannot distinguish entry from back; the caller
6256        // passes `loop_back` (false on a `*` loop's first sync / on a block, true once
6257        // an iteration has been taken, and true on a `+` loop's first sync since its
6258        // mandatory first element is iteration 1). Treating a loop entry as a
6259        // loop-back would over-consume (e.g. `s: A* EOF;` on `c c` would delete both
6260        // `c`s, which ANTLR rejects with `mismatched input`).
6261        let loop_sync = loop_back;
6262        if symbol != TOKEN_EOF && can_delete_in_place {
6263            let mut cursor = self.input.index();
6264            let mut skipped = Vec::new();
6265            loop {
6266                let current = self.token_type_at(cursor);
6267                if current == TOKEN_EOF {
6268                    break;
6269                }
6270                skipped.push(cursor);
6271                let next = self.consume_index(cursor, current);
6272                if next == cursor {
6273                    break;
6274                }
6275                let next_symbol = self.token_type_at(next);
6276                // Stop (and delete the skipped tokens as error nodes) when the next
6277                // token is a real expected continuation. EOF counts only when it is
6278                // an EXPLICIT grammar token (`A* EOF`): then the deleted tokens are
6279                // genuinely extraneous and the generated EOF match consumes the real
6280                // EOF afterwards. An implicit-follow EOF (a nullable exit's inherited
6281                // rule-follow) does NOT count — the loop must exit and leave the
6282                // token, as ANTLR does, instead of deleting up to a synthetic EOF.
6283                let next_is_expected_stop = if next_symbol == TOKEN_EOF {
6284                    explicit_eof_expected
6285                } else {
6286                    expected.contains(next_symbol)
6287                };
6288                if next_is_expected_stop {
6289                    let current_token = self.input.lt(1);
6290                    let expected_symbols = expected.to_btree_set();
6291                    let message = format!(
6292                        "extraneous input {} expecting {}",
6293                        current_token
6294                            .as_ref()
6295                            .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
6296                        self.expected_symbols_display(&expected_symbols)
6297                    );
6298                    self.push_generated_parser_diagnostic(diagnostic_for_token(
6299                        current_token,
6300                        message,
6301                    ));
6302                    self.record_syntax_errors(1);
6303                    let mut children = Vec::with_capacity(skipped.len());
6304                    for index in skipped {
6305                        if let Some(token) = self.token_id_at(index) {
6306                            self.consume();
6307                            children.push(self.error_tree(token));
6308                        }
6309                    }
6310                    if !loop_sync {
6311                        self.reset_generated_recovery_state();
6312                    }
6313                    return Ok(children);
6314                }
6315                // A non-loop block entry deletes at most one token (single-token
6316                // deletion): if LA(2) is not expected, stop scanning so the mismatch
6317                // is reported at the first token instead of skipping ahead.
6318                if !loop_sync {
6319                    break;
6320                }
6321                cursor = next;
6322            }
6323        }
6324        if nullable {
6325            self.generated_sync_expected = Some(expected);
6326            return Ok(Vec::new());
6327        }
6328        let current = self.input.lt(1);
6329        let expected_symbols = expected.to_btree_set();
6330        Err(AntlrError::ParserError {
6331            line: current.as_ref().map(Token::line).unwrap_or_default(),
6332            column: current.as_ref().map(Token::column).unwrap_or_default(),
6333            message: format!(
6334                "mismatched input {} expecting {}",
6335                current
6336                    .as_ref()
6337                    .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
6338                self.expected_symbols_display(&expected_symbols)
6339            ),
6340        })
6341    }
6342
6343    /// Returns a generated-parser prediction when one token of lookahead
6344    /// uniquely selects an alternative for `state_number`.
6345    ///
6346    /// This mirrors the interpreter's LL(1) commit point and lets generated
6347    /// recursive-descent methods avoid invoking the adaptive simulator for
6348    /// simple optional/block/loop decisions.
6349    pub fn ll1_decision_prediction(
6350        &mut self,
6351        atn: &Atn,
6352        state_number: usize,
6353    ) -> Option<ParserAtnPrediction> {
6354        let state = atn.state(state_number)?;
6355        if state.precedence_rule_decision() {
6356            return None;
6357        }
6358        let rule_stop = state
6359            .rule_index()
6360            .and_then(|rule_index| atn.rule_to_stop_state().get(rule_index))?;
6361        let symbol = self.la(1);
6362        let entry = self.cached_decision_lookahead(atn, state, rule_stop);
6363        ll1_greedy_alt(&entry, symbol, state.non_greedy()).map(|alt| ParserAtnPrediction {
6364            alt: alt + 1,
6365            requires_full_context: false,
6366            has_semantic_context: false,
6367            diagnostic: None,
6368        })
6369    }
6370
6371    fn context_expected_symbols(&mut self, atn: &Atn) -> BTreeSet<i32> {
6372        let mut expected = BTreeSet::new();
6373        for index in (1..self.rule_context_stack.len()).rev() {
6374            let invoking_state = self.rule_context_stack[index].invoking_state;
6375            let Ok(state_number) = usize::try_from(invoking_state) else {
6376                continue;
6377            };
6378            let Some(Transition::Rule { follow_state, .. }) = atn
6379                .state(state_number)
6380                .and_then(|state| state.transitions().first())
6381                .map(ParserTransition::data)
6382            else {
6383                continue;
6384            };
6385            let return_state = follow_state;
6386            expected.extend(self.cached_state_expected_symbols(atn, return_state).iter());
6387            if !self.cached_state_can_reach_rule_stop(atn, return_state) {
6388                return expected;
6389            }
6390        }
6391        expected.insert(TOKEN_EOF);
6392        expected
6393    }
6394
6395    fn context_expected_token_set(&mut self, atn: &Atn) -> TokenBitSet {
6396        let mut expected = TokenBitSet::default();
6397        for index in (1..self.rule_context_stack.len()).rev() {
6398            let invoking_state = self.rule_context_stack[index].invoking_state;
6399            let Ok(state_number) = usize::try_from(invoking_state) else {
6400                continue;
6401            };
6402            let Some(Transition::Rule { follow_state, .. }) = atn
6403                .state(state_number)
6404                .and_then(|state| state.transitions().first())
6405                .map(ParserTransition::data)
6406            else {
6407                continue;
6408            };
6409            expected.extend_from(&self.cached_state_expected_token_set(atn, follow_state));
6410            if !self.cached_state_can_reach_rule_stop(atn, follow_state) {
6411                return expected;
6412            }
6413        }
6414        expected.insert(TOKEN_EOF);
6415        expected
6416    }
6417
6418    /// Reports whether `symbol` is in `context_expected_token_set(atn)`
6419    /// without materializing the union.
6420    ///
6421    /// This walks the rule-invocation stack directly, innermost frame first —
6422    /// the same frames, in the same order, with the same rule-stop gating as
6423    /// the same outer-context return-state chain used by adaptive prediction.
6424    /// The nullable
6425    /// exit in `sync_decision` asks only this membership question, and on
6426    /// valid input the innermost frame answers it, so the early exit replaces
6427    /// an O(stack-depth) set union per loop/optional exit with one probe.
6428    fn context_expected_contains(&mut self, atn: &Atn, symbol: i32) -> bool {
6429        for index in (1..self.rule_context_stack.len()).rev() {
6430            let invoking_state = self.rule_context_stack[index].invoking_state;
6431            let Ok(state_number) = usize::try_from(invoking_state) else {
6432                continue;
6433            };
6434            let Some(Transition::Rule { follow_state, .. }) = atn
6435                .state(state_number)
6436                .and_then(|state| state.transitions().first())
6437                .map(ParserTransition::data)
6438            else {
6439                continue;
6440            };
6441            if self
6442                .cached_state_expected_token_set(atn, follow_state)
6443                .contains(symbol)
6444            {
6445                return true;
6446            }
6447            if !self.cached_state_can_reach_rule_stop(atn, follow_state) {
6448                return false;
6449            }
6450        }
6451        symbol == TOKEN_EOF
6452    }
6453
6454    /// Builds a generated no-viable-alternative parser error.
6455    pub fn no_viable_alternative_error(&self, start_index: usize) -> AntlrError {
6456        let error_index = self.input.index();
6457        self.no_viable_alternative_error_at(start_index, error_index)
6458    }
6459
6460    /// Builds a generated no-viable-alternative parser error at the simulator's
6461    /// failing lookahead index. `adaptive_predict` restores the input cursor
6462    /// before returning, so generated parsers have to pass the recorded index
6463    /// explicitly to preserve ANTLR's LL(k) diagnostic span.
6464    pub fn no_viable_alternative_error_at(
6465        &self,
6466        start_index: usize,
6467        error_index: usize,
6468    ) -> AntlrError {
6469        let diagnostic = self.no_viable_alternative(start_index, error_index);
6470        AntlrError::ParserError {
6471            line: diagnostic.line,
6472            column: diagnostic.column,
6473            message: diagnostic.message,
6474        }
6475    }
6476
6477    /// Builds a generated failed-predicate parser error.
6478    pub fn failed_predicate_error(&self, message: impl Into<String>) -> AntlrError {
6479        let current = self.input.lt(1);
6480        AntlrError::ParserError {
6481            line: current.as_ref().map(Token::line).unwrap_or_default(),
6482            column: current.as_ref().map(Token::column).unwrap_or_default(),
6483            message: format!("rule failed predicate: {}", message.into()),
6484        }
6485    }
6486
6487    /// Builds a generated parser error for a semantic predicate with ANTLR's
6488    /// `<fail='...'>` option.
6489    pub fn failed_predicate_option_error(
6490        &self,
6491        rule_index: usize,
6492        message: impl Into<String>,
6493    ) -> AntlrError {
6494        let current = self.input.lt(1);
6495        let rule_name = self
6496            .rule_names()
6497            .get(rule_index)
6498            .map_or_else(|| rule_index.to_string(), Clone::clone);
6499        AntlrError::ParserError {
6500            line: current.as_ref().map(Token::line).unwrap_or_default(),
6501            column: current.as_ref().map(Token::column).unwrap_or_default(),
6502            message: format!("rule {rule_name} {}", message.into()),
6503        }
6504    }
6505
6506    /// Builds a generated parser-action event at the current input position.
6507    pub fn parser_action_at_current(
6508        &mut self,
6509        source_state: usize,
6510        rule_index: usize,
6511        start_index: usize,
6512        consumed_eof: bool,
6513    ) -> ParserAction {
6514        let stop_index = self.rule_stop_token_index(self.input.index(), consumed_eof);
6515        ParserAction::new(source_state, rule_index, start_index, stop_index)
6516    }
6517
6518    /// Offers a committed parser action event to the user semantic hook.
6519    ///
6520    /// Generated parsers call this for action source states that were present
6521    /// in the ATN but not translated into a built-in Rust action template.
6522    pub fn parser_action_hook(&mut self, action: ParserAction, tree: ParseTree) -> bool {
6523        let rule_index = action.rule_index();
6524        let rule_name = self.rule_names().get(rule_index).cloned();
6525        let context = None;
6526        let input = &mut self.input;
6527        let semantic_hooks = &mut self.semantic_hooks;
6528        let member_values = &self.int_members;
6529        let mut ctx = ParserSemCtx {
6530            input,
6531            tree_storage: &self.tree,
6532            rule_index,
6533            coordinate_index: usize::MAX,
6534            rule_name,
6535            context,
6536            tree: Some(tree),
6537            local_int_arg: None,
6538            member_values,
6539            action: Some(action),
6540        };
6541        let handled = semantic_hooks.action(&mut ctx, action);
6542        // This action reached the hook because it had no translated arm. If no
6543        // hook handled it either (`SemanticHooks::action` returns `false`), the
6544        // committed action is silently dropped — record it so the parse entry
6545        // can fail loud under the fail-loud boundary, mirroring unknown
6546        // predicates. `assume-*` policies opt out of the fail-loud recording.
6547        if !handled && matches!(self.unknown_predicate_policy, UnknownSemanticPolicy::Error) {
6548            let coordinate = (rule_index, action.source_state());
6549            if !self.unhandled_action_hits.contains(&coordinate) {
6550                self.unhandled_action_hits.push(coordinate);
6551            }
6552        }
6553        handled
6554    }
6555
6556    /// Attempts to execute a whole generated rule by committing simulator
6557    /// decisions directly. Unsupported constructs or decisions that need
6558    /// full-context / predicate evaluation restore the input cursor and fall
6559    /// back to [`Self::parse_atn_rule`].
6560    pub fn parse_atn_rule_adaptive_or_fallback<'atn>(
6561        &mut self,
6562        atn: &'atn Atn,
6563        simulator: &mut ParserAtnSimulator<'atn>,
6564        rule_index: usize,
6565    ) -> Result<ParseTree, AntlrError> {
6566        let start_index = self.current_visible_index();
6567        self.clear_prediction_diagnostics();
6568        self.reset_per_parse_caches();
6569        self.reset_recognition_arena();
6570        let tree_checkpoint = self.tree.checkpoint();
6571        let mut decision_by_state = vec![None; atn.states().len()];
6572        for (decision, state_number) in atn.decision_to_state().iter().enumerate() {
6573            if let Some(slot) = decision_by_state.get_mut(state_number) {
6574                *slot = Some(decision);
6575            }
6576        }
6577
6578        let result = DirectAdaptiveParser {
6579            parser: self,
6580            atn,
6581            simulator,
6582            decision_by_state,
6583            steps: 0,
6584        }
6585        .parse_rule(rule_index, -1, 0);
6586
6587        match result {
6588            Ok(tree) => {
6589                self.report_token_source_errors();
6590                self.release_tree_scratch_if_idle();
6591                Ok(tree)
6592            }
6593            Err(DirectAdaptiveParseControl::Fallback(reason)) => {
6594                let _ = reason;
6595                self.tree.rollback(tree_checkpoint);
6596                self.input.seek(start_index);
6597                self.parse_atn_rule(atn, rule_index)
6598            }
6599        }
6600    }
6601
6602    /// Parses a generated rule by interpreting the parser ATN from the rule's
6603    /// start state to its stop state.
6604    ///
6605    /// The recognizer backtracks across alternatives and loop exits using token
6606    /// stream indices instead of committing to input consumption immediately.
6607    /// Once a viable ATN path is found, the parser commits the accepted token
6608    /// interval and returns a rule node whose children mirror every grammar
6609    /// rule invocation reached on that path, matching ANTLR's parse-tree
6610    /// shape.
6611    pub fn parse_atn_rule(
6612        &mut self,
6613        atn: &Atn,
6614        rule_index: usize,
6615    ) -> Result<ParseTree, AntlrError> {
6616        self.parse_atn_rule_with_precedence(atn, rule_index, 0)
6617    }
6618
6619    /// Parses a generated rule by interpreting the parser ATN with an initial
6620    /// left-recursive precedence threshold.
6621    pub fn parse_atn_rule_with_precedence(
6622        &mut self,
6623        atn: &Atn,
6624        rule_index: usize,
6625        precedence: i32,
6626    ) -> Result<ParseTree, AntlrError> {
6627        self.parse_atn_rule_with_precedence_inner(atn, rule_index, precedence, None)
6628    }
6629
6630    fn parse_atn_rule_with_precedence_inner(
6631        &mut self,
6632        atn: &Atn,
6633        rule_index: usize,
6634        precedence: i32,
6635        predicate_context: Option<FastPredicateContext<'_>>,
6636    ) -> Result<ParseTree, AntlrError> {
6637        let start_state = atn.rule_to_start_state().get(rule_index).ok_or_else(|| {
6638            AntlrError::Unsupported(format!("rule {rule_index} has no start state"))
6639        })?;
6640        let stop_state = atn
6641            .rule_to_stop_state()
6642            .get(rule_index)
6643            .filter(|state| *state != usize::MAX)
6644            .ok_or_else(|| {
6645                AntlrError::Unsupported(format!("rule {rule_index} has no stop state"))
6646            })?;
6647
6648        let start_index = self.current_visible_index();
6649        self.clear_prediction_diagnostics();
6650        self.reset_per_parse_caches();
6651        self.reset_recognition_arena();
6652        let caller_follow_state = self.pending_invoking_follow_state(atn);
6653        self.fast_recovery_enabled = false;
6654        self.fast_token_nodes_enabled = false;
6655        let top_request = FastRecognizeTopRequest {
6656            start_state,
6657            stop_state,
6658            start_index,
6659            precedence,
6660            caller_follow_state,
6661        };
6662        let first_pass = self.fast_recognize_top(atn, top_request, predicate_context);
6663        self.fast_token_nodes_enabled = self.build_parse_trees;
6664        let needs_tree_retry = matches!(
6665            &first_pass,
6666            Ok((outcome, _))
6667                if self.build_parse_trees
6668                    && self
6669                        .recognition_arena
6670                        .sequence_has_left_recursive_boundary(outcome.nodes)
6671        );
6672        let needs_retry = match &first_pass {
6673            // The FIRST-set prefilter trims speculative rule calls that can't
6674            // match the current lookahead — useful for perf on grammars with
6675            // many epsilon-reachable rules, but the trim also bypasses
6676            // single-token insertion / deletion recovery that ANTLR's
6677            // reference parser runs at the child rule's first consuming
6678            // transition. Retry without the prefilter whenever the first pass
6679            // either produced no outcome at all or produced a recovered
6680            // outcome (diagnostics non-empty), since the second pass might
6681            // surface a child-level recovery with cleaner diagnostics or
6682            // closer parity to ANTLR's tree shape. Left-recursive tree
6683            // boundaries also need the token-node pass; otherwise the fold has
6684            // no concrete left operand to wrap into ANTLR's recursive context.
6685            Err(_) => true,
6686            Ok((outcome, _)) => !outcome.diagnostics.is_empty() || needs_tree_retry,
6687        };
6688        let (outcome, _expected) = if needs_retry {
6689            self.fast_first_set_prefilter = false;
6690            self.fast_recovery_enabled = false;
6691            let clean_retry = self.fast_recognize_top(atn, top_request, predicate_context);
6692            let clean_selected = if needs_tree_retry {
6693                match clean_retry {
6694                    ok @ Ok(_) => ok,
6695                    Err(_) => first_pass,
6696                }
6697            } else {
6698                select_better_top_outcome(first_pass, clean_retry, &self.recognition_arena)
6699            };
6700            let selected = if clean_selected.is_err()
6701                || matches!(&clean_selected, Ok((outcome, _)) if !outcome.diagnostics.is_empty())
6702            {
6703                self.fast_recovery_enabled = true;
6704                let recovery_retry = self.fast_recognize_top(atn, top_request, predicate_context);
6705                select_better_top_outcome(clean_selected, recovery_retry, &self.recognition_arena)
6706            } else {
6707                clean_selected
6708            };
6709            self.fast_first_set_prefilter = true;
6710            self.fast_recovery_enabled = true;
6711            selected.map_err(|expected| {
6712                if predicate_context.is_some()
6713                    && let Some(error) = self.unknown_semantic_error()
6714                {
6715                    self.report_token_source_errors();
6716                    return error;
6717                }
6718                let error = self.recognition_error(rule_index, start_index, &expected);
6719                self.record_syntax_errors(1);
6720                self.report_token_source_errors();
6721                error
6722            })?
6723        } else {
6724            first_pass.expect("first_pass is Ok in the no-retry branch")
6725        };
6726        if predicate_context.is_some()
6727            && let Some(error) = self.unknown_semantic_error()
6728        {
6729            self.report_token_source_errors();
6730            return Err(error);
6731        }
6732        self.record_syntax_errors(self.recognition_arena.diagnostics_len(outcome.diagnostics));
6733        self.dispatch_parser_diagnostics(&self.prediction_diagnostics);
6734        self.dispatch_parser_diagnostics(self.recognition_arena.diagnostics(outcome.diagnostics));
6735        self.report_token_source_errors();
6736        let mut context = ParserRuleContext::with_child_capacity(
6737            rule_index,
6738            self.state(),
6739            if self.build_parse_trees {
6740                self.recognition_arena.sequence_len(outcome.nodes)
6741            } else {
6742                0
6743            },
6744        );
6745        if let Some(token) = self.token_id_at(start_index) {
6746            self.set_context_start(&mut context, token);
6747        }
6748        let stop_index = self.rule_stop_token_index(outcome.index, outcome.consumed_eof);
6749        if let Some(token) = stop_index.and_then(|token_index| self.token_id_at(token_index)) {
6750            self.set_context_stop(&mut context, token);
6751        }
6752        let live_root = if self.build_parse_trees {
6753            self.recognition_arena
6754                .fold_left_recursive_boundaries(outcome.nodes)
6755        } else {
6756            outcome.nodes
6757        };
6758        if self.build_parse_trees {
6759            if self
6760                .recognition_arena
6761                .sequence_has_explicit_token(live_root)
6762            {
6763                let mut cursor = live_root;
6764                while let Some(link) = self.recognition_arena.link(cursor) {
6765                    let child = self.arena_recognized_node_tree(link.head, false, false)?;
6766                    self.tree.add_child(&mut context, child);
6767                    cursor = link.tail;
6768                }
6769            } else {
6770                self.add_arena_implicit_token_children(
6771                    &mut context,
6772                    start_index,
6773                    stop_index,
6774                    live_root,
6775                )?;
6776            }
6777        }
6778        self.finish_recognition_arena(live_root, outcome.diagnostics);
6779        self.input.seek(outcome.index);
6780
6781        let tree = self.rule_node(context);
6782        self.release_tree_scratch_if_idle();
6783        Ok(tree)
6784    }
6785
6786    fn pending_invoking_follow_state(&self, atn: &Atn) -> Option<usize> {
6787        let invoking_state = self.pending_invoking_states.last().copied()?;
6788        let state_number = usize::try_from(invoking_state).ok()?;
6789        match atn.state(state_number)?.transitions().first()?.data() {
6790            Transition::Rule { follow_state, .. } => Some(follow_state),
6791            _ => None,
6792        }
6793    }
6794
6795    #[cfg(test)]
6796    fn caller_follow_token_info(&mut self, index: usize) -> (i32, bool, bool) {
6797        caller_follow_token_info_for_stream(&mut self.input, index)
6798    }
6799
6800    /// Runs the fast recognizer once from the rule's start state and returns
6801    /// the best outcome or the per-attempt expected-token accumulator. The
6802    /// caller flips `fast_first_set_prefilter` between calls when a retry is
6803    /// needed, so the FIRST-set cache is left intact across both passes.
6804    fn fast_recognize_top(
6805        &mut self,
6806        atn: &Atn,
6807        request: FastRecognizeTopRequest,
6808        predicate_context: Option<FastPredicateContext<'_>>,
6809    ) -> Result<(FastRecognizeOutcome, ExpectedTokens), ExpectedTokens> {
6810        let FastRecognizeTopRequest {
6811            start_state,
6812            stop_state,
6813            start_index,
6814            precedence,
6815            caller_follow_state,
6816        } = request;
6817        // `input.size()` is intentionally only the currently buffered token
6818        // count here. Do not restore an up-front fill just to size this map:
6819        // a small floor avoids tiny-input churn, and larger inputs reserve from
6820        // the buffered token count without forcing startup tokenization. The
6821        // 8x multiplier matches the empirical
6822        // memo-insert / token ratio on heavy grammars (C# averages ~6× and
6823        // Kotlin ~12× memo entries per token), so the table avoids one
6824        // rehash on the typical hot path.
6825        let memo_capacity = fast_recognize_memo_capacity(self.input.size());
6826        let mut recognize_scratch = std::mem::take(&mut self.fast_recognize_scratch);
6827        recognize_scratch.prepare(memo_capacity);
6828        let mut expected = ExpectedTokens::default();
6829        let empty_recovery = self.empty_recovery_symbols();
6830        let outcomes = self.recognize_state_fast(
6831            atn,
6832            FastRecognizeRequest {
6833                state_number: start_state,
6834                stop_state,
6835                index: start_index,
6836                rule_start_index: start_index,
6837                decision_start_index: None,
6838                precedence,
6839                depth: 0,
6840                recovery_symbols: empty_recovery,
6841                recovery_state: None,
6842            },
6843            FastRecognizeScratch {
6844                predicate_context,
6845                visiting: &mut recognize_scratch.visiting,
6846                memo: &mut recognize_scratch.memo,
6847                expected: &mut expected,
6848                native_depth: 0,
6849            },
6850        );
6851        recognize_scratch.release_oversized_memo();
6852        self.fast_recognize_scratch = recognize_scratch;
6853        #[cfg(feature = "perf-counters")]
6854        if std::env::var("ANTLR_PERF_DUMP").is_ok() {
6855            perf_counters::dump();
6856            perf_counters::reset();
6857        }
6858        let caller_follow =
6859            caller_follow_state.map(|state| self.cached_state_expected_token_set(atn, state));
6860        let selected = {
6861            let arena = &self.recognition_arena;
6862            let input = &mut self.input;
6863            select_best_fast_outcome(
6864                outcomes.into_iter(),
6865                self.prediction_mode,
6866                caller_follow.as_deref(),
6867                |index| caller_follow_token_info_for_stream(input, index),
6868                arena,
6869            )
6870        };
6871        match selected {
6872            Some(mut outcome) => {
6873                if self.build_parse_trees {
6874                    self.materialize_fast_outcome_nodes(&mut outcome);
6875                }
6876                Ok((outcome, expected))
6877            }
6878            None => Err(expected),
6879        }
6880    }
6881
6882    /// Converts one speculative arena record into the flat public CST.
6883    fn arena_recognized_node_tree(
6884        &mut self,
6885        node_id: RecognizedNodeId,
6886        track_alt_numbers: bool,
6887        track_context_alt_numbers: bool,
6888    ) -> Result<ParseTree, AntlrError> {
6889        let node = self.recognition_arena.node(node_id);
6890        match node {
6891            ArenaRecognizedNode::Token { token } => Ok(self.terminal_tree(token)),
6892            ArenaRecognizedNode::ErrorToken { token } => Ok(self.error_tree(token)),
6893            ArenaRecognizedNode::MissingToken { extra } => {
6894                let (token_type, at_index, text) = match self.recognition_arena.extra(extra) {
6895                    RecognitionExtra::MissingToken {
6896                        token_type,
6897                        at_index,
6898                        text,
6899                    } => (*token_type, *at_index as usize, text.clone()),
6900                    RecognitionExtra::ReturnValues(_) | RecognitionExtra::Diagnostic(_) => {
6901                        unreachable!("missing-token node must reference missing-token extra")
6902                    }
6903                };
6904                let (line, column) = self
6905                    .token_at(at_index)
6906                    .map_or((0, 0), |token| (token.line(), token.column()));
6907                let token = self.insert_synthetic_token(token_type, text, line, column)?;
6908                Ok(self.error_tree(token))
6909            }
6910            ArenaRecognizedNode::Rule {
6911                rule_index,
6912                invoking_state,
6913                alt_number,
6914                start_index,
6915                stop_index,
6916                return_values,
6917                children,
6918            } => {
6919                let mut context = ParserRuleContext::with_child_capacity(
6920                    rule_index as usize,
6921                    invoking_state as isize,
6922                    self.recognition_arena.sequence_len(children),
6923                );
6924                if track_alt_numbers {
6925                    context.set_alt_number(alt_number as usize);
6926                }
6927                if track_context_alt_numbers {
6928                    context.set_context_alt_number(alt_number as usize);
6929                }
6930                if let Some(extra) = return_values {
6931                    let RecognitionExtra::ReturnValues(values) =
6932                        self.recognition_arena.extra(extra)
6933                    else {
6934                        unreachable!("rule node must reference return-values extra");
6935                    };
6936                    for (name, value) in values {
6937                        context.set_int_return(name.clone(), *value);
6938                    }
6939                }
6940                if let Some(token) = self.token_id_at(start_index as usize) {
6941                    self.set_context_start(&mut context, token);
6942                }
6943                if let Some(token) = stop_index.and_then(|index| self.token_id_at(index as usize)) {
6944                    self.set_context_stop(&mut context, token);
6945                }
6946                let mut cursor = self
6947                    .recognition_arena
6948                    .fold_left_recursive_boundaries(children);
6949                while let Some(link) = self.recognition_arena.link(cursor) {
6950                    let child = self.arena_recognized_node_tree(
6951                        link.head,
6952                        track_alt_numbers,
6953                        track_context_alt_numbers,
6954                    )?;
6955                    self.tree.add_child(&mut context, child);
6956                    cursor = link.tail;
6957                }
6958                Ok(self.rule_node(context))
6959            }
6960            ArenaRecognizedNode::LeftRecursiveBoundary { rule_index, .. } => {
6961                Err(AntlrError::Unsupported(format!(
6962                    "unfolded left-recursive boundary for rule {rule_index}"
6963                )))
6964            }
6965        }
6966    }
6967
6968    fn arena_recognized_node_tree_with_implicit_tokens(
6969        &mut self,
6970        node_id: RecognizedNodeId,
6971    ) -> Result<ParseTree, AntlrError> {
6972        let node = self.recognition_arena.node(node_id);
6973        match node {
6974            ArenaRecognizedNode::Rule {
6975                rule_index,
6976                invoking_state,
6977                start_index,
6978                stop_index,
6979                children,
6980                ..
6981            } => {
6982                let mut context = ParserRuleContext::with_child_capacity(
6983                    rule_index as usize,
6984                    invoking_state as isize,
6985                    self.recognition_arena.sequence_len(children),
6986                );
6987                if let Some(token) = self.token_id_at(start_index as usize) {
6988                    self.set_context_start(&mut context, token);
6989                }
6990                if let Some(token) = stop_index.and_then(|index| self.token_id_at(index as usize)) {
6991                    self.set_context_stop(&mut context, token);
6992                }
6993                let children = self
6994                    .recognition_arena
6995                    .fold_left_recursive_boundaries(children);
6996                self.add_arena_implicit_token_children(
6997                    &mut context,
6998                    start_index as usize,
6999                    stop_index.map(|index| index as usize),
7000                    children,
7001                )?;
7002                Ok(self.rule_node(context))
7003            }
7004            _ => self.arena_recognized_node_tree(node_id, false, false),
7005        }
7006    }
7007
7008    fn add_arena_implicit_token_children(
7009        &mut self,
7010        context: &mut ParserRuleContext,
7011        start_index: usize,
7012        stop_index: Option<usize>,
7013        mut children: NodeSeqId,
7014    ) -> Result<(), AntlrError> {
7015        let mut cursor = Some(start_index);
7016        while let Some(link) = self.recognition_arena.link(children) {
7017            if let Some((child_start, child_stop)) = self.recognition_arena.node_span(link.head) {
7018                self.add_visible_terminals_before(context, &mut cursor, child_start)?;
7019                let child = self.arena_recognized_node_tree_with_implicit_tokens(link.head)?;
7020                self.tree.add_child(context, child);
7021                if let Some(child_stop) = child_stop {
7022                    cursor = self.next_visible_after_token(child_stop);
7023                }
7024            } else {
7025                let child = self.arena_recognized_node_tree_with_implicit_tokens(link.head)?;
7026                self.tree.add_child(context, child);
7027            }
7028            children = link.tail;
7029        }
7030        if let Some(stop) = stop_index {
7031            self.add_visible_terminals_through(context, cursor, stop)?;
7032        }
7033        Ok(())
7034    }
7035
7036    fn add_visible_terminals_before(
7037        &mut self,
7038        context: &mut ParserRuleContext,
7039        cursor: &mut Option<usize>,
7040        before: usize,
7041    ) -> Result<(), AntlrError> {
7042        let Some(stop) = before.checked_sub(1) else {
7043            return Ok(());
7044        };
7045        let next = self.add_visible_terminals_through(context, *cursor, stop)?;
7046        *cursor = next;
7047        Ok(())
7048    }
7049
7050    fn add_visible_terminals_through(
7051        &mut self,
7052        context: &mut ParserRuleContext,
7053        mut cursor: Option<usize>,
7054        stop: usize,
7055    ) -> Result<Option<usize>, AntlrError> {
7056        while let Some(index) = cursor {
7057            if index > stop {
7058                return Ok(Some(index));
7059            }
7060            let token = self
7061                .input
7062                .get_id(index)
7063                .ok_or_else(|| AntlrError::ParserError {
7064                    line: 0,
7065                    column: 0,
7066                    message: format!("missing token at index {index}"),
7067                })?;
7068            let is_eof = self.token_type_for_id(token) == TOKEN_EOF;
7069            let child = self.terminal_tree(token);
7070            self.tree.add_child(context, child);
7071            if is_eof {
7072                return Ok(None);
7073            }
7074            cursor = self.next_visible_after_token(index);
7075        }
7076        Ok(None)
7077    }
7078
7079    fn next_visible_after_token(&mut self, index: usize) -> Option<usize> {
7080        let next = self.input.next_visible_after(index);
7081        (next != index).then_some(next)
7082    }
7083
7084    /// Parses a generated rule and returns semantic actions reached on the
7085    /// selected ATN path.
7086    ///
7087    /// This slower path preserves action ordering and token intervals for
7088    /// generated code that replays target-specific action templates after the
7089    /// recognizer has chosen one viable parse path.
7090    pub fn parse_atn_rule_with_actions(
7091        &mut self,
7092        atn: &Atn,
7093        rule_index: usize,
7094    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
7095        self.parse_atn_rule_with_action_options(atn, rule_index, &[], false)
7096    }
7097
7098    /// Parses a generated rule and emits ATN actions plus selected rule-init
7099    /// actions reached on the chosen path.
7100    ///
7101    /// Generated parsers use this when a grammar contains rule-level `@init`
7102    /// templates that must run for nested rule invocations. The runtime keeps
7103    /// the action list path-sensitive, so init templates are replayed only for
7104    /// rules that were actually entered by the selected parse.
7105    pub fn parse_atn_rule_with_action_inits(
7106        &mut self,
7107        atn: &Atn,
7108        rule_index: usize,
7109        init_action_rules: &[usize],
7110    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
7111        self.parse_atn_rule_with_action_options(atn, rule_index, init_action_rules, false)
7112    }
7113
7114    /// Parses a generated rule with optional semantic-action replay features.
7115    ///
7116    /// `track_alt_numbers` is used by grammars that opt into ANTLR's
7117    /// alt-numbered context behavior. It keeps ordinary parse-tree rendering
7118    /// unchanged for grammars that do not request that target template.
7119    pub fn parse_atn_rule_with_action_options(
7120        &mut self,
7121        atn: &Atn,
7122        rule_index: usize,
7123        init_action_rules: &[usize],
7124        track_alt_numbers: bool,
7125    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
7126        self.parse_atn_rule_with_runtime_options(
7127            atn,
7128            rule_index,
7129            ParserRuntimeOptions {
7130                init_action_rules,
7131                track_alt_numbers,
7132                ..ParserRuntimeOptions::default()
7133            },
7134        )
7135    }
7136
7137    /// Parses a generated rule with action replay and parser predicate support.
7138    ///
7139    /// `predicates` maps serialized `(rule_index, pred_index)` coordinates to
7140    /// target-template predicate semantics emitted by the generator. Missing
7141    /// entries are treated as true so unsupported predicate-free grammars keep
7142    /// the previous unconditional transition behavior.
7143    pub fn parse_atn_rule_with_runtime_options(
7144        &mut self,
7145        atn: &Atn,
7146        rule_index: usize,
7147        options: ParserRuntimeOptions<'_>,
7148    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
7149        self.parse_atn_rule_with_runtime_options_and_precedence(atn, rule_index, 0, options)
7150    }
7151
7152    /// Parses a generated rule with action replay, parser predicate support,
7153    /// and an initial left-recursive precedence threshold.
7154    pub fn parse_atn_rule_with_runtime_options_and_precedence(
7155        &mut self,
7156        atn: &Atn,
7157        rule_index: usize,
7158        precedence: i32,
7159        options: ParserRuntimeOptions<'_>,
7160    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
7161        let ParserRuntimeOptions {
7162            init_action_rules,
7163            track_alt_numbers,
7164            track_context_alt_numbers,
7165            predicates,
7166            semantics,
7167            rule_args,
7168            member_actions,
7169            return_actions,
7170            unknown_predicate_policy,
7171        } = options;
7172        let capture_alt_numbers = track_alt_numbers || track_context_alt_numbers;
7173        if init_action_rules.is_empty()
7174            && !capture_alt_numbers
7175            && predicates.is_empty()
7176            && semantics.is_none()
7177            && rule_args.is_empty()
7178            && member_actions.is_empty()
7179            && return_actions.is_empty()
7180            && unknown_predicate_policy == UnknownSemanticPolicy::AssumeTrue
7181            && !atn_has_observable_action_transitions(atn)
7182            && !self.semantic_hooks.observes_parser_decisions()
7183            && (!self.semantic_hooks.observes_parser_predicates()
7184                || !atn_has_predicate_transitions(atn))
7185        {
7186            return self
7187                .parse_atn_rule_with_precedence(atn, rule_index, precedence)
7188                .map(|tree| (tree, Vec::new()));
7189        }
7190        if !self.semantic_hooks.observes_parser_decisions()
7191            && can_use_fast_predicate_recognizer(atn, &options)
7192        {
7193            self.unknown_predicate_policy = unknown_predicate_policy;
7194            let prior_unknown_predicate_hits = std::mem::take(&mut self.unknown_predicate_hits);
7195            let member_values = self.int_members.clone();
7196            let result = self
7197                .parse_atn_rule_with_precedence_inner(
7198                    atn,
7199                    rule_index,
7200                    precedence,
7201                    Some(FastPredicateContext {
7202                        predicates,
7203                        semantics,
7204                        member_values: &member_values,
7205                    }),
7206                )
7207                .map(|tree| (tree, Vec::new()));
7208            if self.unknown_predicate_hits.is_empty() && self.unhandled_action_hits.is_empty() {
7209                self.restore_prior_unknown_predicate_hits(prior_unknown_predicate_hits);
7210            }
7211            return result;
7212        }
7213        self.unknown_predicate_policy = unknown_predicate_policy;
7214        // A generated parent may have already recorded unknown-predicate
7215        // coordinates before descending into this (interpreted) child. Clearing
7216        // unconditionally would drop them before the parent's public entry
7217        // surfaces them, so stash and restore around this call: recognition sees
7218        // only the hits it records itself (so the fail-loud check below reflects
7219        // this rule), and the parent's prior hits are merged back afterward.
7220        let prior_unknown_predicate_hits = std::mem::take(&mut self.unknown_predicate_hits);
7221        let start_state = atn.rule_to_start_state().get(rule_index).ok_or_else(|| {
7222            AntlrError::Unsupported(format!("rule {rule_index} has no start state"))
7223        })?;
7224        let stop_state = atn
7225            .rule_to_stop_state()
7226            .get(rule_index)
7227            .filter(|state| *state != usize::MAX)
7228            .ok_or_else(|| {
7229                AntlrError::Unsupported(format!("rule {rule_index} has no stop state"))
7230            })?;
7231
7232        let start_index = self.current_visible_index();
7233        self.clear_prediction_diagnostics();
7234        self.reset_per_parse_caches();
7235        self.reset_recognition_arena();
7236        let init_action_rules = init_action_rules.iter().copied().collect::<BTreeSet<_>>();
7237        let invoking_state = self.pending_invoking_states.pop();
7238        let local_int_arg = invoking_state
7239            .and_then(|state| usize::try_from(state).ok())
7240            .and_then(|state| rule_local_int_arg(rule_args, state, rule_index, None));
7241        let mut visiting = BTreeSet::new();
7242        let mut memo = BTreeMap::new();
7243        let mut expected = ExpectedTokens::default();
7244        let member_values = self.int_members.clone();
7245        let return_values = BTreeMap::new();
7246        let outcomes = self.recognize_state(
7247            atn,
7248            RecognizeRequest {
7249                state_number: start_state,
7250                stop_state,
7251                index: start_index,
7252                rule_start_index: start_index,
7253                decision_start_index: None,
7254                init_action_rules: &init_action_rules,
7255                predicates,
7256                semantics,
7257                rule_args,
7258                member_actions,
7259                return_actions,
7260                local_int_arg,
7261                member_values,
7262                return_values,
7263                rule_alt_number: 0,
7264                track_alt_numbers: capture_alt_numbers,
7265                consumed_eof: false,
7266                committed_decision: false,
7267                precedence,
7268                depth: 0,
7269                recovery_symbols: BTreeSet::new(),
7270                recovery_state: None,
7271            },
7272            &mut visiting,
7273            &mut memo,
7274            &mut expected,
7275        );
7276        if let Some(error) = self.unknown_semantic_error() {
7277            self.report_token_source_errors();
7278            // Keep the recorded coordinates: when this interpreted rule is a
7279            // child of a generated parent, the parent's catch block recovers an
7280            // ordinary `AntlrError` into a partial subtree, so the fail-loud
7281            // coordinate must survive on the parser for the top-level entry's
7282            // `take_unknown_semantic_error` to surface it. Cross-parse staleness
7283            // is handled by clearing at the top-level generated entry instead.
7284            return Err(error);
7285        }
7286        // Recognition recorded no unresolved coordinate of its own; merge the
7287        // parent's prior hits back so its public entry can still surface them.
7288        self.restore_prior_unknown_predicate_hits(prior_unknown_predicate_hits);
7289        let Some(outcome) = select_best_outcome(
7290            outcomes.into_iter(),
7291            self.prediction_mode,
7292            &self.recognition_arena,
7293        ) else {
7294            let error = self.recognition_error(rule_index, start_index, &expected);
7295            self.record_syntax_errors(1);
7296            self.report_token_source_errors();
7297            return Err(error);
7298        };
7299
7300        self.record_syntax_errors(self.recognition_arena.diagnostics_len(outcome.diagnostics));
7301        self.dispatch_parser_diagnostics(&self.prediction_diagnostics);
7302        self.dispatch_parser_diagnostics(self.recognition_arena.diagnostics(outcome.diagnostics));
7303        self.report_token_source_errors();
7304        let mut actions = outcome.actions;
7305        if init_action_rules.contains(&rule_index) {
7306            actions.insert(
7307                0,
7308                ParserAction::new_rule_init(rule_index, start_index, Some(start_state)),
7309            );
7310        }
7311        let mut context =
7312            ParserRuleContext::new(rule_index, invoking_state.unwrap_or_else(|| self.state()));
7313        if track_alt_numbers {
7314            context.set_alt_number(outcome.alt_number);
7315        }
7316        if track_context_alt_numbers {
7317            context.set_context_alt_number(outcome.alt_number);
7318        }
7319        for (name, value) in outcome.return_values {
7320            context.set_int_return(name, value);
7321        }
7322        if let Some(token) = self.token_id_at(start_index) {
7323            self.set_context_start(&mut context, token);
7324        }
7325        if let Some(token) = self.rule_stop_token_id(outcome.index, outcome.consumed_eof) {
7326            self.set_context_stop(&mut context, token);
7327        }
7328        let live_root = if self.build_parse_trees {
7329            self.recognition_arena
7330                .fold_left_recursive_boundaries(outcome.nodes)
7331        } else {
7332            outcome.nodes
7333        };
7334        if self.build_parse_trees {
7335            let mut nodes = live_root;
7336            while let Some(link) = self.recognition_arena.link(nodes) {
7337                let child = self.arena_recognized_node_tree(
7338                    link.head,
7339                    track_alt_numbers,
7340                    track_context_alt_numbers,
7341                )?;
7342                self.tree.add_child(&mut context, child);
7343                nodes = link.tail;
7344            }
7345        }
7346        self.finish_recognition_arena(live_root, outcome.diagnostics);
7347        self.input.seek(outcome.index);
7348
7349        let tree = self.rule_node(context);
7350        self.release_tree_scratch_if_idle();
7351        Ok((tree, actions))
7352    }
7353
7354    /// Temporary parser entry used by generated parser methods while the parser
7355    /// ATN simulator is being implemented.
7356    ///
7357    /// This keeps generated parser crates buildable and gives us a stable method
7358    /// surface for every grammar rule. It intentionally accepts all remaining
7359    /// tokens into one rule context; it is not the final parser semantics.
7360    pub fn parse_interpreted_rule(&mut self, rule_index: usize) -> Result<ParseTree, AntlrError> {
7361        let mut context = ParserRuleContext::new(rule_index, self.state());
7362        while self.la(1) != TOKEN_EOF {
7363            let token_type = self.la(1);
7364            let child = self.match_token(token_type)?;
7365            if self.build_parse_trees {
7366                self.tree.add_child(&mut context, child);
7367            }
7368        }
7369        if self.build_parse_trees {
7370            let child = self.match_eof()?;
7371            self.tree.add_child(&mut context, child);
7372        }
7373        let tree = self.rule_node(context);
7374        self.release_tree_scratch_if_idle();
7375        Ok(tree)
7376    }
7377
7378    /// Builds the parser error reported when no ATN path can reach the active
7379    /// rule stop state.
7380    fn recognition_error(
7381        &mut self,
7382        rule_index: usize,
7383        start_index: usize,
7384        expected: &ExpectedTokens,
7385    ) -> AntlrError {
7386        let (index, message) = self.expected_error_message(rule_index, start_index, expected);
7387        self.input.seek(index);
7388        let current = self.input.lt(1);
7389        let line = current.as_ref().map(Token::line).unwrap_or_default();
7390        let column = current.as_ref().map(Token::column).unwrap_or_default();
7391        AntlrError::ParserError {
7392            line,
7393            column,
7394            message,
7395        }
7396    }
7397
7398    /// Builds the token index and ANTLR-compatible message for a failed rule.
7399    fn expected_error_message(
7400        &mut self,
7401        rule_index: usize,
7402        start_index: usize,
7403        expected: &ExpectedTokens,
7404    ) -> (usize, String) {
7405        let index = expected
7406            .index
7407            .or_else(|| expected.no_viable.map(|no_viable| no_viable.error_index))
7408            .unwrap_or_else(|| self.input.index());
7409        self.input.seek(index);
7410        let current = self.input.lt(1);
7411        let message = if expected
7412            .no_viable
7413            .as_ref()
7414            .is_some_and(|no_viable| no_viable.error_index == index)
7415        {
7416            let start = expected
7417                .no_viable
7418                .as_ref()
7419                .map_or(start_index, |no_viable| no_viable.start_index);
7420            let text = display_input_text(&self.input.text(start, index));
7421            format!("no viable alternative at input '{text}'")
7422        } else if expected.symbols.is_empty() {
7423            if expected.index.is_some() {
7424                let found = current
7425                    .as_ref()
7426                    .map_or_else(|| "'<EOF>'".to_owned(), token_input_display);
7427                if current
7428                    .as_ref()
7429                    .is_some_and(|token| token.token_type() == TOKEN_EOF)
7430                {
7431                    format!(
7432                        "missing {} at {found}",
7433                        self.expected_symbols_display(&expected.symbols)
7434                    )
7435                } else {
7436                    format!("mismatched input {found}")
7437                }
7438            } else {
7439                format!("no viable alternative while parsing rule {rule_index}")
7440            }
7441        } else {
7442            format!(
7443                "mismatched input {} expecting {}",
7444                current
7445                    .as_ref()
7446                    .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
7447                self.expected_symbols_display(&expected.symbols)
7448            )
7449        };
7450        (index, message)
7451    }
7452
7453    /// Converts a failed child rule into a recovered outcome so the parent can
7454    /// continue after reporting the child diagnostic.
7455    fn child_rule_failure_recovery(
7456        &mut self,
7457        rule_index: usize,
7458        start_index: usize,
7459        sync_symbols: &BTreeSet<i32>,
7460        member_values: BTreeMap<usize, i64>,
7461        expected: &ExpectedTokens,
7462    ) -> Option<RecognizeOutcome> {
7463        let (error_index, message) = self.expected_error_message(rule_index, start_index, expected);
7464        let diagnostic = diagnostic_for_token(self.token_at(error_index), message);
7465        let mut next_index = error_index;
7466        loop {
7467            let symbol = self.token_type_at(next_index);
7468            if sync_symbols.contains(&symbol) {
7469                if next_index == error_index {
7470                    return None;
7471                }
7472                break;
7473            }
7474            if symbol == TOKEN_EOF {
7475                break;
7476            }
7477            let after = self.consume_index(next_index, symbol);
7478            if after == next_index {
7479                break;
7480            }
7481            next_index = after;
7482        }
7483        let mut nodes = NodeSeqId::EMPTY;
7484        let error = self.arena_token_node(error_index, true);
7485        self.arena_prepend(&mut nodes, error);
7486        let diagnostics = self
7487            .recognition_arena
7488            .prepend_diagnostic(DiagnosticSeqId::EMPTY, diagnostic);
7489        Some(RecognizeOutcome {
7490            index: next_index,
7491            consumed_eof: false,
7492            alt_number: 0,
7493            member_values,
7494            return_values: BTreeMap::new(),
7495            diagnostics,
7496            decisions: Vec::new(),
7497            actions: Vec::new(),
7498            nodes,
7499        })
7500    }
7501
7502    /// Adapts the optional recovery result to the normal outcome list used by
7503    /// rule-call transitions.
7504    fn child_rule_failure_recovery_outcomes(
7505        &mut self,
7506        request: ChildRuleFailureRecovery<'_>,
7507    ) -> Vec<RecognizeOutcome> {
7508        let sync_symbols =
7509            state_sync_symbols(request.atn, request.follow_state, request.stop_state);
7510        self.child_rule_failure_recovery(
7511            request.rule_index,
7512            request.start_index,
7513            &sync_symbols,
7514            request.member_values,
7515            request.expected,
7516        )
7517        .into_iter()
7518        .collect()
7519    }
7520
7521    /// Formats expected token types using ANTLR's single-token or set syntax.
7522    fn expected_symbols_display(&self, symbols: &BTreeSet<i32>) -> String {
7523        expected_symbols_display(symbols, self.vocabulary())
7524    }
7525
7526    /// Returns the single-token deletion repair if the token after `index`
7527    /// satisfies the failed consuming transition.
7528    fn single_token_deletion(
7529        &mut self,
7530        transition: ParserTransition<'_>,
7531        index: usize,
7532        max_token_type: i32,
7533        expected_symbols: &BTreeSet<i32>,
7534    ) -> Option<(ParserDiagnostic, usize, i32)> {
7535        let current_symbol = self.token_type_at(index);
7536        if current_symbol == TOKEN_EOF {
7537            return None;
7538        }
7539        let next_index = self.consume_index(index, current_symbol);
7540        if next_index == index {
7541            return None;
7542        }
7543        let next_symbol = self.token_type_at(next_index);
7544        if !transition.matches(next_symbol, 1, max_token_type) {
7545            return None;
7546        }
7547        let transition_expected = transition_expected_symbols(transition, max_token_type);
7548        let expected_display = self.expected_symbols_display(if expected_symbols.is_empty() {
7549            &transition_expected
7550        } else {
7551            expected_symbols
7552        });
7553        let current = self.token_at(index);
7554        let message = format!(
7555            "extraneous input {} expecting {expected_display}",
7556            current
7557                .as_ref()
7558                .map_or_else(|| "'<EOF>'".to_owned(), token_input_display)
7559        );
7560        Some((
7561            diagnostic_for_token(current, message),
7562            next_index,
7563            next_symbol,
7564        ))
7565    }
7566
7567    /// Returns the repair used when deleting the current token lets a recovery
7568    /// state continue with the following token.
7569    fn current_token_deletion(
7570        &mut self,
7571        index: usize,
7572        expected_symbols: &BTreeSet<i32>,
7573    ) -> Option<(ParserDiagnostic, usize, Vec<usize>)> {
7574        if expected_symbols.is_empty() {
7575            return None;
7576        }
7577        let current_symbol = self.token_type_at(index);
7578        if current_symbol == TOKEN_EOF {
7579            return None;
7580        }
7581        let current = self.token_at(index);
7582        let message = format!(
7583            "extraneous input {} expecting {}",
7584            current
7585                .as_ref()
7586                .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
7587            self.expected_symbols_display(expected_symbols)
7588        );
7589        let diagnostic = diagnostic_for_token(current, message);
7590        let mut skipped = Vec::new();
7591        let mut cursor = index;
7592        loop {
7593            let symbol = self.token_type_at(cursor);
7594            if symbol == TOKEN_EOF {
7595                return None;
7596            }
7597            skipped.push(cursor);
7598            let next_index = self.consume_index(cursor, symbol);
7599            if next_index == cursor {
7600                return None;
7601            }
7602            let next_symbol = self.token_type_at(next_index);
7603            if expected_symbols.contains(&next_symbol) {
7604                return Some((diagnostic, next_index, skipped));
7605            }
7606            cursor = next_index;
7607        }
7608    }
7609
7610    /// Returns the single-token insertion repair for a failed consuming
7611    /// transition. The caller validates the repair by continuing from the
7612    /// transition target at the same input index.
7613    fn single_token_insertion(
7614        &mut self,
7615        transition: ParserTransition<'_>,
7616        index: usize,
7617        max_token_type: i32,
7618        expected_symbols: &BTreeSet<i32>,
7619        follow_symbols: &BTreeSet<i32>,
7620    ) -> Option<(ParserDiagnostic, i32, String)> {
7621        let current_symbol = self.token_type_at(index);
7622        if !follow_symbols.contains(&current_symbol) {
7623            return None;
7624        }
7625        let transition_expected = transition_expected_symbols(transition, max_token_type);
7626        let token_type = transition_expected.iter().next().copied()?;
7627        let expected_display = self.expected_symbols_display(if expected_symbols.is_empty() {
7628            &transition_expected
7629        } else {
7630            expected_symbols
7631        });
7632        let mut token_symbols = BTreeSet::new();
7633        token_symbols.insert(token_type);
7634        let missing_token_display = self.expected_symbols_display(&token_symbols);
7635        let current = self.token_at(index);
7636        let message = format!(
7637            "missing {expected_display} at {}",
7638            current
7639                .as_ref()
7640                .map_or_else(|| "'<EOF>'".to_owned(), token_input_display)
7641        );
7642        let text = format!("<missing {missing_token_display}>");
7643        Some((
7644            diagnostic_for_token(current.as_ref(), message),
7645            token_type,
7646            text,
7647        ))
7648    }
7649
7650    /// Explores ANTLR's single-token deletion recovery for the fast recognizer:
7651    /// skip the unexpected current token when the following token satisfies the
7652    /// transition that failed.
7653    fn fast_single_token_deletion_recovery(
7654        &mut self,
7655        recovery: FastRecoveryRequest<'_, '_>,
7656        predicate_context: Option<FastPredicateContext<'_>>,
7657    ) -> Vec<FastRecognizeOutcome> {
7658        let FastRecoveryRequest {
7659            atn,
7660            transition,
7661            expected_symbols,
7662            target,
7663            request,
7664            visiting,
7665            memo,
7666            expected,
7667        } = recovery;
7668        let FastRecognizeRequest {
7669            stop_state,
7670            index,
7671            rule_start_index,
7672            decision_start_index,
7673            precedence,
7674            depth,
7675            ..
7676        } = request;
7677        let Some((diagnostic, next_index, next_symbol)) =
7678            self.single_token_deletion(transition, index, atn.max_token_type(), &expected_symbols)
7679        else {
7680            return Vec::new();
7681        };
7682        let after_next = self.consume_index(next_index, next_symbol);
7683        let empty_recovery = self.empty_recovery_symbols();
7684        self.recognize_state_fast(
7685            atn,
7686            FastRecognizeRequest {
7687                state_number: target,
7688                stop_state,
7689                index: after_next,
7690                rule_start_index,
7691                decision_start_index,
7692                precedence,
7693                depth: depth + 1,
7694                recovery_symbols: empty_recovery,
7695                recovery_state: None,
7696            },
7697            FastRecognizeScratch {
7698                predicate_context,
7699                visiting,
7700                memo,
7701                expected,
7702                native_depth: 0,
7703            },
7704        )
7705        .into_iter()
7706        .map(|mut outcome| {
7707            outcome.consumed_eof |= next_symbol == TOKEN_EOF;
7708            outcome.diagnostics = self
7709                .recognition_arena
7710                .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
7711            if self.fast_token_nodes_enabled {
7712                let token = self.arena_token_node(next_index, false);
7713                self.defer_fast_outcome_node(&mut outcome, token);
7714                let error = self.arena_token_node(index, true);
7715                self.defer_fast_outcome_node(&mut outcome, error);
7716            }
7717            outcome
7718        })
7719        .collect()
7720    }
7721
7722    /// Explores ANTLR's single-token insertion recovery for the fast recognizer:
7723    /// pretend the expected transition token was present and continue without
7724    /// consuming the current token.
7725    fn fast_single_token_insertion_recovery(
7726        &mut self,
7727        recovery: FastRecoveryRequest<'_, '_>,
7728        predicate_context: Option<FastPredicateContext<'_>>,
7729    ) -> Vec<FastRecognizeOutcome> {
7730        let FastRecoveryRequest {
7731            atn,
7732            transition,
7733            expected_symbols,
7734            target,
7735            request,
7736            visiting,
7737            memo,
7738            expected,
7739        } = recovery;
7740        let FastRecognizeRequest {
7741            stop_state,
7742            index,
7743            rule_start_index,
7744            decision_start_index,
7745            precedence,
7746            depth,
7747            ..
7748        } = request;
7749        let follow_symbols = self.cached_state_expected_symbols(atn, transition.target());
7750        let Some((diagnostic, token_type, text)) = self.single_token_insertion(
7751            transition,
7752            index,
7753            atn.max_token_type(),
7754            &expected_symbols,
7755            &follow_symbols,
7756        ) else {
7757            return Vec::new();
7758        };
7759        let empty_recovery = self.empty_recovery_symbols();
7760        self.recognize_state_fast(
7761            atn,
7762            FastRecognizeRequest {
7763                state_number: target,
7764                stop_state,
7765                index,
7766                rule_start_index,
7767                decision_start_index,
7768                precedence,
7769                depth: depth + 1,
7770                recovery_symbols: empty_recovery,
7771                recovery_state: None,
7772            },
7773            FastRecognizeScratch {
7774                predicate_context,
7775                visiting,
7776                memo,
7777                expected,
7778                native_depth: 0,
7779            },
7780        )
7781        .into_iter()
7782        .map(|mut outcome| {
7783            outcome.diagnostics = self
7784                .recognition_arena
7785                .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
7786            let missing = self.arena_missing_token_node(token_type, index, text.clone());
7787            self.defer_fast_outcome_node(&mut outcome, missing);
7788            outcome
7789        })
7790        .collect()
7791    }
7792
7793    /// Retries the current fast-recognition state after deleting one
7794    /// unexpected token that precedes a valid loop or block continuation.
7795    fn fast_current_token_deletion_recovery(
7796        &mut self,
7797        recovery: FastCurrentTokenDeletionRequest<'_, '_>,
7798        predicate_context: Option<FastPredicateContext<'_>>,
7799    ) -> Vec<FastRecognizeOutcome> {
7800        let FastCurrentTokenDeletionRequest {
7801            atn,
7802            expected_symbols,
7803            mut request,
7804            visiting,
7805            memo,
7806            expected,
7807        } = recovery;
7808        if request.index == request.rule_start_index {
7809            return Vec::new();
7810        }
7811        let Some((diagnostic, next_index, skipped)) =
7812            self.current_token_deletion(request.index, &expected_symbols)
7813        else {
7814            return Vec::new();
7815        };
7816        request.state_number = request.recovery_state.unwrap_or(request.state_number);
7817        request.index = next_index;
7818        request.depth += 1;
7819        request.recovery_state = None;
7820        self.recognize_state_fast(
7821            atn,
7822            request,
7823            FastRecognizeScratch {
7824                predicate_context,
7825                visiting,
7826                memo,
7827                expected,
7828                native_depth: 0,
7829            },
7830        )
7831        .into_iter()
7832        .map(|mut outcome| {
7833            outcome.diagnostics = self
7834                .recognition_arena
7835                .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
7836            for index in skipped.iter().rev() {
7837                let error = self.arena_token_node(*index, true);
7838                self.defer_fast_outcome_node(&mut outcome, error);
7839            }
7840            outcome
7841        })
7842        .collect()
7843    }
7844
7845    /// Converts a failed child rule into a recovered fast-recognizer outcome so
7846    /// the parent can keep its child rule context and continue at a sync token.
7847    fn fast_child_rule_failure_recovery(
7848        &mut self,
7849        rule_index: usize,
7850        start_index: usize,
7851        sync_symbols: &BTreeSet<i32>,
7852        expected: &ExpectedTokens,
7853    ) -> Option<FastRecognizeOutcome> {
7854        let (error_index, message) = self.expected_error_message(rule_index, start_index, expected);
7855        let diagnostic = diagnostic_for_token(self.token_at(error_index), message);
7856        let mut next_index = error_index;
7857        loop {
7858            let symbol = self.token_type_at(next_index);
7859            if sync_symbols.contains(&symbol) {
7860                if next_index == error_index {
7861                    return None;
7862                }
7863                break;
7864            }
7865            if symbol == TOKEN_EOF {
7866                break;
7867            }
7868            let after = self.consume_index(next_index, symbol);
7869            if after == next_index {
7870                break;
7871            }
7872            next_index = after;
7873        }
7874        let diagnostics = self
7875            .recognition_arena
7876            .prepend_diagnostic(DiagnosticSeqId::EMPTY, diagnostic);
7877        let mut nodes = NodeSeqId::EMPTY;
7878        if self.fast_token_nodes_enabled {
7879            let error = self.arena_token_node(error_index, true);
7880            self.arena_prepend(&mut nodes, error);
7881        }
7882        Some(FastRecognizeOutcome {
7883            index: next_index,
7884            consumed_eof: false,
7885            diagnostics,
7886            deferred_nodes: FastDeferredNodeId::EMPTY,
7887            nodes,
7888        })
7889    }
7890
7891    /// Adapts the optional child-rule recovery result to the fast-recognizer
7892    /// outcome list used by rule-call transitions.
7893    fn fast_child_rule_failure_recovery_outcomes(
7894        &mut self,
7895        request: FastChildRuleFailureRecoveryRequest<'_>,
7896    ) -> Vec<FastRecognizeOutcome> {
7897        let FastChildRuleFailureRecoveryRequest {
7898            atn,
7899            rule_index,
7900            start_index,
7901            follow_state,
7902            stop_state,
7903            expected,
7904        } = request;
7905        let sync_symbols = state_sync_symbols(atn, follow_state, stop_state);
7906        self.fast_child_rule_failure_recovery(rule_index, start_index, &sync_symbols, expected)
7907            .into_iter()
7908            .collect()
7909    }
7910
7911    fn defer_fast_outcome_node(
7912        &mut self,
7913        outcome: &mut FastRecognizeOutcome,
7914        node: RecognizedNodeId,
7915    ) {
7916        if outcome.deferred_nodes.is_empty() {
7917            self.arena_prepend(&mut outcome.nodes, node);
7918            return;
7919        }
7920        let fragment = self.recognition_arena.prepend(NodeSeqId::EMPTY, node);
7921        let fragment = self.recognition_arena.deferred_fragment(fragment);
7922        outcome.deferred_nodes = self
7923            .recognition_arena
7924            .concat_deferred_nodes(fragment, outcome.deferred_nodes);
7925    }
7926
7927    fn materialize_fast_deferred_nodes(
7928        &mut self,
7929        root: FastDeferredNodeId,
7930        initial_suffix: NodeSeqId,
7931    ) -> NodeSeqId {
7932        if root.is_empty() {
7933            return initial_suffix;
7934        }
7935
7936        enum Frame {
7937            Visit(FastDeferredNodeId),
7938            ContinuePrefix(FastDeferredNodeId),
7939            FinishRule {
7940                rule: FastDeferredRule,
7941                parent_suffix: NodeSeqId,
7942            },
7943        }
7944
7945        let mut result = initial_suffix;
7946        let mut pending = Vec::with_capacity(16);
7947        pending.push(Frame::Visit(root));
7948        let mut fragment_nodes = Vec::new();
7949        while let Some(frame) = pending.pop() {
7950            match frame {
7951                Frame::Visit(deferred) => {
7952                    if deferred.is_empty() {
7953                        continue;
7954                    }
7955
7956                    match self.recognition_arena.deferred_node(deferred) {
7957                        FastDeferredNode::Fragment(sequence) => {
7958                            fragment_nodes.clear();
7959                            fragment_nodes.extend(self.recognition_arena.iter(sequence));
7960                            while let Some(node) = fragment_nodes.pop() {
7961                                self.arena_prepend(&mut result, node);
7962                            }
7963                        }
7964                        FastDeferredNode::Rule(rule) => {
7965                            let rule = self.recognition_arena.deferred_rule(rule);
7966                            let parent_suffix = result;
7967                            result = rule.children;
7968                            pending.push(Frame::FinishRule {
7969                                rule,
7970                                parent_suffix,
7971                            });
7972                            pending.push(Frame::Visit(rule.deferred_children));
7973                        }
7974                        FastDeferredNode::Concat {
7975                            prefix,
7976                            suffix: deferred_suffix,
7977                        } => {
7978                            pending.push(Frame::ContinuePrefix(prefix));
7979                            pending.push(Frame::Visit(deferred_suffix));
7980                        }
7981                    }
7982                }
7983                Frame::ContinuePrefix(prefix) => pending.push(Frame::Visit(prefix)),
7984                Frame::FinishRule {
7985                    rule,
7986                    parent_suffix,
7987                } => {
7988                    let node = self.recognition_arena.push_node(ArenaRecognizedNode::Rule {
7989                        rule_index: rule.rule_index,
7990                        invoking_state: rule.invoking_state,
7991                        alt_number: 0,
7992                        start_index: rule.start_index,
7993                        stop_index: rule.stop_index,
7994                        return_values: None,
7995                        children: result,
7996                    });
7997                    result = parent_suffix;
7998                    self.arena_prepend(&mut result, node);
7999                }
8000            }
8001        }
8002        result
8003    }
8004
8005    fn materialize_fast_outcome_nodes(&mut self, outcome: &mut FastRecognizeOutcome) {
8006        let deferred_nodes = std::mem::take(&mut outcome.deferred_nodes);
8007        outcome.nodes = self.materialize_fast_deferred_nodes(deferred_nodes, outcome.nodes);
8008    }
8009
8010    /// Walks one ordinary `*`/`+` repetition at a time so input length grows
8011    /// heap work instead of the native call stack.
8012    fn recognize_repetition_fast(
8013        &mut self,
8014        atn: &Atn,
8015        request: &FastRecognizeRequest,
8016        shape: FastRepetitionShape,
8017        scratch: FastRecognizeScratch<'_, '_>,
8018    ) -> Vec<FastRecognizeOutcome> {
8019        let FastRecognizeScratch {
8020            predicate_context,
8021            visiting,
8022            memo,
8023            expected,
8024            native_depth,
8025        } = scratch;
8026        let lookahead = if self.fast_first_set_prefilter {
8027            atn.state(request.state_number).and_then(|state| {
8028                state
8029                    .rule_index()
8030                    .and_then(|rule_index| atn.rule_to_stop_state().get(rule_index))
8031                    .map(|rule_stop| self.cached_decision_lookahead(atn, state, rule_stop))
8032            })
8033        } else {
8034            None
8035        };
8036        let mut work = Vec::with_capacity(2);
8037        push_fast_repetition_work(
8038            &mut work,
8039            shape,
8040            FastRepetitionPath {
8041                index: request.index,
8042                deferred_nodes: FastDeferredNodeId::EMPTY,
8043                diagnostics: DiagnosticSeqId::EMPTY,
8044                consumed_eof: false,
8045            },
8046            lookahead.as_deref(),
8047            self.token_type_at(request.index),
8048        );
8049        let mut coordinates = FastRepetitionCoordinates::new(request.index);
8050        let mut outcomes = Vec::new();
8051        while let Some(item) = work.pop() {
8052            match item {
8053                FastRepetitionWork::Enter(path) => {
8054                    if !coordinates.insert_entered(path) {
8055                        continue;
8056                    }
8057                    let body_outcomes = self.recognize_state_fast(
8058                        atn,
8059                        FastRecognizeRequest {
8060                            state_number: shape.enter_target,
8061                            stop_state: shape.body_stop_state,
8062                            index: path.index,
8063                            rule_start_index: request.rule_start_index,
8064                            decision_start_index: request.decision_start_index,
8065                            precedence: request.precedence,
8066                            depth: request.depth.saturating_add(1),
8067                            recovery_symbols: Rc::clone(&request.recovery_symbols),
8068                            recovery_state: request.recovery_state,
8069                        },
8070                        FastRecognizeScratch {
8071                            predicate_context,
8072                            visiting: &mut *visiting,
8073                            memo: &mut *memo,
8074                            expected: &mut *expected,
8075                            native_depth: native_depth + 1,
8076                        },
8077                    );
8078                    for body in body_outcomes.into_iter().rev() {
8079                        // ANTLR rejects nullable repetition bodies. Keep the
8080                        // interpreter bounded for malformed or recovered ATNs
8081                        // by mirroring the existing same-coordinate cycle cut.
8082                        if body.index <= path.index {
8083                            continue;
8084                        }
8085                        let body_fragment = self.recognition_arena.deferred_fragment(body.nodes);
8086                        let body_nodes = self
8087                            .recognition_arena
8088                            .concat_deferred_nodes(body.deferred_nodes, body_fragment);
8089                        let deferred_nodes = self
8090                            .recognition_arena
8091                            .concat_deferred_nodes(path.deferred_nodes, body_nodes);
8092                        let next_path = FastRepetitionPath {
8093                            index: body.index,
8094                            deferred_nodes,
8095                            diagnostics: self
8096                                .recognition_arena
8097                                .concat_diagnostics(path.diagnostics, body.diagnostics),
8098                            consumed_eof: path.consumed_eof || body.consumed_eof,
8099                        };
8100                        let symbol = self.token_type_at(next_path.index);
8101                        push_fast_repetition_work(
8102                            &mut work,
8103                            shape,
8104                            next_path,
8105                            lookahead.as_deref(),
8106                            symbol,
8107                        );
8108                    }
8109                }
8110                FastRepetitionWork::Exit(path) => {
8111                    if !coordinates.insert_exited(path) {
8112                        continue;
8113                    }
8114                    let suffixes = self.recognize_state_fast(
8115                        atn,
8116                        FastRecognizeRequest {
8117                            state_number: shape.exit_target,
8118                            stop_state: request.stop_state,
8119                            index: path.index,
8120                            rule_start_index: request.rule_start_index,
8121                            decision_start_index: request.decision_start_index,
8122                            precedence: request.precedence,
8123                            depth: request.depth.saturating_add(1),
8124                            recovery_symbols: Rc::clone(&request.recovery_symbols),
8125                            recovery_state: request.recovery_state,
8126                        },
8127                        FastRecognizeScratch {
8128                            predicate_context,
8129                            visiting: &mut *visiting,
8130                            memo: &mut *memo,
8131                            expected: &mut *expected,
8132                            native_depth: native_depth + 1,
8133                        },
8134                    );
8135                    for mut outcome in suffixes {
8136                        outcome.deferred_nodes = self
8137                            .recognition_arena
8138                            .concat_deferred_nodes(path.deferred_nodes, outcome.deferred_nodes);
8139                        outcome.diagnostics = self
8140                            .recognition_arena
8141                            .concat_diagnostics(path.diagnostics, outcome.diagnostics);
8142                        outcome.consumed_eof |= path.consumed_eof;
8143                        outcomes.push(outcome);
8144                    }
8145                }
8146            }
8147        }
8148        dedupe_clean_fast_outcomes(&mut outcomes, &mut self.fast_outcome_dedup);
8149        outcomes
8150    }
8151
8152    /// Attempts to reach `stop_state` from `state_number` without committing
8153    /// token consumption to the parser's public stream position.
8154    fn recognize_state_fast(
8155        &mut self,
8156        atn: &Atn,
8157        request: FastRecognizeRequest,
8158        scratch: FastRecognizeScratch<'_, '_>,
8159    ) -> Vec<FastRecognizeOutcome> {
8160        if scratch.native_depth != 0 && scratch.native_depth < FAST_RECOGNIZE_STACK_CHECK_INTERVAL {
8161            return self.recognize_state_fast_inner(atn, request, scratch);
8162        }
8163        self.recognize_state_fast_checked(atn, request, scratch)
8164    }
8165
8166    #[inline(never)]
8167    fn recognize_state_fast_checked(
8168        &mut self,
8169        atn: &Atn,
8170        request: FastRecognizeRequest,
8171        mut scratch: FastRecognizeScratch<'_, '_>,
8172    ) -> Vec<FastRecognizeOutcome> {
8173        scratch.native_depth = 1;
8174        stacker::maybe_grow(FAST_RECOGNIZE_RED_ZONE, FAST_RECOGNIZE_STACK_SIZE, || {
8175            self.recognize_state_fast_inner(atn, request, scratch)
8176        })
8177    }
8178
8179    #[allow(clippy::too_many_lines)]
8180    fn recognize_state_fast_inner(
8181        &mut self,
8182        atn: &Atn,
8183        request: FastRecognizeRequest,
8184        scratch: FastRecognizeScratch<'_, '_>,
8185    ) -> Vec<FastRecognizeOutcome> {
8186        #[cfg(feature = "perf-counters")]
8187        perf_counters::inc(&perf_counters::RFS_CALLS, 1);
8188        let FastRecognizeScratch {
8189            predicate_context,
8190            visiting,
8191            memo,
8192            expected,
8193            native_depth,
8194        } = scratch;
8195        let FastRecognizeRequest {
8196            mut state_number,
8197            stop_state,
8198            mut index,
8199            rule_start_index,
8200            decision_start_index,
8201            precedence,
8202            mut depth,
8203            recovery_symbols,
8204            recovery_state,
8205        } = request;
8206        let max_token_type = atn.max_token_type();
8207        // Walk straight-line epsilon chains in a loop instead of recursing
8208        // into `recognize_state_fast` for each intermediate state. ATN
8209        // serialization places long sequences of `BasicBlock` epsilon
8210        // transitions between decisions: turning that chain into a loop
8211        // collapses many recursive calls (and their memo lookups, vec
8212        // allocations, and visit-set churn) into a single function frame.
8213        // The loop exits as soon as we hit the original state's logic
8214        // (multi-alt, decision, rule call, unmatched atom/range/set, gated
8215        // precedence) so existing fanout, recovery, and memoization still
8216        // apply unchanged.
8217        //
8218        // The inline case also handles single-atom-match states on the
8219        // happy-pass path: when the lone consuming transition matches the
8220        // current lookahead, advance the index and continue without paying
8221        // for a full `recognize_state_fast` recursion. We track tokens we
8222        // consumed inline in `inline_consumed_tokens` so they can be
8223        // prepended onto the eventual outcome list once we hit a state
8224        // whose handling falls outside this fast loop.
8225        let mut inline_consumed_tokens: Vec<usize> = Vec::new();
8226        let mut inline_consumed_eof = false;
8227        loop {
8228            if depth > RECOGNITION_DEPTH_LIMIT {
8229                return Vec::new();
8230            }
8231            if state_number == stop_state {
8232                let mut nodes = NodeSeqId::EMPTY;
8233                if self.fast_token_nodes_enabled {
8234                    for token_index in inline_consumed_tokens.iter().rev() {
8235                        let token = self.arena_token_node(*token_index, false);
8236                        self.arena_prepend(&mut nodes, token);
8237                    }
8238                }
8239                return vec![FastRecognizeOutcome {
8240                    index,
8241                    consumed_eof: inline_consumed_eof,
8242                    diagnostics: DiagnosticSeqId::EMPTY,
8243                    deferred_nodes: FastDeferredNodeId::EMPTY,
8244                    nodes,
8245                }];
8246            }
8247            let Some(state) = atn.state(state_number) else {
8248                return Vec::new();
8249            };
8250            let transitions = state.transitions();
8251            if transitions.len() == 1 && !state.precedence_rule_decision() {
8252                let transition = transitions
8253                    .first()
8254                    .expect("single transition checked above");
8255                let transition_kind = transition.kind();
8256                let target = transition.target();
8257                match transition_kind {
8258                    ParserTransitionKind::Epsilon | ParserTransitionKind::Action
8259                        if left_recursive_boundary(atn, state, target).is_none() =>
8260                    {
8261                        #[cfg(feature = "perf-counters")]
8262                        perf_counters::inc(&perf_counters::EPSILON_TRANSITIONS, 1);
8263                        state_number = target;
8264                        depth += 1;
8265                        continue;
8266                    }
8267                    ParserTransitionKind::Predicate
8268                        if left_recursive_boundary(atn, state, target).is_none() =>
8269                    {
8270                        #[cfg(feature = "perf-counters")]
8271                        perf_counters::inc(&perf_counters::EPSILON_TRANSITIONS, 1);
8272                        if !self.fast_parser_predicate_matches(predicate_context, transition, index)
8273                        {
8274                            record_predicate_no_viable(expected, decision_start_index, index);
8275                            return Vec::new();
8276                        }
8277                        state_number = target;
8278                        depth += 1;
8279                        continue;
8280                    }
8281                    ParserTransitionKind::Precedence
8282                        if packed_i32(transition.arg0()) >= precedence
8283                            && left_recursive_boundary(atn, state, target).is_none() =>
8284                    {
8285                        #[cfg(feature = "perf-counters")]
8286                        perf_counters::inc(&perf_counters::EPSILON_TRANSITIONS, 1);
8287                        state_number = target;
8288                        depth += 1;
8289                        continue;
8290                    }
8291                    // Single-atom / range / set / wildcard / not-set states
8292                    // are common (~17K of ~125K calls on C#) and almost
8293                    // always succeed in pass 1: no fanout, no recovery, no
8294                    // diagnostics. Inline the token match and continue
8295                    // walking instead of recursing — the recursive path
8296                    // would just allocate a Vec, build one outcome, prepend
8297                    // a Token node, and return. Skip pass 2 (recovery
8298                    // enabled): there the failure branch matters and the
8299                    // existing recursive code records expected symbols.
8300                    ParserTransitionKind::Atom
8301                    | ParserTransitionKind::Range
8302                    | ParserTransitionKind::Set
8303                    | ParserTransitionKind::NotSet
8304                    | ParserTransitionKind::Wildcard
8305                        if !self.fast_recovery_enabled =>
8306                    {
8307                        let symbol = self.token_type_at(index);
8308                        if transition.matches_kind(transition_kind, symbol, 1, max_token_type) {
8309                            #[cfg(feature = "perf-counters")]
8310                            perf_counters::inc(&perf_counters::ATOM_RANGE_TRANSITIONS, 1);
8311                            if self.fast_token_nodes_enabled {
8312                                inline_consumed_tokens.push(index);
8313                            }
8314                            inline_consumed_eof |= symbol == TOKEN_EOF;
8315                            index = self.consume_index(index, symbol);
8316                            state_number = target;
8317                            depth += 1;
8318                            continue;
8319                        }
8320                        // Fall through to break and let the regular
8321                        // body handle the no-match case (returns empty).
8322                    }
8323                    _ => {}
8324                }
8325            }
8326            break;
8327        }
8328        // If we collected token nodes inline but bail to the recursive
8329        // body (decision state, rule call, etc.), the outcomes returned
8330        // below will need those token nodes prepended.
8331        let inline_pending = !inline_consumed_tokens.is_empty() || inline_consumed_eof;
8332        let Some(state) = atn.state(state_number) else {
8333            return Vec::new();
8334        };
8335        let transitions = state.transitions();
8336        let transition_count = transitions.len();
8337        if !self.fast_recovery_enabled
8338            && let Some(shape) = fast_repetition_shape(atn, state)
8339        {
8340            let mut outcomes = self.recognize_repetition_fast(
8341                atn,
8342                &FastRecognizeRequest {
8343                    state_number,
8344                    stop_state,
8345                    index,
8346                    rule_start_index,
8347                    decision_start_index,
8348                    precedence,
8349                    depth,
8350                    recovery_symbols: Rc::clone(&recovery_symbols),
8351                    recovery_state,
8352                },
8353                shape,
8354                FastRecognizeScratch {
8355                    predicate_context,
8356                    visiting: &mut *visiting,
8357                    memo: &mut *memo,
8358                    expected: &mut *expected,
8359                    native_depth: native_depth + 1,
8360                },
8361            );
8362            if inline_pending {
8363                for outcome in &mut outcomes {
8364                    outcome.consumed_eof |= inline_consumed_eof;
8365                    if self.fast_token_nodes_enabled {
8366                        for token_index in inline_consumed_tokens.iter().rev() {
8367                            let token = self.arena_token_node(*token_index, false);
8368                            self.defer_fast_outcome_node(outcome, token);
8369                        }
8370                    }
8371                }
8372            }
8373            return outcomes;
8374        }
8375        // In pass 1 (`fast_recovery_enabled == false`) the recovery-related
8376        // fields and the rule/decision boundary indices are pure plumbing —
8377        // they only affect the recovery branch and the no-viable diagnostic
8378        // recording, neither of which fires when recovery is off. Zeroing
8379        // them in the memo key collapses calls that visit the same
8380        // `(state, index)` from different rule-call sites onto one cache
8381        // entry, which is the dominant cost on large grammars (e.g. C#) where
8382        // many rules eventually delegate into the same `expression` /
8383        // `primary_expression` / `type` branches.
8384        let key = if self.fast_recovery_enabled {
8385            FastRecognizeKey {
8386                state_number,
8387                stop_state,
8388                index,
8389                rule_start_index,
8390                decision_start_index,
8391                precedence,
8392                recovery_symbols_id: Rc::as_ptr(&recovery_symbols) as usize,
8393                recovery_state,
8394            }
8395        } else {
8396            FastRecognizeKey {
8397                state_number,
8398                stop_state,
8399                index,
8400                rule_start_index: 0,
8401                decision_start_index: None,
8402                precedence,
8403                recovery_symbols_id: 0,
8404                recovery_state: None,
8405            }
8406        };
8407        // Once the clean-pass probe has established that coordinates do not
8408        // repeat, stop paying for the full memo table. Recovery always keeps
8409        // memoization because cached failures carry diagnostics, while
8410        // repeat-heavy clean parses promote before reaching sparse mode.
8411        let memo_lookup_enabled = self.fast_recovery_enabled
8412            || (transition_count > 1 && self.clean_memo_enabled_for_key(&key));
8413        if memo_lookup_enabled {
8414            if let Some(outcomes) = memo.get(&key) {
8415                #[cfg(feature = "perf-counters")]
8416                {
8417                    perf_counters::inc(&perf_counters::RFS_MEMO_HITS, 1);
8418                    perf_counters::inc(&perf_counters::OUTCOMES_CLONED, outcomes.len() as u64);
8419                }
8420                // Materialize a fresh `Vec` from the cached slice; the caller
8421                // mutates per-outcome state (eof flags, prepended nodes) so we
8422                // can't hand them the shared backing.
8423                if !inline_consumed_tokens.is_empty() || inline_consumed_eof {
8424                    let inline_eof = inline_consumed_eof;
8425                    let inline_tokens = &inline_consumed_tokens;
8426                    return outcomes
8427                        .iter()
8428                        .copied()
8429                        .map(|mut outcome| {
8430                            if inline_eof {
8431                                outcome.consumed_eof = true;
8432                            }
8433                            if self.fast_token_nodes_enabled {
8434                                for token_index in inline_tokens.iter().rev() {
8435                                    let token = self.arena_token_node(*token_index, false);
8436                                    self.defer_fast_outcome_node(&mut outcome, token);
8437                                }
8438                            }
8439                            outcome
8440                        })
8441                        .collect();
8442                }
8443                return outcomes.to_vec();
8444            }
8445            #[cfg(feature = "perf-counters")]
8446            perf_counters::inc(&perf_counters::RFS_MEMO_MISSES, 1);
8447        }
8448
8449        // Cycle detection: clean recognition keeps the narrow static cycle
8450        // guard used on hot paths. Recovery needs the broader epsilon-state
8451        // guard because an otherwise non-nullable loop body can recover as an
8452        // empty child at EOF and re-enter the loop at the same token.
8453        let needs_cycle_guard = if self.fast_recovery_enabled {
8454            transitions.iter().any(ParserTransition::is_epsilon)
8455        } else {
8456            transition_count > 1 && self.state_can_reenter_without_consuming(atn, state_number)
8457        };
8458        #[cfg(feature = "perf-counters")]
8459        if needs_cycle_guard {
8460            perf_counters::inc(&perf_counters::MULTI_TRANS_BODY, 1);
8461        } else {
8462            perf_counters::inc(&perf_counters::SINGLE_TRANS_BODY, 1);
8463            match state
8464                .transitions()
8465                .first()
8466                .expect("single-transition path requires one transition")
8467                .data()
8468            {
8469                Transition::Rule { .. } => {
8470                    perf_counters::inc(&perf_counters::SINGLE_TRANS_RULE, 1);
8471                }
8472                Transition::Atom { .. }
8473                | Transition::Range { .. }
8474                | Transition::Set { .. }
8475                | Transition::NotSet { .. }
8476                | Transition::Wildcard { .. } => {
8477                    perf_counters::inc(&perf_counters::SINGLE_TRANS_ATOM, 1);
8478                }
8479                _ => {
8480                    perf_counters::inc(&perf_counters::SINGLE_TRANS_OTHER, 1);
8481                }
8482            }
8483        }
8484        let has_inserted_cycle_guard = if needs_cycle_guard {
8485            if !visiting.insert(key.clone()) {
8486                #[cfg(feature = "perf-counters")]
8487                perf_counters::inc(&perf_counters::RFS_VISITING_CYCLE, 1);
8488                return Vec::new();
8489            }
8490            true
8491        } else {
8492            false
8493        };
8494        let next_decision_start_index = if starts_prediction_decision(state, transition_count) {
8495            Some(index)
8496        } else {
8497            decision_start_index
8498        };
8499        let (epsilon_recovery_symbols, epsilon_recovery_state) = if self.fast_recovery_enabled {
8500            fast_next_recovery_context(self, atn, state, &recovery_symbols, recovery_state)
8501        } else {
8502            (Rc::clone(&recovery_symbols), recovery_state)
8503        };
8504
8505        // Lookahead-based pruning. At a multi-alternative state we cache the
8506        // look-1 set of every outgoing transition; on visit we keep only the
8507        // transitions whose look-1 can accept the current lookahead (or that
8508        // can be reached without consuming and so could legitimately match a
8509        // shorter input). This is the main speedup vs. blind speculative
8510        // recursion: it lets each visit fan out only to the alternatives that
8511        // could possibly contribute a clean parse, mirroring the SLL phase of
8512        // ANTLR's adaptive prediction.
8513        //
8514        // Pruning is skipped at:
8515        //   * rule-start states (a child rule call may need every internal
8516        //     transition to surface single-token recovery diagnostics that
8517        //     ANTLR's reference parser emits at the rule's first consuming
8518        //     transition; the FIRST-set retry path turns the prefilter off
8519        //     entirely so let's keep this lightweight too),
8520        //   * left-recursive precedence loops (the precedence transition's
8521        //     gating is dynamic),
8522        //   * states with too few alternatives to benefit.
8523        let lookahead_filter = if transition_count > 1
8524            && self.fast_first_set_prefilter
8525            && !state.precedence_rule_decision()
8526            && (!self.fast_recovery_enabled || state.kind() != AtnStateKind::RuleStart)
8527        {
8528            state
8529                .rule_index()
8530                .and_then(|rule_index| atn.rule_to_stop_state().get(rule_index))
8531                .map(|rule_stop| {
8532                    let symbol = self.token_type_at(index);
8533                    let entry = self.cached_decision_lookahead(atn, state, rule_stop);
8534                    (symbol, entry)
8535                })
8536        } else {
8537            None
8538        };
8539        // LL(1) fast path: when the FIRST sets for the decision are disjoint
8540        // and none is nullable, the lookahead deterministically selects one
8541        // alternative. The recursive recognizer can then commit to that single
8542        // alt without iterating every transition through `should_skip_via_lookahead`
8543        // — saving (transition_count - 1) filter probes per visit.
8544        //
8545        // Result is cached per `(state, lookahead_token)` on the parser
8546        // instance, so subsequent visits skip the FIRST-set scan entirely.
8547        let ll1_only_alt: Option<usize> = if transition_count > 1
8548            && let Some((symbol, entry)) = lookahead_filter.as_ref()
8549        {
8550            let key = (state.state_number(), *symbol);
8551            if let Some(&cached) = self.ll1_decision_cache.get(&key) {
8552                cached
8553            } else {
8554                let result = ll1_unique_alt(entry, *symbol);
8555                self.ll1_decision_cache.insert(key, result);
8556                result
8557            }
8558        } else {
8559            None
8560        };
8561        let lookahead_filter = lookahead_filter.as_ref();
8562        // Pre-size only when we expect at least one outcome to land — most
8563        // single-transition fall-throughs (the loop above didn't catch
8564        // because they're atom/rule/predicate) push at most one entry, so
8565        // reserving one slot avoids a reallocation while keeping the
8566        // unused-slot waste at one element.
8567        let mut outcomes: Vec<FastRecognizeOutcome> = Vec::with_capacity(transition_count.min(2));
8568        for (transition_index, transition) in transitions.iter().enumerate() {
8569            if let Some(alt) = ll1_only_alt {
8570                // LL(1) determinism: skip every alt except the chosen one.
8571                if alt != transition_index {
8572                    continue;
8573                }
8574            }
8575            let transition_kind = transition.kind();
8576            if ll1_only_alt.is_none()
8577                && should_skip_via_lookahead(
8578                    transition_kind,
8579                    transition_index,
8580                    lookahead_filter,
8581                    index,
8582                    self.fast_recovery_enabled,
8583                    expected,
8584                )
8585            {
8586                continue;
8587            }
8588            let target = transition.target();
8589            match transition_kind {
8590                ParserTransitionKind::Epsilon | ParserTransitionKind::Action => {
8591                    #[cfg(feature = "perf-counters")]
8592                    perf_counters::inc(&perf_counters::EPSILON_TRANSITIONS, 1);
8593                    let boundary = left_recursive_boundary(atn, state, target);
8594                    outcomes.extend(
8595                        self.recognize_state_fast(
8596                            atn,
8597                            FastRecognizeRequest {
8598                                state_number: target,
8599                                stop_state,
8600                                index,
8601                                rule_start_index,
8602                                decision_start_index: next_decision_start_index,
8603                                precedence,
8604                                depth: depth + 1,
8605                                recovery_symbols: Rc::clone(&epsilon_recovery_symbols),
8606                                recovery_state: epsilon_recovery_state,
8607                            },
8608                            FastRecognizeScratch {
8609                                predicate_context,
8610                                visiting,
8611                                memo,
8612                                expected,
8613                                native_depth: native_depth + 1,
8614                            },
8615                        )
8616                        .into_iter()
8617                        .map(|mut outcome| {
8618                            if let Some(rule_index) = boundary {
8619                                let boundary = self.arena_boundary_node(rule_index, 0);
8620                                self.defer_fast_outcome_node(&mut outcome, boundary);
8621                            }
8622                            outcome
8623                        }),
8624                    );
8625                }
8626                ParserTransitionKind::Predicate => {
8627                    #[cfg(feature = "perf-counters")]
8628                    perf_counters::inc(&perf_counters::EPSILON_TRANSITIONS, 1);
8629                    if self.fast_parser_predicate_matches(predicate_context, transition, index) {
8630                        let boundary = left_recursive_boundary(atn, state, target);
8631                        outcomes.extend(
8632                            self.recognize_state_fast(
8633                                atn,
8634                                FastRecognizeRequest {
8635                                    state_number: target,
8636                                    stop_state,
8637                                    index,
8638                                    rule_start_index,
8639                                    decision_start_index: next_decision_start_index,
8640                                    precedence,
8641                                    depth: depth + 1,
8642                                    recovery_symbols: Rc::clone(&epsilon_recovery_symbols),
8643                                    recovery_state: epsilon_recovery_state,
8644                                },
8645                                FastRecognizeScratch {
8646                                    predicate_context,
8647                                    visiting,
8648                                    memo,
8649                                    expected,
8650                                    native_depth: native_depth + 1,
8651                                },
8652                            )
8653                            .into_iter()
8654                            .map(|mut outcome| {
8655                                if let Some(rule_index) = boundary {
8656                                    let boundary = self.arena_boundary_node(rule_index, 0);
8657                                    self.defer_fast_outcome_node(&mut outcome, boundary);
8658                                }
8659                                outcome
8660                            }),
8661                        );
8662                    } else {
8663                        record_predicate_no_viable(expected, next_decision_start_index, index);
8664                    }
8665                }
8666                ParserTransitionKind::Precedence => {
8667                    let transition_precedence = packed_i32(transition.arg0());
8668                    if transition_precedence >= precedence {
8669                        let boundary = left_recursive_boundary(atn, state, target);
8670                        outcomes.extend(
8671                            self.recognize_state_fast(
8672                                atn,
8673                                FastRecognizeRequest {
8674                                    state_number: target,
8675                                    stop_state,
8676                                    index,
8677                                    rule_start_index,
8678                                    decision_start_index: next_decision_start_index,
8679                                    precedence,
8680                                    depth: depth + 1,
8681                                    recovery_symbols: Rc::clone(&epsilon_recovery_symbols),
8682                                    recovery_state: epsilon_recovery_state,
8683                                },
8684                                FastRecognizeScratch {
8685                                    predicate_context,
8686                                    visiting,
8687                                    memo,
8688                                    expected,
8689                                    native_depth: native_depth + 1,
8690                                },
8691                            )
8692                            .into_iter()
8693                            .map(|mut outcome| {
8694                                if let Some(rule_index) = boundary {
8695                                    let boundary = self.arena_boundary_node(rule_index, 0);
8696                                    self.defer_fast_outcome_node(&mut outcome, boundary);
8697                                }
8698                                outcome
8699                            }),
8700                        );
8701                    }
8702                }
8703                ParserTransitionKind::Rule => {
8704                    let rule_index = transition.arg0() as usize;
8705                    let follow_state = transition.arg1() as usize;
8706                    let rule_precedence = packed_i32(transition.arg2());
8707                    #[cfg(feature = "perf-counters")]
8708                    perf_counters::inc(&perf_counters::RULE_TRANSITIONS, 1);
8709                    let Some(child_stop) = atn.rule_to_stop_state().get(rule_index) else {
8710                        continue;
8711                    };
8712                    // Lookahead-based pruning. The recognizer would otherwise
8713                    // explore every speculative rule call, producing exponential
8714                    // work on grammars with many epsilon-reachable rules. When
8715                    // the rule is non-nullable and its FIRST set excludes the
8716                    // current lookahead, recursion can't find a clean path
8717                    // *through this rule*. Skipping is only safe if some sibling
8718                    // transition can still consume the lookahead — otherwise the
8719                    // rule call is the sole continuation and must run so the
8720                    // single-token insertion / deletion recovery inside the
8721                    // called rule can fire (mirroring ANTLR's reference behavior
8722                    // of conjuring a missing token at child-rule entry).
8723                    let symbol = self.token_type_at(index);
8724                    if self.fast_first_set_prefilter {
8725                        // Probe the shared cross-parse cache first; build
8726                        // the entry on miss and intern it there. The
8727                        // computation is purely a function of the ATN, so
8728                        // the cached entry is reused across parses (and
8729                        // freshly-instantiated parser values that share
8730                        // the same `&'static Atn`).
8731                        //
8732                        // `rule_first_set` returns the computed entry
8733                        // directly — it intentionally skips inserting into
8734                        // the cache when the FIRST-set walk hit a cycle, so
8735                        // we cannot assume the entry is in the cache after
8736                        // computing it.
8737                        let first = self.cached_rule_first_set(atn, target, child_stop);
8738                        if should_skip_rule_via_first_set(
8739                            &first,
8740                            symbol,
8741                            self.fast_recovery_enabled,
8742                            index,
8743                            expected,
8744                        ) {
8745                            continue;
8746                        }
8747                    }
8748                    let expected_before_child =
8749                        self.fast_recovery_enabled.then(|| expected.clone());
8750                    let mut children = self.recognize_state_fast(
8751                        atn,
8752                        FastRecognizeRequest {
8753                            state_number: target,
8754                            stop_state: child_stop,
8755                            index,
8756                            rule_start_index: index,
8757                            decision_start_index: None,
8758                            precedence: rule_precedence,
8759                            depth: depth + 1,
8760                            recovery_symbols: Rc::clone(&epsilon_recovery_symbols),
8761                            recovery_state: epsilon_recovery_state,
8762                        },
8763                        FastRecognizeScratch {
8764                            predicate_context,
8765                            visiting,
8766                            memo,
8767                            expected,
8768                            native_depth: native_depth + 1,
8769                        },
8770                    );
8771                    if children.is_empty() && self.fast_recovery_enabled {
8772                        children = self.fast_child_rule_failure_recovery_outcomes(
8773                            FastChildRuleFailureRecoveryRequest {
8774                                atn,
8775                                rule_index,
8776                                start_index: index,
8777                                follow_state,
8778                                stop_state,
8779                                expected,
8780                            },
8781                        );
8782                    }
8783                    if let Some(expected_before_child) = expected_before_child {
8784                        if children
8785                            .iter()
8786                            .any(|child| child.diagnostics.is_empty() && child.index > index)
8787                        {
8788                            *expected = expected_before_child;
8789                        }
8790                    }
8791                    for child in children {
8792                        let child_index = child.index;
8793                        let child_consumed_eof = child.consumed_eof;
8794                        let child_diagnostics = child.diagnostics;
8795                        let empty_recovery = self.empty_recovery_symbols();
8796                        let follow_outcomes = self.recognize_state_fast(
8797                            atn,
8798                            FastRecognizeRequest {
8799                                state_number: follow_state,
8800                                stop_state,
8801                                index: child_index,
8802                                rule_start_index,
8803                                decision_start_index: next_decision_start_index,
8804                                precedence,
8805                                depth: depth + 1,
8806                                recovery_symbols: empty_recovery,
8807                                recovery_state: None,
8808                            },
8809                            FastRecognizeScratch {
8810                                predicate_context,
8811                                visiting,
8812                                memo,
8813                                expected,
8814                                native_depth: native_depth + 1,
8815                            },
8816                        );
8817                        if follow_outcomes.is_empty() {
8818                            continue;
8819                        }
8820                        let child_stop_index =
8821                            self.rule_stop_token_index(child_index, child_consumed_eof);
8822                        let child_node = self.build_parse_trees.then(|| {
8823                            self.recognition_arena.deferred_rule_node(FastDeferredRule {
8824                                rule_index: u32::try_from(rule_index)
8825                                    .expect("rule index fits in u32"),
8826                                invoking_state: i32::try_from(invoking_state_number(state_number))
8827                                    .expect("invoking state fits in i32"),
8828                                start_index: u32::try_from(index)
8829                                    .expect("rule start index fits in u32"),
8830                                stop_index: child_stop_index.map(|stop_index| {
8831                                    u32::try_from(stop_index).expect("rule stop index fits in u32")
8832                                }),
8833                                deferred_children: child.deferred_nodes,
8834                                children: child.nodes,
8835                            })
8836                        });
8837                        let child_diags_empty = child_diagnostics.is_empty();
8838                        outcomes.extend(follow_outcomes.into_iter().map(|mut outcome| {
8839                            outcome.consumed_eof |= child_consumed_eof;
8840                            // Skip the prepend dance when there's nothing to
8841                            // merge from the child — common case in pass 1.
8842                            if !child_diags_empty {
8843                                outcome.diagnostics = self
8844                                    .recognition_arena
8845                                    .concat_diagnostics(child_diagnostics, outcome.diagnostics);
8846                            }
8847                            if let Some(child_node) = child_node {
8848                                outcome.deferred_nodes = self
8849                                    .recognition_arena
8850                                    .concat_deferred_nodes(child_node, outcome.deferred_nodes);
8851                            }
8852                            outcome
8853                        }));
8854                    }
8855                }
8856                ParserTransitionKind::Atom
8857                | ParserTransitionKind::Range
8858                | ParserTransitionKind::Set
8859                | ParserTransitionKind::NotSet
8860                | ParserTransitionKind::Wildcard => {
8861                    #[cfg(feature = "perf-counters")]
8862                    perf_counters::inc(&perf_counters::ATOM_RANGE_TRANSITIONS, 1);
8863                    let symbol = self.token_type_at(index);
8864                    if transition.matches_kind(transition_kind, symbol, 1, max_token_type) {
8865                        let next_index = self.consume_index(index, symbol);
8866                        let empty_recovery = self.empty_recovery_symbols();
8867                        outcomes.extend(
8868                            self.recognize_state_fast(
8869                                atn,
8870                                FastRecognizeRequest {
8871                                    state_number: target,
8872                                    stop_state,
8873                                    index: next_index,
8874                                    rule_start_index,
8875                                    decision_start_index: next_decision_start_index,
8876                                    precedence,
8877                                    depth: depth + 1,
8878                                    recovery_symbols: empty_recovery,
8879                                    recovery_state: None,
8880                                },
8881                                FastRecognizeScratch {
8882                                    predicate_context,
8883                                    visiting,
8884                                    memo,
8885                                    expected,
8886                                    native_depth: native_depth + 1,
8887                                },
8888                            )
8889                            .into_iter()
8890                            .map(|mut outcome| {
8891                                outcome.consumed_eof |= symbol == TOKEN_EOF;
8892                                if self.fast_token_nodes_enabled {
8893                                    let token = self.arena_token_node(index, false);
8894                                    self.defer_fast_outcome_node(&mut outcome, token);
8895                                }
8896                                outcome
8897                            }),
8898                        );
8899                    } else {
8900                        if !self.fast_recovery_enabled {
8901                            // In pass 1 there is no recovery to attempt; the
8902                            // recovery branch below would never run, and the
8903                            // `expected_symbols` computation is just there
8904                            // to gate that branch. Skipping it eliminates
8905                            // ~1× `state_expected_symbols` lookup per failed
8906                            // atom transition (≈82K on mono-statement.cs)
8907                            // for zero observable behavior change.
8908                            continue;
8909                        }
8910                        let expected_symbols = fast_recovery_expected_symbols(
8911                            self,
8912                            atn,
8913                            state.state_number(),
8914                            &recovery_symbols,
8915                        );
8916                        if expected_symbols.contains(&symbol) {
8917                            continue;
8918                        }
8919                        {
8920                            expected.record_transition(index, transition, max_token_type);
8921                            record_no_viable_if_ambiguous(
8922                                expected,
8923                                next_decision_start_index,
8924                                index,
8925                            );
8926                            outcomes.extend(self.fast_single_token_deletion_recovery(
8927                                FastRecoveryRequest {
8928                                    atn,
8929                                    transition,
8930                                    expected_symbols: Rc::clone(&expected_symbols),
8931                                    target,
8932                                    request: FastRecognizeRequest {
8933                                        state_number,
8934                                        stop_state,
8935                                        index,
8936                                        rule_start_index,
8937                                        decision_start_index,
8938                                        precedence,
8939                                        depth,
8940                                        recovery_symbols: Rc::clone(&recovery_symbols),
8941                                        recovery_state,
8942                                    },
8943                                    visiting,
8944                                    memo,
8945                                    expected,
8946                                },
8947                                predicate_context,
8948                            ));
8949                            if !state_is_left_recursive_rule(atn, state) {
8950                                outcomes.extend(self.fast_single_token_insertion_recovery(
8951                                    FastRecoveryRequest {
8952                                        atn,
8953                                        transition,
8954                                        expected_symbols: Rc::clone(&expected_symbols),
8955                                        target,
8956                                        request: FastRecognizeRequest {
8957                                            state_number,
8958                                            stop_state,
8959                                            index,
8960                                            rule_start_index,
8961                                            decision_start_index,
8962                                            precedence,
8963                                            depth,
8964                                            recovery_symbols: Rc::clone(&recovery_symbols),
8965                                            recovery_state,
8966                                        },
8967                                        visiting,
8968                                        memo,
8969                                        expected,
8970                                    },
8971                                    predicate_context,
8972                                ));
8973                            }
8974                            outcomes.extend(self.fast_current_token_deletion_recovery(
8975                                FastCurrentTokenDeletionRequest {
8976                                    atn,
8977                                    expected_symbols,
8978                                    request: FastRecognizeRequest {
8979                                        state_number,
8980                                        stop_state,
8981                                        index,
8982                                        rule_start_index,
8983                                        decision_start_index,
8984                                        precedence,
8985                                        depth,
8986                                        recovery_symbols: Rc::clone(&recovery_symbols),
8987                                        recovery_state,
8988                                    },
8989                                    visiting,
8990                                    memo,
8991                                    expected,
8992                                },
8993                                predicate_context,
8994                            ));
8995                        }
8996                    }
8997                }
8998            }
8999        }
9000
9001        if has_inserted_cycle_guard {
9002            visiting.remove(&key);
9003        }
9004        if matches!(
9005            self.prediction_mode,
9006            PredictionMode::Ll | PredictionMode::LlExactAmbigDetection
9007        ) && self.fast_recovery_enabled
9008        {
9009            // Without recovery enabled every outcome already has empty
9010            // diagnostics, so the discard pass is a no-op — skipping it
9011            // saves an iter+retain on each of the ~1M visits.
9012            discard_recovered_fast_outcomes_if_clean_path_exists(&mut outcomes);
9013        }
9014        if self.fast_recovery_enabled {
9015            dedupe_fast_outcomes(&mut outcomes, &self.recognition_arena);
9016        } else {
9017            dedupe_clean_fast_outcomes(&mut outcomes, &mut self.fast_outcome_dedup);
9018        }
9019        // Skip memoization for single-transition states whose outcome is
9020        // unambiguous: they only get re-entered if the caller revisits the
9021        // exact same call site, which is rare since the loop above already
9022        // collapsed straight-line epsilon walks. Multi-alternative states
9023        // are where backtracking actually revisits the same coordinate, so
9024        // we still memoize there. With recovery on we keep the existing
9025        // memoization unconditionally because the recovery branch may
9026        // record diagnostics that the cache must surface to repeated
9027        // failed visits.
9028        let should_memoize = self.fast_recovery_enabled
9029            || (transition_count > 1 && self.clean_memo_mode != CleanMemoMode::Sparse);
9030        // Apply inline pending state to each outcome before returning.
9031        // Tokens consumed inline by the loop-collapse don't appear in the
9032        // recursive recognizer's output, so we need to prepend them here.
9033        let mut apply_inline_pending = |mut outcome: FastRecognizeOutcome| -> FastRecognizeOutcome {
9034            if inline_consumed_eof {
9035                outcome.consumed_eof = true;
9036            }
9037            if !inline_consumed_tokens.is_empty() {
9038                for token_index in inline_consumed_tokens.iter().rev() {
9039                    let token = self.arena_token_node(*token_index, false);
9040                    self.defer_fast_outcome_node(&mut outcome, token);
9041                }
9042            }
9043            outcome
9044        };
9045        if should_memoize {
9046            #[cfg(feature = "perf-counters")]
9047            {
9048                perf_counters::inc(&perf_counters::MEMO_INSERTED, 1);
9049                perf_counters::inc(&perf_counters::OUTCOMES_PUSHED, outcomes.len() as u64);
9050                match outcomes.len() {
9051                    0 => perf_counters::inc(&perf_counters::OUTCOMES_RETURN_0, 1),
9052                    1 => perf_counters::inc(&perf_counters::OUTCOMES_RETURN_1, 1),
9053                    _ => perf_counters::inc(&perf_counters::OUTCOMES_RETURN_N, 1),
9054                }
9055            }
9056            // The memo is keyed by the loop-exit `(state_number, index)` so
9057            // the inline-consumed tokens belong to *this* call's output, not
9058            // the cached result. Memoize the bare outcomes (without the
9059            // inline-pending data), then prepend the inline data on return.
9060            let stored: Rc<[FastRecognizeOutcome]> = Rc::from(outcomes);
9061            memo.insert(key, Rc::clone(&stored));
9062            if inline_pending {
9063                return stored
9064                    .iter()
9065                    .copied()
9066                    .map(&mut apply_inline_pending)
9067                    .collect();
9068            }
9069            return stored.to_vec();
9070        }
9071        #[cfg(feature = "perf-counters")]
9072        match outcomes.len() {
9073            0 => perf_counters::inc(&perf_counters::OUTCOMES_RETURN_0, 1),
9074            1 => perf_counters::inc(&perf_counters::OUTCOMES_RETURN_1, 1),
9075            _ => perf_counters::inc(&perf_counters::OUTCOMES_RETURN_N, 1),
9076        }
9077        if inline_pending {
9078            return outcomes.into_iter().map(apply_inline_pending).collect();
9079        }
9080        outcomes
9081    }
9082
9083    /// Explores single-token deletion recovery while preserving the matched
9084    /// token and skipped error token in the selected parse tree path.
9085    fn single_token_deletion_recovery(
9086        &mut self,
9087        recovery: RecoveryRequest<'_, '_>,
9088    ) -> Vec<RecognizeOutcome> {
9089        let RecoveryRequest {
9090            atn,
9091            transition,
9092            expected_symbols,
9093            target,
9094            request,
9095            visiting,
9096            memo,
9097            expected,
9098        } = recovery;
9099        let RecognizeRequest {
9100            stop_state,
9101            index,
9102            rule_start_index,
9103            decision_start_index,
9104            init_action_rules,
9105            predicates,
9106            semantics,
9107            rule_args,
9108            member_actions,
9109            return_actions,
9110            local_int_arg,
9111            member_values,
9112            return_values,
9113            rule_alt_number,
9114            track_alt_numbers,
9115            consumed_eof,
9116            precedence,
9117            depth,
9118            ..
9119        } = request;
9120        let Some((diagnostic, next_index, next_symbol)) =
9121            self.single_token_deletion(transition, index, atn.max_token_type(), &expected_symbols)
9122        else {
9123            return Vec::new();
9124        };
9125        let after_next = self.consume_index(next_index, next_symbol);
9126        self.recognize_state(
9127            atn,
9128            RecognizeRequest {
9129                state_number: target,
9130                stop_state,
9131                index: after_next,
9132                rule_start_index,
9133                decision_start_index,
9134                init_action_rules,
9135                predicates,
9136                semantics,
9137                rule_args,
9138                member_actions,
9139                return_actions,
9140                local_int_arg,
9141                member_values,
9142                return_values,
9143                rule_alt_number,
9144                track_alt_numbers,
9145                consumed_eof: consumed_eof || next_symbol == TOKEN_EOF,
9146                committed_decision: false,
9147                precedence,
9148                depth: depth + 1,
9149                recovery_symbols: BTreeSet::new(),
9150                recovery_state: None,
9151            },
9152            visiting,
9153            memo,
9154            expected,
9155        )
9156        .into_iter()
9157        .map(|mut outcome| {
9158            outcome.consumed_eof |= next_symbol == TOKEN_EOF;
9159            outcome.diagnostics = self
9160                .recognition_arena
9161                .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
9162            let token = self.arena_token_node(next_index, false);
9163            self.arena_prepend(&mut outcome.nodes, token);
9164            let error = self.arena_token_node(index, true);
9165            self.arena_prepend(&mut outcome.nodes, error);
9166            outcome
9167        })
9168        .collect()
9169    }
9170
9171    /// Retries the current recognition state after deleting one unexpected
9172    /// token, preserving the deleted token as an error node in the parse tree.
9173    fn current_token_deletion_recovery(
9174        &mut self,
9175        recovery: CurrentTokenDeletionRequest<'_, '_>,
9176    ) -> Vec<RecognizeOutcome> {
9177        let CurrentTokenDeletionRequest {
9178            atn,
9179            expected_symbols,
9180            mut request,
9181            visiting,
9182            memo,
9183            expected,
9184        } = recovery;
9185        let error_index = request.index;
9186        if error_index == request.rule_start_index {
9187            return Vec::new();
9188        }
9189        let Some((diagnostic, next_index, skipped)) =
9190            self.current_token_deletion(error_index, &expected_symbols)
9191        else {
9192            return Vec::new();
9193        };
9194        request.state_number = request.recovery_state.unwrap_or(request.state_number);
9195        request.index = next_index;
9196        request.committed_decision = false;
9197        request.depth += 1;
9198        request.recovery_state = None;
9199        self.recognize_state(atn, request, visiting, memo, expected)
9200            .into_iter()
9201            .map(|mut outcome| {
9202                outcome.diagnostics = self
9203                    .recognition_arena
9204                    .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
9205                for index in skipped.iter().rev() {
9206                    let error = self.arena_token_node(*index, true);
9207                    self.arena_prepend(&mut outcome.nodes, error);
9208                }
9209                outcome
9210            })
9211            .collect()
9212    }
9213
9214    /// Falls back after deletion/insertion repairs cannot continue from a
9215    /// failed consuming transition.
9216    fn consuming_failure_fallback(
9217        &mut self,
9218        fallback: ConsumingFailureFallback<'_>,
9219        visiting: &mut BTreeSet<RecognizeKey>,
9220        memo: &mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
9221        expected: &mut ExpectedTokens,
9222    ) -> Vec<RecognizeOutcome> {
9223        if fallback.expected_symbols.is_empty() {
9224            return Vec::new();
9225        }
9226        if fallback.symbol == TOKEN_EOF {
9227            return self.eof_consuming_failure_fallback(fallback, expected);
9228        }
9229        self.non_eof_consuming_failure_fallback(fallback, visiting, memo, expected)
9230    }
9231
9232    /// Keeps unexpected non-EOF input visible as an error node when no repair
9233    /// path can otherwise reach the transition target.
9234    fn non_eof_consuming_failure_fallback(
9235        &mut self,
9236        fallback: ConsumingFailureFallback<'_>,
9237        visiting: &mut BTreeSet<RecognizeKey>,
9238        memo: &mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
9239        expected: &mut ExpectedTokens,
9240    ) -> Vec<RecognizeOutcome> {
9241        let ConsumingFailureFallback {
9242            atn,
9243            target,
9244            request,
9245            symbol,
9246            expected_symbols,
9247            decision_start_index,
9248            decision,
9249        } = fallback;
9250        let error_index = request.index;
9251        let diagnostic =
9252            self.recovery_failure_diagnostic(error_index, decision_start_index, &expected_symbols);
9253        let next_index = self.consume_index(error_index, symbol);
9254        self.recognize_state(
9255            atn,
9256            RecognizeRequest {
9257                state_number: target,
9258                stop_state: request.stop_state,
9259                index: next_index,
9260                rule_start_index: request.rule_start_index,
9261                decision_start_index,
9262                init_action_rules: request.init_action_rules,
9263                predicates: request.predicates,
9264                semantics: request.semantics,
9265                rule_args: request.rule_args,
9266                member_actions: request.member_actions,
9267                return_actions: request.return_actions,
9268                local_int_arg: request.local_int_arg,
9269                member_values: request.member_values,
9270                return_values: request.return_values,
9271                rule_alt_number: request.rule_alt_number,
9272                track_alt_numbers: request.track_alt_numbers,
9273                consumed_eof: request.consumed_eof,
9274                committed_decision: false,
9275                precedence: request.precedence,
9276                depth: request.depth + 1,
9277                recovery_symbols: BTreeSet::new(),
9278                recovery_state: None,
9279            },
9280            visiting,
9281            memo,
9282            expected,
9283        )
9284        .into_iter()
9285        .map(|mut outcome| {
9286            prepend_decision(&mut outcome, decision);
9287            outcome.diagnostics = self
9288                .recognition_arena
9289                .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
9290            let error = self.arena_token_node(error_index, true);
9291            self.arena_prepend(&mut outcome.nodes, error);
9292            outcome
9293        })
9294        .collect()
9295    }
9296
9297    /// Stops the current rule at EOF after a nested failure, matching ANTLR's
9298    /// behavior of unwinding instead of inserting caller tokens at EOF.
9299    fn eof_consuming_failure_fallback(
9300        &mut self,
9301        fallback: ConsumingFailureFallback<'_>,
9302        expected: &ExpectedTokens,
9303    ) -> Vec<RecognizeOutcome> {
9304        let request = fallback.request;
9305        if request.index == request.rule_start_index {
9306            return Vec::new();
9307        }
9308        let diagnostic =
9309            self.eof_rule_recovery_diagnostic(request.index, &fallback.expected_symbols, expected);
9310        let diagnostics = self
9311            .recognition_arena
9312            .prepend_diagnostic(DiagnosticSeqId::EMPTY, diagnostic);
9313        vec![RecognizeOutcome {
9314            index: request.index,
9315            consumed_eof: request.consumed_eof,
9316            alt_number: request.rule_alt_number,
9317            member_values: request.member_values,
9318            return_values: request.return_values,
9319            diagnostics,
9320            decisions: Vec::new(),
9321            actions: Vec::new(),
9322            nodes: NodeSeqId::EMPTY,
9323        }]
9324    }
9325
9326    /// Explores single-token insertion recovery while adding a conjured
9327    /// missing-token error node to the selected parse tree path.
9328    fn single_token_insertion_recovery(
9329        &mut self,
9330        recovery: RecoveryRequest<'_, '_>,
9331    ) -> Vec<RecognizeOutcome> {
9332        let RecoveryRequest {
9333            atn,
9334            transition,
9335            expected_symbols,
9336            target,
9337            request,
9338            visiting,
9339            memo,
9340            expected,
9341        } = recovery;
9342        let RecognizeRequest {
9343            stop_state,
9344            index,
9345            rule_start_index,
9346            decision_start_index,
9347            init_action_rules,
9348            predicates,
9349            semantics,
9350            rule_args,
9351            member_actions,
9352            return_actions,
9353            local_int_arg,
9354            member_values,
9355            return_values,
9356            rule_alt_number,
9357            track_alt_numbers,
9358            consumed_eof,
9359            precedence,
9360            depth,
9361            ..
9362        } = request;
9363        let follow_symbols = state_expected_symbols(atn, transition.target());
9364        let Some((diagnostic, token_type, text)) = self.single_token_insertion(
9365            transition,
9366            index,
9367            atn.max_token_type(),
9368            &expected_symbols,
9369            &follow_symbols,
9370        ) else {
9371            return Vec::new();
9372        };
9373        self.recognize_state(
9374            atn,
9375            RecognizeRequest {
9376                state_number: target,
9377                stop_state,
9378                index,
9379                rule_start_index,
9380                decision_start_index,
9381                init_action_rules,
9382                predicates,
9383                semantics,
9384                rule_args,
9385                member_actions,
9386                return_actions,
9387                local_int_arg,
9388                member_values,
9389                return_values,
9390                rule_alt_number,
9391                track_alt_numbers,
9392                consumed_eof,
9393                committed_decision: false,
9394                precedence,
9395                depth: depth + 1,
9396                recovery_symbols: BTreeSet::new(),
9397                recovery_state: None,
9398            },
9399            visiting,
9400            memo,
9401            expected,
9402        )
9403        .into_iter()
9404        .map(|mut outcome| {
9405            outcome.diagnostics = self
9406                .recognition_arena
9407                .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
9408            let missing = self.arena_missing_token_node(token_type, index, text.clone());
9409            self.arena_prepend(&mut outcome.nodes, missing);
9410            outcome
9411        })
9412        .collect()
9413    }
9414
9415    /// Attempts to reach `stop_state` and carries semantic actions for the
9416    /// selected parser path.
9417    #[allow(clippy::too_many_lines)]
9418    fn recognize_state(
9419        &mut self,
9420        atn: &Atn,
9421        request: RecognizeRequest<'_>,
9422        visiting: &mut BTreeSet<RecognizeKey>,
9423        memo: &mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
9424        expected: &mut ExpectedTokens,
9425    ) -> Vec<RecognizeOutcome> {
9426        let request_template = request.clone();
9427        let RecognizeRequest {
9428            state_number,
9429            stop_state,
9430            index,
9431            rule_start_index,
9432            decision_start_index,
9433            init_action_rules,
9434            predicates,
9435            semantics,
9436            rule_args,
9437            member_actions,
9438            return_actions,
9439            local_int_arg,
9440            member_values,
9441            return_values,
9442            rule_alt_number,
9443            track_alt_numbers,
9444            consumed_eof,
9445            committed_decision,
9446            precedence,
9447            depth,
9448            recovery_symbols,
9449            recovery_state,
9450        } = request;
9451        if depth > RECOGNITION_DEPTH_LIMIT {
9452            return Vec::new();
9453        }
9454        if state_number == stop_state {
9455            return stop_outcome(
9456                index,
9457                consumed_eof,
9458                rule_alt_number,
9459                member_values,
9460                return_values,
9461            );
9462        }
9463        let key = RecognizeKey {
9464            state_number,
9465            stop_state,
9466            index,
9467            rule_start_index,
9468            decision_start_index,
9469            local_int_arg,
9470            member_values: member_values.clone(),
9471            return_values: return_values.clone(),
9472            rule_alt_number,
9473            track_alt_numbers,
9474            consumed_eof,
9475            committed_decision,
9476            precedence,
9477            recovery_symbols: recovery_symbols.clone(),
9478            recovery_state,
9479        };
9480        if let Some(outcomes) = memo.get(&key) {
9481            return outcomes.clone();
9482        }
9483
9484        let visit_key = key.clone();
9485        if !visiting.insert(visit_key.clone()) {
9486            return Vec::new();
9487        }
9488
9489        let Some(state) = atn.state(state_number) else {
9490            visiting.remove(&visit_key);
9491            return Vec::new();
9492        };
9493        let decision_override_generation = self.decision_override_generation;
9494        let transitions = state.transitions();
9495        let transition_count = transitions.len();
9496        let overridden_transition = if transition_count > 1
9497            && self.semantic_hooks.observes_parser_decisions()
9498        {
9499            atn.decision_to_state()
9500                .iter()
9501                .position(|candidate| candidate == state_number)
9502                .and_then(|decision| {
9503                    self.semantic_hooks
9504                        .parser_decision_override(decision, index, transition_count)
9505                })
9506                .and_then(|alternative| alternative.checked_sub(1))
9507                .filter(|alternative| *alternative < transition_count)
9508        } else {
9509            None
9510        };
9511        if overridden_transition.is_some() {
9512            self.decision_override_generation = self.decision_override_generation.wrapping_add(1);
9513        }
9514        let next_decision_start_index = if starts_prediction_decision(state, transition_count) {
9515            Some(index)
9516        } else {
9517            decision_start_index
9518        };
9519        let (epsilon_recovery_symbols, epsilon_recovery_state) =
9520            next_recovery_context(atn, state, &recovery_symbols, recovery_state);
9521        let mut outcomes = Vec::new();
9522        for (transition_index, transition) in transitions.iter().enumerate() {
9523            if overridden_transition.is_some_and(|forced| forced != transition_index) {
9524                continue;
9525            }
9526            let transition_committed =
9527                committed_decision || overridden_transition == Some(transition_index);
9528            let mut transition_request = request_template.clone();
9529            transition_request.committed_decision = transition_committed;
9530            let decision =
9531                transition_decision(atn, state, transition_count, transition_index, predicates);
9532            let next_alt_number = next_alt_number(
9533                state,
9534                transition_count,
9535                transition_index,
9536                rule_alt_number,
9537                track_alt_numbers,
9538            );
9539            let transition_data = transition.data();
9540            match &transition_data {
9541                Transition::Epsilon { target } | Transition::Action { target, .. } => {
9542                    let action_rule_index = match &transition_data {
9543                        Transition::Action { rule_index, .. } => Some(*rule_index),
9544                        _ => None,
9545                    };
9546                    outcomes.extend(self.recognize_epsilon_or_action_step(
9547                        atn,
9548                        &transition_request,
9549                        EpsilonActionStep {
9550                            source_state: state_number,
9551                            target: *target,
9552                            action_rule_index,
9553                            left_recursive_boundary: left_recursive_boundary(atn, state, *target),
9554                            decision,
9555                            decision_start_index: next_decision_start_index,
9556                            alt_number: next_alt_number,
9557                            recovery_symbols: epsilon_recovery_symbols.clone(),
9558                            recovery_state: epsilon_recovery_state,
9559                        },
9560                        RecognizeScratch {
9561                            visiting,
9562                            memo,
9563                            expected,
9564                        },
9565                    ));
9566                }
9567                Transition::Predicate {
9568                    target,
9569                    rule_index,
9570                    pred_index,
9571                    ..
9572                } => {
9573                    let predicate = PredicateEval {
9574                        index,
9575                        rule_index: *rule_index,
9576                        pred_index: *pred_index,
9577                        predicates,
9578                        semantics,
9579                        context: None,
9580                        local_int_arg,
9581                        member_values: &member_values,
9582                    };
9583                    if self.parser_predicate_matches(predicate) {
9584                        let left_recursive_boundary = left_recursive_boundary(atn, state, *target);
9585                        outcomes.extend(
9586                            self.recognize_state(
9587                                atn,
9588                                RecognizeRequest {
9589                                    state_number: *target,
9590                                    stop_state,
9591                                    index,
9592                                    rule_start_index,
9593                                    decision_start_index: next_decision_start_index,
9594                                    init_action_rules,
9595                                    predicates,
9596                                    semantics,
9597                                    rule_args,
9598                                    member_actions,
9599                                    return_actions,
9600                                    local_int_arg,
9601                                    member_values: member_values.clone(),
9602                                    return_values: return_values.clone(),
9603                                    rule_alt_number: next_alt_number,
9604                                    track_alt_numbers,
9605                                    consumed_eof,
9606                                    committed_decision: transition_committed,
9607                                    precedence,
9608                                    depth: depth + 1,
9609                                    recovery_symbols: epsilon_recovery_symbols.clone(),
9610                                    recovery_state: epsilon_recovery_state,
9611                                },
9612                                visiting,
9613                                memo,
9614                                expected,
9615                            )
9616                            .into_iter()
9617                            .map(|mut outcome| {
9618                                prepend_decision(&mut outcome, decision);
9619                                if let Some(rule_index) = left_recursive_boundary {
9620                                    let boundary =
9621                                        self.arena_boundary_node(rule_index, next_alt_number);
9622                                    self.arena_prepend(&mut outcome.nodes, boundary);
9623                                }
9624                                outcome
9625                            }),
9626                        );
9627                    } else if let Some(message) = semantics
9628                        .and_then(|semantics| {
9629                            self.parser_semantic_ir_predicate_failure_message(
9630                                *rule_index,
9631                                *pred_index,
9632                                semantics,
9633                            )
9634                        })
9635                        .or_else(|| {
9636                            self.parser_predicate_failure_message(
9637                                *rule_index,
9638                                *pred_index,
9639                                predicates,
9640                            )
9641                        })
9642                    {
9643                        outcomes.push(self.predicate_failure_recovery(PredicateFailureRecovery {
9644                            rule_index: *rule_index,
9645                            index,
9646                            message,
9647                            member_values: member_values.clone(),
9648                            return_values: return_values.clone(),
9649                            rule_alt_number,
9650                        }));
9651                    } else {
9652                        record_predicate_no_viable(expected, next_decision_start_index, index);
9653                    }
9654                }
9655                Transition::Precedence {
9656                    target,
9657                    precedence: transition_precedence,
9658                } => {
9659                    if *transition_precedence >= precedence {
9660                        outcomes.extend(
9661                            self.recognize_state(
9662                                atn,
9663                                RecognizeRequest {
9664                                    state_number: *target,
9665                                    stop_state,
9666                                    index,
9667                                    rule_start_index,
9668                                    decision_start_index: next_decision_start_index,
9669                                    init_action_rules,
9670                                    predicates,
9671                                    semantics,
9672                                    rule_args,
9673                                    member_actions,
9674                                    return_actions,
9675                                    local_int_arg,
9676                                    member_values: member_values.clone(),
9677                                    return_values: return_values.clone(),
9678                                    rule_alt_number: next_alt_number,
9679                                    track_alt_numbers,
9680                                    consumed_eof,
9681                                    committed_decision: transition_committed,
9682                                    precedence,
9683                                    depth: depth + 1,
9684                                    recovery_symbols: epsilon_recovery_symbols.clone(),
9685                                    recovery_state: epsilon_recovery_state,
9686                                },
9687                                visiting,
9688                                memo,
9689                                expected,
9690                            )
9691                            .into_iter()
9692                            .map(|mut outcome| {
9693                                prepend_decision(&mut outcome, decision);
9694                                outcome
9695                            }),
9696                        );
9697                    }
9698                }
9699                Transition::Rule {
9700                    target,
9701                    rule_index,
9702                    follow_state,
9703                    precedence: rule_precedence,
9704                    ..
9705                } => {
9706                    let Some(child_stop) = atn.rule_to_stop_state().get(*rule_index) else {
9707                        continue;
9708                    };
9709                    let child_local_int_arg =
9710                        rule_local_int_arg(rule_args, state_number, *rule_index, local_int_arg);
9711                    let expected_before_child = expected.clone();
9712                    let children = self.recognize_state(
9713                        atn,
9714                        RecognizeRequest {
9715                            state_number: *target,
9716                            stop_state: child_stop,
9717                            index,
9718                            rule_start_index: index,
9719                            decision_start_index: None,
9720                            init_action_rules,
9721                            predicates,
9722                            semantics,
9723                            rule_args,
9724                            member_actions,
9725                            return_actions,
9726                            local_int_arg: child_local_int_arg,
9727                            member_values: member_values.clone(),
9728                            return_values: BTreeMap::new(),
9729                            rule_alt_number: 0,
9730                            track_alt_numbers,
9731                            consumed_eof: false,
9732                            committed_decision: transition_committed,
9733                            precedence: *rule_precedence,
9734                            depth: depth + 1,
9735                            recovery_symbols: epsilon_recovery_symbols.clone(),
9736                            recovery_state: epsilon_recovery_state,
9737                        },
9738                        visiting,
9739                        memo,
9740                        expected,
9741                    );
9742                    let children = if children.is_empty() {
9743                        self.child_rule_failure_recovery_outcomes(ChildRuleFailureRecovery {
9744                            atn,
9745                            rule_index: *rule_index,
9746                            start_index: index,
9747                            follow_state: *follow_state,
9748                            stop_state,
9749                            member_values: member_values.clone(),
9750                            expected,
9751                        })
9752                    } else {
9753                        children
9754                    };
9755                    let preserve_child_expected =
9756                        self.child_expected_reaches_clean_eof(&children, expected);
9757                    restore_expected(
9758                        &children,
9759                        index,
9760                        expected,
9761                        expected_before_child,
9762                        preserve_child_expected,
9763                    );
9764                    for child in children {
9765                        let child_stop_index =
9766                            self.rule_stop_token_index(child.index, child.consumed_eof);
9767                        let child_nodes = self
9768                            .recognition_arena
9769                            .fold_left_recursive_boundaries(child.nodes);
9770                        let child_node = self.arena_rule_node(ArenaRuleSpec {
9771                            rule_index: *rule_index,
9772                            invoking_state: invoking_state_number(state_number),
9773                            alt_number: child.alt_number,
9774                            start_index: index,
9775                            stop_index: child_stop_index,
9776                            return_values: child.return_values.clone(),
9777                            children: child_nodes,
9778                        });
9779                        outcomes.extend(
9780                            self.recognize_state(
9781                                atn,
9782                                RecognizeRequest {
9783                                    state_number: *follow_state,
9784                                    stop_state,
9785                                    index: child.index,
9786                                    rule_start_index,
9787                                    decision_start_index: next_decision_start_index,
9788                                    init_action_rules,
9789                                    predicates,
9790                                    semantics,
9791                                    rule_args,
9792                                    member_actions,
9793                                    return_actions,
9794                                    local_int_arg,
9795                                    member_values: child.member_values.clone(),
9796                                    return_values: return_values.clone(),
9797                                    rule_alt_number,
9798                                    track_alt_numbers,
9799                                    consumed_eof: consumed_eof || child.consumed_eof,
9800                                    committed_decision: transition_committed
9801                                        && child.index == index,
9802                                    precedence,
9803                                    depth: depth + 1,
9804                                    recovery_symbols: BTreeSet::new(),
9805                                    recovery_state: None,
9806                                },
9807                                visiting,
9808                                memo,
9809                                expected,
9810                            )
9811                            .into_iter()
9812                            .map(|mut outcome| {
9813                                outcome.consumed_eof |= child.consumed_eof;
9814                                outcome.diagnostics = self
9815                                    .recognition_arena
9816                                    .concat_diagnostics(child.diagnostics, outcome.diagnostics);
9817                                let mut decisions = child.decisions.clone();
9818                                decisions.append(&mut outcome.decisions);
9819                                outcome.decisions = decisions;
9820                                prepend_decision(&mut outcome, decision);
9821                                let mut actions = child.actions.clone();
9822                                if init_action_rules.contains(rule_index) {
9823                                    actions.insert(
9824                                        0,
9825                                        ParserAction::new_rule_init(
9826                                            *rule_index,
9827                                            index,
9828                                            Some(*follow_state),
9829                                        ),
9830                                    );
9831                                }
9832                                actions.append(&mut outcome.actions);
9833                                outcome.actions = actions;
9834                                self.arena_prepend(&mut outcome.nodes, child_node);
9835                                outcome
9836                            }),
9837                        );
9838                    }
9839                }
9840                Transition::Atom { target, .. }
9841                | Transition::Range { target, .. }
9842                | Transition::Set { target, .. }
9843                | Transition::NotSet { target, .. }
9844                | Transition::Wildcard { target, .. } => {
9845                    let symbol = self.token_type_at(index);
9846                    if transition_data.matches(symbol, 1, atn.max_token_type()) {
9847                        let next_index = self.consume_index(index, symbol);
9848                        outcomes.extend(
9849                            self.recognize_state(
9850                                atn,
9851                                RecognizeRequest {
9852                                    state_number: *target,
9853                                    stop_state,
9854                                    index: next_index,
9855                                    rule_start_index,
9856                                    decision_start_index: next_decision_start_index,
9857                                    init_action_rules,
9858                                    predicates,
9859                                    semantics,
9860                                    rule_args,
9861                                    member_actions,
9862                                    return_actions,
9863                                    local_int_arg,
9864                                    member_values: member_values.clone(),
9865                                    return_values: return_values.clone(),
9866                                    rule_alt_number: next_alt_number,
9867                                    track_alt_numbers,
9868                                    consumed_eof: consumed_eof || symbol == TOKEN_EOF,
9869                                    committed_decision: false,
9870                                    precedence,
9871                                    depth: depth + 1,
9872                                    recovery_symbols: BTreeSet::new(),
9873                                    recovery_state: None,
9874                                },
9875                                visiting,
9876                                memo,
9877                                expected,
9878                            )
9879                            .into_iter()
9880                            .map(|mut outcome| {
9881                                prepend_decision(&mut outcome, decision);
9882                                outcome.consumed_eof |= symbol == TOKEN_EOF;
9883                                let token = self.arena_token_node(index, false);
9884                                self.arena_prepend(&mut outcome.nodes, token);
9885                                outcome
9886                            }),
9887                        );
9888                    } else {
9889                        let expected_symbols =
9890                            recovery_expected_symbols(atn, state.state_number(), &recovery_symbols);
9891                        if expected_symbols.contains(&symbol) && !transition_committed {
9892                            continue;
9893                        }
9894                        expected.record_transition(index, transition, atn.max_token_type());
9895                        record_no_viable_if_ambiguous(expected, next_decision_start_index, index);
9896                        let before_recovery = outcomes.len();
9897                        let recovery_request = transition_request.clone();
9898                        if transition_committed {
9899                            outcomes.extend(self.consuming_failure_fallback(
9900                                ConsumingFailureFallback {
9901                                    atn,
9902                                    target: *target,
9903                                    request: recovery_request,
9904                                    symbol,
9905                                    expected_symbols,
9906                                    decision_start_index: next_decision_start_index,
9907                                    decision,
9908                                },
9909                                visiting,
9910                                memo,
9911                                expected,
9912                            ));
9913                            break;
9914                        }
9915                        outcomes.extend(
9916                            self.single_token_deletion_recovery(RecoveryRequest {
9917                                atn,
9918                                transition,
9919                                expected_symbols: expected_symbols.clone(),
9920                                target: *target,
9921                                request: recovery_request.clone(),
9922                                visiting,
9923                                memo,
9924                                expected,
9925                            })
9926                            .into_iter()
9927                            .map(|mut outcome| {
9928                                prepend_decision(&mut outcome, decision);
9929                                outcome
9930                            }),
9931                        );
9932                        if !state_is_left_recursive_rule(atn, state) {
9933                            outcomes.extend(
9934                                self.single_token_insertion_recovery(RecoveryRequest {
9935                                    atn,
9936                                    transition,
9937                                    expected_symbols: expected_symbols.clone(),
9938                                    target: *target,
9939                                    request: recovery_request.clone(),
9940                                    visiting,
9941                                    memo,
9942                                    expected,
9943                                })
9944                                .into_iter()
9945                                .map(|mut outcome| {
9946                                    prepend_decision(&mut outcome, decision);
9947                                    outcome
9948                                }),
9949                            );
9950                        }
9951                        outcomes.extend(self.current_token_deletion_recovery(
9952                            CurrentTokenDeletionRequest {
9953                                atn,
9954                                expected_symbols: expected_symbols.clone(),
9955                                request: recovery_request.clone(),
9956                                visiting,
9957                                memo,
9958                                expected,
9959                            },
9960                        ));
9961                        if outcomes.len() == before_recovery {
9962                            outcomes.extend(self.consuming_failure_fallback(
9963                                ConsumingFailureFallback {
9964                                    atn,
9965                                    target: *target,
9966                                    request: recovery_request,
9967                                    symbol,
9968                                    expected_symbols,
9969                                    decision_start_index: next_decision_start_index,
9970                                    decision,
9971                                },
9972                                visiting,
9973                                memo,
9974                                expected,
9975                            ));
9976                        }
9977                    }
9978                }
9979            }
9980            if self.decision_override_generation != decision_override_generation {
9981                break;
9982            }
9983        }
9984
9985        visiting.remove(&visit_key);
9986        self.record_prediction_diagnostics(atn, state, index, &outcomes);
9987        if matches!(
9988            self.prediction_mode,
9989            PredictionMode::Ll | PredictionMode::LlExactAmbigDetection
9990        ) {
9991            discard_recovered_outcomes_if_clean_path_exists(&mut outcomes, &self.recognition_arena);
9992        }
9993        dedupe_outcomes(&mut outcomes, &self.recognition_arena);
9994        memo.insert(key, outcomes.clone());
9995        outcomes
9996    }
9997
9998    /// Follows an epsilon or semantic-action transition while preserving the
9999    /// path-local side effects that may later become generated action output.
10000    fn recognize_epsilon_or_action_step(
10001        &mut self,
10002        atn: &Atn,
10003        request: &RecognizeRequest<'_>,
10004        step: EpsilonActionStep,
10005        scratch: RecognizeScratch<'_>,
10006    ) -> Vec<RecognizeOutcome> {
10007        let RecognizeScratch {
10008            visiting,
10009            memo,
10010            expected,
10011        } = scratch;
10012        let action = step.action_rule_index.map(|rule_index| {
10013            ParserAction::new(
10014                step.source_state,
10015                rule_index,
10016                request.rule_start_index,
10017                self.rule_stop_token_index(request.index, request.consumed_eof),
10018            )
10019        });
10020        let next_member_values = if action.is_some() {
10021            member_values_after_action(
10022                step.source_state,
10023                request.member_actions,
10024                request.semantics,
10025                &request.member_values,
10026            )
10027        } else {
10028            request.member_values.clone()
10029        };
10030        let next_return_values = action.map_or_else(
10031            || request.return_values.clone(),
10032            |action| {
10033                return_values_after_action(
10034                    step.source_state,
10035                    action.rule_index(),
10036                    request.return_actions,
10037                    request.semantics,
10038                    &request.return_values,
10039                )
10040            },
10041        );
10042
10043        self.recognize_state(
10044            atn,
10045            RecognizeRequest {
10046                state_number: step.target,
10047                stop_state: request.stop_state,
10048                index: request.index,
10049                rule_start_index: request.rule_start_index,
10050                decision_start_index: step.decision_start_index,
10051                init_action_rules: request.init_action_rules,
10052                predicates: request.predicates,
10053                semantics: request.semantics,
10054                rule_args: request.rule_args,
10055                member_actions: request.member_actions,
10056                return_actions: request.return_actions,
10057                local_int_arg: request.local_int_arg,
10058                member_values: next_member_values,
10059                return_values: next_return_values,
10060                rule_alt_number: if step.left_recursive_boundary.is_some() {
10061                    0
10062                } else {
10063                    step.alt_number
10064                },
10065                track_alt_numbers: request.track_alt_numbers,
10066                consumed_eof: request.consumed_eof,
10067                committed_decision: request.committed_decision,
10068                precedence: request.precedence,
10069                depth: request.depth + 1,
10070                recovery_symbols: step.recovery_symbols,
10071                recovery_state: step.recovery_state,
10072            },
10073            visiting,
10074            memo,
10075            expected,
10076        )
10077        .into_iter()
10078        .map(|mut outcome| {
10079            prepend_decision(&mut outcome, step.decision);
10080            if let Some(rule_index) = step.left_recursive_boundary {
10081                let boundary = self.arena_boundary_node(rule_index, step.alt_number);
10082                self.arena_prepend(&mut outcome.nodes, boundary);
10083            }
10084            if let Some(action) = action {
10085                outcome.actions.insert(0, action);
10086            }
10087            outcome
10088        })
10089        .collect()
10090    }
10091
10092    /// Reads the token type at an absolute token-stream index without moving
10093    /// the parser's stream cursor. The fast recognizer probes lookahead at
10094    /// every state visit, so avoiding the seek round-trip is a measurable
10095    /// hot-path win on long inputs.
10096    fn token_type_at(&mut self, index: usize) -> i32 {
10097        if index >= FAST_RECOGNIZER_DEFERRED_FILL_AT && !self.input.is_filled() {
10098            self.input.fill();
10099        }
10100        self.input.token_type_at_index(index)
10101    }
10102
10103    /// Returns the cached `state_expected_symbols` set for an ATN state.
10104    ///
10105    /// The fast recognizer consults this set on every state visit through
10106    /// `next_recovery_context`; the underlying DFS is a pure function of the
10107    /// ATN, so caching the `Rc` lets clones reduce to a reference bump.
10108    ///
10109    /// Caching is layered through `intern_recovery_symbols` so two ATN states
10110    /// with the same expected-symbol set share one `Rc`. That invariant is
10111    /// what lets `FastRecognizeKey` hash on `recovery_symbols` by pointer
10112    /// without violating the `Hash`/`Eq` contract — `recovery_symbols` is
10113    /// always interned before it ends up in a key.
10114    fn cached_state_expected_symbols(
10115        &mut self,
10116        atn: &Atn,
10117        state_number: usize,
10118    ) -> Rc<BTreeSet<i32>> {
10119        if let Some(cached) = self.state_expected_cache.get(&state_number) {
10120            return Rc::clone(cached);
10121        }
10122        let symbols = state_expected_symbols(atn, state_number);
10123        let entry = self.intern_recovery_symbols(symbols);
10124        self.state_expected_cache
10125            .insert(state_number, Rc::clone(&entry));
10126        entry
10127    }
10128
10129    fn cached_state_expected_token_set(
10130        &mut self,
10131        atn: &Atn,
10132        state_number: usize,
10133    ) -> Rc<TokenBitSet> {
10134        if let Some(cached) = self.state_expected_token_cache.get(&state_number) {
10135            return Rc::clone(cached);
10136        }
10137        // Purely a function of the ATN, so back the per-parser cache with the
10138        // thread-shared one — fresh parser instances (one per parse in
10139        // generated usage) start warm instead of rewalking the ATN.
10140        let symbols = with_shared_atn_caches(atn, |cache| {
10141            if let Some(cached) = cache.state_expected_tokens.get(&state_number) {
10142                return Rc::clone(cached);
10143            }
10144            let symbols = Rc::new(state_expected_token_set(atn, state_number));
10145            cache
10146                .state_expected_tokens
10147                .insert(state_number, Rc::clone(&symbols));
10148            symbols
10149        });
10150        self.state_expected_token_cache
10151            .insert(state_number, Rc::clone(&symbols));
10152        symbols
10153    }
10154
10155    fn cached_state_can_reach_rule_stop(&mut self, atn: &Atn, state_number: usize) -> bool {
10156        if self.rule_stop_reach_cache.len() <= state_number {
10157            self.rule_stop_reach_cache
10158                .resize_with(atn.states().len().max(state_number + 1), || None);
10159        }
10160        if let Some(reaches) = self.rule_stop_reach_cache[state_number] {
10161            return reaches;
10162        }
10163        let reaches = with_shared_atn_caches(atn, |cache| {
10164            *cache
10165                .rule_stop_reach
10166                .entry(state_number)
10167                .or_insert_with(|| state_can_reach_rule_stop(atn, state_number))
10168        });
10169        self.rule_stop_reach_cache[state_number] = Some(reaches);
10170        reaches
10171    }
10172
10173    /// Returns the parser's empty `recovery_symbols` singleton so callers can
10174    /// share an `Rc` instead of allocating new `BTreeSet`s for the common case.
10175    fn empty_recovery_symbols(&self) -> Rc<BTreeSet<i32>> {
10176        Rc::clone(&self.empty_recovery_symbols)
10177    }
10178
10179    /// Returns the interned `Rc` form of a `recovery_symbols` set so the fast
10180    /// recognizer can hash and compare keys by pointer.
10181    ///
10182    /// Every `Rc<BTreeSet<i32>>` that flows into a `FastRecognizeKey` must
10183    /// come from this method or the empty singleton; otherwise two
10184    /// content-equal `Rc`s could end up with different `Rc::as_ptr` values,
10185    /// and the pointer-keyed hash on `FastRecognizeKey` would split equivalent
10186    /// recognition coordinates.
10187    fn intern_recovery_symbols(&mut self, set: BTreeSet<i32>) -> Rc<BTreeSet<i32>> {
10188        if set.is_empty() {
10189            return Rc::clone(&self.empty_recovery_symbols);
10190        }
10191        let candidate = Rc::new(set);
10192        match self.recovery_symbols_intern.get(&candidate) {
10193            Some(existing) => Rc::clone(existing),
10194            None => {
10195                self.recovery_symbols_intern
10196                    .insert(Rc::clone(&candidate), Rc::clone(&candidate));
10197                candidate
10198            }
10199        }
10200    }
10201
10202    /// Returns the cached look-1 entry for a decision state, computing it on
10203    /// first use. Multi-alternative states are visited many times during
10204    /// recognition; sharing the entry through `Rc` keeps the prefilter to one
10205    /// hash lookup per visit.
10206    fn cached_decision_lookahead(
10207        &mut self,
10208        atn: &Atn,
10209        state: AtnState<'_>,
10210        rule_stop_state: usize,
10211    ) -> Rc<DecisionLookahead> {
10212        // Hit the parser-instance cache first. Decision lookahead is purely
10213        // a function of the ATN/state, so on a warm cache we skip the
10214        // thread-local + RefCell + HashMap-entry dance through
10215        // SHARED_ATN_CACHES — which on multi-trans-heavy grammars (C# does
10216        // ~58K multi-trans visits per parse) shows up as RefCell borrow and
10217        // hashmap-entry overhead in profiles.
10218        if let Some(cached) = self.decision_lookahead_cache.get(&state.state_number()) {
10219            return Rc::clone(cached);
10220        }
10221        let entry = with_shared_atn_caches(atn, |cache| {
10222            if let Some(cached) = cache.decision_lookahead.get(&state.state_number()) {
10223                return Rc::clone(cached);
10224            }
10225            let mut entry = DecisionLookahead {
10226                transitions: Vec::with_capacity(state.transitions().len()),
10227            };
10228            for transition in &state.transitions() {
10229                entry.transitions.push(transition_first_set(
10230                    atn,
10231                    transition,
10232                    rule_stop_state,
10233                    &mut cache.first_set,
10234                ));
10235            }
10236            let entry = Rc::new(entry);
10237            cache
10238                .decision_lookahead
10239                .insert(state.state_number(), Rc::clone(&entry));
10240            entry
10241        });
10242        self.decision_lookahead_cache
10243            .insert(state.state_number(), Rc::clone(&entry));
10244        entry
10245    }
10246
10247    fn cached_rule_first_set(
10248        &mut self,
10249        atn: &Atn,
10250        target: usize,
10251        child_stop: usize,
10252    ) -> Rc<FirstSet> {
10253        if self.rule_first_set_cache.len() <= target {
10254            self.rule_first_set_cache
10255                .resize_with(atn.states().len().max(target + 1), || None);
10256        }
10257        if let Some(cached) = self
10258            .rule_first_set_cache
10259            .get(target)
10260            .and_then(Option::as_ref)
10261        {
10262            return Rc::clone(cached);
10263        }
10264        let first = with_shared_first_set_cache(atn, |cache| {
10265            rule_first_set(atn, target, child_stop, cache)
10266        });
10267        self.rule_first_set_cache[target] = Some(Rc::clone(&first));
10268        first
10269    }
10270
10271    fn state_can_reenter_without_consuming(&mut self, atn: &Atn, state_number: usize) -> bool {
10272        let atn_key = SharedAtnCacheKey::for_atn(atn);
10273        if self.empty_cycle_cache_atn != Some(atn_key) {
10274            self.empty_cycle_cache.clear();
10275            self.empty_cycle_cache_atn = Some(atn_key);
10276        }
10277        if self.empty_cycle_cache.len() <= state_number {
10278            self.empty_cycle_cache
10279                .resize_with(atn.state_count().max(state_number + 1), || None);
10280        }
10281        if let Some(cached) = self.empty_cycle_cache[state_number] {
10282            return cached;
10283        }
10284        let mut visited = FxHashSet::with_capacity_and_hasher(64, FxBuildHasher::default());
10285        let result = self.empty_path_reaches_state(atn, state_number, state_number, &mut visited);
10286        self.empty_cycle_cache[state_number] = Some(result);
10287        result
10288    }
10289
10290    fn empty_path_reaches_state(
10291        &mut self,
10292        atn: &Atn,
10293        state_number: usize,
10294        target_state: usize,
10295        visited: &mut FxHashSet<usize>,
10296    ) -> bool {
10297        enum Work {
10298            Visit(usize),
10299            RuleFollow {
10300                target: usize,
10301                rule_index: usize,
10302                follow_state: usize,
10303            },
10304        }
10305
10306        let mut work = vec![Work::Visit(state_number)];
10307        while let Some(item) = work.pop() {
10308            match item {
10309                Work::Visit(state_number) => {
10310                    if !visited.insert(state_number) {
10311                        continue;
10312                    }
10313                    let Some(state) = atn.state(state_number) else {
10314                        continue;
10315                    };
10316                    let transitions = state.transitions();
10317                    for transition_index in (0..transitions.len()).rev() {
10318                        let transition = transitions
10319                            .get(transition_index)
10320                            .expect("in-bounds parser transition");
10321                        let kind = transition.kind();
10322                        let target = transition.target();
10323                        match kind {
10324                            ParserTransitionKind::Atom
10325                            | ParserTransitionKind::Range
10326                            | ParserTransitionKind::Set
10327                            | ParserTransitionKind::NotSet
10328                            | ParserTransitionKind::Wildcard => {}
10329                            ParserTransitionKind::Rule => {
10330                                if target == target_state {
10331                                    return true;
10332                                }
10333                                work.push(Work::RuleFollow {
10334                                    target,
10335                                    rule_index: transition.arg0() as usize,
10336                                    follow_state: transition.arg1() as usize,
10337                                });
10338                                work.push(Work::Visit(target));
10339                            }
10340                            ParserTransitionKind::Epsilon
10341                            | ParserTransitionKind::Predicate
10342                            | ParserTransitionKind::Action
10343                            | ParserTransitionKind::Precedence => {
10344                                if target == target_state {
10345                                    return true;
10346                                }
10347                                work.push(Work::Visit(target));
10348                            }
10349                        }
10350                    }
10351                }
10352                Work::RuleFollow {
10353                    target,
10354                    rule_index,
10355                    follow_state,
10356                } => {
10357                    let Some(child_stop) = atn.rule_to_stop_state().get(rule_index) else {
10358                        continue;
10359                    };
10360                    if self.cached_rule_first_set(atn, target, child_stop).nullable {
10361                        if follow_state == target_state {
10362                            return true;
10363                        }
10364                        work.push(Work::Visit(follow_state));
10365                    }
10366                }
10367            }
10368        }
10369        false
10370    }
10371
10372    /// Decides whether the clean recognizer should use its full outcome memo
10373    /// table for this coordinate.
10374    fn clean_memo_enabled_for_key(&mut self, key: &FastRecognizeKey) -> bool {
10375        match self.clean_memo_mode {
10376            CleanMemoMode::Promote => true,
10377            CleanMemoMode::Probe => self.observe_clean_memo_probe(key),
10378            CleanMemoMode::Sparse => {
10379                self.clean_memo_sparse_samples += 1;
10380                if self.clean_memo_sparse_samples < CLEAN_MEMO_REPROBE_INTERVAL {
10381                    return false;
10382                }
10383                self.clean_memo_sparse_samples = 0;
10384                self.clean_memo_mode = CleanMemoMode::Probe;
10385                self.clean_memo_probe_samples = 0;
10386                self.clean_memo_probe_repeats = 0;
10387                self.clean_memo_probe_seen.clear();
10388                self.observe_clean_memo_probe(key)
10389            }
10390        }
10391    }
10392
10393    fn observe_clean_memo_probe(&mut self, key: &FastRecognizeKey) -> bool {
10394        self.clean_memo_probe_samples += 1;
10395        if !self.clean_memo_probe_seen.insert(key.clone()) {
10396            self.clean_memo_probe_repeats += 1;
10397        }
10398        if self.clean_memo_probe_repeats >= CLEAN_MEMO_REPEAT_LIMIT {
10399            self.clean_memo_mode = CleanMemoMode::Promote;
10400            self.clean_memo_probe_seen.clear();
10401            return true;
10402        }
10403        if self.clean_memo_probe_samples >= CLEAN_MEMO_PROBE_LIMIT {
10404            self.clean_memo_mode = CleanMemoMode::Sparse;
10405            self.clean_memo_sparse_samples = 0;
10406            self.clean_memo_probe_seen.clear();
10407            return false;
10408        }
10409        true
10410    }
10411
10412    /// Borrows the visible token at an absolute token-stream index.
10413    fn token_at(&self, index: usize) -> Option<TokenView<'_>> {
10414        self.input.get(index)
10415    }
10416
10417    /// Returns the compact token ID at an absolute token-stream index.
10418    fn token_id_at(&self, index: usize) -> Option<TokenId> {
10419        self.input.get_id(index)
10420    }
10421
10422    fn arena_token_node(&mut self, index: usize, error: bool) -> RecognizedNodeId {
10423        let token = self
10424            .token_id_at(index)
10425            .expect("recognized token index must exist in the token store");
10426        let node = if error {
10427            ArenaRecognizedNode::ErrorToken { token }
10428        } else {
10429            ArenaRecognizedNode::Token { token }
10430        };
10431        self.recognition_arena.push_node(node)
10432    }
10433
10434    fn arena_missing_token_node(
10435        &mut self,
10436        token_type: i32,
10437        at_index: usize,
10438        text: String,
10439    ) -> RecognizedNodeId {
10440        let extra = self
10441            .recognition_arena
10442            .push_extra(RecognitionExtra::MissingToken {
10443                token_type,
10444                at_index: u32::try_from(at_index).expect("missing-token stream index fits in u32"),
10445                text,
10446            });
10447        self.recognition_arena
10448            .push_node(ArenaRecognizedNode::MissingToken { extra })
10449    }
10450
10451    fn arena_rule_node(&mut self, spec: ArenaRuleSpec) -> RecognizedNodeId {
10452        let ArenaRuleSpec {
10453            rule_index,
10454            invoking_state,
10455            alt_number,
10456            start_index,
10457            stop_index,
10458            return_values,
10459            children,
10460        } = spec;
10461        let return_values = (!return_values.is_empty()).then(|| {
10462            self.recognition_arena
10463                .push_extra(RecognitionExtra::ReturnValues(return_values))
10464        });
10465        self.recognition_arena.push_node(ArenaRecognizedNode::Rule {
10466            rule_index: u32::try_from(rule_index).expect("rule index fits in u32"),
10467            invoking_state: i32::try_from(invoking_state).expect("invoking state fits in i32"),
10468            alt_number: u32::try_from(alt_number).expect("alternative number fits in u32"),
10469            start_index: u32::try_from(start_index).expect("rule start index fits in u32"),
10470            stop_index: stop_index
10471                .map(|index| u32::try_from(index).expect("rule stop index fits in u32")),
10472            return_values,
10473            children,
10474        })
10475    }
10476
10477    fn arena_boundary_node(&mut self, rule_index: usize, alt_number: usize) -> RecognizedNodeId {
10478        self.recognition_arena
10479            .push_node(ArenaRecognizedNode::LeftRecursiveBoundary {
10480                rule_index: u32::try_from(rule_index).expect("rule index fits in u32"),
10481                alt_number: u32::try_from(alt_number).expect("alternative number fits in u32"),
10482            })
10483    }
10484
10485    fn arena_prepend(&mut self, sequence: &mut NodeSeqId, node: RecognizedNodeId) {
10486        *sequence = self.recognition_arena.prepend(*sequence, node);
10487    }
10488
10489    fn finish_recognition_arena(&mut self, root: NodeSeqId, diagnostics: DiagnosticSeqId) {
10490        self.last_recognition_arena_root = root;
10491        self.last_recognition_arena_diagnostics = diagnostics;
10492        #[cfg(feature = "perf-counters")]
10493        if std::env::var("ANTLR_PERF_DUMP").is_ok() {
10494            let stats = self.recognition_arena_stats();
10495            #[allow(clippy::print_stderr)]
10496            {
10497                eprintln!("perf recognition_nodes_total={}", stats.total_nodes);
10498                eprintln!("perf recognition_nodes_live={}", stats.live_nodes);
10499                eprintln!("perf recognition_nodes_dead={}", stats.dead_nodes);
10500                eprintln!("perf recognition_nodes_capacity={}", stats.node_capacity);
10501                eprintln!("perf recognition_links_total={}", stats.total_links);
10502                eprintln!("perf recognition_links_live={}", stats.live_links);
10503                eprintln!("perf recognition_links_dead={}", stats.dead_links);
10504                eprintln!("perf recognition_links_capacity={}", stats.link_capacity);
10505                eprintln!("perf recognition_extras_total={}", stats.total_extras);
10506                eprintln!("perf recognition_extras_live={}", stats.live_extras);
10507                eprintln!("perf recognition_extras_dead={}", stats.dead_extras);
10508                eprintln!("perf recognition_extras_capacity={}", stats.extra_capacity);
10509            }
10510        }
10511    }
10512
10513    fn reset_recognition_arena(&mut self) {
10514        self.recognition_arena.reset();
10515        self.last_recognition_arena_root = NodeSeqId::EMPTY;
10516        self.last_recognition_arena_diagnostics = DiagnosticSeqId::EMPTY;
10517    }
10518
10519    /// Normalizes the current token-stream cursor to the next parser-visible
10520    /// token before capturing a rule start boundary.
10521    fn current_visible_index(&mut self) -> usize {
10522        let index = self.input.index();
10523        self.input.seek(index);
10524        self.input.index()
10525    }
10526
10527    /// Reports whether a child rule reached EOF cleanly while also recording
10528    /// an EOF expectation from a longer path inside that child.
10529    fn child_expected_reaches_clean_eof(
10530        &mut self,
10531        children: &[RecognizeOutcome],
10532        expected: &ExpectedTokens,
10533    ) -> bool {
10534        let Some(index) = expected.index else {
10535            return false;
10536        };
10537        self.token_type_at(index) == TOKEN_EOF
10538            && children
10539                .iter()
10540                .any(|child| child.diagnostics.is_empty() && child.index == index)
10541    }
10542
10543    /// Finds the previous token visible to the parser before `index`.
10544    ///
10545    /// The token stream cursor skips hidden-channel tokens, so subtracting one
10546    /// from a visible-token index can point at whitespace. Parser intervals use
10547    /// this helper to stop at the previous visible token while preserving hidden
10548    /// text inside the rendered interval.
10549    fn previous_token_index(&self, index: usize) -> Option<usize> {
10550        self.input.previous_visible_token_index(index)
10551    }
10552
10553    /// Returns the token-stream index used as a rule stop boundary.
10554    ///
10555    /// EOF transitions keep the cursor on EOF, so a rule that consumed EOF must
10556    /// stop at `index` rather than at the previous visible token.
10557    fn rule_stop_token_index(&mut self, index: usize, consumed_eof: bool) -> Option<usize> {
10558        if consumed_eof && self.token_type_at(index) == TOKEN_EOF {
10559            Some(index)
10560        } else {
10561            self.previous_token_index(index)
10562        }
10563    }
10564
10565    /// Stop-token index for a rule's `@after` action, matching the boundary that
10566    /// `finish_rule` records on the rule context.
10567    ///
10568    /// A rule that matched EOF leaves the cursor parked on the EOF token
10569    /// (`CommonTokenStream::consume` does not advance past EOF), so the stop is
10570    /// the current index rather than the previous visible token. Without this,
10571    /// `$stop`/`$text` in an `@after` action on a rule like `r: a* EOF;` would
10572    /// report the token before EOF (or `None` for empty input), diverging from
10573    /// the rule context that `finish_rule` builds.
10574    ///
10575    /// NOTE: this infers `consumed_eof` from the cursor, which is wrong when a
10576    /// rule ends right before EOF without matching it (the cursor is parked on
10577    /// EOF, but the rule did not consume it). Prefer
10578    /// [`Self::after_action_stop_index_for_tree`], which reuses the stop token the
10579    /// rule context already recorded with the real flag. Kept for callers without
10580    /// the rule tree in hand.
10581    #[must_use]
10582    pub fn after_action_stop_index(&mut self, current_index: usize) -> Option<usize> {
10583        let consumed_eof = self.token_type_at(current_index) == TOKEN_EOF;
10584        self.rule_stop_token_index(current_index, consumed_eof)
10585    }
10586
10587    /// Stop-token index for a rule's `@after` action, taken from the stop token
10588    /// the rule context already recorded.
10589    ///
10590    /// `finish_rule` computes the rule stop with the real `consumed_eof` flag, so
10591    /// reading it back keeps `$stop`/`$text` in an `@after` action aligned with
10592    /// the rule context — even when the rule ends immediately before EOF without
10593    /// matching it (cursor parked on EOF, but `consumed_eof` is false). Falls back
10594    /// to the cursor-based inference only when the tree carries no rule stop.
10595    #[must_use]
10596    pub fn after_action_stop_index_for_tree(
10597        &mut self,
10598        tree: ParseTree,
10599        current_index: usize,
10600    ) -> Option<usize> {
10601        if let Some(stop) = self
10602            .node(tree)
10603            .as_rule()
10604            .and_then(crate::tree::RuleNodeView::stop_id)
10605        {
10606            return Some(stop.index());
10607        }
10608        self.after_action_stop_index(current_index)
10609    }
10610
10611    /// Start-token index for a rule's `@after` action, taken from the start token
10612    /// the rule context already recorded.
10613    ///
10614    /// `enter_rule` sets the rule context start to the first visible token (it
10615    /// skips leading hidden-channel tokens), so reading it back keeps `$start` /
10616    /// `$text` in an `@after` action aligned with the rule context — even when the
10617    /// rule begins after a hidden prefix (e.g. leading whitespace) that the raw
10618    /// pre-rule cursor still points at. Falls back to `fallback_index` only when
10619    /// the tree carries no rule start.
10620    #[must_use]
10621    pub fn after_action_start_index_for_tree(
10622        &self,
10623        tree: ParseTree,
10624        fallback_index: usize,
10625    ) -> usize {
10626        if let Some(start) = self
10627            .node(tree)
10628            .as_rule()
10629            .and_then(crate::tree::RuleNodeView::start_id)
10630        {
10631            return start.index();
10632        }
10633        fallback_index
10634    }
10635
10636    /// Returns the rule stop token for a selected parse path.
10637    ///
10638    /// EOF transitions do not advance the token-stream cursor, so an EOF match
10639    /// must use the current token rather than the previous visible token.
10640    fn rule_stop_token_id(&mut self, index: usize, consumed_eof: bool) -> Option<TokenId> {
10641        self.rule_stop_token_index(index, consumed_eof)
10642            .and_then(|token_index| self.token_id_at(token_index))
10643    }
10644
10645    /// Recovers from a semantic predicate with an ANTLR `<fail='...'>` option.
10646    ///
10647    /// Generated Java reports the failed-predicate message at the current
10648    /// lookahead, then consumes until rule recovery can resume. The metadata
10649    /// runtime models the same visible tree shape by keeping skipped tokens as
10650    /// error nodes and returning from the active rule at EOF.
10651    fn predicate_failure_recovery(
10652        &mut self,
10653        request: PredicateFailureRecovery<'_>,
10654    ) -> RecognizeOutcome {
10655        let PredicateFailureRecovery {
10656            rule_index,
10657            index,
10658            message,
10659            member_values,
10660            return_values,
10661            rule_alt_number,
10662        } = request;
10663        let rule_name = self
10664            .rule_names()
10665            .get(rule_index)
10666            .map_or_else(|| rule_index.to_string(), Clone::clone);
10667        let diagnostic = diagnostic_for_token(
10668            self.token_at(index).as_ref(),
10669            format!("rule {rule_name} {message}"),
10670        );
10671        let mut reversed_nodes = NodeSeqId::EMPTY;
10672        let mut next_index = index;
10673        loop {
10674            let symbol = self.token_type_at(next_index);
10675            if symbol == TOKEN_EOF {
10676                break;
10677            }
10678            let error = self.arena_token_node(next_index, true);
10679            self.arena_prepend(&mut reversed_nodes, error);
10680            let after = self.consume_index(next_index, symbol);
10681            if after == next_index {
10682                break;
10683            }
10684            next_index = after;
10685        }
10686        let nodes = self.recognition_arena.reverse_sequence(reversed_nodes);
10687        let diagnostics = self
10688            .recognition_arena
10689            .prepend_diagnostic(DiagnosticSeqId::EMPTY, diagnostic);
10690        RecognizeOutcome {
10691            index: next_index,
10692            consumed_eof: false,
10693            alt_number: rule_alt_number,
10694            member_values,
10695            return_values,
10696            diagnostics,
10697            decisions: Vec::new(),
10698            actions: Vec::new(),
10699            nodes,
10700        }
10701    }
10702
10703    /// Evaluates a user hook for a predicate coordinate that has no generated
10704    /// runtime table entry.
10705    fn parser_semantic_hook_result(
10706        &mut self,
10707        request: ParserSemanticHookRequest<'_>,
10708    ) -> Option<bool> {
10709        let ParserSemanticHookRequest {
10710            index,
10711            rule_index,
10712            pred_index,
10713            context,
10714            local_int_arg,
10715            member_values,
10716        } = request;
10717        let rule_name = self.rule_names().get(rule_index).cloned();
10718        self.input.seek(index);
10719        let input = &mut self.input;
10720        let semantic_hooks = &mut self.semantic_hooks;
10721        let mut ctx = ParserSemCtx {
10722            input,
10723            tree_storage: &self.tree,
10724            rule_index,
10725            coordinate_index: pred_index,
10726            rule_name,
10727            context,
10728            tree: None,
10729            local_int_arg,
10730            member_values,
10731            action: None,
10732        };
10733        semantic_hooks.sempred(&mut ctx, rule_index, pred_index)
10734    }
10735
10736    /// Re-inserts unknown-predicate coordinates recorded before a nested
10737    /// interpreted recognition, preserving order and skipping any the nested
10738    /// call already recorded, so a generated parent's fail-loud coordinates
10739    /// survive descending into an interpreted child.
10740    fn restore_prior_unknown_predicate_hits(&mut self, prior: Vec<(usize, usize)>) {
10741        if prior.is_empty() {
10742            return;
10743        }
10744        let mut merged = prior;
10745        for coordinate in std::mem::take(&mut self.unknown_predicate_hits) {
10746            if !merged.contains(&coordinate) {
10747                merged.push(coordinate);
10748            }
10749        }
10750        self.unknown_predicate_hits = merged;
10751    }
10752
10753    /// Applies the active [`UnknownSemanticPolicy`] to a predicate coordinate
10754    /// that has no entry in the generated predicate table.
10755    ///
10756    /// Under [`UnknownSemanticPolicy::Error`] the coordinate is recorded and
10757    /// the guarded path is abandoned; the parse entry surfaces the recorded
10758    /// coordinates as [`AntlrError::Unsupported`] once recognition finishes,
10759    /// because a parse that consulted an unknown predicate is unreliable no
10760    /// matter which paths were ultimately selected.
10761    fn unknown_predicate_result(&mut self, rule_index: usize, pred_index: usize) -> bool {
10762        apply_unknown_predicate_policy(
10763            self.unknown_predicate_policy,
10764            rule_index,
10765            pred_index,
10766            &mut self.unknown_predicate_hits,
10767        )
10768    }
10769
10770    /// Builds the fail-loud error for unknown predicate coordinates recorded
10771    /// by the current parse, if any.
10772    fn unknown_semantic_error(&self) -> Option<AntlrError> {
10773        use std::fmt::Write as _;
10774        if self.unknown_predicate_hits.is_empty() && self.unhandled_action_hits.is_empty() {
10775            return None;
10776        }
10777        let mut message = String::new();
10778        for (rule_index, pred_index) in &self.unknown_predicate_hits {
10779            if !message.is_empty() {
10780                message.push_str("; ");
10781            }
10782            let _ = match self.rule_names().get(*rule_index) {
10783                Some(rule_name) => write!(
10784                    message,
10785                    "unsupported semantic predicate: rule={rule_name}({rule_index}) pred_index={pred_index}"
10786                ),
10787                None => write!(
10788                    message,
10789                    "unsupported semantic predicate: rule_index={rule_index} pred_index={pred_index}"
10790                ),
10791            };
10792        }
10793        for (rule_index, source_state) in &self.unhandled_action_hits {
10794            if !message.is_empty() {
10795                message.push_str("; ");
10796            }
10797            let _ = match self.rule_names().get(*rule_index) {
10798                Some(rule_name) => write!(
10799                    message,
10800                    "unhandled semantic action: rule={rule_name}({rule_index}) state={source_state}"
10801                ),
10802                None => write!(
10803                    message,
10804                    "unhandled semantic action: rule_index={rule_index} state={source_state}"
10805                ),
10806            };
10807        }
10808        Some(AntlrError::Unsupported(message))
10809    }
10810
10811    /// Evaluates one lowered predicate expression at the requested input
10812    /// position.
10813    ///
10814    /// This sits in the prediction hot loop, so the context borrows the
10815    /// speculative member state read-only and the rule name by reference —
10816    /// no per-evaluation allocation. Only the hook escape path materializes
10817    /// owned copies, and only when a hook is actually consulted.
10818    fn parser_semir_predicate_matches(
10819        &mut self,
10820        semantics: &ParserSemantics,
10821        predicate: &ParserSemanticPredicate,
10822        request: ParserSemanticHookRequest<'_>,
10823    ) -> bool {
10824        self.input.seek(request.index);
10825        let rule_name = self
10826            .data
10827            .rule_names()
10828            .get(request.rule_index)
10829            .map(String::as_str);
10830        let unknown_predicate_policy = self.unknown_predicate_policy;
10831        let mut ctx = ParserSemIrCtx {
10832            input: &mut self.input,
10833            tree_storage: &self.tree,
10834            semantic_hooks: &mut self.semantic_hooks,
10835            rule_index: request.rule_index,
10836            coordinate_index: request.pred_index,
10837            rule_name,
10838            context: request.context,
10839            local_int_arg: request.local_int_arg,
10840            member_values: request.member_values,
10841            invoked_predicates: &mut self.invoked_predicates,
10842            unknown_predicate_policy,
10843            unknown_predicate_hits: &mut self.unknown_predicate_hits,
10844        };
10845        semir::eval_pred(&semantics.ir, predicate.expr, &mut ctx)
10846    }
10847
10848    fn fast_parser_predicate_matches(
10849        &mut self,
10850        context: Option<FastPredicateContext<'_>>,
10851        transition: ParserTransition<'_>,
10852        index: usize,
10853    ) -> bool {
10854        let Some(context) = context else {
10855            return true;
10856        };
10857        let rule_index = transition.arg0() as usize;
10858        let pred_index = transition.arg1() as usize;
10859        let key = (index, rule_index, pred_index);
10860        if let Some(result) = self.fast_predicate_cache.get(&key) {
10861            return *result;
10862        }
10863        let result = self.parser_predicate_matches(PredicateEval {
10864            index,
10865            rule_index,
10866            pred_index,
10867            predicates: context.predicates,
10868            semantics: context.semantics,
10869            context: None,
10870            local_int_arg: None,
10871            member_values: context.member_values,
10872        });
10873        self.fast_predicate_cache.insert(key, result);
10874        result
10875    }
10876
10877    fn parser_predicate_matches(&mut self, eval: PredicateEval<'_>) -> bool {
10878        let PredicateEval {
10879            index,
10880            rule_index,
10881            pred_index,
10882            predicates,
10883            semantics,
10884            context,
10885            local_int_arg,
10886            member_values,
10887        } = eval;
10888        if let Some((semantics, predicate)) = semantics.and_then(|semantics| {
10889            semantics
10890                .predicates
10891                .iter()
10892                .find(|predicate| {
10893                    predicate.rule_index == rule_index && predicate.pred_index == pred_index
10894                })
10895                .map(|predicate| (semantics, predicate))
10896        }) {
10897            return self.parser_semir_predicate_matches(
10898                semantics,
10899                predicate,
10900                ParserSemanticHookRequest {
10901                    index,
10902                    rule_index,
10903                    pred_index,
10904                    context,
10905                    local_int_arg,
10906                    member_values,
10907                },
10908            );
10909        }
10910        let Some((_, _, predicate)) = predicates
10911            .iter()
10912            .find(|(rule, pred, _)| *rule == rule_index && *pred == pred_index)
10913        else {
10914            if let Some(result) = self.parser_semantic_hook_result(ParserSemanticHookRequest {
10915                index,
10916                rule_index,
10917                pred_index,
10918                context,
10919                local_int_arg,
10920                member_values,
10921            }) {
10922                return result;
10923            }
10924            return self.unknown_predicate_result(rule_index, pred_index);
10925        };
10926        self.input.seek(index);
10927        match predicate {
10928            ParserPredicate::True => true,
10929            ParserPredicate::False => false,
10930            ParserPredicate::FalseWithMessage { .. } => false,
10931            ParserPredicate::Invoke { value } => {
10932                let key = (rule_index, pred_index);
10933                if !self.invoked_predicates.contains(&key) {
10934                    self.invoked_predicates.push(key);
10935                    use std::io::Write as _;
10936                    let mut stdout = std::io::stdout().lock();
10937                    let _ = writeln!(stdout, "eval={value}");
10938                }
10939                *value
10940            }
10941            ParserPredicate::LookaheadTextEquals { offset, text } => self
10942                .input
10943                .lt(*offset)
10944                .is_some_and(|token| Token::text(&token) == Some(*text)),
10945            ParserPredicate::LookaheadNotEquals { offset, token_type } => {
10946                self.la(*offset) != *token_type
10947            }
10948            ParserPredicate::TokenPairAdjacent => {
10949                let Some(first) = self.input.lt_id(-2).map(TokenId::index) else {
10950                    return false;
10951                };
10952                let Some(second) = self.input.lt_id(-1).map(TokenId::index) else {
10953                    return false;
10954                };
10955                first + 1 == second
10956            }
10957            ParserPredicate::ContextChildRuleTextNotEquals { rule_index, text } => context
10958                .and_then(|context| {
10959                    context
10960                        .child_rules(&self.tree, self.input.token_store(), *rule_index)
10961                        .next()
10962                        .map(crate::tree::RuleNodeView::text)
10963                })
10964                .is_none_or(|actual| actual != *text),
10965            ParserPredicate::LocalIntEquals { value } => {
10966                local_int_arg.is_none_or(|(_, actual)| actual == *value)
10967            }
10968            ParserPredicate::LocalIntLessOrEqual { value } => {
10969                local_int_arg.is_none_or(|(_, actual)| actual <= *value)
10970            }
10971            ParserPredicate::MemberModuloEquals {
10972                member,
10973                modulus,
10974                value,
10975                equals,
10976            } => {
10977                if *modulus == 0 {
10978                    return false;
10979                }
10980                let actual = member_values.get(member).copied().unwrap_or_default() % *modulus;
10981                (actual == *value) == *equals
10982            }
10983            ParserPredicate::MemberEquals {
10984                member,
10985                value,
10986                equals,
10987            } => {
10988                let actual = member_values.get(member).copied().unwrap_or_default();
10989                (actual == *value) == *equals
10990            }
10991        }
10992    }
10993
10994    /// Returns a generated fail-option message for a predicate coordinate.
10995    fn parser_predicate_failure_message(
10996        &self,
10997        rule_index: usize,
10998        pred_index: usize,
10999        predicates: &[(usize, usize, ParserPredicate)],
11000    ) -> Option<&'static str> {
11001        predicates
11002            .iter()
11003            .find_map(|(rule, pred, predicate)| match predicate {
11004                ParserPredicate::FalseWithMessage { message }
11005                    if *rule == rule_index && *pred == pred_index =>
11006                {
11007                    Some(*message)
11008                }
11009                _ => None,
11010            })
11011    }
11012
11013    /// Returns a generated fail-option message for a `SemIR` predicate
11014    /// coordinate.
11015    pub fn parser_semantic_ir_predicate_failure_message(
11016        &self,
11017        rule_index: usize,
11018        pred_index: usize,
11019        semantics: &ParserSemantics,
11020    ) -> Option<&'static str> {
11021        semantics
11022            .predicates
11023            .iter()
11024            .find(|predicate| {
11025                predicate.rule_index == rule_index && predicate.pred_index == pred_index
11026            })
11027            .and_then(|predicate| predicate.failure_message)
11028    }
11029
11030    /// Returns the token-stream index after consuming `symbol` at `index`.
11031    ///
11032    /// EOF is not advanced by ANTLR token streams, so EOF transitions keep the
11033    /// index stable and rely on `consumed_eof` to record that EOF was matched.
11034    /// The parser's stream cursor is left untouched: speculative recognition
11035    /// reads ahead by absolute index, so paying for `seek` on every visited
11036    /// state would dominate the hot path. Real consumption is committed by
11037    /// `parse_atn_rule` via `seek` once a viable outcome is selected.
11038    fn consume_index(&mut self, index: usize, symbol: i32) -> usize {
11039        if symbol == TOKEN_EOF {
11040            return index;
11041        }
11042        self.input.next_visible_after(index)
11043    }
11044
11045    /// Builds ANTLR's no-viable-alternative diagnostic for an ambiguous
11046    /// decision that failed after consuming a shared prefix.
11047    fn no_viable_alternative(&self, start_index: usize, error_index: usize) -> ParserDiagnostic {
11048        let text = display_input_text(&self.input.text(start_index, error_index));
11049        diagnostic_for_token(
11050            self.token_at(error_index).as_ref(),
11051            format!("no viable alternative at input '{text}'"),
11052        )
11053    }
11054
11055    /// Selects the diagnostic for a failed consuming transition after all
11056    /// recovery repairs have been ruled out.
11057    fn recovery_failure_diagnostic(
11058        &self,
11059        index: usize,
11060        decision_start_index: Option<usize>,
11061        expected_symbols: &BTreeSet<i32>,
11062    ) -> ParserDiagnostic {
11063        if expected_symbols.len() > 1 {
11064            if let Some(decision_start) = no_viable_decision_start(decision_start_index, index) {
11065                return self.no_viable_alternative(decision_start, index);
11066            }
11067        }
11068        diagnostic_for_token(
11069            self.token_at(index).as_ref(),
11070            format!(
11071                "mismatched input {} expecting {}",
11072                self.token_at(index)
11073                    .as_ref()
11074                    .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
11075                self.expected_symbols_display(expected_symbols)
11076            ),
11077        )
11078    }
11079
11080    /// Builds the EOF diagnostic used when ANTLR unwinds a failed nested rule
11081    /// instead of inserting missing tokens in the caller.
11082    fn eof_rule_recovery_diagnostic(
11083        &self,
11084        index: usize,
11085        expected_symbols: &BTreeSet<i32>,
11086        expected: &ExpectedTokens,
11087    ) -> ParserDiagnostic {
11088        let symbols = if expected.index == Some(index) && !expected.symbols.is_empty() {
11089            &expected.symbols
11090        } else {
11091            expected_symbols
11092        };
11093        diagnostic_for_token(
11094            self.token_at(index).as_ref(),
11095            format!(
11096                "mismatched input {} expecting {}",
11097                self.token_at(index)
11098                    .as_ref()
11099                    .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
11100                self.expected_symbols_display(symbols)
11101            ),
11102        )
11103    }
11104
11105    /// Returns token text for a buffered token interval used by generated
11106    /// `$text` actions.
11107    ///
11108    /// ANTLR treats EOF as a range boundary rather than printable input text,
11109    /// even when an action interval explicitly stops at the EOF token.
11110    pub fn text_interval(&self, start: usize, stop: Option<usize>) -> String {
11111        let Some(stop) = stop else {
11112            return String::new();
11113        };
11114        let stop = if self
11115            .token_at(stop)
11116            .is_some_and(|token| token.token_type() == TOKEN_EOF)
11117        {
11118            let Some(previous) = self.previous_token_index(stop) else {
11119                return String::new();
11120            };
11121            previous
11122        } else {
11123            stop
11124        };
11125        self.input.text(start, stop)
11126    }
11127
11128    /// Resets per-parse prediction diagnostics while keeping the parser-level
11129    /// reporting flag configured by generated harness code.
11130    fn clear_prediction_diagnostics(&mut self) {
11131        self.prediction_diagnostics.clear();
11132        self.reported_prediction_diagnostics.clear();
11133    }
11134
11135    /// Drops every per-parse cache that depends on ATN identity or pins
11136    /// recovery-symbol allocations.
11137    ///
11138    /// `BaseParser::parse_atn_rule` takes `&Atn` on each invocation, so the
11139    /// same parser instance can legally be driven against different grammars
11140    /// in sequence. The four caches reset here are keyed by raw ATN
11141    /// coordinates (state numbers, rule indexes) and would silently hand back
11142    /// entries from a previous ATN if reused — pruning lookahead against the
11143    /// wrong transitions or pinning recovery `Rc<BTreeSet<i32>>` allocations
11144    /// for the rest of the process. Clearing them on every parse entry keeps
11145    /// the perf wins (caches still amortize within one parse) without making
11146    /// long-lived parsers leak memory or surface stale ATN data:
11147    ///
11148    /// * `rule_first_set_cache` and `decision_lookahead_cache` are pure
11149    ///   functions of the ATN's state graph.
11150    /// * `state_expected_cache`, `state_expected_token_cache`,
11151    ///   `rule_stop_reach_cache`, and
11152    ///   `recovery_symbols_intern` together form
11153    ///   the identity invariant that lets `FastRecognizeKey` hash
11154    ///   `recovery_symbols` by pointer; they have to be cleared in lockstep
11155    ///   so a stale interned `Rc` cannot outlive its map entry.
11156    /// * `empty_cycle_cache` is grammar-static and carries its own ATN key, so
11157    ///   it is retained here and invalidated lazily when the ATN changes.
11158    fn reset_per_parse_caches(&mut self) {
11159        self.rule_first_set_cache.clear();
11160        self.decision_lookahead_cache.clear();
11161        self.ll1_decision_cache.clear();
11162        self.fast_predicate_cache.clear();
11163        self.rule_stop_reach_cache.clear();
11164        self.clean_memo_mode = CleanMemoMode::Probe;
11165        self.clean_memo_probe_seen.clear();
11166        self.clean_memo_probe_samples = 0;
11167        self.clean_memo_probe_repeats = 0;
11168        self.clean_memo_sparse_samples = 0;
11169        self.recovery_symbols_intern.clear();
11170        self.state_expected_cache.clear();
11171        self.state_expected_token_cache.clear();
11172    }
11173
11174    /// Buffers ANTLR-style diagnostic-listener messages for decision states
11175    /// where multiple clean alternatives survive full-context recognition.
11176    fn record_prediction_diagnostics(
11177        &mut self,
11178        atn: &Atn,
11179        state: AtnState<'_>,
11180        start_index: usize,
11181        outcomes: &[RecognizeOutcome],
11182    ) {
11183        if !self.report_diagnostic_errors || state.transitions().len() < 2 {
11184            return;
11185        }
11186        let Some(decision) = atn
11187            .decision_to_state()
11188            .iter()
11189            .position(|state_number| state_number == state.state_number())
11190        else {
11191            return;
11192        };
11193        let Some(rule_index) = state.rule_index() else {
11194            return;
11195        };
11196        let mut alts_by_end = BTreeMap::<usize, BTreeSet<usize>>::new();
11197        for outcome in outcomes
11198            .iter()
11199            .filter(|outcome| outcome.diagnostics.is_empty())
11200        {
11201            let Some(alt) = outcome.decisions.first() else {
11202                continue;
11203            };
11204            alts_by_end
11205                .entry(outcome.index)
11206                .or_default()
11207                .insert(alt + 1);
11208        }
11209        let Some((&end_index, ambig_alts)) = alts_by_end
11210            .iter()
11211            .filter(|(_, alts)| alts.len() > 1)
11212            .max_by_key(|(end, _)| *end)
11213        else {
11214            return;
11215        };
11216        let rule_name = self
11217            .rule_names()
11218            .get(rule_index)
11219            .map_or_else(|| "<unknown>".to_owned(), Clone::clone);
11220        let stop_index = self.previous_token_index(end_index).unwrap_or(start_index);
11221        let input = display_input_text(&self.input.text(start_index, stop_index));
11222        let alts = ambig_alts
11223            .iter()
11224            .map(usize::to_string)
11225            .collect::<Vec<_>>()
11226            .join(", ");
11227        let key = (decision, start_index, format!("{alts}:{input}"));
11228        if !self.reported_prediction_diagnostics.insert(key) {
11229            return;
11230        }
11231        let start_diagnostic = diagnostic_for_token(
11232            self.token_at(start_index),
11233            format!("reportAttemptingFullContext d={decision} ({rule_name}), input='{input}'"),
11234        );
11235        let stop_diagnostic = diagnostic_for_token(
11236            self.token_at(stop_index),
11237            format!(
11238                "reportAmbiguity d={decision} ({rule_name}): ambigAlts={{{alts}}}, input='{input}'"
11239            ),
11240        );
11241        self.prediction_diagnostics.push(start_diagnostic);
11242        self.prediction_diagnostics.push(stop_diagnostic);
11243    }
11244
11245    /// Formats the tokens expected from an ATN state using ANTLR display names.
11246    pub fn expected_tokens_at_state(&self, atn: &Atn, state_number: usize) -> String {
11247        expected_symbols_display(
11248            &state_expected_symbols(atn, state_number),
11249            self.vocabulary(),
11250        )
11251    }
11252
11253    /// Expected-token set at the parser's current ATN state — ANTLR's
11254    /// `getExpectedTokens()`. Generated recognizers expose this as
11255    /// `self.expected_tokens()` for embedded test actions
11256    /// (`self.expected_tokens().to_token_string(self.vocabulary())`).
11257    pub fn expected_tokens_current(&self, atn: &Atn) -> ExpectedTokenSet {
11258        let state = usize::try_from(self.data().state()).unwrap_or(0);
11259        ExpectedTokenSet {
11260            symbols: state_expected_symbols(atn, state),
11261        }
11262    }
11263
11264    /// Enables the bail error strategy: the first syntax error aborts the
11265    /// parse instead of recovering.
11266    pub const fn set_bail_on_error(&mut self, bail: bool) {
11267        self.bail_on_error = bail;
11268    }
11269
11270    /// Whether the bail error strategy is active.
11271    #[must_use]
11272    pub const fn bail_on_error(&self) -> bool {
11273        self.bail_on_error
11274    }
11275
11276    /// Names of the rules on the live invocation stack, current rule first —
11277    /// ANTLR's `getRuleInvocationStack()`.
11278    pub fn rule_invocation_stack(&self) -> Vec<String> {
11279        self.rule_context_stack
11280            .iter()
11281            .rev()
11282            .map(|frame| {
11283                self.data()
11284                    .rule_names()
11285                    .get(frame.rule_index)
11286                    .cloned()
11287                    .unwrap_or_else(|| format!("<{}>", frame.rule_index))
11288            })
11289            .collect()
11290    }
11291
11292    /// Invoking-state chain for the active rule context, current rule first.
11293    ///
11294    /// The root frame is excluded, matching Java's `RuleContext.toString()`.
11295    pub fn active_invocation_states(&self) -> Vec<isize> {
11296        self.rule_context_stack
11297            .iter()
11298            .skip(1)
11299            .rev()
11300            .map(|frame| frame.invoking_state)
11301            .collect()
11302    }
11303
11304    /// Formats a buffered token in ANTLR's diagnostic token display form.
11305    pub fn token_display_at(&self, index: usize) -> Option<String> {
11306        self.token_at(index).map(|token| format!("{token}"))
11307    }
11308}
11309
11310impl<'atn, S, H> DirectAdaptiveParser<'atn, '_, S, H>
11311where
11312    S: TokenSource,
11313    H: SemanticHooks,
11314{
11315    fn parse_rule(
11316        &mut self,
11317        rule_index: usize,
11318        invoking_state: isize,
11319        precedence: i32,
11320    ) -> DirectAdaptiveParseResult<ParseTree> {
11321        let start_state = self.atn.rule_to_start_state().get(rule_index).ok_or(
11322            DirectAdaptiveParseControl::Fallback(DirectAdaptiveFallback::MissingAtn),
11323        )?;
11324        let stop_state = self
11325            .atn
11326            .rule_to_stop_state()
11327            .get(rule_index)
11328            .filter(|state| *state != usize::MAX)
11329            .ok_or(DirectAdaptiveParseControl::Fallback(
11330                DirectAdaptiveFallback::MissingAtn,
11331            ))?;
11332        let start_index = self.parser.current_visible_index();
11333        let mut context = ParserRuleContext::new(rule_index, invoking_state);
11334        if let Some(token) = self.parser.token_id_at(start_index) {
11335            self.parser.set_context_start(&mut context, token);
11336        }
11337        let mut state_number = start_state;
11338        let mut consumed_eof = false;
11339        while state_number != stop_state {
11340            self.step()?;
11341            let (transition, boundary) = self.next_transition(state_number, precedence)?;
11342            if boundary.is_some() {
11343                return Err(DirectAdaptiveParseControl::Fallback(
11344                    DirectAdaptiveFallback::LeftRecursiveBoundary,
11345                ));
11346            }
11347            match transition.data() {
11348                Transition::Epsilon { target } => {
11349                    state_number = target;
11350                }
11351                Transition::Precedence {
11352                    target,
11353                    precedence: transition_precedence,
11354                } => {
11355                    if transition_precedence < precedence {
11356                        return Err(DirectAdaptiveParseControl::Fallback(
11357                            DirectAdaptiveFallback::Precedence,
11358                        ));
11359                    }
11360                    state_number = target;
11361                }
11362                Transition::Rule {
11363                    rule_index,
11364                    follow_state,
11365                    precedence: rule_precedence,
11366                    ..
11367                } => {
11368                    let child = self.parse_rule(
11369                        rule_index,
11370                        invoking_state_number(state_number),
11371                        rule_precedence,
11372                    )?;
11373                    if self.parser.build_parse_trees {
11374                        self.parser.tree.add_child(&mut context, child);
11375                    }
11376                    state_number = follow_state;
11377                }
11378                Transition::Atom { .. }
11379                | Transition::Range { .. }
11380                | Transition::Set { .. }
11381                | Transition::NotSet { .. }
11382                | Transition::Wildcard { .. } => {
11383                    let (matched_eof, child) = self.consume_transition(transition)?;
11384                    consumed_eof |= matched_eof;
11385                    if let Some(child) = child {
11386                        self.parser.tree.add_child(&mut context, child);
11387                    }
11388                    state_number = transition.target();
11389                }
11390                Transition::Predicate { .. } => {
11391                    return Err(DirectAdaptiveParseControl::Fallback(
11392                        DirectAdaptiveFallback::Predicate,
11393                    ));
11394                }
11395                Transition::Action { .. } => {
11396                    return Err(DirectAdaptiveParseControl::Fallback(
11397                        DirectAdaptiveFallback::Action,
11398                    ));
11399                }
11400            }
11401        }
11402
11403        let stop_index = self
11404            .parser
11405            .rule_stop_token_index(self.parser.input.index(), consumed_eof);
11406        if let Some(token) = stop_index.and_then(|index| self.parser.token_id_at(index)) {
11407            self.parser.set_context_stop(&mut context, token);
11408        }
11409        Ok(self.parser.rule_node(context))
11410    }
11411
11412    const fn step(&mut self) -> DirectAdaptiveParseResult<()> {
11413        self.steps += 1;
11414        if self.steps > ADAPTIVE_DIRECT_STEP_LIMIT {
11415            return Err(DirectAdaptiveParseControl::Fallback(
11416                DirectAdaptiveFallback::StepLimit,
11417            ));
11418        }
11419        Ok(())
11420    }
11421
11422    fn next_transition(
11423        &mut self,
11424        state_number: usize,
11425        precedence: i32,
11426    ) -> DirectAdaptiveParseResult<(ParserTransition<'atn>, Option<usize>)> {
11427        let state = self
11428            .atn
11429            .state(state_number)
11430            .ok_or(DirectAdaptiveParseControl::Fallback(
11431                DirectAdaptiveFallback::MissingAtn,
11432            ))?;
11433        if state.is_rule_stop() {
11434            return Err(DirectAdaptiveParseControl::Fallback(
11435                DirectAdaptiveFallback::RuleStop,
11436            ));
11437        }
11438        let transition_index =
11439            self.transition_index(state_number, state.transitions().len(), precedence)?;
11440        let transition = state.transitions().get(transition_index).ok_or(
11441            DirectAdaptiveParseControl::Fallback(DirectAdaptiveFallback::NoTransition),
11442        )?;
11443        let boundary = match &transition.data() {
11444            Transition::Epsilon { target } | Transition::Precedence { target, .. } => {
11445                left_recursive_boundary(self.atn, state, *target)
11446            }
11447            _ => None,
11448        };
11449        Ok((transition, boundary))
11450    }
11451
11452    fn transition_index(
11453        &mut self,
11454        state_number: usize,
11455        transition_count: usize,
11456        precedence: i32,
11457    ) -> DirectAdaptiveParseResult<usize> {
11458        match transition_count {
11459            0 => Err(DirectAdaptiveParseControl::Fallback(
11460                DirectAdaptiveFallback::NoTransition,
11461            )),
11462            1 => Ok(0),
11463            _ => {
11464                if let Some(alt) = self.ll1_transition_index(state_number, transition_count)? {
11465                    return Ok(alt);
11466                }
11467                let decision = self
11468                    .decision_by_state
11469                    .get(state_number)
11470                    .and_then(|decision| *decision)
11471                    .ok_or(DirectAdaptiveParseControl::Fallback(
11472                        DirectAdaptiveFallback::UnknownDecision,
11473                    ))?;
11474                let prediction = self
11475                    .simulator
11476                    .adaptive_predict_stream_info_with_precedence(
11477                        decision,
11478                        direct_precedence(precedence),
11479                        &mut self.parser.input,
11480                    )
11481                    .map_err(|_| {
11482                        DirectAdaptiveParseControl::Fallback(DirectAdaptiveFallback::Prediction)
11483                    })?;
11484                if prediction.has_semantic_context {
11485                    return Err(DirectAdaptiveParseControl::Fallback(
11486                        DirectAdaptiveFallback::SemanticContext,
11487                    ));
11488                }
11489                prediction
11490                    .alt
11491                    .checked_sub(1)
11492                    .filter(|index| *index < transition_count)
11493                    .ok_or(DirectAdaptiveParseControl::Fallback(
11494                        DirectAdaptiveFallback::InvalidAlt,
11495                    ))
11496            }
11497        }
11498    }
11499
11500    fn ll1_transition_index(
11501        &mut self,
11502        state_number: usize,
11503        transition_count: usize,
11504    ) -> DirectAdaptiveParseResult<Option<usize>> {
11505        let state = self
11506            .atn
11507            .state(state_number)
11508            .ok_or(DirectAdaptiveParseControl::Fallback(
11509                DirectAdaptiveFallback::MissingAtn,
11510            ))?;
11511        if state.precedence_rule_decision() {
11512            return Ok(None);
11513        }
11514        let Some(rule_stop) = state
11515            .rule_index()
11516            .and_then(|rule_index| self.atn.rule_to_stop_state().get(rule_index))
11517        else {
11518            return Ok(None);
11519        };
11520        let symbol = self.parser.input.la_token(1);
11521        let entry = self
11522            .parser
11523            .cached_decision_lookahead(self.atn, state, rule_stop);
11524        Ok(
11525            ll1_greedy_alt(&entry, symbol, state.non_greedy())
11526                .filter(|alt| *alt < transition_count),
11527        )
11528    }
11529
11530    fn consume_transition(
11531        &mut self,
11532        transition: ParserTransition<'_>,
11533    ) -> DirectAdaptiveParseResult<(bool, Option<ParseTree>)> {
11534        let symbol = self.parser.input.la_token(1);
11535        if !transition.matches(symbol, 1, self.atn.max_token_type()) {
11536            return Err(DirectAdaptiveParseControl::Fallback(
11537                DirectAdaptiveFallback::TokenMismatch,
11538            ));
11539        }
11540        let token = self
11541            .parser
11542            .input
11543            .lt_id(1)
11544            .ok_or(DirectAdaptiveParseControl::Fallback(
11545                DirectAdaptiveFallback::TokenMismatch,
11546            ))?;
11547        let matched_eof = symbol == TOKEN_EOF;
11548        if !matched_eof {
11549            self.parser.consume();
11550        }
11551        let child = self
11552            .parser
11553            .build_parse_trees
11554            .then(|| self.parser.terminal_tree(token));
11555        Ok((matched_eof, child))
11556    }
11557}
11558
11559/// Detects the loop edge where ANTLR would call `pushNewRecursionContext` for a
11560/// transformed left-recursive rule.
11561fn left_recursive_boundary(atn: &Atn, state: AtnState<'_>, target: usize) -> Option<usize> {
11562    if !state.precedence_rule_decision() {
11563        return None;
11564    }
11565    let target_state = atn.state(target)?;
11566    if target_state.kind() == AtnStateKind::LoopEnd {
11567        return None;
11568    }
11569    state.rule_index()
11570}
11571
11572/// Selects the first outer alternative observed for a rule path.
11573///
11574/// ANTLR's alt-numbered tree contexts store the rule alternative chosen at the
11575/// outer decision. The metadata recognizer only needs this when a generated
11576/// grammar opts into that target template; otherwise the value remains `0` and
11577/// parse-tree rendering is unchanged.
11578fn next_alt_number(
11579    state: AtnState<'_>,
11580    transition_count: usize,
11581    transition_index: usize,
11582    current_alt_number: usize,
11583    track_alt_numbers: bool,
11584) -> usize {
11585    if !track_alt_numbers || current_alt_number != 0 || transition_count <= 1 {
11586        return current_alt_number;
11587    }
11588    if matches!(
11589        state.kind(),
11590        AtnStateKind::Basic
11591            | AtnStateKind::BlockStart
11592            | AtnStateKind::PlusBlockStart
11593            | AtnStateKind::StarBlockStart
11594            | AtnStateKind::StarLoopEntry
11595    ) && !state.precedence_rule_decision()
11596    {
11597        return transition_index + 1;
11598    }
11599    current_alt_number
11600}
11601
11602/// Converts an ATN state number into the signed invoking-state slot used by
11603/// ANTLR parse-tree contexts, saturating only for impossible platform widths.
11604fn invoking_state_number(state_number: usize) -> isize {
11605    isize::try_from(state_number).unwrap_or(isize::MAX)
11606}
11607
11608const fn packed_i32(value: u32) -> i32 {
11609    i32::from_le_bytes(value.to_le_bytes())
11610}
11611
11612fn direct_precedence(precedence: i32) -> usize {
11613    usize::try_from(precedence.max(0)).unwrap_or_default()
11614}
11615
11616fn token_input_display(token: &impl Token) -> String {
11617    format!("'{}'", token.text().unwrap_or("<EOF>"))
11618}
11619
11620fn display_input_text(text: &str) -> String {
11621    let mut out = String::new();
11622    for ch in text.chars() {
11623        match ch {
11624            '\n' => out.push_str("\\n"),
11625            '\r' => out.push_str("\\r"),
11626            '\t' => out.push_str("\\t"),
11627            other => out.push(other),
11628        }
11629    }
11630    out
11631}
11632
11633fn diagnostic_for_token<T: Token>(token: Option<T>, message: String) -> ParserDiagnostic {
11634    let (line, column) = token.map_or((0, 0), |token| (token.line(), token.column()));
11635    ParserDiagnostic {
11636        line,
11637        column,
11638        message,
11639    }
11640}
11641
11642fn expected_symbols_display(symbols: &BTreeSet<i32>, vocabulary: &Vocabulary) -> String {
11643    expected_symbols_display_iter(symbols.iter().copied(), vocabulary)
11644}
11645
11646fn expected_symbols_display_iter(
11647    symbols: impl IntoIterator<Item = i32>,
11648    vocabulary: &Vocabulary,
11649) -> String {
11650    let items = symbols
11651        .into_iter()
11652        .map(|symbol| expected_symbol_display(symbol, vocabulary))
11653        .collect::<Vec<_>>();
11654    if let [single] = items.as_slice() {
11655        return single.clone();
11656    }
11657    format!("{{{}}}", items.join(", "))
11658}
11659
11660fn expected_symbol_display(symbol: i32, vocabulary: &Vocabulary) -> String {
11661    if symbol == TOKEN_EOF {
11662        return "<EOF>".to_owned();
11663    }
11664    vocabulary.display_name(symbol)
11665}
11666
11667fn caller_follow_token_info_for_stream<S: TokenSource>(
11668    input: &mut CommonTokenStream<S>,
11669    index: usize,
11670) -> (i32, bool, bool) {
11671    // Generated callers own statement separators; leave them available when
11672    // an interpreted child rule can either stop before or consume one.
11673    if index >= FAST_RECOGNIZER_DEFERRED_FILL_AT && !input.is_filled() {
11674        input.fill();
11675    }
11676    let token_type = input.token_type_at_index(index);
11677    let visible_channel = input.channel();
11678    let token = input.get(index);
11679    let is_boundary = token
11680        .as_ref()
11681        .and_then(Token::text)
11682        .is_some_and(is_caller_follow_boundary_text);
11683    let is_boundary_gap = token.as_ref().is_some_and(|token| {
11684        token.channel() != visible_channel
11685            || is_caller_follow_boundary_gap_text(token.text_or_empty())
11686    });
11687    (token_type, is_boundary, is_boundary_gap)
11688}
11689
11690fn is_caller_follow_boundary_text(text: &str) -> bool {
11691    text.chars().any(|ch| ch == ';' || ch == '\n')
11692        && text.chars().all(|ch| ch.is_whitespace() || ch == ';')
11693}
11694
11695fn is_caller_follow_boundary_gap_text(text: &str) -> bool {
11696    text.chars().all(|ch| ch.is_whitespace() || ch == ';')
11697}
11698
11699/// Returns whether `state` belongs to an ANTLR-transformed left-recursive rule.
11700/// Inline insertion in those precedence loops can synthesize a missing operand
11701/// before an operator and then block the legitimate loop-exit path.
11702fn state_is_left_recursive_rule(atn: &Atn, state: AtnState<'_>) -> bool {
11703    let Some(rule_index) = state.rule_index() else {
11704        return false;
11705    };
11706    atn.rule_to_start_state()
11707        .get(rule_index)
11708        .and_then(|state_number| atn.state(state_number))
11709        .is_some_and(AtnState::left_recursive_rule)
11710}
11711
11712/// Picks the better of two `parse_atn_rule` passes (with and without the
11713/// FIRST-set prefilter). A clean outcome (no diagnostics) always wins over a
11714/// recovered one; among recovered outcomes the second pass is preferred
11715/// because the no-prefilter walk reaches ANTLR-style recovery inside child
11716/// rules. If both passes failed, the second pass's expected-token snapshot
11717/// is returned so the caller renders the same diagnostic ANTLR would.
11718fn select_better_top_outcome(
11719    first: Result<(FastRecognizeOutcome, ExpectedTokens), ExpectedTokens>,
11720    second: Result<(FastRecognizeOutcome, ExpectedTokens), ExpectedTokens>,
11721    arena: &RecognitionArena,
11722) -> Result<(FastRecognizeOutcome, ExpectedTokens), ExpectedTokens> {
11723    match (first, second) {
11724        (Ok(first), Ok(second)) => {
11725            if arena.diagnostics(first.0.diagnostics).next().is_none() {
11726                Ok(first)
11727            } else {
11728                Ok(second)
11729            }
11730        }
11731        (Ok(first), Err(_)) => Ok(first),
11732        (Err(_), Ok(second)) => Ok(second),
11733        (Err(_), Err(second_expected)) => Err(second_expected),
11734    }
11735}
11736
11737/// Chooses the outermost parse result that consumed the most input.
11738///
11739/// The recognizer intentionally keeps shorter endpoints available while walking
11740/// nested rule transitions so callers can satisfy following tokens such as
11741/// `expr 'and' expr`. Only the public rule entry commits to one endpoint.
11742fn select_best_fast_outcome(
11743    outcomes: impl Iterator<Item = FastRecognizeOutcome>,
11744    prediction_mode: PredictionMode,
11745    caller_follow: Option<&TokenBitSet>,
11746    mut token_info_at: impl FnMut(usize) -> (i32, bool, bool),
11747    arena: &RecognitionArena,
11748) -> Option<FastRecognizeOutcome> {
11749    let mut best = None;
11750    let mut best_caller_follow = None;
11751    for outcome in outcomes {
11752        if matches!(
11753            prediction_mode,
11754            PredictionMode::Ll | PredictionMode::LlExactAmbigDetection
11755        ) && outcome.diagnostics.is_empty()
11756            && let Some(follow) = caller_follow
11757        {
11758            let (token_type, is_boundary, _) = token_info_at(outcome.index);
11759            if is_boundary && follow.contains(token_type) {
11760                let replace =
11761                    best_caller_follow
11762                        .as_ref()
11763                        .is_none_or(|existing: &FastRecognizeOutcome| {
11764                            (outcome.index, outcome.consumed_eof)
11765                                < (existing.index, existing.consumed_eof)
11766                        });
11767                if replace {
11768                    best_caller_follow = Some(outcome);
11769                }
11770            }
11771        }
11772        let Some(existing) = best else {
11773            best = Some(outcome);
11774            continue;
11775        };
11776        let outcome_position = (outcome.index, outcome.consumed_eof);
11777        let best_position = (existing.index, existing.consumed_eof);
11778        let better = match prediction_mode {
11779            PredictionMode::Ll | PredictionMode::LlExactAmbigDetection => outcome_is_better(
11780                outcome_position,
11781                outcome.diagnostics,
11782                best_position,
11783                existing.diagnostics,
11784                arena,
11785            ),
11786            PredictionMode::Sll => outcome.index > existing.index,
11787        };
11788        best = Some(if better { outcome } else { existing });
11789    }
11790    let should_use_caller_follow =
11791        best_caller_follow
11792            .as_ref()
11793            .zip(best.as_ref())
11794            .is_some_and(|(candidate, selected)| {
11795                if !selected.diagnostics.is_empty() {
11796                    return true;
11797                }
11798                candidate.index < selected.index
11799                    && (candidate.index..selected.index).all(|index| token_info_at(index).2)
11800            });
11801    if should_use_caller_follow {
11802        best_caller_follow
11803    } else {
11804        best
11805    }
11806}
11807
11808fn select_best_outcome(
11809    outcomes: impl Iterator<Item = RecognizeOutcome>,
11810    prediction_mode: PredictionMode,
11811    arena: &RecognitionArena,
11812) -> Option<RecognizeOutcome> {
11813    let outcomes = outcomes.collect::<Vec<_>>();
11814    let prefer_first_tie = outcomes
11815        .iter()
11816        .any(|outcome| arena.sequence_needs_stable_tie(outcome.nodes));
11817    outcomes.into_iter().reduce(|best, outcome| {
11818        let outcome_position = (outcome.index, outcome.consumed_eof);
11819        let best_position = (best.index, best.consumed_eof);
11820        let better = match prediction_mode {
11821            PredictionMode::Ll | PredictionMode::LlExactAmbigDetection => {
11822                outcome_is_better(
11823                    outcome_position,
11824                    outcome.diagnostics,
11825                    best_position,
11826                    best.diagnostics,
11827                    arena,
11828                ) || (!prefer_first_tie
11829                    && outcome_position == best_position
11830                    && arena.diagnostics_len(outcome.diagnostics)
11831                        == arena.diagnostics_len(best.diagnostics)
11832                    && arena.diagnostics_recovery_rank(outcome.diagnostics)
11833                        == arena.diagnostics_recovery_rank(best.diagnostics)
11834                    && (outcome.decisions < best.decisions
11835                        || (outcome.decisions == best.decisions && outcome.actions > best.actions)))
11836            }
11837            PredictionMode::Sll => {
11838                outcome_position > best_position
11839                    || (outcome_position == best_position
11840                        && !prefer_first_tie
11841                        && (outcome.decisions < best.decisions
11842                            || (outcome.decisions == best.decisions
11843                                && outcome_is_better(
11844                                    outcome_position,
11845                                    outcome.diagnostics,
11846                                    best_position,
11847                                    best.diagnostics,
11848                                    arena,
11849                                ))))
11850            }
11851        };
11852        if better {
11853            return outcome;
11854        }
11855        best
11856    })
11857}
11858
11859/// Records the serialized transition order at parser decision states.
11860///
11861/// When two clean paths consume the same input, ANTLR's adaptive prediction
11862/// chooses by alternative order. Keeping this compact trace lets the metadata
11863/// recognizer distinguish greedy and non-greedy optional blocks without a full
11864/// prediction simulator.
11865fn transition_decision(
11866    atn: &Atn,
11867    state: AtnState<'_>,
11868    transition_count: usize,
11869    transition_index: usize,
11870    predicates: &[(usize, usize, ParserPredicate)],
11871) -> Option<usize> {
11872    if transition_count <= 1
11873        || state.precedence_rule_decision()
11874        || decision_reaches_unsupported_predicate(atn, state, predicates)
11875    {
11876        return None;
11877    }
11878    Some(transition_index)
11879}
11880
11881/// Reports whether a state should reset the active no-viable decision start.
11882///
11883/// Loop entry/back states are continuations of the surrounding adaptive
11884/// prediction; resetting at those states would turn LL-star failures back into
11885/// ordinary mismatches.
11886fn starts_prediction_decision(state: AtnState<'_>, transition_count: usize) -> bool {
11887    transition_count > 1
11888        && !matches!(
11889            state.kind(),
11890            AtnStateKind::PlusLoopBack | AtnStateKind::StarLoopBack | AtnStateKind::StarLoopEntry
11891        )
11892}
11893
11894/// Marks a farthest expected-token set as no-viable when multiple alternatives
11895/// failed after the active decision had already consumed input.
11896fn record_no_viable_if_ambiguous(
11897    expected: &mut ExpectedTokens,
11898    decision_start_index: Option<usize>,
11899    index: usize,
11900) {
11901    if expected.index == Some(index) && expected.symbols.len() > 1 {
11902        if let Some(decision_start) = no_viable_decision_start(decision_start_index, index) {
11903            expected.record_no_viable(decision_start, index);
11904        }
11905    }
11906}
11907
11908/// Records a no-viable decision caused by a failed semantic predicate before
11909/// any consuming transition can contribute an expected-token set.
11910const fn record_predicate_no_viable(
11911    expected: &mut ExpectedTokens,
11912    decision_start_index: Option<usize>,
11913    index: usize,
11914) {
11915    if let Some(decision_start) = decision_start_index {
11916        expected.record_no_viable(decision_start, index);
11917    }
11918}
11919
11920/// Returns the active decision start only when the error is past that start.
11921const fn no_viable_decision_start(
11922    decision_start_index: Option<usize>,
11923    index: usize,
11924) -> Option<usize> {
11925    match decision_start_index {
11926        Some(start) if index > start => Some(start),
11927        _ => None,
11928    }
11929}
11930
11931/// Restores expected-token bookkeeping when a child rule found a clean
11932/// consuming path; failures in longer child alternatives should not pollute the
11933/// caller's final expectation set.
11934fn restore_expected(
11935    children: &[RecognizeOutcome],
11936    child_start_index: usize,
11937    expected: &mut ExpectedTokens,
11938    snapshot: ExpectedTokens,
11939    preserve_child_expected: bool,
11940) {
11941    if preserve_child_expected {
11942        return;
11943    }
11944    if children
11945        .iter()
11946        .any(|child| child.diagnostics.is_empty() && child.index > child_start_index)
11947    {
11948        *expected = snapshot;
11949    }
11950}
11951
11952/// Reports whether a decision can reach a predicate the generator did not
11953/// translate. Static alternative order is unsafe for those context predicates.
11954fn decision_reaches_unsupported_predicate(
11955    atn: &Atn,
11956    state: AtnState<'_>,
11957    predicates: &[(usize, usize, ParserPredicate)],
11958) -> bool {
11959    state.transitions().iter().any(|transition| {
11960        transition_reaches_unsupported_predicate(atn, transition, predicates, &mut BTreeSet::new())
11961    })
11962}
11963
11964/// Walks epsilon-like edges from one transition to find unsupported predicates.
11965fn transition_reaches_unsupported_predicate(
11966    atn: &Atn,
11967    transition: ParserTransition<'_>,
11968    predicates: &[(usize, usize, ParserPredicate)],
11969    visited: &mut BTreeSet<usize>,
11970) -> bool {
11971    match &transition.data() {
11972        Transition::Predicate {
11973            rule_index,
11974            pred_index,
11975            ..
11976        } => !predicates
11977            .iter()
11978            .any(|(rule, pred, _)| rule == rule_index && pred == pred_index),
11979        Transition::Epsilon { target }
11980        | Transition::Action { target, .. }
11981        | Transition::Rule { target, .. } => {
11982            state_reaches_unsupported_predicate(atn, *target, predicates, visited)
11983        }
11984        Transition::Precedence { .. }
11985        | Transition::Atom { .. }
11986        | Transition::Range { .. }
11987        | Transition::Set { .. }
11988        | Transition::NotSet { .. }
11989        | Transition::Wildcard { .. } => false,
11990    }
11991}
11992
11993/// Finds an unsupported predicate reachable before a consuming transition.
11994fn state_reaches_unsupported_predicate(
11995    atn: &Atn,
11996    state_number: usize,
11997    predicates: &[(usize, usize, ParserPredicate)],
11998    visited: &mut BTreeSet<usize>,
11999) -> bool {
12000    if !visited.insert(state_number) {
12001        return false;
12002    }
12003    let Some(state) = atn.state(state_number) else {
12004        return false;
12005    };
12006    state.transitions().iter().any(|transition| {
12007        transition_reaches_unsupported_predicate(atn, transition, predicates, visited)
12008    })
12009}
12010
12011/// Adds a decision step to the front of an already-recognized suffix path.
12012fn prepend_decision(outcome: &mut RecognizeOutcome, decision: Option<usize>) {
12013    if let Some(decision) = decision {
12014        outcome.decisions.insert(0, decision);
12015    }
12016}
12017
12018fn outcome_is_better(
12019    outcome_position: (usize, bool),
12020    outcome_diagnostics: DiagnosticSeqId,
12021    best_position: (usize, bool),
12022    best_diagnostics: DiagnosticSeqId,
12023    arena: &RecognitionArena,
12024) -> bool {
12025    let outcome_len = arena.diagnostics_len(outcome_diagnostics);
12026    let best_len = arena.diagnostics_len(best_diagnostics);
12027    outcome_position > best_position
12028        || (outcome_position == best_position
12029            && (outcome_len < best_len
12030                || (outcome_len == best_len
12031                    && arena.diagnostics_recovery_rank(outcome_diagnostics)
12032                        < arena.diagnostics_recovery_rank(best_diagnostics))))
12033}
12034
12035fn discard_recovered_fast_outcomes_if_clean_path_exists(outcomes: &mut Vec<FastRecognizeOutcome>) {
12036    if outcomes
12037        .iter()
12038        .any(|outcome| outcome.diagnostics.is_empty())
12039    {
12040        outcomes.retain(|outcome| outcome.diagnostics.is_empty());
12041    }
12042}
12043
12044fn discard_recovered_outcomes_if_clean_path_exists(
12045    outcomes: &mut Vec<RecognizeOutcome>,
12046    arena: &RecognitionArena,
12047) {
12048    if outcomes
12049        .iter()
12050        .any(|outcome| outcome_has_rule_failure_diagnostic(outcome, arena))
12051    {
12052        return;
12053    }
12054    if outcomes
12055        .iter()
12056        .any(|outcome| outcome.diagnostics.is_empty())
12057    {
12058        outcomes.retain(|outcome| outcome.diagnostics.is_empty());
12059    }
12060}
12061
12062/// Reports whether a recovered outcome came from an explicit predicate
12063/// fail-option and therefore should compete with shorter clean loop exits.
12064fn outcome_has_rule_failure_diagnostic(
12065    outcome: &RecognizeOutcome,
12066    arena: &RecognitionArena,
12067) -> bool {
12068    arena
12069        .diagnostics(outcome.diagnostics)
12070        .any(|diagnostic| diagnostic.message.starts_with("rule "))
12071}
12072
12073/// Removes equivalent endpoints before memoizing a state result while
12074/// preserving ATN transition-discovery order.
12075///
12076/// Outcomes are compared on observable recognition state — the input index,
12077/// EOF consumption, and diagnostics — without descending into the parse-tree
12078/// fragment carried by `nodes`. Two paths reaching the same point with
12079/// different node trees would otherwise prevent memoization from collapsing
12080/// equivalent suffixes and explode the speculative-path cache.
12081///
12082/// The first occurrence per recognition key wins, which matches ANTLR's
12083/// greedy alternative selection: serialized ATNs put greedy `*`/`+` loop-back
12084/// transitions before loop-exit, so the first-discovered outcome carries the
12085/// greedy parse-tree fragment.
12086fn dedupe_fast_outcomes(outcomes: &mut Vec<FastRecognizeOutcome>, arena: &RecognitionArena) {
12087    if outcomes.len() < 2 {
12088        return;
12089    }
12090    let mut seen = FxHashSet::with_capacity_and_hasher(outcomes.len(), FxBuildHasher::default());
12091    outcomes.retain(|outcome| {
12092        seen.insert((
12093            outcome.index,
12094            outcome.consumed_eof,
12095            arena.diagnostics_len(outcome.diagnostics),
12096            arena.diagnostics_recovery_rank(outcome.diagnostics),
12097        ))
12098    });
12099}
12100
12101const FAST_OUTCOME_INLINE_KEYS: usize = 8;
12102const FAST_OUTCOME_BITS_PER_WORD: usize = 64;
12103const MAX_FAST_OUTCOME_DENSE_BYTES: usize = 64 * 1024;
12104const MAX_RETAINED_FAST_OUTCOME_SPARSE_KEYS: usize = 65_536;
12105
12106#[derive(Clone, Copy, Debug, Eq, PartialEq)]
12107enum FastOutcomeDedupStrategy {
12108    Inline,
12109    Dense,
12110    Sparse,
12111}
12112
12113impl FastOutcomeDedupScratch {
12114    fn prepare_dense(&mut self, word_count: usize) {
12115        while let Some(word_index) = self.touched_dense_words.pop() {
12116            self.dense_words[usize::try_from(word_index).expect("u32 fits in usize")] = 0;
12117        }
12118        if self.dense_words.len() < word_count {
12119            self.dense_words.resize(word_count, 0);
12120        }
12121    }
12122}
12123
12124fn clean_fast_outcome_dense_layout(outcomes: &[FastRecognizeOutcome]) -> Option<(usize, usize)> {
12125    let first_index = outcomes.first()?.index;
12126    let (min_index, max_index) = outcomes[1..].iter().fold(
12127        (first_index, first_index),
12128        |(min_index, max_index), outcome| {
12129            (min_index.min(outcome.index), max_index.max(outcome.index))
12130        },
12131    );
12132    let index_span = max_index.checked_sub(min_index)?.checked_add(1)?;
12133    let bit_count = index_span.checked_mul(2)?;
12134    let word_count =
12135        bit_count.checked_add(FAST_OUTCOME_BITS_PER_WORD - 1)? / FAST_OUTCOME_BITS_PER_WORD;
12136    let dense_bytes = word_count.checked_mul(size_of::<u64>())?;
12137    let sparse_key_bytes = outcomes.len().checked_mul(size_of::<(usize, bool)>())?;
12138    (dense_bytes <= MAX_FAST_OUTCOME_DENSE_BYTES && dense_bytes <= sparse_key_bytes)
12139        .then_some((min_index, word_count))
12140}
12141
12142#[cfg(feature = "perf-counters")]
12143fn record_clean_fast_outcome_dedup(
12144    strategy: FastOutcomeDedupStrategy,
12145    input_len: usize,
12146    output_len: usize,
12147    dense_words: usize,
12148) {
12149    let counter = match strategy {
12150        FastOutcomeDedupStrategy::Inline => &perf_counters::OUTCOME_DEDUPE_INLINE,
12151        FastOutcomeDedupStrategy::Dense => &perf_counters::OUTCOME_DEDUPE_DENSE,
12152        FastOutcomeDedupStrategy::Sparse => &perf_counters::OUTCOME_DEDUPE_SPARSE,
12153    };
12154    perf_counters::inc(
12155        &perf_counters::OUTCOME_DEDUPE_INPUTS,
12156        u64::try_from(input_len).unwrap_or(u64::MAX),
12157    );
12158    perf_counters::inc(
12159        &perf_counters::OUTCOME_DEDUPE_REMOVED,
12160        u64::try_from(input_len - output_len).unwrap_or(u64::MAX),
12161    );
12162    perf_counters::inc(counter, 1);
12163    perf_counters::inc(
12164        &perf_counters::OUTCOME_DEDUPE_DENSE_WORDS,
12165        u64::try_from(dense_words).unwrap_or(u64::MAX),
12166    );
12167}
12168
12169/// Removes duplicate clean endpoints while preserving transition-discovery
12170/// order. Tiny lists stay on the stack; larger compact ranges use a direct
12171/// bitmap, and only wide sparse ranges pay for hashing.
12172fn dedupe_clean_fast_outcomes(
12173    outcomes: &mut Vec<FastRecognizeOutcome>,
12174    scratch: &mut FastOutcomeDedupScratch,
12175) -> FastOutcomeDedupStrategy {
12176    #[cfg(feature = "perf-counters")]
12177    let input_len = outcomes.len();
12178    if outcomes.len() <= FAST_OUTCOME_INLINE_KEYS {
12179        let mut inline_keys = [(0, false); FAST_OUTCOME_INLINE_KEYS];
12180        let mut inline_len = 0_usize;
12181        outcomes.retain(|outcome| {
12182            let key = (outcome.index, outcome.consumed_eof);
12183            if inline_keys[..inline_len].contains(&key) {
12184                return false;
12185            }
12186            inline_keys[inline_len] = key;
12187            inline_len += 1;
12188            true
12189        });
12190        #[cfg(feature = "perf-counters")]
12191        record_clean_fast_outcome_dedup(
12192            FastOutcomeDedupStrategy::Inline,
12193            input_len,
12194            outcomes.len(),
12195            0,
12196        );
12197        return FastOutcomeDedupStrategy::Inline;
12198    }
12199
12200    if let Some((base_index, word_count)) = clean_fast_outcome_dense_layout(outcomes) {
12201        scratch.prepare_dense(word_count);
12202        outcomes.retain(|outcome| {
12203            let bit_index = (outcome.index - base_index) * 2 + usize::from(outcome.consumed_eof);
12204            let word_index = bit_index / FAST_OUTCOME_BITS_PER_WORD;
12205            let bit = 1_u64 << (bit_index % FAST_OUTCOME_BITS_PER_WORD);
12206            let word = &mut scratch.dense_words[word_index];
12207            if *word & bit != 0 {
12208                return false;
12209            }
12210            if *word == 0 {
12211                scratch
12212                    .touched_dense_words
12213                    .push(u32::try_from(word_index).expect("dense outcome bitmap is capped"));
12214            }
12215            *word |= bit;
12216            true
12217        });
12218        #[cfg(feature = "perf-counters")]
12219        record_clean_fast_outcome_dedup(
12220            FastOutcomeDedupStrategy::Dense,
12221            input_len,
12222            outcomes.len(),
12223            word_count,
12224        );
12225        return FastOutcomeDedupStrategy::Dense;
12226    }
12227
12228    scratch.sparse_keys.clear();
12229    scratch.sparse_keys.reserve(outcomes.len());
12230    outcomes.retain(|outcome| {
12231        scratch
12232            .sparse_keys
12233            .insert((outcome.index, outcome.consumed_eof))
12234    });
12235    #[cfg(feature = "perf-counters")]
12236    record_clean_fast_outcome_dedup(
12237        FastOutcomeDedupStrategy::Sparse,
12238        input_len,
12239        outcomes.len(),
12240        0,
12241    );
12242    if scratch.sparse_keys.capacity() > MAX_RETAINED_FAST_OUTCOME_SPARSE_KEYS {
12243        scratch.sparse_keys = FxHashSet::default();
12244    }
12245    FastOutcomeDedupStrategy::Sparse
12246}
12247
12248/// Sorts and removes equivalent endpoints, including action traces and the
12249/// arena-backed node sequence's structural contents.
12250fn dedupe_outcomes(outcomes: &mut Vec<RecognizeOutcome>, arena: &RecognitionArena) {
12251    outcomes.sort_unstable_by(|left, right| compare_recognize_outcomes(left, right, arena));
12252    outcomes
12253        .dedup_by(|left, right| compare_recognize_outcomes(left, right, arena) == Ordering::Equal);
12254}
12255
12256fn compare_recognize_outcomes(
12257    left: &RecognizeOutcome,
12258    right: &RecognizeOutcome,
12259    arena: &RecognitionArena,
12260) -> Ordering {
12261    left.index
12262        .cmp(&right.index)
12263        .then_with(|| left.consumed_eof.cmp(&right.consumed_eof))
12264        .then_with(|| left.alt_number.cmp(&right.alt_number))
12265        .then_with(|| left.member_values.cmp(&right.member_values))
12266        .then_with(|| left.return_values.cmp(&right.return_values))
12267        .then_with(|| arena.compare_diagnostics(left.diagnostics, right.diagnostics))
12268        .then_with(|| left.decisions.cmp(&right.decisions))
12269        .then_with(|| left.actions.cmp(&right.actions))
12270        .then_with(|| arena.compare_sequences(left.nodes, right.nodes))
12271}
12272
12273impl<S, H> Recognizer for BaseParser<S, H>
12274where
12275    S: TokenSource,
12276    H: SemanticHooks,
12277{
12278    fn data(&self) -> &RecognizerData {
12279        &self.data
12280    }
12281
12282    fn data_mut(&mut self) -> &mut RecognizerData {
12283        &mut self.data
12284    }
12285}
12286
12287impl<S, H> Parser for BaseParser<S, H>
12288where
12289    S: TokenSource,
12290    H: SemanticHooks,
12291{
12292    fn build_parse_trees(&self) -> bool {
12293        self.build_parse_trees
12294    }
12295
12296    fn set_build_parse_trees(&mut self, build: bool) {
12297        self.build_parse_trees = build;
12298    }
12299
12300    fn number_of_syntax_errors(&self) -> usize {
12301        Self::number_of_syntax_errors(self)
12302    }
12303
12304    fn report_diagnostic_errors(&self) -> bool {
12305        self.report_diagnostic_errors
12306    }
12307
12308    fn set_report_diagnostic_errors(&mut self, report: bool) {
12309        self.report_diagnostic_errors = report;
12310    }
12311
12312    fn prediction_mode(&self) -> PredictionMode {
12313        self.prediction_mode
12314    }
12315
12316    fn set_prediction_mode(&mut self, mode: PredictionMode) {
12317        self.prediction_mode = mode;
12318    }
12319}
12320
12321#[cfg(test)]
12322mod tests {
12323    use super::*;
12324    use crate::atn::parser::{
12325        ParserAtnPredictionDiagnostic, ParserAtnPredictionDiagnosticKind, ParserAtnSimulator,
12326    };
12327    use crate::atn::serialized::{AtnDeserializer, SerializedAtn};
12328    use crate::token::{
12329        DEFAULT_CHANNEL, HIDDEN_CHANNEL, Token, TokenId, TokenSink, TokenSpec, TokenStoreError,
12330    };
12331    use crate::token_stream::CommonTokenStream;
12332    use crate::tree::{NodeKind, ParseTreeStats};
12333    use crate::vocabulary::Vocabulary;
12334    use std::cell::RefCell;
12335    use std::mem::size_of;
12336    use std::rc::Rc;
12337    use std::sync::{Arc, Mutex};
12338
12339    #[test]
12340    fn fx_hasher_write_matches_typed_methods_for_full_words() {
12341        // PR #5 review (Greptile P2): future key types whose `Hash` impl funnels
12342        // bytes through `Hasher::write` (e.g. `String`, `[u8; 8]`, slice-typed
12343        // fields) must hash the same as the typed methods, otherwise an
12344        // `FxHashMap` keyed on such a type silently disagrees with itself
12345        // depending on which entry point the caller used. Verify the
12346        // little-endian word equivalence this PR established.
12347        let value: u64 = 0x0102_0304_0506_0708;
12348        let mut typed = FxHasher::default();
12349        typed.write_u64(value);
12350        let mut bytewise = FxHasher::default();
12351        bytewise.write(&value.to_le_bytes());
12352        assert_eq!(typed.finish(), bytewise.finish());
12353    }
12354
12355    #[derive(Clone, Debug)]
12356    struct TestToken {
12357        spec: TokenSpec,
12358        id: TokenId,
12359        source_name: String,
12360    }
12361
12362    impl TestToken {
12363        fn new(token_type: i32) -> Self {
12364            Self {
12365                spec: TokenSpec::explicit(token_type, ""),
12366                id: TokenId::try_from(0).expect("zero token ID"),
12367                source_name: String::new(),
12368            }
12369        }
12370
12371        fn eof(source_name: &str, index: usize, line: usize, column: usize) -> Self {
12372            Self {
12373                spec: TokenSpec::eof(index, index, line, column),
12374                id: TokenId::try_from(0).expect("zero token ID"),
12375                source_name: source_name.to_owned(),
12376            }
12377        }
12378
12379        fn with_text(mut self, text: impl Into<String>) -> Self {
12380            self.spec.text = Some(text.into());
12381            self
12382        }
12383
12384        const fn with_channel(mut self, channel: i32) -> Self {
12385            self.spec.channel = channel;
12386            self
12387        }
12388
12389        const fn with_span(mut self, start: usize, stop: usize) -> Self {
12390            self.spec.start = start;
12391            self.spec.stop = stop;
12392            self.spec.start_byte = start;
12393            self.spec.stop_byte = match stop.checked_add(1) {
12394                Some(end) if end >= start => end,
12395                Some(_) | None => start,
12396            };
12397            self
12398        }
12399
12400        const fn with_position(mut self, line: usize, column: usize) -> Self {
12401            self.spec.line = line;
12402            self.spec.column = column;
12403            self
12404        }
12405
12406        fn set_token_index(&mut self, index: isize) {
12407            self.id = TokenId::try_from(index.max(0).cast_unsigned()).expect("test token index");
12408        }
12409    }
12410
12411    impl Token for TestToken {
12412        fn token_id(&self) -> TokenId {
12413            self.id
12414        }
12415
12416        fn token_type(&self) -> i32 {
12417            self.spec.token_type
12418        }
12419
12420        fn channel(&self) -> i32 {
12421            self.spec.channel
12422        }
12423
12424        fn start(&self) -> usize {
12425            self.spec.start
12426        }
12427
12428        fn stop(&self) -> usize {
12429            self.spec.stop
12430        }
12431
12432        fn line(&self) -> usize {
12433            self.spec.line
12434        }
12435
12436        fn column(&self) -> usize {
12437            self.spec.column
12438        }
12439
12440        fn text(&self) -> Option<&str> {
12441            self.spec.text.as_deref()
12442        }
12443
12444        fn source_name(&self) -> &str {
12445            &self.source_name
12446        }
12447
12448        fn start_byte(&self) -> usize {
12449            self.spec.start_byte
12450        }
12451
12452        fn stop_byte(&self) -> usize {
12453            self.spec.stop_byte
12454        }
12455    }
12456
12457    #[derive(Debug)]
12458    struct Source {
12459        tokens: Vec<TestToken>,
12460        index: usize,
12461    }
12462
12463    impl TokenSource for Source {
12464        fn next_token(&mut self, sink: &mut TokenSink<'_>) -> Result<TokenId, TokenStoreError> {
12465            let token = self
12466                .tokens
12467                .get(self.index)
12468                .cloned()
12469                .unwrap_or_else(|| TestToken::eof("parser-test", self.index, 1, self.index));
12470            self.index += 1;
12471            sink.push(token.spec)
12472        }
12473
12474        fn line(&self) -> usize {
12475            1
12476        }
12477
12478        fn column(&self) -> usize {
12479            self.index
12480        }
12481
12482        fn source_name(&self) -> &'static str {
12483            "parser-test"
12484        }
12485    }
12486
12487    #[derive(Clone, Debug, Eq, PartialEq)]
12488    struct RecordedDiagnostic {
12489        grammar_file_name: String,
12490        line: usize,
12491        column: usize,
12492        message: String,
12493        error: Option<AntlrError>,
12494    }
12495
12496    #[derive(Clone, Debug)]
12497    struct RecordingErrorListener {
12498        diagnostics: Arc<Mutex<Vec<RecordedDiagnostic>>>,
12499    }
12500
12501    impl<R> crate::ErrorListener<R> for RecordingErrorListener
12502    where
12503        R: Recognizer + ?Sized,
12504    {
12505        fn syntax_error(
12506            &mut self,
12507            recognizer: &R,
12508            line: usize,
12509            column: usize,
12510            message: &str,
12511            error: Option<&AntlrError>,
12512        ) {
12513            self.diagnostics
12514                .lock()
12515                .expect("recorded diagnostics lock")
12516                .push(RecordedDiagnostic {
12517                    grammar_file_name: recognizer.grammar_file_name().to_owned(),
12518                    line,
12519                    column,
12520                    message: message.to_owned(),
12521                    error: error.cloned(),
12522                });
12523        }
12524    }
12525
12526    #[derive(Debug)]
12527    struct ReportingSource {
12528        source: Source,
12529        diagnostics: Rc<RefCell<Vec<TokenSourceError>>>,
12530    }
12531
12532    impl TokenSource for ReportingSource {
12533        fn next_token(&mut self, sink: &mut TokenSink<'_>) -> Result<TokenId, TokenStoreError> {
12534            self.source.next_token(sink)
12535        }
12536
12537        fn line(&self) -> usize {
12538            self.source.line()
12539        }
12540
12541        fn column(&self) -> usize {
12542            self.source.column()
12543        }
12544
12545        fn source_name(&self) -> &str {
12546            self.source.source_name()
12547        }
12548
12549        fn report_error(&self, error: &TokenSourceError) -> bool {
12550            self.diagnostics.borrow_mut().push(error.clone());
12551            true
12552        }
12553    }
12554
12555    fn mini_parser_data() -> RecognizerData {
12556        RecognizerData::new(
12557            "Mini.g4",
12558            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
12559        )
12560        .with_rule_names(["s"])
12561    }
12562
12563    fn mini_parser(tokens: Vec<TestToken>) -> BaseParser<Source> {
12564        let data = mini_parser_data();
12565        BaseParser::new(CommonTokenStream::new(Source { tokens, index: 0 }), data)
12566    }
12567
12568    fn mini_parser_with_hooks<H>(tokens: Vec<TestToken>, hooks: H) -> BaseParser<Source, H>
12569    where
12570        H: SemanticHooks,
12571    {
12572        BaseParser::with_semantic_hooks(
12573            CommonTokenStream::new(Source { tokens, index: 0 }),
12574            mini_parser_data(),
12575            hooks,
12576        )
12577    }
12578
12579    #[test]
12580    fn parser_dispatches_recovery_diagnostics_through_registered_listeners() {
12581        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 0, 1, 0)]);
12582        parser.remove_error_listeners();
12583        let diagnostics = Arc::new(Mutex::new(Vec::new()));
12584        parser.add_error_listener(RecordingErrorListener {
12585            diagnostics: Arc::clone(&diagnostics),
12586        });
12587        let parser_diagnostics = [ParserDiagnostic {
12588            line: 1,
12589            column: 2,
12590            message: "missing 'x' at 'y'".to_owned(),
12591        }];
12592        let token_errors = [
12593            TokenSourceError::new(1, 1, "token recognition error at: '@'"),
12594            TokenSourceError::new(1, 3, "token recognition error at: '#'"),
12595        ];
12596
12597        parser.dispatch_generated_diagnostics(&parser_diagnostics, &token_errors);
12598
12599        assert_eq!(
12600            *diagnostics.lock().expect("recorded diagnostics lock"),
12601            [
12602                RecordedDiagnostic {
12603                    grammar_file_name: "Mini.g4".to_owned(),
12604                    line: 1,
12605                    column: 1,
12606                    message: "token recognition error at: '@'".to_owned(),
12607                    error: None,
12608                },
12609                RecordedDiagnostic {
12610                    grammar_file_name: "Mini.g4".to_owned(),
12611                    line: 1,
12612                    column: 2,
12613                    message: "missing 'x' at 'y'".to_owned(),
12614                    error: None,
12615                },
12616                RecordedDiagnostic {
12617                    grammar_file_name: "Mini.g4".to_owned(),
12618                    line: 1,
12619                    column: 3,
12620                    message: "token recognition error at: '#'".to_owned(),
12621                    error: None,
12622                },
12623            ]
12624        );
12625
12626        parser.remove_error_listeners();
12627        parser.dispatch_generated_diagnostics(&parser_diagnostics, &token_errors);
12628        assert_eq!(
12629            diagnostics.lock().expect("recorded diagnostics lock").len(),
12630            3
12631        );
12632    }
12633
12634    #[test]
12635    fn parser_leaves_token_errors_to_source_owned_listeners() {
12636        let source_diagnostics = Rc::new(RefCell::new(Vec::new()));
12637        let source = ReportingSource {
12638            source: Source {
12639                tokens: vec![TestToken::eof("parser-test", 0, 1, 0)],
12640                index: 0,
12641            },
12642            diagnostics: Rc::clone(&source_diagnostics),
12643        };
12644        let mut parser = BaseParser::new(CommonTokenStream::new(source), mini_parser_data());
12645        parser.remove_error_listeners();
12646        let parser_diagnostics = Arc::new(Mutex::new(Vec::new()));
12647        parser.add_error_listener(RecordingErrorListener {
12648            diagnostics: Arc::clone(&parser_diagnostics),
12649        });
12650        let source_error = TokenSourceError::new(2, 4, "token recognition error at: '$'");
12651
12652        parser.dispatch_token_source_errors(std::slice::from_ref(&source_error));
12653
12654        assert_eq!(*source_diagnostics.borrow(), [source_error]);
12655        assert!(
12656            parser_diagnostics
12657                .lock()
12658                .expect("recorded diagnostics lock")
12659                .is_empty()
12660        );
12661    }
12662
12663    fn finish_atn(builder: ParserAtnBuilder) -> Atn {
12664        builder.finish().expect("valid packed parser ATN")
12665    }
12666
12667    fn nested_rule_chain_atn(depth: usize) -> Atn {
12668        nested_rule_graph_atn(depth, false, false)
12669    }
12670
12671    fn nested_rule_graph_atn(depth: usize, branching: bool, consuming_follows: bool) -> Atn {
12672        assert!(depth > 0);
12673        let mut atn = ParserAtnBuilder::new(2);
12674        let mut starts = Vec::with_capacity(depth);
12675        let mut stops = Vec::with_capacity(depth);
12676        let mut follows = Vec::with_capacity(depth.saturating_sub(1));
12677        for rule_index in 0..depth {
12678            starts.push(
12679                atn.add_state(AtnStateKind::RuleStart, Some(rule_index))
12680                    .expect("rule start")
12681                    .index(),
12682            );
12683        }
12684        for rule_index in 0..depth {
12685            stops.push(
12686                atn.add_state(AtnStateKind::RuleStop, Some(rule_index))
12687                    .expect("rule stop")
12688                    .index(),
12689            );
12690        }
12691        if consuming_follows {
12692            for rule_index in 0..depth - 1 {
12693                follows.push(
12694                    atn.add_state(AtnStateKind::Basic, Some(rule_index))
12695                        .expect("rule follow")
12696                        .index(),
12697                );
12698            }
12699        }
12700        atn.set_rule_to_start_state(starts.clone())
12701            .expect("rule start states");
12702        atn.set_rule_to_stop_state(stops.clone())
12703            .expect("rule stop states");
12704        for rule_index in 0..depth - 1 {
12705            let follow_state = if consuming_follows {
12706                follows[rule_index]
12707            } else {
12708                stops[rule_index]
12709            };
12710            atn.add_transition(
12711                starts[rule_index],
12712                ParserTransitionSpec::Rule {
12713                    target: starts[rule_index + 1],
12714                    rule_index: rule_index + 1,
12715                    follow_state,
12716                    precedence: 0,
12717                },
12718            )
12719            .expect("nested rule transition");
12720            if branching {
12721                atn.add_transition(
12722                    starts[rule_index],
12723                    ParserTransitionSpec::Atom {
12724                        target: stops[rule_index],
12725                        label: 2,
12726                    },
12727                )
12728                .expect("dead branch transition");
12729            }
12730            if consuming_follows {
12731                atn.add_transition(
12732                    follow_state,
12733                    ParserTransitionSpec::Atom {
12734                        target: stops[rule_index],
12735                        label: 1,
12736                    },
12737                )
12738                .expect("consuming follow transition");
12739            }
12740        }
12741        let token_set = atn.add_interval_set([(1, 1)]).expect("token set");
12742        atn.add_transition(
12743            starts[depth - 1],
12744            ParserTransitionSpec::Set {
12745                target: stops[depth - 1],
12746                set: token_set,
12747            },
12748        )
12749        .expect("terminal set transition");
12750        if branching {
12751            atn.add_transition(
12752                starts[depth - 1],
12753                ParserTransitionSpec::Atom {
12754                    target: stops[depth - 1],
12755                    label: 2,
12756                },
12757            )
12758            .expect("dead leaf branch transition");
12759        }
12760        finish_atn(atn)
12761    }
12762
12763    fn ordinary_star_loop_atn() -> Atn {
12764        let mut atn = ParserAtnBuilder::new(2);
12765        for (state_number, kind, rule_index) in [
12766            (0, AtnStateKind::RuleStart, 0),
12767            (1, AtnStateKind::StarLoopEntry, 0),
12768            (2, AtnStateKind::Basic, 0),
12769            (3, AtnStateKind::StarLoopBack, 0),
12770            (4, AtnStateKind::LoopEnd, 0),
12771            (5, AtnStateKind::Basic, 0),
12772            (6, AtnStateKind::RuleStop, 0),
12773            (7, AtnStateKind::RuleStart, 1),
12774            (8, AtnStateKind::Basic, 1),
12775            (9, AtnStateKind::RuleStop, 1),
12776        ] {
12777            assert_eq!(
12778                atn.add_state(kind, Some(rule_index))
12779                    .expect("state")
12780                    .index(),
12781                state_number
12782            );
12783        }
12784        atn.set_rule_to_start_state(vec![0, 7])
12785            .expect("rule start states");
12786        atn.set_rule_to_stop_state(vec![6, 9])
12787            .expect("rule stop states");
12788        atn.add_decision_state(1).expect("decision state");
12789        atn.set_loop_back_state(4, 3).expect("loop back state");
12790        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
12791            .expect("transition");
12792        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
12793            .expect("transition");
12794        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 4 })
12795            .expect("transition");
12796        atn.add_transition(
12797            2,
12798            ParserTransitionSpec::Rule {
12799                target: 7,
12800                rule_index: 1,
12801                follow_state: 3,
12802                precedence: 0,
12803            },
12804        )
12805        .expect("transition");
12806        atn.add_transition(3, ParserTransitionSpec::Epsilon { target: 1 })
12807            .expect("transition");
12808        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
12809            .expect("transition");
12810        atn.add_transition(
12811            5,
12812            ParserTransitionSpec::Atom {
12813                target: 6,
12814                label: TOKEN_EOF,
12815            },
12816        )
12817        .expect("transition");
12818        atn.add_transition(7, ParserTransitionSpec::Epsilon { target: 8 })
12819            .expect("transition");
12820        atn.add_transition(
12821            8,
12822            ParserTransitionSpec::Atom {
12823                target: 9,
12824                label: 1,
12825            },
12826        )
12827        .expect("transition");
12828        finish_atn(atn)
12829    }
12830
12831    /// ATN for `s : (X | X X)* EOF`.
12832    fn ambiguous_ordinary_star_loop_atn() -> Atn {
12833        let mut atn = ParserAtnBuilder::new(1);
12834        for (state_number, kind) in [
12835            (0, AtnStateKind::RuleStart),
12836            (1, AtnStateKind::StarLoopEntry),
12837            (2, AtnStateKind::StarBlockStart),
12838            (3, AtnStateKind::Basic),
12839            (4, AtnStateKind::BlockEnd),
12840            (5, AtnStateKind::StarLoopBack),
12841            (6, AtnStateKind::LoopEnd),
12842            (7, AtnStateKind::Basic),
12843            (8, AtnStateKind::RuleStop),
12844        ] {
12845            assert_eq!(
12846                atn.add_state(kind, Some(0)).expect("state").index(),
12847                state_number
12848            );
12849        }
12850        atn.set_rule_to_start_state(vec![0])
12851            .expect("rule start states");
12852        atn.set_rule_to_stop_state(vec![8])
12853            .expect("rule stop states");
12854        atn.set_end_state(2, 4).expect("block end state");
12855        atn.set_loop_back_state(6, 5).expect("loop back state");
12856        atn.add_decision_state(1).expect("decision state");
12857        atn.add_decision_state(2).expect("decision state");
12858        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
12859            .expect("transition");
12860        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
12861            .expect("transition");
12862        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 6 })
12863            .expect("transition");
12864        atn.add_transition(
12865            2,
12866            ParserTransitionSpec::Atom {
12867                target: 4,
12868                label: 1,
12869            },
12870        )
12871        .expect("transition");
12872        atn.add_transition(
12873            2,
12874            ParserTransitionSpec::Atom {
12875                target: 3,
12876                label: 1,
12877            },
12878        )
12879        .expect("transition");
12880        atn.add_transition(
12881            3,
12882            ParserTransitionSpec::Atom {
12883                target: 4,
12884                label: 1,
12885            },
12886        )
12887        .expect("transition");
12888        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
12889            .expect("transition");
12890        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 1 })
12891            .expect("transition");
12892        atn.add_transition(6, ParserTransitionSpec::Epsilon { target: 7 })
12893            .expect("transition");
12894        atn.add_transition(
12895            7,
12896            ParserTransitionSpec::Atom {
12897                target: 8,
12898                label: TOKEN_EOF,
12899            },
12900        )
12901        .expect("transition");
12902        finish_atn(atn)
12903    }
12904
12905    fn ordinary_plus_loop_atn() -> Atn {
12906        let mut atn = ParserAtnBuilder::new(2);
12907        for (state_number, kind, rule_index) in [
12908            (0, AtnStateKind::RuleStart, 0),
12909            (1, AtnStateKind::Basic, 0),
12910            (2, AtnStateKind::PlusLoopBack, 0),
12911            (3, AtnStateKind::LoopEnd, 0),
12912            (4, AtnStateKind::Basic, 0),
12913            (5, AtnStateKind::RuleStop, 0),
12914            (6, AtnStateKind::RuleStart, 1),
12915            (7, AtnStateKind::Basic, 1),
12916            (8, AtnStateKind::RuleStop, 1),
12917        ] {
12918            assert_eq!(
12919                atn.add_state(kind, Some(rule_index))
12920                    .expect("state")
12921                    .index(),
12922                state_number
12923            );
12924        }
12925        atn.set_rule_to_start_state(vec![0, 6])
12926            .expect("rule start states");
12927        atn.set_rule_to_stop_state(vec![5, 8])
12928            .expect("rule stop states");
12929        atn.add_decision_state(2).expect("decision state");
12930        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
12931            .expect("transition");
12932        atn.add_transition(
12933            1,
12934            ParserTransitionSpec::Rule {
12935                target: 6,
12936                rule_index: 1,
12937                follow_state: 2,
12938                precedence: 0,
12939            },
12940        )
12941        .expect("transition");
12942        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 1 })
12943            .expect("transition");
12944        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 3 })
12945            .expect("transition");
12946        atn.add_transition(3, ParserTransitionSpec::Epsilon { target: 4 })
12947            .expect("transition");
12948        atn.add_transition(
12949            4,
12950            ParserTransitionSpec::Atom {
12951                target: 5,
12952                label: TOKEN_EOF,
12953            },
12954        )
12955        .expect("transition");
12956        atn.add_transition(6, ParserTransitionSpec::Epsilon { target: 7 })
12957            .expect("transition");
12958        atn.add_transition(
12959            7,
12960            ParserTransitionSpec::Atom {
12961                target: 8,
12962                label: 1,
12963            },
12964        )
12965        .expect("transition");
12966        finish_atn(atn)
12967    }
12968
12969    fn repeated_x_tokens(count: usize) -> Vec<TestToken> {
12970        let mut tokens = (0..count)
12971            .map(|_| TestToken::new(1).with_text("x"))
12972            .collect::<Vec<_>>();
12973        tokens.push(TestToken::eof("parser-test", count, 1, count));
12974        tokens
12975    }
12976
12977    fn left_recursive_loop_with_caller_follow_atn(caller_symbol: i32) -> Atn {
12978        let mut atn = ParserAtnBuilder::new(2);
12979        assert_eq!(
12980            atn.add_state(AtnStateKind::RuleStart, Some(0))
12981                .expect("state")
12982                .index(),
12983            0
12984        );
12985        assert_eq!(
12986            atn.add_state(AtnStateKind::Basic, Some(0))
12987                .expect("state")
12988                .index(),
12989            1
12990        );
12991        assert_eq!(
12992            atn.add_state(AtnStateKind::Basic, Some(0))
12993                .expect("state")
12994                .index(),
12995            2
12996        );
12997        assert_eq!(
12998            atn.add_state(AtnStateKind::RuleStart, Some(1))
12999                .expect("state")
13000                .index(),
13001            3
13002        );
13003        atn.set_left_recursive_rule(3)
13004            .expect("left-recursive rule start");
13005        assert_eq!(
13006            atn.add_state(AtnStateKind::StarLoopEntry, Some(1))
13007                .expect("state")
13008                .index(),
13009            4
13010        );
13011        atn.set_precedence_rule_decision(4)
13012            .expect("precedence decision");
13013        assert_eq!(
13014            atn.add_state(AtnStateKind::Basic, Some(1))
13015                .expect("state")
13016                .index(),
13017            5
13018        );
13019        assert_eq!(
13020            atn.add_state(AtnStateKind::Basic, Some(1))
13021                .expect("state")
13022                .index(),
13023            6
13024        );
13025        assert_eq!(
13026            atn.add_state(AtnStateKind::LoopEnd, Some(1))
13027                .expect("state")
13028                .index(),
13029            7
13030        );
13031        assert_eq!(
13032            atn.add_state(AtnStateKind::RuleStop, Some(1))
13033                .expect("state")
13034                .index(),
13035            8
13036        );
13037        assert_eq!(
13038            atn.add_state(AtnStateKind::RuleStop, Some(0))
13039                .expect("state")
13040                .index(),
13041            9
13042        );
13043        atn.set_rule_to_start_state(vec![0, 3])
13044            .expect("rule start states");
13045        atn.set_rule_to_stop_state(vec![9, 8])
13046            .expect("rule stop states");
13047        atn.add_transition(
13048            1,
13049            ParserTransitionSpec::Rule {
13050                target: 3,
13051                rule_index: 1,
13052                follow_state: 2,
13053                precedence: 0,
13054            },
13055        )
13056        .expect("transition");
13057        atn.add_transition(
13058            2,
13059            ParserTransitionSpec::Atom {
13060                target: 9,
13061                label: caller_symbol,
13062            },
13063        )
13064        .expect("transition");
13065        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
13066            .expect("transition");
13067        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 7 })
13068            .expect("transition");
13069        atn.add_transition(
13070            5,
13071            ParserTransitionSpec::Precedence {
13072                target: 6,
13073                precedence: 1,
13074            },
13075        )
13076        .expect("transition");
13077        atn.add_transition(
13078            6,
13079            ParserTransitionSpec::Atom {
13080                target: 4,
13081                label: 1,
13082            },
13083        )
13084        .expect("transition");
13085        atn.add_transition(7, ParserTransitionSpec::Epsilon { target: 8 })
13086            .expect("transition");
13087        finish_atn(atn)
13088    }
13089
13090    fn parser_inside_left_recursive_callee(symbol: i32) -> BaseParser<Source> {
13091        let mut parser = mini_parser(vec![
13092            TestToken::new(symbol).with_text("lookahead"),
13093            TestToken::eof("parser-test", 1, 1, 1),
13094        ]);
13095        parser.rule_context_stack = vec![
13096            RuleContextFrame {
13097                rule_index: 0,
13098                invoking_state: -1,
13099            },
13100            RuleContextFrame {
13101                rule_index: 1,
13102                invoking_state: 1,
13103            },
13104        ];
13105        parser
13106    }
13107
13108    fn left_recursive_loop_with_shared_gt_prefix_atn() -> Atn {
13109        // StarLoopEntry with two operator alts that share leading token 1 (`>`):
13110        //   prec 2: token 1, token 1  (shift `>>`)
13111        //   prec 1: token 1           (relational `>`)
13112        let mut atn = ParserAtnBuilder::new(1);
13113        for (state, kind, rule) in [
13114            (0, AtnStateKind::RuleStart, 0),
13115            (1, AtnStateKind::StarLoopEntry, 0),
13116            (2, AtnStateKind::Basic, 0), // ops hub
13117            (3, AtnStateKind::Basic, 0), // shift prec
13118            (4, AtnStateKind::Basic, 0), // shift first >
13119            (5, AtnStateKind::Basic, 0), // shift second >
13120            (6, AtnStateKind::Basic, 0), // rel prec
13121            (7, AtnStateKind::Basic, 0), // rel >
13122            (8, AtnStateKind::LoopEnd, 0),
13123            (9, AtnStateKind::RuleStop, 0),
13124        ] {
13125            assert_eq!(
13126                atn.add_state(kind, Some(rule)).expect("state").index(),
13127                state
13128            );
13129            if state == 0 {
13130                atn.set_left_recursive_rule(state)
13131                    .expect("left-recursive rule start");
13132            } else if state == 1 {
13133                atn.set_precedence_rule_decision(state)
13134                    .expect("precedence decision");
13135            }
13136        }
13137        atn.set_rule_to_start_state(vec![0])
13138            .expect("rule start states");
13139        atn.set_rule_to_stop_state(vec![9])
13140            .expect("rule stop states");
13141        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
13142            .expect("ops");
13143        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 8 })
13144            .expect("exit");
13145        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 3 })
13146            .expect("to shift");
13147        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 6 })
13148            .expect("to rel");
13149        atn.add_transition(
13150            3,
13151            ParserTransitionSpec::Precedence {
13152                target: 4,
13153                precedence: 2,
13154            },
13155        )
13156        .expect("shift prec");
13157        atn.add_transition(
13158            4,
13159            ParserTransitionSpec::Atom {
13160                target: 5,
13161                label: 1,
13162            },
13163        )
13164        .expect("shift first >");
13165        atn.add_transition(
13166            5,
13167            ParserTransitionSpec::Atom {
13168                target: 1,
13169                label: 1,
13170            },
13171        )
13172        .expect("shift second >");
13173        atn.add_transition(
13174            6,
13175            ParserTransitionSpec::Precedence {
13176                target: 7,
13177                precedence: 1,
13178            },
13179        )
13180        .expect("rel prec");
13181        atn.add_transition(
13182            7,
13183            ParserTransitionSpec::Atom {
13184                target: 1,
13185                label: 1,
13186            },
13187        )
13188        .expect("rel >");
13189        atn.add_transition(8, ParserTransitionSpec::Epsilon { target: 9 })
13190            .expect("loop end");
13191        finish_atn(atn)
13192    }
13193
13194    fn left_recursive_loop_with_rule_wrapped_gt_prefix_atn() -> Atn {
13195        let mut atn = ParserAtnBuilder::new(2);
13196        for (state, kind, rule) in [
13197            (0, AtnStateKind::RuleStart, 0),
13198            (1, AtnStateKind::StarLoopEntry, 0),
13199            (2, AtnStateKind::Basic, 0),
13200            (3, AtnStateKind::Basic, 0),
13201            (4, AtnStateKind::Basic, 0),
13202            (5, AtnStateKind::Basic, 0),
13203            (6, AtnStateKind::Basic, 0),
13204            (7, AtnStateKind::Basic, 0),
13205            (8, AtnStateKind::LoopEnd, 0),
13206            (9, AtnStateKind::RuleStop, 0),
13207            (10, AtnStateKind::RuleStart, 1),
13208            (11, AtnStateKind::Basic, 1),
13209            (12, AtnStateKind::RuleStop, 1),
13210        ] {
13211            assert_eq!(
13212                atn.add_state(kind, Some(rule)).expect("state").index(),
13213                state
13214            );
13215            if state == 0 {
13216                atn.set_left_recursive_rule(state)
13217                    .expect("left-recursive rule start");
13218            } else if state == 1 {
13219                atn.set_precedence_rule_decision(state)
13220                    .expect("precedence decision");
13221            }
13222        }
13223        atn.set_rule_to_start_state(vec![0, 10])
13224            .expect("rule start states");
13225        atn.set_rule_to_stop_state(vec![9, 12])
13226            .expect("rule stop states");
13227        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
13228            .expect("ops");
13229        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 8 })
13230            .expect("exit");
13231        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 3 })
13232            .expect("to shift");
13233        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 6 })
13234            .expect("to relational");
13235        atn.add_transition(
13236            3,
13237            ParserTransitionSpec::Precedence {
13238                target: 4,
13239                precedence: 2,
13240            },
13241        )
13242        .expect("shift precedence");
13243        atn.add_transition(
13244            4,
13245            ParserTransitionSpec::Rule {
13246                target: 10,
13247                rule_index: 1,
13248                follow_state: 5,
13249                precedence: 0,
13250            },
13251        )
13252        .expect("first shift token helper");
13253        atn.add_transition(
13254            5,
13255            ParserTransitionSpec::Atom {
13256                target: 1,
13257                label: 1,
13258            },
13259        )
13260        .expect("second shift token");
13261        atn.add_transition(
13262            6,
13263            ParserTransitionSpec::Precedence {
13264                target: 7,
13265                precedence: 1,
13266            },
13267        )
13268        .expect("relational precedence");
13269        atn.add_transition(
13270            7,
13271            ParserTransitionSpec::Atom {
13272                target: 1,
13273                label: 1,
13274            },
13275        )
13276        .expect("relational token");
13277        atn.add_transition(8, ParserTransitionSpec::Epsilon { target: 9 })
13278            .expect("loop end");
13279        atn.add_transition(10, ParserTransitionSpec::Epsilon { target: 11 })
13280            .expect("helper entry");
13281        atn.add_transition(
13282            11,
13283            ParserTransitionSpec::Atom {
13284                target: 12,
13285                label: 1,
13286            },
13287        )
13288        .expect("first shift token");
13289        finish_atn(atn)
13290    }
13291
13292    fn left_recursive_loop_with_predicate_and_multi_token_prefix_atn() -> Atn {
13293        let mut atn = ParserAtnBuilder::new(1);
13294        for (state, kind) in [
13295            (0, AtnStateKind::RuleStart),
13296            (1, AtnStateKind::StarLoopEntry),
13297            (2, AtnStateKind::Basic),
13298            (3, AtnStateKind::Basic),
13299            (4, AtnStateKind::Basic),
13300            (5, AtnStateKind::Basic),
13301            (6, AtnStateKind::Basic),
13302            (7, AtnStateKind::Basic),
13303            (8, AtnStateKind::Basic),
13304            (9, AtnStateKind::LoopEnd),
13305            (10, AtnStateKind::RuleStop),
13306        ] {
13307            assert_eq!(atn.add_state(kind, Some(0)).expect("state").index(), state);
13308            if state == 0 {
13309                atn.set_left_recursive_rule(state)
13310                    .expect("left-recursive rule start");
13311            } else if state == 1 {
13312                atn.set_precedence_rule_decision(state)
13313                    .expect("precedence decision");
13314            }
13315        }
13316        atn.set_rule_to_start_state(vec![0])
13317            .expect("rule start states");
13318        atn.set_rule_to_stop_state(vec![10])
13319            .expect("rule stop states");
13320        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
13321            .expect("ops");
13322        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 9 })
13323            .expect("exit");
13324        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 3 })
13325            .expect("to multi-token operator");
13326        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 6 })
13327            .expect("to predicate operator");
13328        atn.add_transition(
13329            3,
13330            ParserTransitionSpec::Precedence {
13331                target: 4,
13332                precedence: 2,
13333            },
13334        )
13335        .expect("multi-token precedence");
13336        atn.add_transition(
13337            4,
13338            ParserTransitionSpec::Atom {
13339                target: 5,
13340                label: 1,
13341            },
13342        )
13343        .expect("multi-token first");
13344        atn.add_transition(
13345            5,
13346            ParserTransitionSpec::Atom {
13347                target: 1,
13348                label: 1,
13349            },
13350        )
13351        .expect("multi-token second");
13352        atn.add_transition(
13353            6,
13354            ParserTransitionSpec::Precedence {
13355                target: 7,
13356                precedence: 2,
13357            },
13358        )
13359        .expect("predicate precedence");
13360        atn.add_transition(
13361            7,
13362            ParserTransitionSpec::Predicate {
13363                target: 8,
13364                rule_index: 0,
13365                pred_index: 0,
13366                context_dependent: false,
13367            },
13368        )
13369        .expect("operator predicate");
13370        atn.add_transition(
13371            8,
13372            ParserTransitionSpec::Atom {
13373                target: 1,
13374                label: 1,
13375            },
13376        )
13377        .expect("predicate single token");
13378        atn.add_transition(9, ParserTransitionSpec::Epsilon { target: 10 })
13379            .expect("loop end");
13380        finish_atn(atn)
13381    }
13382
13383    fn left_recursive_loop_with_nullable_operator_prefix_atn() -> Atn {
13384        let mut atn = ParserAtnBuilder::new(2);
13385        for (state, kind, rule) in [
13386            (0, AtnStateKind::RuleStart, 0),
13387            (1, AtnStateKind::StarLoopEntry, 0),
13388            (2, AtnStateKind::Basic, 0),
13389            (3, AtnStateKind::Basic, 0),
13390            (4, AtnStateKind::Basic, 0),
13391            (5, AtnStateKind::LoopEnd, 0),
13392            (6, AtnStateKind::RuleStop, 0),
13393            (7, AtnStateKind::RuleStart, 1),
13394            (8, AtnStateKind::RuleStop, 1),
13395            (9, AtnStateKind::Basic, 1),
13396        ] {
13397            assert_eq!(
13398                atn.add_state(kind, Some(rule)).expect("state").index(),
13399                state
13400            );
13401            if state == 0 {
13402                atn.set_left_recursive_rule(state)
13403                    .expect("left-recursive rule start");
13404            } else if state == 1 {
13405                atn.set_precedence_rule_decision(state)
13406                    .expect("precedence decision");
13407            }
13408        }
13409        atn.set_rule_to_start_state(vec![0, 7])
13410            .expect("rule start states");
13411        atn.set_rule_to_stop_state(vec![6, 8])
13412            .expect("rule stop states");
13413        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
13414            .expect("transition");
13415        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 5 })
13416            .expect("transition");
13417        atn.add_transition(
13418            2,
13419            ParserTransitionSpec::Precedence {
13420                target: 3,
13421                precedence: 3,
13422            },
13423        )
13424        .expect("transition");
13425        atn.add_transition(
13426            3,
13427            ParserTransitionSpec::Rule {
13428                target: 7,
13429                rule_index: 1,
13430                follow_state: 4,
13431                precedence: 0,
13432            },
13433        )
13434        .expect("transition");
13435        atn.add_transition(
13436            4,
13437            ParserTransitionSpec::Atom {
13438                target: 1,
13439                label: 1,
13440            },
13441        )
13442        .expect("transition");
13443        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 6 })
13444            .expect("transition");
13445        atn.add_transition(
13446            7,
13447            ParserTransitionSpec::Precedence {
13448                target: 9,
13449                precedence: 1,
13450            },
13451        )
13452        .expect("transition");
13453        atn.add_transition(9, ParserTransitionSpec::Epsilon { target: 8 })
13454            .expect("transition");
13455        finish_atn(atn)
13456    }
13457
13458    fn left_recursive_loop_with_predicate_guarded_operator_atn() -> Atn {
13459        let mut atn = ParserAtnBuilder::new(2);
13460        for (state, kind) in [
13461            (0, AtnStateKind::RuleStart),
13462            (1, AtnStateKind::StarLoopEntry),
13463            (2, AtnStateKind::Basic),
13464            (3, AtnStateKind::Basic),
13465            (4, AtnStateKind::Basic),
13466            (5, AtnStateKind::LoopEnd),
13467            (6, AtnStateKind::RuleStop),
13468        ] {
13469            assert_eq!(atn.add_state(kind, Some(0)).expect("state").index(), state);
13470            if state == 0 {
13471                atn.set_left_recursive_rule(state)
13472                    .expect("left-recursive rule start");
13473            } else if state == 1 {
13474                atn.set_precedence_rule_decision(state)
13475                    .expect("precedence decision");
13476            }
13477        }
13478        atn.set_rule_to_start_state(vec![0])
13479            .expect("rule start states");
13480        atn.set_rule_to_stop_state(vec![6])
13481            .expect("rule stop states");
13482        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
13483            .expect("transition");
13484        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 5 })
13485            .expect("transition");
13486        atn.add_transition(
13487            2,
13488            ParserTransitionSpec::Precedence {
13489                target: 3,
13490                precedence: 1,
13491            },
13492        )
13493        .expect("transition");
13494        atn.add_transition(
13495            3,
13496            ParserTransitionSpec::Predicate {
13497                target: 4,
13498                rule_index: 0,
13499                pred_index: 0,
13500                context_dependent: false,
13501            },
13502        )
13503        .expect("transition");
13504        atn.add_transition(
13505            4,
13506            ParserTransitionSpec::Atom {
13507                target: 1,
13508                label: 1,
13509            },
13510        )
13511        .expect("transition");
13512        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 6 })
13513            .expect("transition");
13514        finish_atn(atn)
13515    }
13516
13517    fn left_recursive_loop_with_nullable_follow_call_atn(caller_symbol: i32) -> Atn {
13518        let mut atn = ParserAtnBuilder::new(2);
13519        for (state, kind, rule) in [
13520            (0, AtnStateKind::RuleStart, 0),
13521            (1, AtnStateKind::Basic, 0),
13522            (2, AtnStateKind::Basic, 0),
13523            (3, AtnStateKind::Basic, 0),
13524            (4, AtnStateKind::RuleStop, 0),
13525            (5, AtnStateKind::RuleStart, 1),
13526            (6, AtnStateKind::StarLoopEntry, 1),
13527            (7, AtnStateKind::Basic, 1),
13528            (8, AtnStateKind::Basic, 1),
13529            (9, AtnStateKind::LoopEnd, 1),
13530            (10, AtnStateKind::RuleStop, 1),
13531            (11, AtnStateKind::RuleStart, 2),
13532            (12, AtnStateKind::RuleStop, 2),
13533        ] {
13534            assert_eq!(
13535                atn.add_state(kind, Some(rule)).expect("state").index(),
13536                state
13537            );
13538            if state == 5 {
13539                atn.set_left_recursive_rule(state)
13540                    .expect("left-recursive rule start");
13541            } else if state == 6 {
13542                atn.set_precedence_rule_decision(state)
13543                    .expect("precedence decision");
13544            }
13545        }
13546        atn.set_rule_to_start_state(vec![0, 5, 11])
13547            .expect("rule start states");
13548        atn.set_rule_to_stop_state(vec![4, 10, 12])
13549            .expect("rule stop states");
13550        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
13551            .expect("transition");
13552        atn.add_transition(
13553            1,
13554            ParserTransitionSpec::Rule {
13555                target: 5,
13556                rule_index: 1,
13557                follow_state: 2,
13558                precedence: 0,
13559            },
13560        )
13561        .expect("transition");
13562        atn.add_transition(
13563            2,
13564            ParserTransitionSpec::Rule {
13565                target: 11,
13566                rule_index: 2,
13567                follow_state: 3,
13568                precedence: 0,
13569            },
13570        )
13571        .expect("transition");
13572        atn.add_transition(
13573            3,
13574            ParserTransitionSpec::Atom {
13575                target: 4,
13576                label: caller_symbol,
13577            },
13578        )
13579        .expect("transition");
13580        atn.add_transition(6, ParserTransitionSpec::Epsilon { target: 7 })
13581            .expect("transition");
13582        atn.add_transition(6, ParserTransitionSpec::Epsilon { target: 9 })
13583            .expect("transition");
13584        atn.add_transition(
13585            7,
13586            ParserTransitionSpec::Precedence {
13587                target: 8,
13588                precedence: 1,
13589            },
13590        )
13591        .expect("transition");
13592        atn.add_transition(
13593            8,
13594            ParserTransitionSpec::Atom {
13595                target: 6,
13596                label: 1,
13597            },
13598        )
13599        .expect("transition");
13600        atn.add_transition(9, ParserTransitionSpec::Epsilon { target: 10 })
13601            .expect("transition");
13602        atn.add_transition(11, ParserTransitionSpec::Epsilon { target: 12 })
13603            .expect("transition");
13604        finish_atn(atn)
13605    }
13606
13607    fn left_recursive_loop_with_nullable_parent_return_atn(caller_symbol: i32) -> Atn {
13608        let mut atn = ParserAtnBuilder::new(2);
13609        for (state, kind, rule) in [
13610            (0, AtnStateKind::RuleStart, 0),
13611            (1, AtnStateKind::Basic, 0),
13612            (2, AtnStateKind::Basic, 0),
13613            (3, AtnStateKind::RuleStop, 0),
13614            (4, AtnStateKind::RuleStart, 1),
13615            (5, AtnStateKind::Basic, 1),
13616            (6, AtnStateKind::Basic, 1),
13617            (7, AtnStateKind::RuleStop, 1),
13618            (8, AtnStateKind::RuleStart, 2),
13619            (9, AtnStateKind::StarLoopEntry, 2),
13620            (10, AtnStateKind::Basic, 2),
13621            (11, AtnStateKind::Basic, 2),
13622            (12, AtnStateKind::LoopEnd, 2),
13623            (13, AtnStateKind::RuleStop, 2),
13624        ] {
13625            assert_eq!(
13626                atn.add_state(kind, Some(rule)).expect("state").index(),
13627                state
13628            );
13629            if state == 8 {
13630                atn.set_left_recursive_rule(state)
13631                    .expect("left-recursive rule start");
13632            } else if state == 9 {
13633                atn.set_precedence_rule_decision(state)
13634                    .expect("precedence decision");
13635            }
13636        }
13637        atn.set_rule_to_start_state(vec![0, 4, 8])
13638            .expect("rule start states");
13639        atn.set_rule_to_stop_state(vec![3, 7, 13])
13640            .expect("rule stop states");
13641        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
13642            .expect("transition");
13643        atn.add_transition(
13644            1,
13645            ParserTransitionSpec::Rule {
13646                target: 4,
13647                rule_index: 1,
13648                follow_state: 2,
13649                precedence: 0,
13650            },
13651        )
13652        .expect("transition");
13653        atn.add_transition(
13654            2,
13655            ParserTransitionSpec::Atom {
13656                target: 3,
13657                label: caller_symbol,
13658            },
13659        )
13660        .expect("transition");
13661        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
13662            .expect("transition");
13663        atn.add_transition(
13664            5,
13665            ParserTransitionSpec::Rule {
13666                target: 8,
13667                rule_index: 2,
13668                follow_state: 6,
13669                precedence: 0,
13670            },
13671        )
13672        .expect("transition");
13673        atn.add_transition(6, ParserTransitionSpec::Epsilon { target: 7 })
13674            .expect("transition");
13675        atn.add_transition(9, ParserTransitionSpec::Epsilon { target: 10 })
13676            .expect("transition");
13677        atn.add_transition(9, ParserTransitionSpec::Epsilon { target: 12 })
13678            .expect("transition");
13679        atn.add_transition(
13680            10,
13681            ParserTransitionSpec::Precedence {
13682                target: 11,
13683                precedence: 1,
13684            },
13685        )
13686        .expect("transition");
13687        atn.add_transition(
13688            11,
13689            ParserTransitionSpec::Atom {
13690                target: 9,
13691                label: 1,
13692            },
13693        )
13694        .expect("transition");
13695        atn.add_transition(12, ParserTransitionSpec::Epsilon { target: 13 })
13696            .expect("transition");
13697        finish_atn(atn)
13698    }
13699
13700    fn left_recursive_loop_with_recursive_operand_return_atn(caller_symbol: i32) -> Atn {
13701        let mut atn = ParserAtnBuilder::new(2);
13702        for (state, kind, rule) in [
13703            (0, AtnStateKind::RuleStart, 0),
13704            (1, AtnStateKind::Basic, 0),
13705            (2, AtnStateKind::Basic, 0),
13706            (3, AtnStateKind::RuleStop, 0),
13707            (4, AtnStateKind::RuleStart, 1),
13708            (5, AtnStateKind::StarLoopEntry, 1),
13709            (6, AtnStateKind::Basic, 1),
13710            (7, AtnStateKind::Basic, 1),
13711            (8, AtnStateKind::Basic, 1),
13712            (9, AtnStateKind::Basic, 1),
13713            (10, AtnStateKind::LoopEnd, 1),
13714            (11, AtnStateKind::RuleStop, 1),
13715        ] {
13716            assert_eq!(
13717                atn.add_state(kind, Some(rule)).expect("state").index(),
13718                state
13719            );
13720            if state == 4 {
13721                atn.set_left_recursive_rule(state)
13722                    .expect("left-recursive rule start");
13723            } else if state == 5 {
13724                atn.set_precedence_rule_decision(state)
13725                    .expect("precedence decision");
13726            }
13727        }
13728        atn.set_rule_to_start_state(vec![0, 4])
13729            .expect("rule start states");
13730        atn.set_rule_to_stop_state(vec![3, 11])
13731            .expect("rule stop states");
13732        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
13733            .expect("transition");
13734        atn.add_transition(
13735            1,
13736            ParserTransitionSpec::Rule {
13737                target: 4,
13738                rule_index: 1,
13739                follow_state: 2,
13740                precedence: 0,
13741            },
13742        )
13743        .expect("transition");
13744        atn.add_transition(
13745            2,
13746            ParserTransitionSpec::Atom {
13747                target: 3,
13748                label: caller_symbol,
13749            },
13750        )
13751        .expect("transition");
13752        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 6 })
13753            .expect("transition");
13754        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 10 })
13755            .expect("transition");
13756        atn.add_transition(
13757            6,
13758            ParserTransitionSpec::Precedence {
13759                target: 7,
13760                precedence: 1,
13761            },
13762        )
13763        .expect("transition");
13764        atn.add_transition(
13765            7,
13766            ParserTransitionSpec::Atom {
13767                target: 8,
13768                label: 1,
13769            },
13770        )
13771        .expect("transition");
13772        atn.add_transition(
13773            8,
13774            ParserTransitionSpec::Rule {
13775                target: 4,
13776                rule_index: 1,
13777                follow_state: 9,
13778                precedence: 2,
13779            },
13780        )
13781        .expect("transition");
13782        atn.add_transition(9, ParserTransitionSpec::Epsilon { target: 5 })
13783            .expect("transition");
13784        atn.add_transition(10, ParserTransitionSpec::Epsilon { target: 11 })
13785            .expect("transition");
13786        finish_atn(atn)
13787    }
13788
13789    #[test]
13790    fn left_recursive_loop_defers_overlapping_caller_lookahead() {
13791        let overlapping_atn = left_recursive_loop_with_caller_follow_atn(1);
13792        let unambiguous_atn = left_recursive_loop_with_caller_follow_atn(2);
13793
13794        let mut overlapping = parser_inside_left_recursive_callee(1);
13795        assert_eq!(
13796            overlapping.left_recursive_loop_enter_prediction(&overlapping_atn, 4, 0),
13797            None
13798        );
13799
13800        let mut unambiguous_enter = parser_inside_left_recursive_callee(1);
13801        assert_eq!(
13802            unambiguous_enter.left_recursive_loop_enter_prediction(&unambiguous_atn, 4, 0),
13803            Some(true)
13804        );
13805
13806        let mut unambiguous_exit = parser_inside_left_recursive_callee(2);
13807        assert_eq!(
13808            unambiguous_exit.left_recursive_loop_enter_prediction(&unambiguous_atn, 4, 0),
13809            Some(false)
13810        );
13811
13812        assert_eq!(
13813            overlapping.left_recursive_loop_enter_prediction(&unambiguous_atn, 4, 0),
13814            Some(true),
13815            "overlap results must not leak across ATNs"
13816        );
13817    }
13818
13819    #[test]
13820    fn left_recursive_loop_enters_after_nullable_operator_prefix() {
13821        let atn = left_recursive_loop_with_nullable_operator_prefix_atn();
13822        let mut parser = mini_parser(vec![
13823            TestToken::new(1).with_text("operator"),
13824            TestToken::eof("parser-test", 1, 1, 1),
13825        ]);
13826        parser.rule_context_stack = vec![RuleContextFrame {
13827            rule_index: 0,
13828            invoking_state: -1,
13829        }];
13830
13831        assert_eq!(
13832            parser.left_recursive_loop_enter_prediction(&atn, 1, 0),
13833            Some(true)
13834        );
13835        assert_eq!(
13836            parser.left_recursive_loop_enter_prediction(&atn, 1, 0),
13837            Some(true),
13838            "cached operator lookahead must preserve the nullable prefix return path"
13839        );
13840        assert_eq!(
13841            parser.left_recursive_loop_enter_prediction(&atn, 1, 2),
13842            Some(true),
13843            "the nullable child must use its rule-call precedence, not the caller precedence"
13844        );
13845    }
13846
13847    #[test]
13848    fn left_recursive_loop_defers_multi_token_prefix_that_shadows_lower_single_token() {
13849        // Models Java `>` (relational, prec 1, one token) vs `>>` (shift, prec 2,
13850        // two tokens). At prec 2 only shift is viable; one-token lookahead on `>`
13851        // must defer so StarLoopEntry adaptive predict can exit when the second
13852        // `>` is absent (as in `a < b > c`).
13853        let atn = left_recursive_loop_with_shared_gt_prefix_atn();
13854        let mut parser = mini_parser(vec![
13855            TestToken::new(1).with_text(">"),
13856            TestToken::new(2).with_text("id"),
13857            TestToken::eof("parser-test", 1, 1, 1),
13858        ]);
13859        parser.rule_context_stack = vec![RuleContextFrame {
13860            rule_index: 0,
13861            invoking_state: -1,
13862        }];
13863
13864        assert_eq!(
13865            parser.left_recursive_loop_enter_prediction(&atn, 1, 0),
13866            Some(true),
13867            "at low precedence relational `>` is a single-token operator"
13868        );
13869        assert_eq!(
13870            parser.left_recursive_loop_enter_prediction(&atn, 1, 1),
13871            Some(true),
13872            "relational remains single-token at its own precedence"
13873        );
13874        assert_eq!(
13875            parser.left_recursive_loop_enter_prediction(&atn, 1, 2),
13876            None,
13877            "at shift precedence, bare `>` must not force enter"
13878        );
13879    }
13880
13881    #[test]
13882    fn left_recursive_loop_preserves_rule_wrapped_operator_continuation() {
13883        let atn = left_recursive_loop_with_rule_wrapped_gt_prefix_atn();
13884        let mut parser = mini_parser(vec![
13885            TestToken::new(1).with_text(">"),
13886            TestToken::new(2).with_text("id"),
13887            TestToken::eof("parser-test", 1, 1, 1),
13888        ]);
13889        parser.rule_context_stack = vec![RuleContextFrame {
13890            rule_index: 0,
13891            invoking_state: -1,
13892        }];
13893
13894        assert_eq!(
13895            parser.left_recursive_loop_enter_prediction(&atn, 1, 0),
13896            Some(true),
13897            "the direct relational alternative remains a one-token operator"
13898        );
13899        assert_eq!(
13900            parser.left_recursive_loop_enter_prediction(&atn, 1, 2),
13901            None,
13902            "a token matched in the helper rule must return to the second shift token"
13903        );
13904    }
13905
13906    #[test]
13907    fn left_recursive_loop_preserves_predicate_and_multi_token_reachability() {
13908        let atn = left_recursive_loop_with_predicate_and_multi_token_prefix_atn();
13909        let mut parser = mini_parser(vec![
13910            TestToken::new(1).with_text(">"),
13911            TestToken::new(2).with_text("id"),
13912            TestToken::eof("parser-test", 1, 1, 1),
13913        ]);
13914        parser.rule_context_stack = vec![RuleContextFrame {
13915            rule_index: 0,
13916            invoking_state: -1,
13917        }];
13918
13919        assert_eq!(
13920            parser.left_recursive_loop_enter_prediction(&atn, 1, 2),
13921            None,
13922            "a predicate-gated single-token path must not be hidden by a multi-token path"
13923        );
13924    }
13925
13926    #[test]
13927    fn left_recursive_loop_defers_predicate_guarded_operator() {
13928        let atn = left_recursive_loop_with_predicate_guarded_operator_atn();
13929        let mut parser = mini_parser_with_hooks(
13930            vec![
13931                TestToken::new(1).with_text("operator"),
13932                TestToken::eof("parser-test", 1, 1, 1),
13933            ],
13934            RejectingPredicateHooks::default(),
13935        );
13936        parser.rule_context_stack = vec![RuleContextFrame {
13937            rule_index: 0,
13938            invoking_state: -1,
13939        }];
13940
13941        assert_eq!(
13942            parser.left_recursive_loop_enter_prediction(&atn, 1, 0),
13943            None,
13944            "a false predicate must be evaluated before entering the operator alternative"
13945        );
13946        assert_eq!(
13947            parser.left_recursive_loop_enter_prediction(&atn, 1, 0),
13948            None,
13949            "cached predicate-dependent lookahead must keep deferring"
13950        );
13951    }
13952
13953    #[test]
13954    fn left_recursive_loop_defers_through_nullable_caller_rule_call() {
13955        let atn = left_recursive_loop_with_nullable_follow_call_atn(1);
13956        let mut parser = parser_inside_left_recursive_callee(1);
13957
13958        assert_eq!(
13959            parser.left_recursive_loop_enter_prediction(&atn, 6, 0),
13960            None
13961        );
13962        assert_eq!(
13963            parser.left_recursive_loop_enter_prediction(&atn, 6, 0),
13964            None,
13965            "the cached overlap must preserve the nullable child return path"
13966        );
13967    }
13968
13969    #[test]
13970    fn left_recursive_loop_defers_through_nullable_parent_return() {
13971        let atn = left_recursive_loop_with_nullable_parent_return_atn(1);
13972        let mut parser = mini_parser(vec![
13973            TestToken::new(1).with_text("lookahead"),
13974            TestToken::eof("parser-test", 1, 1, 1),
13975        ]);
13976        parser.rule_context_stack = vec![
13977            RuleContextFrame {
13978                rule_index: 0,
13979                invoking_state: -1,
13980            },
13981            RuleContextFrame {
13982                rule_index: 1,
13983                invoking_state: 1,
13984            },
13985            RuleContextFrame {
13986                rule_index: 2,
13987                invoking_state: 5,
13988            },
13989        ];
13990
13991        assert_eq!(
13992            parser.left_recursive_loop_enter_prediction(&atn, 9, 0),
13993            None,
13994            "a nullable caller must unwind to its parent's consuming follow path"
13995        );
13996        assert_eq!(
13997            parser.left_recursive_loop_enter_prediction(&atn, 9, 0),
13998            None,
13999            "the caller-overlap cache must not retain a false negative"
14000        );
14001    }
14002
14003    #[test]
14004    fn left_recursive_loop_defers_after_recursive_operand_returns_to_loop() {
14005        let atn = left_recursive_loop_with_recursive_operand_return_atn(1);
14006        let mut parser = mini_parser(vec![
14007            TestToken::new(1).with_text("lookahead"),
14008            TestToken::eof("parser-test", 1, 1, 1),
14009        ]);
14010        parser.rule_context_stack = vec![
14011            RuleContextFrame {
14012                rule_index: 0,
14013                invoking_state: -1,
14014            },
14015            RuleContextFrame {
14016                rule_index: 1,
14017                invoking_state: 1,
14018            },
14019            RuleContextFrame {
14020                rule_index: 1,
14021                invoking_state: 8,
14022            },
14023        ];
14024
14025        assert_eq!(
14026            parser.left_recursive_loop_enter_prediction(&atn, 5, 0),
14027            None,
14028            "a recursive operand return must preserve its parent caller context"
14029        );
14030        assert_eq!(
14031            parser.left_recursive_loop_enter_prediction(&atn, 5, 0),
14032            None,
14033            "the caller-overlap cache must preserve the loop-boundary return"
14034        );
14035    }
14036
14037    fn token_then_eof_atn() -> Atn {
14038        AtnDeserializer::new(&SerializedAtn::from_i32(&[
14039            4, 1, 2, // version, parser, max token type
14040            3, // states
14041            2, 0, // rule start
14042            1, 0, // basic
14043            7, 0, // rule stop
14044            0, // non-greedy states
14045            0, // precedence states
14046            1, // rules
14047            0, // rule 0 start
14048            0, // modes
14049            0, // sets
14050            2, // transitions
14051            0, 1, 5, 1, 0, 0, // match token 1
14052            1, 2, 5, -1, 0, 0, // match EOF
14053            0, // decisions
14054        ]))
14055        .deserialize_parser()
14056        .expect("artificial parser ATN should deserialize")
14057    }
14058
14059    fn epsilon_cycle_atn() -> Atn {
14060        let mut atn = ParserAtnBuilder::new(1);
14061        for (state_number, kind) in [
14062            (0, AtnStateKind::RuleStart),
14063            (1, AtnStateKind::Basic),
14064            (2, AtnStateKind::RuleStop),
14065        ] {
14066            assert_eq!(
14067                atn.add_state(kind, Some(0)).expect("state").index(),
14068                state_number
14069            );
14070        }
14071        atn.set_rule_to_start_state(vec![0])
14072            .expect("rule start states");
14073        atn.set_rule_to_stop_state(vec![2])
14074            .expect("rule stop states");
14075        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
14076            .expect("transition");
14077        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 1 })
14078            .expect("self-cycle transition");
14079        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
14080            .expect("exit transition");
14081        finish_atn(atn)
14082    }
14083
14084    fn eof_then_action_atn() -> Atn {
14085        AtnDeserializer::new(&SerializedAtn::from_i32(&[
14086            4, 1, 1, // version, parser, max token type
14087            3, // states
14088            2, 0, // rule start
14089            1, 0, // basic
14090            7, 0, // rule stop
14091            0, // non-greedy states
14092            0, // precedence states
14093            1, // rules
14094            0, // rule 0 start
14095            0, // modes
14096            0, // sets
14097            2, // transitions
14098            0, 1, 5, -1, 0, 0, // match EOF
14099            1, 2, 6, 0, 0, 0, // parser action
14100            0, // decisions
14101        ]))
14102        .deserialize_parser()
14103        .expect("artificial parser ATN should deserialize")
14104    }
14105
14106    fn noop_action_then_token_then_eof_atn() -> Atn {
14107        AtnDeserializer::new(&SerializedAtn::from_i32(&[
14108            4, 1, 2, // version, parser, max token type
14109            4, // states
14110            2, 0, // rule start
14111            1, 0, // basic
14112            1, 0, // basic
14113            7, 0, // rule stop
14114            0, // non-greedy states
14115            0, // precedence states
14116            1, // rules
14117            0, // rule 0 start
14118            0, // modes
14119            0, // sets
14120            3, // transitions
14121            0, 1, 6, 0, -1, 0, // no-op parser action
14122            1, 2, 5, 1, 0, 0, // match token 1
14123            2, 3, 5, -1, 0, 0, // match EOF
14124            0, // decisions
14125        ]))
14126        .deserialize_parser()
14127        .expect("artificial no-op action ATN should deserialize")
14128    }
14129
14130    fn two_alt_decision_atn() -> Atn {
14131        let mut atn = ParserAtnBuilder::new(2);
14132        assert_eq!(
14133            atn.add_state(AtnStateKind::RuleStart, Some(0))
14134                .expect("state")
14135                .index(),
14136            0
14137        );
14138        assert_eq!(
14139            atn.add_state(AtnStateKind::BlockStart, Some(0))
14140                .expect("state")
14141                .index(),
14142            1
14143        );
14144        assert_eq!(
14145            atn.add_state(AtnStateKind::Basic, Some(0))
14146                .expect("state")
14147                .index(),
14148            2
14149        );
14150        assert_eq!(
14151            atn.add_state(AtnStateKind::Basic, Some(0))
14152                .expect("state")
14153                .index(),
14154            3
14155        );
14156        assert_eq!(
14157            atn.add_state(AtnStateKind::BlockEnd, Some(0))
14158                .expect("state")
14159                .index(),
14160            4
14161        );
14162        assert_eq!(
14163            atn.add_state(AtnStateKind::RuleStop, Some(0))
14164                .expect("state")
14165                .index(),
14166            5
14167        );
14168        atn.set_rule_to_start_state(vec![0])
14169            .expect("rule start states");
14170        atn.set_rule_to_stop_state(vec![5])
14171            .expect("rule stop states");
14172        atn.add_decision_state(1).expect("decision state");
14173        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
14174            .expect("transition");
14175        atn.add_transition(
14176            1,
14177            ParserTransitionSpec::Atom {
14178                target: 2,
14179                label: 1,
14180            },
14181        )
14182        .expect("transition");
14183        atn.add_transition(
14184            1,
14185            ParserTransitionSpec::Atom {
14186                target: 3,
14187                label: 2,
14188            },
14189        )
14190        .expect("transition");
14191        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 4 })
14192            .expect("transition");
14193        atn.add_transition(3, ParserTransitionSpec::Epsilon { target: 4 })
14194            .expect("transition");
14195        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
14196            .expect("transition");
14197        finish_atn(atn)
14198    }
14199
14200    /// ATN for `start : (A)? B EOF ;` (A=1, B=2, C=3, max token type 3).
14201    /// State 1 is the nullable optional-block decision; its sync set is {A, B}.
14202    fn optional_then_b_eof_atn() -> Atn {
14203        let mut atn = ParserAtnBuilder::new(3);
14204        assert_eq!(
14205            atn.add_state(AtnStateKind::RuleStart, Some(0))
14206                .expect("state")
14207                .index(),
14208            0
14209        );
14210        assert_eq!(
14211            atn.add_state(AtnStateKind::BlockStart, Some(0))
14212                .expect("state")
14213                .index(),
14214            1
14215        );
14216        assert_eq!(
14217            atn.add_state(AtnStateKind::Basic, Some(0))
14218                .expect("state")
14219                .index(),
14220            2
14221        );
14222        assert_eq!(
14223            atn.add_state(AtnStateKind::Basic, Some(0))
14224                .expect("state")
14225                .index(),
14226            3
14227        );
14228        assert_eq!(
14229            atn.add_state(AtnStateKind::Basic, Some(0))
14230                .expect("state")
14231                .index(),
14232            4
14233        );
14234        assert_eq!(
14235            atn.add_state(AtnStateKind::RuleStop, Some(0))
14236                .expect("state")
14237                .index(),
14238            5
14239        );
14240        atn.set_rule_to_start_state(vec![0])
14241            .expect("rule start states");
14242        atn.set_rule_to_stop_state(vec![5])
14243            .expect("rule stop states");
14244        atn.add_decision_state(1).expect("decision state");
14245        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
14246            .expect("transition");
14247        // Optional block: match A then fall through, or skip straight to state 3.
14248        atn.add_transition(
14249            1,
14250            ParserTransitionSpec::Atom {
14251                target: 3,
14252                label: 1,
14253            },
14254        )
14255        .expect("transition");
14256        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 3 })
14257            .expect("transition");
14258        // Match B, then EOF.
14259        atn.add_transition(
14260            3,
14261            ParserTransitionSpec::Atom {
14262                target: 4,
14263                label: 2,
14264            },
14265        )
14266        .expect("transition");
14267        atn.add_transition(
14268            4,
14269            ParserTransitionSpec::Atom {
14270                target: 5,
14271                label: TOKEN_EOF,
14272            },
14273        )
14274        .expect("transition");
14275        finish_atn(atn)
14276    }
14277
14278    #[test]
14279    fn sync_decision_deletes_only_a_single_token() {
14280        // ANTLR sync recovery deletes exactly one token, only when LA(2) is
14281        // expected. `(A)? B EOF` at the optional-block decision:
14282        //  - `C B`   -> single-token deletion: one error node for the extra `C`.
14283        //  - `C C B` -> LA(2) is `C` (not expected), so NO deletion; sync returns
14284        //               without consuming and records the expected set for the
14285        //               subsequent mismatch (the parser must not over-consume both
14286        //               `C`s and accept the input).
14287        let atn = optional_then_b_eof_atn();
14288
14289        let mut single = mini_parser(vec![
14290            TestToken::new(3).with_text("c"),
14291            TestToken::new(2).with_text("b"),
14292            TestToken::eof("parser-test", 1, 2, 2),
14293        ]);
14294        single.rule_context_stack = vec![RuleContextFrame {
14295            rule_index: 0,
14296            invoking_state: 0,
14297        }];
14298        let children = single
14299            .sync_decision(&atn, 1, true, false)
14300            .expect("single extraneous token recovers");
14301        assert_eq!(children.len(), 1);
14302        assert_eq!(single.node(children[0]).kind(), NodeKind::Error);
14303        assert_eq!(single.number_of_syntax_errors(), 1);
14304        // Exactly one token consumed (the cursor now sits on `b`).
14305        assert_eq!(single.la(1), 2);
14306
14307        let mut double = mini_parser(vec![
14308            TestToken::new(3).with_text("c"),
14309            TestToken::new(3).with_text("c"),
14310            TestToken::new(2).with_text("b"),
14311            TestToken::eof("parser-test", 1, 3, 3),
14312        ]);
14313        double.rule_context_stack = vec![RuleContextFrame {
14314            rule_index: 0,
14315            invoking_state: 0,
14316        }];
14317        let result = double.sync_decision(&atn, 1, true, false);
14318        // No single-token deletion fires (LA(2) is `c`, not expected): sync must NOT
14319        // consume either `c`. It reports the mismatch at the first `c` (so the parser
14320        // does not over-consume both and accept the input). Nothing is consumed, so
14321        // the cursor still sits on the first `c` for rule-level recovery.
14322        let error = result.expect_err("two extraneous tokens must not be deleted by sync");
14323        match error {
14324            AntlrError::ParserError { message, .. } => {
14325                assert!(message.starts_with("mismatched input"), "got: {message}");
14326            }
14327            other => panic!("expected a mismatched-input ParserError, got {other:?}"),
14328        }
14329        assert_eq!(double.la(1), 3);
14330    }
14331
14332    /// The real serialized ATN that `antlr4-rust-gen` emits for
14333    /// `grammar T; s : A* EOF; A:'a'; C:'c';` — a `*` loop whose follow set after
14334    /// the loop is `EOF`. The loop decision is state 5.
14335    fn star_loop_then_eof_atn() -> Atn {
14336        AtnDeserializer::new(&SerializedAtn::from_i32(&[
14337            4, 1, 3, 11, 2, 0, 7, 0, 1, 0, 5, 0, 4, 8, 0, 10, 0, 12, 0, 7, 9, 0, 1, 0, 1, 0, 1, 0,
14338            0, 0, 1, 0, 0, 0, 10, 0, 5, 1, 0, 0, 0, 2, 4, 5, 1, 0, 0, 3, 2, 1, 0, 0, 0, 4, 7, 1, 0,
14339            0, 0, 5, 3, 1, 0, 0, 0, 5, 6, 1, 0, 0, 0, 6, 8, 1, 0, 0, 0, 7, 5, 1, 0, 0, 0, 8, 9, 5,
14340            0, 0, 1, 9, 1, 1, 0, 0, 0, 1, 5,
14341        ]))
14342        .deserialize_parser()
14343        .expect("star-loop-then-EOF ATN should deserialize")
14344    }
14345
14346    /// ATN for `s : a+ Y ; a : X ;`.
14347    ///
14348    /// At EOF, recovery can synthesize an empty failed `a` child. The enclosing
14349    /// `+` loop must not treat that zero-width child as a successful iteration
14350    /// and then re-enter the loop at the same token index.
14351    fn plus_loop_with_recovering_body_atn() -> Atn {
14352        let mut atn = ParserAtnBuilder::new(2);
14353        assert_eq!(
14354            atn.add_state(AtnStateKind::RuleStart, Some(0))
14355                .expect("state")
14356                .index(),
14357            0
14358        );
14359        assert_eq!(
14360            atn.add_state(AtnStateKind::PlusBlockStart, Some(0))
14361                .expect("state")
14362                .index(),
14363            1
14364        );
14365        assert_eq!(
14366            atn.add_state(AtnStateKind::Basic, Some(0))
14367                .expect("state")
14368                .index(),
14369            2
14370        );
14371        assert_eq!(
14372            atn.add_state(AtnStateKind::BlockEnd, Some(0))
14373                .expect("state")
14374                .index(),
14375            3
14376        );
14377        assert_eq!(
14378            atn.add_state(AtnStateKind::PlusLoopBack, Some(0))
14379                .expect("state")
14380                .index(),
14381            4
14382        );
14383        assert_eq!(
14384            atn.add_state(AtnStateKind::LoopEnd, Some(0))
14385                .expect("state")
14386                .index(),
14387            5
14388        );
14389        assert_eq!(
14390            atn.add_state(AtnStateKind::RuleStop, Some(0))
14391                .expect("state")
14392                .index(),
14393            6
14394        );
14395        assert_eq!(
14396            atn.add_state(AtnStateKind::RuleStart, Some(1))
14397                .expect("state")
14398                .index(),
14399            7
14400        );
14401        assert_eq!(
14402            atn.add_state(AtnStateKind::Basic, Some(1))
14403                .expect("state")
14404                .index(),
14405            8
14406        );
14407        assert_eq!(
14408            atn.add_state(AtnStateKind::RuleStop, Some(1))
14409                .expect("state")
14410                .index(),
14411            9
14412        );
14413        atn.set_rule_to_start_state(vec![0, 7])
14414            .expect("rule start states");
14415        atn.set_rule_to_stop_state(vec![6, 9])
14416            .expect("rule stop states");
14417        atn.set_end_state(1, 3).expect("block end state");
14418        atn.set_loop_back_state(5, 4).expect("loop back state");
14419        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
14420            .expect("transition");
14421        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
14422            .expect("transition");
14423        atn.add_transition(
14424            2,
14425            ParserTransitionSpec::Rule {
14426                target: 7,
14427                rule_index: 1,
14428                follow_state: 3,
14429                precedence: 0,
14430            },
14431        )
14432        .expect("transition");
14433        atn.add_transition(3, ParserTransitionSpec::Epsilon { target: 4 })
14434            .expect("transition");
14435        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 1 })
14436            .expect("transition");
14437        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
14438            .expect("transition");
14439        atn.add_transition(
14440            5,
14441            ParserTransitionSpec::Atom {
14442                target: 6,
14443                label: 2,
14444            },
14445        )
14446        .expect("transition");
14447        atn.add_transition(
14448            7,
14449            ParserTransitionSpec::Atom {
14450                target: 8,
14451                label: 1,
14452            },
14453        )
14454        .expect("transition");
14455        atn.add_transition(8, ParserTransitionSpec::Epsilon { target: 9 })
14456            .expect("transition");
14457        finish_atn(atn)
14458    }
14459
14460    #[test]
14461    fn runtime_options_default_exits_recovering_empty_plus_iteration() {
14462        let atn = plus_loop_with_recovering_body_atn();
14463        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
14464
14465        let error = parser
14466            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
14467            .expect_err("EOF recovery should report a bounded mismatch");
14468
14469        let AntlrError::ParserError { message, .. } = error else {
14470            panic!("expected ParserError, got {error:?}");
14471        };
14472        assert_eq!(message, "mismatched input '<EOF>' expecting {'x', 2}");
14473        assert_eq!(parser.number_of_syntax_errors(), 1);
14474        assert_eq!(parser.input.index(), 0, "EOF remains unconsumed");
14475    }
14476
14477    #[test]
14478    fn sync_decision_deletes_token_before_eof_at_loop_back() {
14479        // `s : A* EOF` on `c`: the loop decision (state 5) can recover onto EOF.
14480        // At the loop ENTRY (loop_back = false) a single unexpected token before
14481        // EOF is deleted as an error node (then the generated EOF match consumes
14482        // the real EOF) — matching ANTLR's `(s c <EOF>)` + "extraneous input".
14483        // EOF must be a valid scan-stop for this to fire.
14484        let atn = star_loop_then_eof_atn();
14485        let mut parser = mini_parser(vec![
14486            TestToken::new(2).with_text("c"),
14487            TestToken::eof("parser-test", 1, 1, 1),
14488        ]);
14489        parser.rule_context_stack = vec![RuleContextFrame {
14490            rule_index: 0,
14491            invoking_state: 0,
14492        }];
14493        let children = parser
14494            .sync_decision(&atn, 5, true, false)
14495            .expect("single token before EOF recovers");
14496        assert_eq!(children.len(), 1);
14497        assert_eq!(parser.node(children[0]).kind(), NodeKind::Error);
14498        assert_eq!(parser.number_of_syntax_errors(), 1);
14499        assert_eq!(
14500            parser.la(1),
14501            TOKEN_EOF,
14502            "EOF is left for the rule's EOF match"
14503        );
14504    }
14505
14506    #[test]
14507    fn sync_decision_does_not_delete_two_tokens_before_eof_at_loop_entry() {
14508        // `s : A* EOF` on `c c`: at the loop ENTRY (loop_back = false) ANTLR does
14509        // single-token deletion, which fails because LA(2) = `c` is not expected —
14510        // so it reports `mismatched input` and consumes nothing (ANTLR: `(s c c)`
14511        // with no EOF). The scan must NOT multi-token-consume both `c`s here.
14512        let atn = star_loop_then_eof_atn();
14513        let mut parser = mini_parser(vec![
14514            TestToken::new(2).with_text("c"),
14515            TestToken::new(2).with_text("c"),
14516            TestToken::eof("parser-test", 1, 2, 2),
14517        ]);
14518        parser.rule_context_stack = vec![RuleContextFrame {
14519            rule_index: 0,
14520            invoking_state: 0,
14521        }];
14522        let error = parser
14523            .sync_decision(&atn, 5, true, false)
14524            .expect_err("two tokens at the loop entry must not be deleted");
14525        match error {
14526            AntlrError::ParserError { message, .. } => {
14527                assert!(message.starts_with("mismatched input"), "got: {message}");
14528            }
14529            other => panic!("expected mismatched-input ParserError, got {other:?}"),
14530        }
14531        assert_eq!(
14532            parser.la(1),
14533            2,
14534            "nothing consumed; cursor still on first `c`"
14535        );
14536    }
14537
14538    #[test]
14539    fn sync_decision_consumes_until_eof_at_loop_back() {
14540        // Same `s : A* EOF` decision, but at a loop-BACK (loop_back = true, i.e.
14541        // after ≥1 `A` matched). ANTLR uses multi-token `consumeUntil(recoverSet)`
14542        // there, so two unexpected tokens before EOF are BOTH deleted and the rule
14543        // recovers (matching `(s a c c <EOF>)` for input `a c c`). Here we feed the
14544        // post-`a` state directly: `c c <EOF>` with loop_back = true.
14545        let atn = star_loop_then_eof_atn();
14546        let mut parser = mini_parser(vec![
14547            TestToken::new(2).with_text("c"),
14548            TestToken::new(2).with_text("c"),
14549            TestToken::eof("parser-test", 1, 2, 2),
14550        ]);
14551        parser.rule_context_stack = vec![RuleContextFrame {
14552            rule_index: 0,
14553            invoking_state: 0,
14554        }];
14555        let children = parser
14556            .sync_decision(&atn, 5, false, true)
14557            .expect("loop-back multi-token deletion recovers onto EOF");
14558        assert_eq!(children.len(), 2, "both `c`s deleted as error nodes");
14559        assert!(
14560            children
14561                .iter()
14562                .all(|child| parser.node(*child).kind() == NodeKind::Error)
14563        );
14564        assert_eq!(parser.number_of_syntax_errors(), 1);
14565        assert_eq!(parser.la(1), TOKEN_EOF, "EOF left for the rule's EOF match");
14566    }
14567
14568    fn predicate_after_token_atn() -> Atn {
14569        let mut atn = ParserAtnBuilder::new(2);
14570        assert_eq!(
14571            atn.add_state(AtnStateKind::RuleStart, Some(0))
14572                .expect("state")
14573                .index(),
14574            0
14575        );
14576        assert_eq!(
14577            atn.add_state(AtnStateKind::Basic, Some(0))
14578                .expect("state")
14579                .index(),
14580            1
14581        );
14582        assert_eq!(
14583            atn.add_state(AtnStateKind::Basic, Some(0))
14584                .expect("state")
14585                .index(),
14586            2
14587        );
14588        assert_eq!(
14589            atn.add_state(AtnStateKind::Basic, Some(0))
14590                .expect("state")
14591                .index(),
14592            3
14593        );
14594        assert_eq!(
14595            atn.add_state(AtnStateKind::RuleStop, Some(0))
14596                .expect("state")
14597                .index(),
14598            4
14599        );
14600        atn.set_rule_to_start_state(vec![0])
14601            .expect("rule start states");
14602        atn.set_rule_to_stop_state(vec![4])
14603            .expect("rule stop states");
14604        atn.add_transition(
14605            0,
14606            ParserTransitionSpec::Atom {
14607                target: 1,
14608                label: 1,
14609            },
14610        )
14611        .expect("transition");
14612        atn.add_transition(
14613            1,
14614            ParserTransitionSpec::Predicate {
14615                target: 2,
14616                rule_index: 0,
14617                pred_index: 0,
14618                context_dependent: false,
14619            },
14620        )
14621        .expect("transition");
14622        atn.add_transition(
14623            2,
14624            ParserTransitionSpec::Atom {
14625                target: 3,
14626                label: 2,
14627            },
14628        )
14629        .expect("transition");
14630        atn.add_transition(3, ParserTransitionSpec::Epsilon { target: 4 })
14631            .expect("transition");
14632        finish_atn(atn)
14633    }
14634
14635    fn predicate_gated_same_lookahead_atn(pred_indexes: [usize; 2]) -> Atn {
14636        let mut atn = ParserAtnBuilder::new(1);
14637        for (state_number, kind) in [
14638            (0, AtnStateKind::RuleStart),
14639            (1, AtnStateKind::BlockStart),
14640            (2, AtnStateKind::Basic),
14641            (3, AtnStateKind::Basic),
14642            (4, AtnStateKind::Basic),
14643            (5, AtnStateKind::Basic),
14644            (6, AtnStateKind::BlockEnd),
14645            (7, AtnStateKind::RuleStop),
14646        ] {
14647            assert_eq!(
14648                atn.add_state(kind, Some(0)).expect("state").index(),
14649                state_number
14650            );
14651        }
14652        atn.set_rule_to_start_state(vec![0])
14653            .expect("rule start states");
14654        atn.set_rule_to_stop_state(vec![7])
14655            .expect("rule stop states");
14656        atn.add_decision_state(1).expect("decision state");
14657        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
14658            .expect("transition");
14659        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
14660            .expect("transition");
14661        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 3 })
14662            .expect("transition");
14663        atn.add_transition(
14664            2,
14665            ParserTransitionSpec::Predicate {
14666                target: 4,
14667                rule_index: 0,
14668                pred_index: pred_indexes[0],
14669                context_dependent: false,
14670            },
14671        )
14672        .expect("transition");
14673        atn.add_transition(
14674            3,
14675            ParserTransitionSpec::Predicate {
14676                target: 5,
14677                rule_index: 0,
14678                pred_index: pred_indexes[1],
14679                context_dependent: false,
14680            },
14681        )
14682        .expect("transition");
14683        atn.add_transition(
14684            4,
14685            ParserTransitionSpec::Atom {
14686                target: 6,
14687                label: 1,
14688            },
14689        )
14690        .expect("transition");
14691        atn.add_transition(
14692            5,
14693            ParserTransitionSpec::Atom {
14694                target: 6,
14695                label: 1,
14696            },
14697        )
14698        .expect("transition");
14699        atn.add_transition(
14700            6,
14701            ParserTransitionSpec::Atom {
14702                target: 7,
14703                label: TOKEN_EOF,
14704            },
14705        )
14706        .expect("transition");
14707        finish_atn(atn)
14708    }
14709
14710    fn nested_nullable_context_atn() -> Atn {
14711        let mut atn = ParserAtnBuilder::new(1);
14712        for state_number in 0..=20 {
14713            let kind = match state_number {
14714                0 | 10 | 16 => AtnStateKind::RuleStart,
14715                9 | 15 | 20 => AtnStateKind::RuleStop,
14716                _ => AtnStateKind::Basic,
14717            };
14718            let rule_index = match state_number {
14719                0..=9 => 0,
14720                10..=15 => 1,
14721                _ => 2,
14722            };
14723            assert_eq!(
14724                atn.add_state(kind, Some(rule_index))
14725                    .expect("state")
14726                    .index(),
14727                state_number
14728            );
14729        }
14730        atn.set_rule_to_start_state(vec![0, 10, 16])
14731            .expect("rule start states");
14732        atn.set_rule_to_stop_state(vec![9, 15, 20])
14733            .expect("rule stop states");
14734        atn.add_transition(
14735            1,
14736            ParserTransitionSpec::Rule {
14737                target: 10,
14738                rule_index: 1,
14739                follow_state: 8,
14740                precedence: 0,
14741            },
14742        )
14743        .expect("transition");
14744        atn.add_transition(
14745            8,
14746            ParserTransitionSpec::Atom {
14747                target: 9,
14748                label: 1,
14749            },
14750        )
14751        .expect("transition");
14752        atn.add_transition(8, ParserTransitionSpec::Epsilon { target: 9 })
14753            .expect("transition");
14754        atn.add_transition(
14755            2,
14756            ParserTransitionSpec::Rule {
14757                target: 16,
14758                rule_index: 2,
14759                follow_state: 14,
14760                precedence: 0,
14761            },
14762        )
14763        .expect("transition");
14764        atn.add_transition(14, ParserTransitionSpec::Epsilon { target: 15 })
14765            .expect("transition");
14766        finish_atn(atn)
14767    }
14768
14769    fn generated_match_recovery_atn() -> Atn {
14770        let mut atn = ParserAtnBuilder::new(2);
14771        assert_eq!(
14772            atn.add_state(AtnStateKind::RuleStart, Some(0))
14773                .expect("state")
14774                .index(),
14775            0
14776        );
14777        assert_eq!(
14778            atn.add_state(AtnStateKind::Basic, Some(0))
14779                .expect("state")
14780                .index(),
14781            1
14782        );
14783        assert_eq!(
14784            atn.add_state(AtnStateKind::Basic, Some(0))
14785                .expect("state")
14786                .index(),
14787            2
14788        );
14789        assert_eq!(
14790            atn.add_state(AtnStateKind::RuleStop, Some(0))
14791                .expect("state")
14792                .index(),
14793            3
14794        );
14795        assert_eq!(
14796            atn.add_state(AtnStateKind::RuleStart, Some(1))
14797                .expect("state")
14798                .index(),
14799            4
14800        );
14801        assert_eq!(
14802            atn.add_state(AtnStateKind::RuleStop, Some(1))
14803                .expect("state")
14804                .index(),
14805            5
14806        );
14807        atn.set_rule_to_start_state(vec![0, 4])
14808            .expect("rule start states");
14809        atn.set_rule_to_stop_state(vec![3, 5])
14810            .expect("rule stop states");
14811        atn.add_transition(
14812            1,
14813            ParserTransitionSpec::Rule {
14814                target: 4,
14815                rule_index: 1,
14816                follow_state: 2,
14817                precedence: 0,
14818            },
14819        )
14820        .expect("transition");
14821        atn.add_transition(
14822            2,
14823            ParserTransitionSpec::Atom {
14824                target: 3,
14825                label: TOKEN_EOF,
14826            },
14827        )
14828        .expect("transition");
14829        finish_atn(atn)
14830    }
14831
14832    fn complement_set_atn() -> Atn {
14833        let mut atn = ParserAtnBuilder::new(1);
14834        assert_eq!(
14835            atn.add_state(AtnStateKind::RuleStart, Some(0))
14836                .expect("state")
14837                .index(),
14838            0
14839        );
14840        assert_eq!(
14841            atn.add_state(AtnStateKind::RuleStop, Some(0))
14842                .expect("state")
14843                .index(),
14844            1
14845        );
14846        atn.set_rule_to_start_state(vec![0])
14847            .expect("rule start states");
14848        atn.set_rule_to_stop_state(vec![1])
14849            .expect("rule stop states");
14850        let excluded = atn.add_interval_set([(1, 1)]).expect("excluded set");
14851        atn.add_transition(
14852            0,
14853            ParserTransitionSpec::NotSet {
14854                target: 1,
14855                set: excluded,
14856            },
14857        )
14858        .expect("transition");
14859        finish_atn(atn)
14860    }
14861
14862    /// ATN for `start : . EOF ;`: a wildcard whose follow state explicitly matches
14863    /// EOF. State 0 (`RuleStart`) -wildcard-> 2 -EOF-> 1 (`RuleStop`).
14864    fn wildcard_then_eof_atn() -> Atn {
14865        let mut atn = ParserAtnBuilder::new(1);
14866        assert_eq!(
14867            atn.add_state(AtnStateKind::RuleStart, Some(0))
14868                .expect("state")
14869                .index(),
14870            0
14871        );
14872        assert_eq!(
14873            atn.add_state(AtnStateKind::RuleStop, Some(0))
14874                .expect("state")
14875                .index(),
14876            1
14877        );
14878        assert_eq!(
14879            atn.add_state(AtnStateKind::Basic, Some(0))
14880                .expect("state")
14881                .index(),
14882            2
14883        );
14884        atn.set_rule_to_start_state(vec![0])
14885            .expect("rule start states");
14886        atn.set_rule_to_stop_state(vec![1])
14887            .expect("rule stop states");
14888        atn.add_transition(0, ParserTransitionSpec::Wildcard { target: 2 })
14889            .expect("transition");
14890        atn.add_transition(
14891            2,
14892            ParserTransitionSpec::Atom {
14893                target: 1,
14894                label: TOKEN_EOF,
14895            },
14896        )
14897        .expect("transition");
14898        finish_atn(atn)
14899    }
14900
14901    #[test]
14902    fn parser_matches_token_and_reports_mismatch() {
14903        let source = Source {
14904            tokens: vec![
14905                TestToken::new(1).with_text("x"),
14906                TestToken::eof("parser-test", 1, 1, 1),
14907            ],
14908            index: 0,
14909        };
14910        let data = RecognizerData::new(
14911            "Mini.g4",
14912            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
14913        );
14914        let mut parser = BaseParser::new(CommonTokenStream::new(source), data);
14915        let matched = parser.match_token(1).expect("token 1 should match");
14916        assert_eq!(parser.node(matched).text(), "x");
14917        assert!(parser.match_token(1).is_err());
14918    }
14919
14920    #[test]
14921    fn parser_matches_token_sets() {
14922        let mut parser = mini_parser(vec![
14923            TestToken::new(1).with_text("x"),
14924            TestToken::eof("parser-test", 1, 1, 1),
14925        ]);
14926
14927        let matched = parser
14928            .match_set(&[(1, 1), (3, 4)])
14929            .expect("token set should match");
14930        assert_eq!(parser.node(matched).text(), "x");
14931        assert!(parser.match_not_set(&[(1, 1)], 1, 4).is_err());
14932    }
14933
14934    #[test]
14935    fn generated_rule_api_tracks_state_and_precedence() {
14936        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
14937
14938        let context = parser.enter_rule(7, 2);
14939        assert_eq!(context.rule_index(), 2);
14940        assert_eq!(parser.state(), 7);
14941        assert_eq!(
14942            parser.rule_context_stack,
14943            vec![RuleContextFrame {
14944                rule_index: 2,
14945                invoking_state: 7
14946            }]
14947        );
14948
14949        let recursive = parser.enter_recursion_rule(11, 3, 4);
14950        assert_eq!(recursive.rule_index(), 3);
14951        assert!(parser.precpred(4));
14952        assert!(parser.precpred(5));
14953        assert!(!parser.precpred(3));
14954
14955        let next = parser.push_new_recursion_context(13, 3);
14956        assert_eq!(next.invoking_state(), 13);
14957        parser.unroll_recursion_context();
14958        assert_eq!(parser.precedence_stack, vec![0]);
14959        assert_eq!(
14960            parser.rule_context_stack,
14961            vec![RuleContextFrame {
14962                rule_index: 2,
14963                invoking_state: 7
14964            }]
14965        );
14966
14967        parser.exit_rule();
14968        assert!(parser.rule_context_stack.is_empty());
14969    }
14970
14971    #[test]
14972    fn reset_rewinds_input_and_clears_parser_owned_parse_state() {
14973        let mut parser = mini_parser(vec![
14974            TestToken::new(1).with_text("x"),
14975            TestToken::eof("parser-test", 1, 1, 1),
14976        ]);
14977        let matched = parser.match_token(1).expect("token should match");
14978        assert_eq!(parser.node(matched).text(), "x");
14979        parser.record_generated_syntax_error();
14980        parser.set_int_member(7, 11);
14981        parser.set_build_parse_trees(false);
14982        parser.set_report_diagnostic_errors(true);
14983        parser.set_prediction_mode(PredictionMode::Sll);
14984        parser.set_bail_on_error(true);
14985        let _context = parser.enter_recursion_rule(9, 0, 4);
14986        parser.pending_invoking_states.push(5);
14987        parser.unknown_predicate_hits.push((0, 1));
14988        parser.unhandled_action_hits.push((0, 2));
14989
14990        parser.reset();
14991
14992        assert_eq!(parser.input.index(), 0);
14993        assert_eq!(parser.la(1), 1);
14994        assert_eq!(parser.state(), -1);
14995        assert_eq!(parser.number_of_syntax_errors(), 0);
14996        assert_eq!(parser.parse_tree_storage().node_count(), 0);
14997        assert!(parser.rule_context_stack.is_empty());
14998        assert!(parser.pending_invoking_states.is_empty());
14999        assert_eq!(parser.precedence_stack, [0]);
15000        assert!(parser.unknown_predicate_hits.is_empty());
15001        assert!(parser.unhandled_action_hits.is_empty());
15002        assert_eq!(parser.int_member(7), Some(11));
15003        assert!(!parser.build_parse_trees());
15004        assert!(parser.report_diagnostic_errors());
15005        assert_eq!(parser.prediction_mode(), PredictionMode::Sll);
15006        assert!(parser.bail_on_error());
15007    }
15008
15009    #[test]
15010    fn set_token_stream_replaces_input_and_resets_parser() {
15011        let mut parser = mini_parser(vec![
15012            TestToken::new(1).with_text("old"),
15013            TestToken::eof("parser-test", 1, 1, 1),
15014        ]);
15015        parser.consume();
15016        parser.record_generated_syntax_error();
15017        let replacement = CommonTokenStream::new(Source {
15018            tokens: vec![
15019                TestToken::new(2).with_text("new"),
15020                TestToken::eof("parser-test", 1, 1, 1),
15021            ],
15022            index: 0,
15023        });
15024
15025        parser.set_token_stream(replacement);
15026
15027        assert_eq!(parser.input.index(), 0);
15028        assert_eq!(parser.la(1), 2);
15029        assert_eq!(parser.input.text_all(), "new");
15030        assert_eq!(parser.number_of_syntax_errors(), 0);
15031    }
15032
15033    #[test]
15034    fn active_invocation_states_exclude_the_root_frame() {
15035        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
15036
15037        let _root = parser.enter_rule(0, 0);
15038        assert!(parser.active_invocation_states().is_empty());
15039
15040        let marker = parser.push_invoking_state(6);
15041        let _child = parser.enter_rule(2, 1);
15042        parser.discard_invoking_state(marker);
15043        assert_eq!(parser.active_invocation_states(), [6]);
15044
15045        let marker = parser.push_invoking_state(13);
15046        let _grandchild = parser.enter_rule(4, 2);
15047        parser.discard_invoking_state(marker);
15048        assert_eq!(parser.active_invocation_states(), [13, 6]);
15049
15050        parser.exit_rule();
15051        parser.exit_rule();
15052        parser.exit_rule();
15053    }
15054
15055    #[test]
15056    fn parser_predicates_support_token_adjacency() {
15057        let mut parser = mini_parser(vec![
15058            TestToken::new(1).with_text("=").with_span(0, 0),
15059            TestToken::new(1).with_text(">").with_span(1, 1),
15060            TestToken::eof("parser-test", 2, 1, 2),
15061        ]);
15062        parser.consume();
15063        parser.consume();
15064
15065        let predicates = [(0, 0, ParserPredicate::TokenPairAdjacent)];
15066
15067        assert!(parser.parser_semantic_predicate_matches(&predicates, 0, 0));
15068
15069        let mut parser = mini_parser(vec![
15070            TestToken::new(1).with_text("=").with_span(0, 0),
15071            TestToken::new(1)
15072                .with_text(" ")
15073                .with_channel(HIDDEN_CHANNEL)
15074                .with_span(1, 1),
15075            TestToken::new(1).with_text(">").with_span(2, 2),
15076            TestToken::eof("parser-test", 3, 1, 3),
15077        ]);
15078        parser.consume();
15079        parser.consume();
15080
15081        assert!(!parser.parser_semantic_predicate_matches(&predicates, 0, 0));
15082    }
15083
15084    #[test]
15085    fn parser_predicates_support_context_child_text_checks() {
15086        let mut parser = mini_parser(vec![
15087            TestToken::new(1).with_text("var"),
15088            TestToken::eof("parser-test", 1, 1, 1),
15089        ]);
15090        let mut context = ParserRuleContext::new(1, 0);
15091        let mut child_context = ParserRuleContext::new(2, 0);
15092        let terminal = parser.terminal_tree(TokenId::try_from(0).expect("test token ID"));
15093        parser.tree.add_child(&mut child_context, terminal);
15094        let child = parser.rule_node(child_context);
15095        parser.tree.add_child(&mut context, child);
15096        let predicates = [(
15097            1,
15098            0,
15099            ParserPredicate::ContextChildRuleTextNotEquals {
15100                rule_index: 2,
15101                text: "var",
15102            },
15103        )];
15104
15105        assert!(
15106            !parser.parser_semantic_predicate_matches_with_context_and_local(
15107                &predicates,
15108                1,
15109                0,
15110                &context,
15111                0,
15112            )
15113        );
15114    }
15115
15116    #[test]
15117    fn context_expected_symbols_walks_nullable_parent_contexts() {
15118        let atn = nested_nullable_context_atn();
15119        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
15120        parser.rule_context_stack = vec![
15121            RuleContextFrame {
15122                rule_index: 0,
15123                invoking_state: 0,
15124            },
15125            RuleContextFrame {
15126                rule_index: 1,
15127                invoking_state: 1,
15128            },
15129            RuleContextFrame {
15130                rule_index: 2,
15131                invoking_state: 2,
15132            },
15133        ];
15134
15135        let expected = parser.context_expected_symbols(&atn);
15136
15137        assert!(expected.contains(&1));
15138        assert!(expected.contains(&TOKEN_EOF));
15139    }
15140
15141    #[test]
15142    fn prediction_context_return_states_track_rule_stack_changes() {
15143        let atn = nested_nullable_context_atn();
15144        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
15145        parser.rule_context_stack = vec![
15146            RuleContextFrame {
15147                rule_index: 0,
15148                invoking_state: 0,
15149            },
15150            RuleContextFrame {
15151                rule_index: 1,
15152                invoking_state: 1,
15153            },
15154            RuleContextFrame {
15155                rule_index: 2,
15156                invoking_state: 2,
15157            },
15158        ];
15159
15160        let initial_version = parser.rule_context_version();
15161        let first: Vec<_> = parser.prediction_context_return_states(&atn).collect();
15162        let second: Vec<_> = parser.prediction_context_return_states(&atn).collect();
15163        assert_eq!(first, second);
15164        assert_eq!(parser.rule_context_version(), initial_version);
15165
15166        parser.exit_rule();
15167        let after_pop: Vec<_> = parser.prediction_context_return_states(&atn).collect();
15168        assert_ne!(first, after_pop);
15169        assert_ne!(parser.rule_context_version(), initial_version);
15170    }
15171
15172    #[test]
15173    fn generated_match_token_recovers_missing_token_from_context_follow() {
15174        let atn = generated_match_recovery_atn();
15175        let data = RecognizerData::new(
15176            "Mini.g4",
15177            Vocabulary::new(
15178                [None, Some("'X'"), Some("'Y'")],
15179                [None, Some("X"), Some("Y")],
15180                [None::<&str>, None, None],
15181            ),
15182        );
15183        let mut parser = BaseParser::new(
15184            CommonTokenStream::new(Source {
15185                tokens: vec![TestToken::eof("parser-test", 3, 1, 3)],
15186                index: 0,
15187            }),
15188            data,
15189        );
15190        parser.rule_context_stack = vec![
15191            RuleContextFrame {
15192                rule_index: 0,
15193                invoking_state: 0,
15194            },
15195            RuleContextFrame {
15196                rule_index: 1,
15197                invoking_state: 1,
15198            },
15199        ];
15200        assert_eq!(parser.number_of_syntax_errors(), 0);
15201
15202        let node = parser
15203            .match_token_recovering(2, 5, &atn)
15204            .expect("generated match should insert missing token");
15205
15206        assert_eq!(node.children().len(), 1);
15207        assert_eq!(parser.node(node.children()[0]).text(), "<missing 'Y'>");
15208        assert_eq!(
15209            node.clone()
15210                .into_child_iter()
15211                .map(|child| parser.node(child).text())
15212                .collect::<Vec<_>>(),
15213            ["<missing 'Y'>"]
15214        );
15215        // Single-token insertion synthesizes a missing token and consumes nothing,
15216        // so no EOF terminal is consumed even though lookahead is EOF.
15217        assert!(!node.consumed_eof());
15218        assert_eq!(parser.la(1), TOKEN_EOF);
15219        assert_eq!(parser.number_of_syntax_errors(), 1);
15220        assert_eq!(
15221            parser.generated_parser_diagnostics,
15222            [ParserDiagnostic {
15223                line: 1,
15224                column: 3,
15225                message: "missing 'Y' at '<EOF>'".to_owned(),
15226            }]
15227        );
15228    }
15229
15230    #[test]
15231    fn generated_match_token_counts_single_token_deletion_recovery() {
15232        let atn = generated_match_recovery_atn();
15233        let data = RecognizerData::new(
15234            "Mini.g4",
15235            Vocabulary::new(
15236                [None, Some("'X'"), Some("'Y'"), Some("'Z'")],
15237                [None, Some("X"), Some("Y"), Some("Z")],
15238                [None::<&str>, None, None, None],
15239            ),
15240        );
15241        let mut parser = BaseParser::new(
15242            CommonTokenStream::new(Source {
15243                tokens: vec![
15244                    TestToken::new(3).with_text("z"),
15245                    TestToken::new(2).with_text("y"),
15246                    TestToken::eof("parser-test", 3, 1, 3),
15247                ],
15248                index: 0,
15249            }),
15250            data,
15251        );
15252
15253        let node = parser
15254            .match_token_recovering(2, 5, &atn)
15255            .expect("generated match should delete the extraneous token");
15256
15257        assert_eq!(node.children().len(), 2);
15258        assert_eq!(parser.node(node.children()[0]).kind(), NodeKind::Error);
15259        assert_eq!(parser.node(node.children()[0]).text(), "z");
15260        assert_eq!(parser.node(node.children()[1]).text(), "y");
15261        assert_eq!(
15262            node.into_child_iter()
15263                .map(|child| parser.node(child).text())
15264                .collect::<Vec<_>>(),
15265            ["z", "y"]
15266        );
15267        assert_eq!(parser.number_of_syntax_errors(), 1);
15268    }
15269
15270    #[test]
15271    fn generated_match_token_iterates_single_success_without_a_children_vec() {
15272        let atn = generated_match_recovery_atn();
15273        let data = RecognizerData::new(
15274            "Mini.g4",
15275            Vocabulary::new(
15276                [None, Some("'X'"), Some("'Y'")],
15277                [None, Some("X"), Some("Y")],
15278                [None::<&str>, None, None],
15279            ),
15280        );
15281        let mut parser = BaseParser::new(
15282            CommonTokenStream::new(Source {
15283                tokens: vec![
15284                    TestToken::new(2).with_text("y"),
15285                    TestToken::eof("parser-test", 1, 1, 1),
15286                ],
15287                index: 0,
15288            }),
15289            data,
15290        );
15291
15292        let node = parser
15293            .match_token_recovering(2, 5, &atn)
15294            .expect("generated match should consume the expected token");
15295
15296        assert_eq!(
15297            node.into_child_iter()
15298                .map(|child| parser.node(child).text())
15299                .collect::<Vec<_>>(),
15300            ["y"]
15301        );
15302        assert_eq!(parser.number_of_syntax_errors(), 0);
15303    }
15304
15305    #[test]
15306    fn generated_diagnostic_restore_rolls_back_syntax_error_count() {
15307        let atn = generated_match_recovery_atn();
15308        let data = RecognizerData::new(
15309            "Mini.g4",
15310            Vocabulary::new(
15311                [None, Some("'X'"), Some("'Y'")],
15312                [None, Some("X"), Some("Y")],
15313                [None::<&str>, None, None],
15314            ),
15315        );
15316        let mut parser = BaseParser::new(
15317            CommonTokenStream::new(Source {
15318                tokens: vec![TestToken::eof("parser-test", 3, 1, 3)],
15319                index: 0,
15320            }),
15321            data,
15322        );
15323        parser.rule_context_stack = vec![
15324            RuleContextFrame {
15325                rule_index: 0,
15326                invoking_state: 0,
15327            },
15328            RuleContextFrame {
15329                rule_index: 1,
15330                invoking_state: 1,
15331            },
15332        ];
15333        let marker = parser.generated_diagnostics_checkpoint();
15334
15335        let _ = parser
15336            .match_token_recovering(2, 5, &atn)
15337            .expect("generated match should insert missing token");
15338        assert_eq!(parser.number_of_syntax_errors(), 1);
15339
15340        parser.restore_generated_diagnostics(marker);
15341
15342        assert_eq!(parser.number_of_syntax_errors(), 0);
15343        assert!(parser.generated_parser_diagnostics.is_empty());
15344    }
15345
15346    #[test]
15347    fn generated_prediction_diagnostics_use_adaptive_context() {
15348        let atn = two_alt_decision_atn();
15349        let data = RecognizerData::new(
15350            "Mini.g4",
15351            Vocabulary::new(
15352                [None, Some("'x'"), Some("'y'")],
15353                [None, Some("X"), Some("Y")],
15354                [None::<&str>, None, None],
15355            ),
15356        )
15357        .with_rule_names(["s"]);
15358        let mut parser = BaseParser::new(
15359            CommonTokenStream::new(Source {
15360                tokens: vec![
15361                    TestToken::new(1)
15362                        .with_text("x")
15363                        .with_position(1, 0)
15364                        .with_span(0, 0),
15365                    TestToken::new(2)
15366                        .with_text("y")
15367                        .with_position(1, 2)
15368                        .with_span(1, 1),
15369                    TestToken::eof("parser-test", 2, 1, 3),
15370                ],
15371                index: 0,
15372            }),
15373            data,
15374        );
15375        parser.set_report_diagnostic_errors(true);
15376
15377        parser.record_generated_prediction_diagnostic(
15378            &atn,
15379            1,
15380            &ParserAtnPrediction {
15381                alt: 1,
15382                requires_full_context: true,
15383                has_semantic_context: false,
15384                diagnostic: Some(ParserAtnPredictionDiagnostic {
15385                    kind: ParserAtnPredictionDiagnosticKind::ContextSensitivity,
15386                    start_index: 0,
15387                    sll_stop_index: 1,
15388                    ll_stop_index: 0,
15389                    conflicting_alts: vec![1, 2],
15390                    exact: false,
15391                }),
15392            },
15393        );
15394        // Ambiguities from the default LL prediction mode are non-exact, so —
15395        // matching Java's exactOnly DiagnosticErrorListener — only the
15396        // attempting-full-context line is reported. Exact-ambiguity mode
15397        // reports the ambiguity itself.
15398        parser.record_generated_prediction_diagnostic(
15399            &atn,
15400            1,
15401            &ParserAtnPrediction {
15402                alt: 1,
15403                requires_full_context: true,
15404                has_semantic_context: false,
15405                diagnostic: Some(ParserAtnPredictionDiagnostic {
15406                    kind: ParserAtnPredictionDiagnosticKind::Ambiguity,
15407                    start_index: 0,
15408                    sll_stop_index: 1,
15409                    ll_stop_index: 1,
15410                    conflicting_alts: vec![1, 2],
15411                    exact: false,
15412                }),
15413            },
15414        );
15415
15416        assert_eq!(
15417            parser.generated_parser_diagnostics,
15418            [
15419                ParserDiagnostic {
15420                    line: 1,
15421                    column: 2,
15422                    message: "reportAttemptingFullContext d=0 (s), input='xy'".to_owned(),
15423                },
15424                ParserDiagnostic {
15425                    line: 1,
15426                    column: 0,
15427                    message: "reportContextSensitivity d=0 (s), input='x'".to_owned(),
15428                },
15429                ParserDiagnostic {
15430                    line: 1,
15431                    column: 2,
15432                    message: "reportAttemptingFullContext d=0 (s), input='xy'".to_owned(),
15433                },
15434            ]
15435        );
15436    }
15437
15438    #[test]
15439    fn generated_match_not_set_recovers_empty_complement_at_eof() {
15440        let atn = complement_set_atn();
15441        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
15442        parser.rule_context_stack = vec![RuleContextFrame {
15443            rule_index: 0,
15444            invoking_state: 0,
15445        }];
15446
15447        let node = parser
15448            .match_not_token_set_recovering(
15449                atn.token_set(0).expect("excluded token set"),
15450                1,
15451                1,
15452                1,
15453                &atn,
15454            )
15455            .expect("empty complement should recover at EOF");
15456
15457        assert_eq!(node.children().len(), 1);
15458        // Recovery synthesizes a missing token without consuming EOF, so the
15459        // enclosing rule must not record EOF as its stop token.
15460        assert!(!node.consumed_eof());
15461        assert_eq!(parser.la(1), TOKEN_EOF);
15462        assert_eq!(
15463            parser.generated_parser_diagnostics,
15464            [ParserDiagnostic {
15465                line: 1,
15466                column: 1,
15467                message: "missing {} at '<EOF>'".to_owned(),
15468            }]
15469        );
15470    }
15471
15472    #[test]
15473    fn wildcard_recovers_via_insertion_when_follow_expects_eof_at_eof() {
15474        // `start : . EOF ;` on empty input. The wildcard is modeled as an
15475        // empty-complement not-set; at EOF the follow state (the explicit EOF
15476        // match) expects EOF, so even in the start rule recovery must perform
15477        // single-token insertion (`<missing ...>`) rather than aborting — matching
15478        // ANTLR's `(start <missing ...> <EOF>)` / "missing ... at '<EOF>'".
15479        let atn = wildcard_then_eof_atn();
15480        let data = RecognizerData::new(
15481            "Mini.g4",
15482            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
15483        );
15484        let mut parser = BaseParser::new(
15485            CommonTokenStream::new(Source {
15486                tokens: vec![TestToken::eof("parser-test", 1, 1, 1)],
15487                index: 0,
15488            }),
15489            data,
15490        );
15491        parser.rule_context_stack = vec![RuleContextFrame {
15492            rule_index: 0,
15493            invoking_state: 0,
15494        }];
15495
15496        let node = parser
15497            .match_not_set_recovering(&[], 1, atn.max_token_type(), 2, &atn)
15498            .expect("wildcard at EOF should recover by insertion when follow expects EOF");
15499
15500        // A single `<missing ...>` error node is inserted; EOF is not consumed.
15501        assert_eq!(node.children().len(), 1);
15502        assert!(!node.consumed_eof());
15503        assert!(
15504            parser
15505                .node(node.children()[0])
15506                .text()
15507                .starts_with("<missing")
15508        );
15509        assert_eq!(parser.la(1), TOKEN_EOF);
15510        assert_eq!(
15511            parser.generated_parser_diagnostics,
15512            [ParserDiagnostic {
15513                line: 1,
15514                column: 1,
15515                message: "missing 'x' at '<EOF>'".to_owned(),
15516            }]
15517        );
15518    }
15519
15520    #[test]
15521    fn generated_rule_recovery_consumes_to_parent_follow() {
15522        let atn = generated_match_recovery_atn();
15523        let data = RecognizerData::new(
15524            "Mini.g4",
15525            Vocabulary::new(
15526                [None, Some("'X'"), Some("'Y'"), Some("'Z'")],
15527                [None, Some("X"), Some("Y"), Some("Z")],
15528                [None::<&str>, None, None, None],
15529            ),
15530        );
15531        let mut parser = BaseParser::new(
15532            CommonTokenStream::new(Source {
15533                tokens: vec![
15534                    TestToken::new(3).with_text("z"),
15535                    TestToken::eof("parser-test", 1, 1, 1),
15536                ],
15537                index: 0,
15538            }),
15539            data,
15540        );
15541        let _parent = parser.enter_rule(0, 0);
15542        let marker = parser.push_invoking_state(1);
15543        let mut child = parser.enter_rule(4, 1);
15544        parser.discard_invoking_state(marker);
15545
15546        parser.recover_generated_rule(
15547            &mut child,
15548            &atn,
15549            AntlrError::ParserError {
15550                line: 1,
15551                column: 0,
15552                message: "mismatched input 'z' expecting {'X', 'Y'}".to_owned(),
15553            },
15554        );
15555        let tree = parser.finish_rule(child, false);
15556
15557        assert_eq!(parser.la(1), TOKEN_EOF);
15558        assert_eq!(
15559            parser.node(tree).to_string_tree_with_names(&["s", "a"]),
15560            "(a z)"
15561        );
15562        assert_eq!(parser.number_of_syntax_errors(), 1);
15563        assert_eq!(
15564            parser.generated_parser_diagnostics,
15565            [ParserDiagnostic {
15566                line: 1,
15567                column: 0,
15568                message: "mismatched input 'z' expecting {'X', 'Y'}".to_owned(),
15569            }]
15570        );
15571        parser.exit_rule();
15572    }
15573
15574    #[test]
15575    fn generated_rule_recovery_forces_progress_after_repeated_error_state() {
15576        let atn = nested_nullable_context_atn();
15577        let mut parser = mini_parser(vec![
15578            TestToken::new(1).with_text("x"),
15579            TestToken::eof("parser-test", 1, 1, 1),
15580        ]);
15581        parser.rule_context_stack = vec![
15582            RuleContextFrame {
15583                rule_index: 0,
15584                invoking_state: 0,
15585            },
15586            RuleContextFrame {
15587                rule_index: 1,
15588                invoking_state: 1,
15589            },
15590            RuleContextFrame {
15591                rule_index: 2,
15592                invoking_state: 2,
15593            },
15594        ];
15595        parser.set_state(20);
15596        let mut context = ParserRuleContext::new(2, 2);
15597
15598        parser.recover_generated_rule(
15599            &mut context,
15600            &atn,
15601            AntlrError::NoViableAlternative {
15602                input: "'x'".to_owned(),
15603            },
15604        );
15605        assert_eq!(parser.input.index(), 0);
15606
15607        parser.set_state(21);
15608        parser.recover_generated_rule(
15609            &mut context,
15610            &atn,
15611            AntlrError::NoViableAlternative {
15612                input: "'x'".to_owned(),
15613            },
15614        );
15615        assert_eq!(parser.input.index(), 0);
15616        assert_eq!(
15617            parser.generated_recovery_error_states,
15618            BTreeSet::from([20, 21])
15619        );
15620
15621        parser.set_state(20);
15622        parser.recover_generated_rule(
15623            &mut context,
15624            &atn,
15625            AntlrError::NoViableAlternative {
15626                input: "'x'".to_owned(),
15627            },
15628        );
15629
15630        assert_eq!(parser.input.index(), 1);
15631        assert_eq!(parser.la(1), TOKEN_EOF);
15632        assert!(context.has_matched_child());
15633        assert_eq!(parser.generated_recovery_error_states, BTreeSet::from([20]));
15634
15635        parser.match_eof().expect("EOF should match");
15636        assert_eq!(parser.generated_recovery_error_index, None);
15637        assert!(parser.generated_recovery_error_states.is_empty());
15638    }
15639
15640    #[test]
15641    fn greedy_ll1_alt_handles_nullable_loop_exit() {
15642        let mut body_symbols = TokenBitSet::default();
15643        body_symbols.insert(1);
15644        let entry = DecisionLookahead {
15645            transitions: vec![
15646                TransitionLookSet {
15647                    symbols: body_symbols,
15648                    nullable: false,
15649                },
15650                TransitionLookSet {
15651                    symbols: TokenBitSet::default(),
15652                    nullable: true,
15653                },
15654            ],
15655        };
15656
15657        assert_eq!(ll1_unique_alt(&entry, 2), None);
15658        assert_eq!(ll1_greedy_alt(&entry, 2, false), Some(1));
15659        assert_eq!(ll1_greedy_alt(&entry, 1, false), None);
15660        assert_eq!(ll1_greedy_alt(&entry, 1, true), None);
15661    }
15662
15663    #[test]
15664    fn ordinary_repetition_builds_tree_in_input_order() {
15665        for atn in [ordinary_star_loop_atn(), ordinary_plus_loop_atn()] {
15666            let mut parser = mini_parser(repeated_x_tokens(3));
15667            let tree = parser
15668                .parse_atn_rule(&atn, 0)
15669                .expect("ordinary repetition should parse");
15670
15671            let root = parser
15672                .node(tree)
15673                .as_rule()
15674                .expect("entry result should be a rule");
15675            let body_rules = root.child_rules(1).collect::<Vec<_>>();
15676            assert_eq!(root.text(), "xxx<EOF>");
15677            assert_eq!(body_rules.len(), 3);
15678            assert_eq!(
15679                body_rules
15680                    .iter()
15681                    .map(|rule| rule.start_id().expect("body start").index())
15682                    .collect::<Vec<_>>(),
15683                [0, 1, 2]
15684            );
15685            assert_eq!(
15686                body_rules
15687                    .iter()
15688                    .map(|rule| rule.stop_id().expect("body stop").index())
15689                    .collect::<Vec<_>>(),
15690                [0, 1, 2]
15691            );
15692            assert_eq!(parser.number_of_syntax_errors(), 0);
15693        }
15694    }
15695
15696    #[test]
15697    fn deeply_nested_deferred_rules_materialize_on_small_stack() {
15698        const DEPTH: usize = 20_000;
15699
15700        std::thread::Builder::new()
15701            .name("deferred-rule-materialization".to_owned())
15702            .stack_size(256 * 1024)
15703            .spawn(|| {
15704                let mut parser = mini_parser(vec![TestToken::eof("parser-test", 0, 1, 0)]);
15705                let mut root = FastDeferredNodeId::EMPTY;
15706                for depth in 0..DEPTH {
15707                    root = parser
15708                        .recognition_arena
15709                        .deferred_rule_node(FastDeferredRule {
15710                            rule_index: u32::try_from(depth).expect("depth fits in u32"),
15711                            invoking_state: i32::try_from(depth).expect("depth fits in i32"),
15712                            start_index: 0,
15713                            stop_index: None,
15714                            deferred_children: root,
15715                            children: NodeSeqId::EMPTY,
15716                        });
15717                }
15718
15719                let mut children = parser.materialize_fast_deferred_nodes(root, NodeSeqId::EMPTY);
15720                for expected_rule in (0..DEPTH).rev() {
15721                    let mut nodes = parser.recognition_arena.iter(children);
15722                    let node = nodes.next().expect("nested rule node");
15723                    assert!(nodes.next().is_none(), "each rule has one child");
15724                    let ArenaRecognizedNode::Rule {
15725                        rule_index,
15726                        children: nested,
15727                        ..
15728                    } = parser.recognition_arena.node(node)
15729                    else {
15730                        panic!("expected nested rule");
15731                    };
15732                    assert_eq!(rule_index as usize, expected_rule);
15733                    children = nested;
15734                }
15735                assert!(children.is_empty());
15736            })
15737            .expect("small-stack thread should start")
15738            .join()
15739            .expect("deferred rules should materialize without recursion");
15740    }
15741
15742    #[test]
15743    fn deeply_nested_rule_calls_grow_the_stack() {
15744        const DEPTH: usize = 4_096;
15745        const STACK_SIZE: usize = 256 * 1024;
15746        let atn = nested_rule_chain_atn(DEPTH);
15747        std::thread::Builder::new()
15748            .name("nested-adaptive-set-rules".to_owned())
15749            .stack_size(STACK_SIZE)
15750            .spawn(move || {
15751                let mut parser = mini_parser(vec![TestToken::new(1).with_text("x")]);
15752                parser.set_build_parse_trees(false);
15753                // This test isolates recognizer depth from the separately
15754                // cached FIRST-set metadata walk.
15755                parser.fast_first_set_prefilter = false;
15756                parser
15757                    .parse_atn_rule(&atn, 0)
15758                    .expect("nested rule chain should grow the native stack");
15759                assert_eq!(parser.input.index(), 1);
15760            })
15761            .expect("small-stack thread should start")
15762            .join()
15763            .expect("nested rule chain should not overflow its stack");
15764    }
15765
15766    #[test]
15767    fn deeply_nested_branching_rules_grow_the_stack() {
15768        const DEPTH: usize = 4_096;
15769        const STACK_SIZE: usize = 256 * 1024;
15770        let atn = nested_rule_graph_atn(DEPTH, true, false);
15771        std::thread::Builder::new()
15772            .name("nested-branching-rules".to_owned())
15773            .stack_size(STACK_SIZE)
15774            .spawn(move || {
15775                let mut parser = mini_parser(vec![TestToken::new(1).with_text("x")]);
15776                parser.set_build_parse_trees(false);
15777                parser
15778                    .parse_atn_rule(&atn, 0)
15779                    .expect("branching rule chain should grow the native stack");
15780                assert_eq!(parser.input.index(), 1);
15781            })
15782            .expect("small-stack thread should start")
15783            .join()
15784            .expect("branching rule chain should not overflow its stack");
15785    }
15786
15787    #[test]
15788    fn deeply_nested_rule_follows_grow_the_stack() {
15789        const DEPTH: usize = 4_096;
15790        const STACK_SIZE: usize = 256 * 1024;
15791        let atn = nested_rule_graph_atn(DEPTH, false, true);
15792        std::thread::Builder::new()
15793            .name("nested-rule-follows".to_owned())
15794            .stack_size(STACK_SIZE)
15795            .spawn(move || {
15796                let mut parser = mini_parser(repeated_x_tokens(DEPTH));
15797                parser.set_build_parse_trees(false);
15798                parser.fast_first_set_prefilter = false;
15799                parser
15800                    .parse_atn_rule(&atn, 0)
15801                    .expect("rule follow chain should grow the native stack");
15802                assert_eq!(parser.input.index(), DEPTH);
15803            })
15804            .expect("small-stack thread should start")
15805            .join()
15806            .expect("nested rule follow chain should not overflow its stack");
15807    }
15808
15809    #[test]
15810    fn deeply_nested_recovery_grows_the_stack() {
15811        const DEPTH: usize = 4_096;
15812        const STACK_SIZE: usize = 256 * 1024;
15813        let atn = nested_rule_chain_atn(DEPTH);
15814        std::thread::Builder::new()
15815            .name("nested-rule-recovery".to_owned())
15816            .stack_size(STACK_SIZE)
15817            .spawn(move || {
15818                let mut parser = mini_parser(vec![
15819                    TestToken::new(2).with_text("z"),
15820                    TestToken::new(1).with_text("x"),
15821                    TestToken::eof("parser-test", 2, 1, 2),
15822                ]);
15823                parser.set_build_parse_trees(false);
15824                parser.fast_first_set_prefilter = false;
15825                parser
15826                    .parse_atn_rule(&atn, 0)
15827                    .expect("nested recovery should grow the native stack");
15828                assert_eq!(parser.input.index(), 2);
15829                assert_eq!(parser.number_of_syntax_errors(), 1);
15830            })
15831            .expect("small-stack thread should start")
15832            .join()
15833            .expect("nested rule recovery should not overflow its stack");
15834    }
15835
15836    #[test]
15837    fn ambiguous_ordinary_repetition_merges_equivalent_coordinates() {
15838        const REPETITIONS: usize = 64;
15839
15840        let atn = ambiguous_ordinary_star_loop_atn();
15841        let mut parser = mini_parser(repeated_x_tokens(REPETITIONS));
15842        let tree = parser
15843            .parse_atn_rule(&atn, 0)
15844            .expect("ambiguous ordinary repetition should parse");
15845
15846        let root = parser
15847            .node(tree)
15848            .as_rule()
15849            .expect("entry result should be a rule");
15850        assert_eq!(root.text(), format!("{}<EOF>", "x".repeat(REPETITIONS)));
15851        assert_eq!(parser.input.index(), REPETITIONS);
15852        assert!(
15853            parser.recognition_arena.deferred_nodes.len() <= REPETITIONS * 8,
15854            "equivalent segmentations should keep deferred storage linear"
15855        );
15856        assert_eq!(parser.number_of_syntax_errors(), 0);
15857    }
15858
15859    #[test]
15860    fn long_ordinary_repetition_does_not_consume_native_stack() {
15861        const REPETITIONS: usize = 20_000;
15862
15863        for atn in [ordinary_star_loop_atn(), ordinary_plus_loop_atn()] {
15864            let mut parser = mini_parser(repeated_x_tokens(REPETITIONS));
15865            parser.set_build_parse_trees(false);
15866            parser
15867                .parse_atn_rule(&atn, 0)
15868                .expect("long ordinary repetition should parse");
15869
15870            assert_eq!(parser.input.index(), REPETITIONS);
15871            assert_eq!(parser.number_of_syntax_errors(), 0);
15872        }
15873    }
15874
15875    #[test]
15876    fn long_rule_repetition_materializes_tree_with_linear_arena_growth() {
15877        const REPETITIONS: usize = 2_000;
15878        let expected_text = format!("{}<EOF>", "x".repeat(REPETITIONS));
15879
15880        for atn in [ordinary_star_loop_atn(), ordinary_plus_loop_atn()] {
15881            let mut parser = mini_parser(repeated_x_tokens(REPETITIONS));
15882            let tree = parser
15883                .parse_atn_rule(&atn, 0)
15884                .expect("long rule repetition should parse");
15885
15886            let root = parser
15887                .node(tree)
15888                .as_rule()
15889                .expect("entry result should be a rule");
15890            assert_eq!(root.text(), expected_text);
15891            assert_eq!(root.child_rules(1).count(), REPETITIONS);
15892            let first_body = root.child_rules(1).next().expect("first body rule");
15893            let last_body = root.child_rules(1).next_back().expect("last body rule");
15894            assert_eq!(first_body.start_id().expect("first body start").index(), 0);
15895            assert_eq!(
15896                last_body.stop_id().expect("last body stop").index(),
15897                REPETITIONS - 1
15898            );
15899
15900            let stats = parser.recognition_arena_stats();
15901            assert_eq!(
15902                (stats.total_nodes, stats.live_nodes, stats.dead_nodes),
15903                (REPETITIONS, REPETITIONS, 0)
15904            );
15905            assert_eq!(
15906                (stats.total_links, stats.live_links, stats.dead_links),
15907                (REPETITIONS, REPETITIONS, 0)
15908            );
15909            assert_eq!(parser.recognition_arena.deferred_rules.len(), REPETITIONS);
15910            assert_eq!(
15911                parser.recognition_arena.deferred_nodes.len(),
15912                REPETITIONS * 2 - 1
15913            );
15914            assert_eq!(parser.number_of_syntax_errors(), 0);
15915        }
15916    }
15917
15918    #[test]
15919    fn clean_memo_probe_selects_sparse_promote_and_reprobe_modes() {
15920        let key = |state_number| FastRecognizeKey {
15921            state_number,
15922            stop_state: 10,
15923            index: state_number,
15924            rule_start_index: 0,
15925            decision_start_index: None,
15926            precedence: 0,
15927            recovery_symbols_id: 0,
15928            recovery_state: None,
15929        };
15930
15931        let mut sparse = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
15932        for state_number in 0..(CLEAN_MEMO_PROBE_LIMIT - 1) {
15933            assert!(sparse.clean_memo_enabled_for_key(&key(state_number)));
15934        }
15935        assert!(!sparse.clean_memo_enabled_for_key(&key(CLEAN_MEMO_PROBE_LIMIT)));
15936        assert_eq!(sparse.clean_memo_mode, CleanMemoMode::Sparse);
15937
15938        let mut promote = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
15939        let repeated = key(1);
15940        for _ in 0..=CLEAN_MEMO_REPEAT_LIMIT {
15941            assert!(promote.clean_memo_enabled_for_key(&repeated));
15942        }
15943        assert_eq!(promote.clean_memo_mode, CleanMemoMode::Promote);
15944
15945        for _ in 1..CLEAN_MEMO_REPROBE_INTERVAL {
15946            assert!(!sparse.clean_memo_enabled_for_key(&repeated));
15947        }
15948        assert!(sparse.clean_memo_enabled_for_key(&repeated));
15949        assert_eq!(sparse.clean_memo_mode, CleanMemoMode::Probe);
15950        for _ in 0..CLEAN_MEMO_REPEAT_LIMIT {
15951            assert!(sparse.clean_memo_enabled_for_key(&repeated));
15952        }
15953        assert_eq!(sparse.clean_memo_mode, CleanMemoMode::Promote);
15954    }
15955
15956    #[test]
15957    fn fast_recognize_memo_capacity_scales_from_small_floor_to_bounded_maximum() {
15958        assert_eq!(
15959            fast_recognize_memo_capacity(0),
15960            FAST_RECOGNIZE_MIN_MEMO_CAPACITY
15961        );
15962        assert_eq!(
15963            fast_recognize_memo_capacity(FAST_RECOGNIZE_MIN_MEMO_CAPACITY / 8),
15964            FAST_RECOGNIZE_MIN_MEMO_CAPACITY
15965        );
15966        assert_eq!(fast_recognize_memo_capacity(1_000), 8_000);
15967        assert_eq!(
15968            fast_recognize_memo_capacity(usize::MAX),
15969            FAST_RECOGNIZE_MAX_MEMO_CAPACITY
15970        );
15971    }
15972
15973    #[test]
15974    fn fast_recognize_scratch_reuses_small_tables_and_releases_oversized_memo() {
15975        let mut scratch = FastRecognizeTopScratch::default();
15976        scratch.prepare(FAST_RECOGNIZE_MIN_MEMO_CAPACITY);
15977        let retained_capacity = scratch.memo.capacity();
15978        assert!(retained_capacity >= FAST_RECOGNIZE_MIN_MEMO_CAPACITY);
15979        assert!(retained_capacity <= FAST_RECOGNIZE_MAX_RETAINED_MEMO_CAPACITY);
15980
15981        let larger_capacity = retained_capacity + 1;
15982        scratch.prepare(larger_capacity);
15983        let grown_capacity = scratch.memo.capacity();
15984        assert!(grown_capacity >= larger_capacity);
15985        assert!(grown_capacity <= FAST_RECOGNIZE_MAX_RETAINED_MEMO_CAPACITY);
15986
15987        scratch.memo.insert(
15988            FastRecognizeKey {
15989                state_number: 0,
15990                stop_state: 0,
15991                index: 0,
15992                rule_start_index: 0,
15993                decision_start_index: None,
15994                precedence: 0,
15995                recovery_symbols_id: 0,
15996                recovery_state: None,
15997            },
15998            Rc::from([FastRecognizeOutcome {
15999                index: 0,
16000                consumed_eof: false,
16001                diagnostics: DiagnosticSeqId::EMPTY,
16002                deferred_nodes: FastDeferredNodeId::EMPTY,
16003                nodes: NodeSeqId::EMPTY,
16004            }]),
16005        );
16006        scratch.release_oversized_memo();
16007        assert!(scratch.memo.is_empty());
16008        assert_eq!(scratch.memo.capacity(), grown_capacity);
16009
16010        scratch
16011            .memo
16012            .reserve(FAST_RECOGNIZE_MAX_RETAINED_MEMO_CAPACITY * 2);
16013        assert!(scratch.memo.capacity() > FAST_RECOGNIZE_MAX_RETAINED_MEMO_CAPACITY);
16014
16015        scratch.release_oversized_memo();
16016        assert!(scratch.memo.is_empty());
16017        assert_eq!(scratch.memo.capacity(), 0);
16018    }
16019
16020    #[test]
16021    fn clean_empty_multi_alt_outcomes_are_memoized() {
16022        let mut atn = ParserAtnBuilder::new(2);
16023        assert_eq!(
16024            atn.add_state(AtnStateKind::RuleStart, Some(0))
16025                .expect("state")
16026                .index(),
16027            0
16028        );
16029        assert_eq!(
16030            atn.add_state(AtnStateKind::BlockStart, Some(0))
16031                .expect("state")
16032                .index(),
16033            1
16034        );
16035        assert_eq!(
16036            atn.add_state(AtnStateKind::RuleStop, Some(0))
16037                .expect("state")
16038                .index(),
16039            2
16040        );
16041        atn.set_rule_to_start_state(vec![0])
16042            .expect("rule start states");
16043        atn.set_rule_to_stop_state(vec![2])
16044            .expect("rule stop states");
16045        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
16046            .expect("transition");
16047        atn.add_transition(
16048            1,
16049            ParserTransitionSpec::Atom {
16050                target: 2,
16051                label: 1,
16052            },
16053        )
16054        .expect("transition");
16055        atn.add_transition(
16056            1,
16057            ParserTransitionSpec::Atom {
16058                target: 2,
16059                label: 2,
16060            },
16061        )
16062        .expect("transition");
16063        let atn = finish_atn(atn);
16064
16065        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 0, 1, 0)]);
16066        parser.fast_recovery_enabled = false;
16067        let mut visiting = FxHashSet::default();
16068        let mut memo = FxHashMap::default();
16069        let mut expected = ExpectedTokens::default();
16070        let outcomes = parser.recognize_state_fast(
16071            &atn,
16072            FastRecognizeRequest {
16073                state_number: 1,
16074                stop_state: 2,
16075                index: 0,
16076                rule_start_index: 0,
16077                decision_start_index: None,
16078                precedence: 0,
16079                depth: 0,
16080                recovery_symbols: parser.empty_recovery_symbols(),
16081                recovery_state: None,
16082            },
16083            FastRecognizeScratch {
16084                predicate_context: None,
16085                visiting: &mut visiting,
16086                memo: &mut memo,
16087                expected: &mut expected,
16088                native_depth: 0,
16089            },
16090        );
16091
16092        assert!(outcomes.is_empty());
16093        assert_eq!(memo.len(), 1);
16094        assert!(memo.values().next().expect("memo entry").is_empty());
16095
16096        parser.clean_memo_mode = CleanMemoMode::Sparse;
16097        visiting.clear();
16098        memo.clear();
16099        expected = ExpectedTokens::default();
16100        let sparse_outcomes = parser.recognize_state_fast(
16101            &atn,
16102            FastRecognizeRequest {
16103                state_number: 1,
16104                stop_state: 2,
16105                index: 0,
16106                rule_start_index: 0,
16107                decision_start_index: None,
16108                precedence: 0,
16109                depth: 0,
16110                recovery_symbols: parser.empty_recovery_symbols(),
16111                recovery_state: None,
16112            },
16113            FastRecognizeScratch {
16114                predicate_context: None,
16115                visiting: &mut visiting,
16116                memo: &mut memo,
16117                expected: &mut expected,
16118                native_depth: 0,
16119            },
16120        );
16121
16122        assert!(sparse_outcomes.is_empty());
16123        assert!(memo.is_empty());
16124    }
16125
16126    #[test]
16127    fn wildcard_matches_non_eof_only() {
16128        let mut parser = mini_parser(vec![
16129            TestToken::new(1).with_text("x"),
16130            TestToken::eof("parser-test", 1, 1, 1),
16131        ]);
16132        let matched = parser.match_wildcard().expect("wildcard");
16133        assert_eq!(parser.node(matched).text(), "x");
16134        assert!(parser.match_wildcard().is_err());
16135    }
16136
16137    #[test]
16138    fn add_parse_child_records_match_even_without_tree_building() {
16139        // `sync_decision`'s "is the current context empty" flag must reflect real
16140        // matches, not parse-tree children: when `build_parse_trees(false)`,
16141        // `children` stays empty but `has_matched_child` must still flip so nested
16142        // recovery does not wrongly suppress single-token deletion.
16143        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
16144        let token = TestToken::new(1).with_text("x");
16145
16146        parser.set_build_parse_trees(false);
16147        let mut ctx = ParserRuleContext::new(0, 0);
16148        assert!(!ctx.has_matched_child());
16149        let child = parser.terminal_tree(token.id);
16150        parser.add_parse_child(&mut ctx, child);
16151        // Tree building is off, so no child is stored...
16152        assert_eq!(ctx.child_count(), 0);
16153        assert_eq!(parser.parse_tree_storage().node_count(), 0);
16154        // ...but the match is recorded, so the context is no longer "empty".
16155        assert!(ctx.has_matched_child());
16156
16157        // With tree building on, the child is stored and the match is recorded.
16158        parser.set_build_parse_trees(true);
16159        let mut ctx = ParserRuleContext::new(0, 0);
16160        let child = parser.terminal_tree(token.id);
16161        parser.add_parse_child(&mut ctx, child);
16162        assert_eq!(ctx.child_count(), 1);
16163        assert!(ctx.has_matched_child());
16164    }
16165
16166    #[test]
16167    fn disabled_tree_building_does_not_grow_flat_storage() {
16168        let mut parser = mini_parser(vec![
16169            TestToken::new(1).with_text("x"),
16170            TestToken::new(1).with_text("y"),
16171            TestToken::eof("parser-test", 2, 1, 2),
16172        ]);
16173        parser.set_build_parse_trees(false);
16174        let mut context = ParserRuleContext::new(0, -1);
16175
16176        for _ in 0..2 {
16177            let child = parser.match_token(1).expect("token should match");
16178            parser.add_parse_child(&mut context, child);
16179        }
16180        let current = parser.input.lt_id(1).expect("EOF token");
16181        let error = parser.error_tree(current);
16182        parser.add_parse_child(&mut context, error);
16183        let root = parser.rule_node(context);
16184
16185        assert_eq!(
16186            parser.parse_tree_storage().stats(),
16187            ParseTreeStats::default()
16188        );
16189        assert!(
16190            parser
16191                .parse_tree_storage()
16192                .node(parser.token_store(), root)
16193                .is_none(),
16194            "the no-tree sentinel must not resolve to stored data"
16195        );
16196    }
16197
16198    #[test]
16199    fn disabled_tree_building_skips_recognition_rule_node_storage() {
16200        let atn = ordinary_star_loop_atn();
16201        let mut parser = mini_parser(repeated_x_tokens(3));
16202        parser.set_build_parse_trees(false);
16203
16204        parser
16205            .parse_atn_rule(&atn, 0)
16206            .expect("ordinary repetition should parse without a tree");
16207
16208        assert_eq!(parser.input.index(), 3);
16209        assert!(parser.recognition_arena.nodes.is_empty());
16210        assert!(parser.recognition_arena.seq_links.is_empty());
16211        assert!(parser.recognition_arena.deferred_nodes.is_empty());
16212        assert!(parser.recognition_arena.deferred_rules.is_empty());
16213        assert!(!parser.fast_token_nodes_enabled);
16214        assert!(parser.fast_recognize_scratch.memo.is_empty());
16215    }
16216
16217    #[test]
16218    fn parser_interprets_simple_atn_rule() {
16219        let atn = token_then_eof_atn();
16220        let mut parser = mini_parser(vec![
16221            TestToken::new(1).with_text("x"),
16222            TestToken::eof("parser-test", 1, 1, 1),
16223        ]);
16224
16225        let tree = parser
16226            .parse_atn_rule(&atn, 0)
16227            .expect("artificial parser rule should parse");
16228        assert_eq!(parser.node(tree).text(), "x<EOF>");
16229        assert_eq!(parser.number_of_syntax_errors(), 0);
16230        assert_eq!(
16231            parser
16232                .node(tree)
16233                .first_rule_stop(0)
16234                .expect("rule should stop at EOF")
16235                .token_type(),
16236            TOKEN_EOF
16237        );
16238
16239        let mut parser = mini_parser(vec![
16240            TestToken::new(1).with_text("x"),
16241            TestToken::eof("parser-test", 1, 1, 1),
16242        ]);
16243        let (tree, actions) = parser
16244            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
16245            .expect("runtime-option parser rule should parse");
16246        assert!(actions.is_empty());
16247        assert_eq!(
16248            parser
16249                .node(tree)
16250                .first_rule_stop(0)
16251                .expect("rule should stop at EOF")
16252                .token_type(),
16253            TOKEN_EOF
16254        );
16255    }
16256
16257    #[test]
16258    fn runtime_options_default_ignores_noop_action_transitions() {
16259        let atn = noop_action_then_token_then_eof_atn();
16260        let mut parser = mini_parser(vec![
16261            TestToken::new(1).with_text("x"),
16262            TestToken::eof("parser-test", 1, 1, 1),
16263        ]);
16264
16265        let (tree, actions) = parser
16266            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
16267            .expect("no-op parser action should not force action replay");
16268
16269        assert_eq!(parser.node(tree).text(), "x<EOF>");
16270        assert!(
16271            actions.is_empty(),
16272            "action_index=None transitions are ANTLR metadata, not replay actions"
16273        );
16274        assert_eq!(parser.number_of_syntax_errors(), 0);
16275    }
16276
16277    #[test]
16278    fn parser_exposes_buffered_token_stream_after_parse() {
16279        let atn = token_then_eof_atn();
16280        let mut parser = mini_parser(vec![
16281            TestToken::new(1).with_text("x"),
16282            TestToken::eof("parser-test", 1, 1, 1),
16283        ]);
16284
16285        let tree = parser
16286            .parse_atn_rule(&atn, 0)
16287            .expect("artificial parser rule should parse");
16288        assert_eq!(parser.node(tree).text(), "x<EOF>");
16289
16290        let stream = parser.token_stream();
16291        let source_index_after_parse = stream.token_source().index;
16292        let buffered = stream.tokens().collect::<Vec<_>>();
16293        assert_eq!(buffered.len(), 2);
16294        assert_eq!(buffered[0].text(), Some("x"));
16295        assert_eq!(buffered[0].token_id().index(), 0);
16296        assert_eq!(buffered[1].token_type(), TOKEN_EOF);
16297        assert_eq!(stream.token_source().index, source_index_after_parse);
16298        drop(buffered);
16299
16300        let stream = parser.into_token_stream();
16301        assert_eq!(stream.token_source().index, source_index_after_parse);
16302        assert_eq!(
16303            stream.tokens().next().expect("first token").text(),
16304            Some("x")
16305        );
16306        assert_eq!(
16307            stream.tokens().nth(1).expect("EOF token").token_type(),
16308            TOKEN_EOF
16309        );
16310    }
16311
16312    #[test]
16313    fn parsed_file_exposes_all_buffered_tokens() {
16314        let atn = token_then_eof_atn();
16315        let mut parser = mini_parser(vec![
16316            TestToken::new(99)
16317                .with_text(" comment")
16318                .with_channel(HIDDEN_CHANNEL),
16319            TestToken::new(1).with_text("x"),
16320            TestToken::eof("parser-test", 9, 1, 9),
16321        ]);
16322
16323        let tree = parser
16324            .parse_atn_rule(&atn, 0)
16325            .expect("artificial parser rule should parse");
16326        let parsed = parser.into_parsed_file(tree);
16327
16328        assert_eq!(
16329            parsed
16330                .tokens()
16331                .iter()
16332                .map(|token| (token.token_type(), token.channel(), token.text()))
16333                .collect::<Vec<_>>(),
16334            [
16335                (99, HIDDEN_CHANNEL, Some(" comment")),
16336                (1, DEFAULT_CHANNEL, Some("x")),
16337                (TOKEN_EOF, DEFAULT_CHANNEL, Some("<EOF>")),
16338            ]
16339        );
16340        assert_eq!(parsed.tokens().into_iter().count(), 3);
16341    }
16342
16343    #[test]
16344    fn parser_syntax_error_count_tracks_interpreted_recovery() {
16345        let atn = token_then_eof_atn();
16346        let mut parser = mini_parser(vec![
16347            TestToken::new(1).with_text("x"),
16348            TestToken::new(2).with_text("y"),
16349            TestToken::eof("parser-test", 2, 1, 2),
16350        ]);
16351
16352        let tree = parser
16353            .parse_atn_rule(&atn, 0)
16354            .expect("invalid token should recover into an error node");
16355
16356        assert_eq!(parser.number_of_syntax_errors(), 1);
16357        assert_eq!(
16358            parser
16359                .node(tree)
16360                .first_error_token()
16361                .expect("recovery should embed an error token")
16362                .text(),
16363            Some("y")
16364        );
16365    }
16366
16367    #[test]
16368    fn parser_syntax_error_count_tracks_failed_interpreted_parse() {
16369        let atn = token_then_eof_atn();
16370        let mut parser = mini_parser(vec![
16371            TestToken::new(2).with_text("y"),
16372            TestToken::eof("parser-test", 1, 1, 1),
16373        ]);
16374
16375        let error = parser
16376            .parse_atn_rule(&atn, 0)
16377            .expect_err("start-rule mismatch should remain a parser error");
16378
16379        assert_eq!(parser.number_of_syntax_errors(), 1);
16380        assert!(matches!(error, AntlrError::ParserError { .. }));
16381    }
16382
16383    #[test]
16384    fn adaptive_direct_rule_uses_simulator_decision() {
16385        let atn = two_alt_decision_atn();
16386        let mut simulator = ParserAtnSimulator::new(&atn);
16387        let mut parser = mini_parser(vec![
16388            TestToken::new(2).with_text("y"),
16389            TestToken::eof("parser-test", 1, 1, 1),
16390        ]);
16391
16392        let tree = parser
16393            .parse_atn_rule_adaptive_or_fallback(&atn, &mut simulator, 0)
16394            .expect("direct adaptive rule should parse");
16395
16396        assert_eq!(parser.node(tree).text(), "y");
16397        assert_eq!(parser.input.index(), 1);
16398    }
16399
16400    #[test]
16401    fn adaptive_direct_rule_restores_input_on_fallback() {
16402        let atn = predicate_after_token_atn();
16403        let mut simulator = ParserAtnSimulator::new(&atn);
16404        let mut parser = mini_parser(vec![
16405            TestToken::new(1).with_text("x"),
16406            TestToken::new(2).with_text("y"),
16407            TestToken::eof("parser-test", 2, 1, 2),
16408        ]);
16409
16410        let tree = parser
16411            .parse_atn_rule_adaptive_or_fallback(&atn, &mut simulator, 0)
16412            .expect("fallback recognizer should parse");
16413
16414        assert_eq!(parser.node(tree).text(), "xy");
16415        assert_eq!(parser.input.index(), 2);
16416        let stats = parser.parse_tree_storage().stats();
16417        assert_eq!(stats.nodes, parser.node(tree).descendants().count());
16418        assert_eq!(stats.edges, stats.nodes.saturating_sub(1));
16419        assert_eq!(stats.scratch_links, 0);
16420    }
16421
16422    #[test]
16423    fn unknown_predicate_policy_defaults_to_assume_true() {
16424        let atn = predicate_after_token_atn();
16425        let mut parser = mini_parser(vec![
16426            TestToken::new(1).with_text("x"),
16427            TestToken::new(2).with_text("y"),
16428            TestToken::eof("parser-test", 2, 1, 2),
16429        ]);
16430
16431        let (tree, _) = parser
16432            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
16433            .expect("unknown predicate should pass under the default policy");
16434
16435        assert_eq!(parser.node(tree).text(), "xy");
16436        assert_eq!(parser.number_of_syntax_errors(), 0);
16437    }
16438
16439    #[test]
16440    fn predicate_gated_same_lookahead_uses_viable_alternative() {
16441        let atn = predicate_gated_same_lookahead_atn([0, 1]);
16442        let mut parser = mini_parser(vec![
16443            TestToken::new(1).with_text("x"),
16444            TestToken::eof("parser-test", 1, 1, 1),
16445        ]);
16446
16447        let (tree, _) = parser
16448            .parse_atn_rule_with_runtime_options(
16449                &atn,
16450                0,
16451                ParserRuntimeOptions {
16452                    predicates: &[
16453                        (0, 0, ParserPredicate::False),
16454                        (0, 1, ParserPredicate::True),
16455                    ],
16456                    ..ParserRuntimeOptions::default()
16457                },
16458            )
16459            .expect("the second predicate-gated alternative should match");
16460
16461        assert_eq!(parser.node(tree).text(), "x<EOF>");
16462        assert_eq!(parser.number_of_syntax_errors(), 0);
16463        assert_eq!(parser.fast_predicate_cache.get(&(0, 0, 0)), Some(&false));
16464        assert_eq!(parser.fast_predicate_cache.get(&(0, 0, 1)), Some(&true));
16465    }
16466
16467    #[test]
16468    fn nested_interpreted_parse_preserves_prior_unknown_predicate_hits() {
16469        // A generated parent may record an unknown-predicate coordinate, then
16470        // descend into an interpreted child. The child's interpreter entry must
16471        // not wipe the parent's recorded hit before the top-level surfaces it.
16472        let atn = token_then_eof_atn();
16473        let mut parser = mini_parser(vec![
16474            TestToken::new(1).with_text("x"),
16475            TestToken::eof("parser-test", 1, 1, 1),
16476        ]);
16477
16478        // Simulate the parent having recorded a fail-loud coordinate.
16479        parser.unknown_predicate_hits.push((7, 3));
16480
16481        // Run an interpreted child parse that records no coordinate of its own.
16482        parser
16483            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
16484            .expect("child rule parses");
16485
16486        // The parent's coordinate must still be present for the top-level entry.
16487        let error = parser
16488            .take_unknown_semantic_error()
16489            .expect("parent's recorded coordinate must survive the nested interpreted parse");
16490        let AntlrError::Unsupported(message) = error else {
16491            panic!("expected AntlrError::Unsupported, got {error:?}");
16492        };
16493        assert!(message.contains("pred_index=3"), "message: {message}");
16494    }
16495
16496    #[test]
16497    fn unknown_predicate_policy_assume_false_kills_the_guarded_path() {
16498        let atn = predicate_after_token_atn();
16499        let mut parser = mini_parser(vec![
16500            TestToken::new(1).with_text("x"),
16501            TestToken::new(2).with_text("y"),
16502            TestToken::eof("parser-test", 2, 1, 2),
16503        ]);
16504
16505        let result = parser.parse_atn_rule_with_runtime_options(
16506            &atn,
16507            0,
16508            ParserRuntimeOptions {
16509                unknown_predicate_policy: UnknownSemanticPolicy::AssumeFalse,
16510                ..ParserRuntimeOptions::default()
16511            },
16512        );
16513
16514        assert!(
16515            result.is_err(),
16516            "the only path is predicate-guarded, so assume-false must fail the parse"
16517        );
16518    }
16519
16520    #[test]
16521    fn predicate_failure_message_keeps_semantic_recovery_path() {
16522        let atn = predicate_after_token_atn();
16523        let mut parser = mini_parser(vec![
16524            TestToken::new(1).with_text("x"),
16525            TestToken::new(2).with_text("y"),
16526            TestToken::eof("parser-test", 2, 1, 2),
16527        ]);
16528
16529        let (tree, _) = parser
16530            .parse_atn_rule_with_runtime_options(
16531                &atn,
16532                0,
16533                ParserRuntimeOptions {
16534                    predicates: &[(
16535                        0,
16536                        0,
16537                        ParserPredicate::FalseWithMessage {
16538                            message: "predicate rejected input",
16539                        },
16540                    )],
16541                    ..ParserRuntimeOptions::default()
16542                },
16543            )
16544            .expect("failure-message predicates recover through the semantic interpreter");
16545
16546        assert_eq!(parser.node(tree).text(), "xy");
16547        assert_eq!(parser.number_of_syntax_errors(), 1);
16548        assert!(
16549            parser.fast_predicate_cache.is_empty(),
16550            "failure-message predicates need the semantic interpreter's recovery outcome"
16551        );
16552    }
16553
16554    #[test]
16555    fn unknown_predicate_policy_error_names_the_coordinate() {
16556        let atn = predicate_after_token_atn();
16557        let mut parser = mini_parser(vec![
16558            TestToken::new(1).with_text("x"),
16559            TestToken::new(2).with_text("y"),
16560            TestToken::eof("parser-test", 2, 1, 2),
16561        ]);
16562
16563        let error = parser
16564            .parse_atn_rule_with_runtime_options(
16565                &atn,
16566                0,
16567                ParserRuntimeOptions {
16568                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
16569                    ..ParserRuntimeOptions::default()
16570                },
16571            )
16572            .expect_err("evaluating an unknown predicate under Error policy must fail");
16573
16574        let AntlrError::Unsupported(message) = error else {
16575            panic!("expected AntlrError::Unsupported, got {error:?}");
16576        };
16577        assert!(
16578            message.contains("unsupported semantic predicate"),
16579            "message should name the failure class: {message}"
16580        );
16581        assert!(
16582            message.contains("pred_index=0"),
16583            "message should carry the coordinate: {message}"
16584        );
16585    }
16586
16587    #[test]
16588    fn fail_loud_hits_do_not_leak_into_a_reused_interpreter_parse() {
16589        // A parser reused after a fail-loud parse must not carry the old
16590        // coordinates into a later parse. The fail-loud return keeps the hits
16591        // (so a generated parent can surface a recovered child's coordinate),
16592        // and the next parse's entry stashes/replaces them, so a subsequent
16593        // clean parse surfaces no stale error.
16594        let atn = predicate_after_token_atn();
16595        let mut parser = mini_parser(vec![
16596            TestToken::new(1).with_text("x"),
16597            TestToken::new(2).with_text("y"),
16598            TestToken::eof("parser-test", 2, 1, 2),
16599        ]);
16600
16601        parser
16602            .parse_atn_rule_with_runtime_options(
16603                &atn,
16604                0,
16605                ParserRuntimeOptions {
16606                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
16607                    ..ParserRuntimeOptions::default()
16608                },
16609            )
16610            .expect_err("first parse fails loud under the Error policy");
16611
16612        // The failed parse kept its coordinate on the parser (so a generated
16613        // parent could surface a recovered child). A top-level reuse resets the
16614        // hits — generated parsers call `reset_unknown_semantic_hits` at their
16615        // public entry; direct interpreter-API callers do the same.
16616        parser.reset_unknown_semantic_hits();
16617        assert!(
16618            parser.take_unknown_semantic_error().is_none(),
16619            "reset must drop stale unknown-predicate coordinates before a reused parse"
16620        );
16621    }
16622
16623    #[derive(Debug, Default)]
16624    struct RecordingHooks {
16625        predicates: Vec<(usize, usize, usize, Option<String>)>,
16626        actions: Vec<(usize, String, Option<String>)>,
16627        action_trees: Vec<Option<String>>,
16628    }
16629
16630    impl SemanticHooks for RecordingHooks {
16631        fn sempred<S>(
16632            &mut self,
16633            ctx: &mut ParserSemCtx<'_, S>,
16634            rule_index: usize,
16635            pred_index: usize,
16636        ) -> Option<bool>
16637        where
16638            S: TokenSource,
16639        {
16640            self.predicates.push((
16641                ctx.input_index(),
16642                rule_index,
16643                pred_index,
16644                ctx.token_text(1)
16645                    .and_then(|token| token.text().map(str::to_owned)),
16646            ));
16647            Some(true)
16648        }
16649
16650        fn action<S>(&mut self, ctx: &mut ParserSemCtx<'_, S>, action: ParserAction) -> bool
16651        where
16652            S: TokenSource,
16653        {
16654            self.actions.push((
16655                action.source_state(),
16656                ctx.action_text(),
16657                ctx.rule_name().map(str::to_owned),
16658            ));
16659            self.action_trees.push(ctx.tree().map(Node::text));
16660            true
16661        }
16662    }
16663
16664    #[derive(Debug, Default)]
16665    struct RejectingPredicateHooks {
16666        predicates: Vec<(usize, usize, usize, Option<String>)>,
16667    }
16668
16669    impl SemanticHooks for RejectingPredicateHooks {
16670        fn sempred<S>(
16671            &mut self,
16672            ctx: &mut ParserSemCtx<'_, S>,
16673            rule_index: usize,
16674            pred_index: usize,
16675        ) -> Option<bool>
16676        where
16677            S: TokenSource,
16678        {
16679            self.predicates.push((
16680                ctx.input_index(),
16681                rule_index,
16682                pred_index,
16683                ctx.token_text(1)
16684                    .and_then(|token| token.text().map(str::to_owned)),
16685            ));
16686            Some(false)
16687        }
16688    }
16689
16690    #[test]
16691    fn fast_predicate_cache_replays_hook_once_per_coordinate_and_input() {
16692        let atn = predicate_gated_same_lookahead_atn([0, 0]);
16693        let mut parser = mini_parser_with_hooks(
16694            vec![
16695                TestToken::new(1).with_text("x"),
16696                TestToken::eof("parser-test", 1, 1, 1),
16697            ],
16698            RecordingHooks::default(),
16699        );
16700
16701        let (tree, _) = parser
16702            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
16703            .expect("both alternatives share one replay-safe predicate result");
16704
16705        assert_eq!(parser.node(tree).text(), "x<EOF>");
16706        assert_eq!(
16707            parser.semantic_hooks.predicates,
16708            vec![(0, 0, 0, Some("x".to_owned()))]
16709        );
16710        assert_eq!(parser.fast_predicate_cache.get(&(0, 0, 0)), Some(&true));
16711    }
16712
16713    #[test]
16714    fn semantic_hook_handles_unknown_predicate_before_error_policy() {
16715        let atn = predicate_after_token_atn();
16716        let mut parser = mini_parser_with_hooks(
16717            vec![
16718                TestToken::new(1).with_text("x"),
16719                TestToken::new(2).with_text("y"),
16720                TestToken::eof("parser-test", 2, 1, 2),
16721            ],
16722            RecordingHooks::default(),
16723        );
16724
16725        let (tree, _) = parser
16726            .parse_atn_rule_with_runtime_options(
16727                &atn,
16728                0,
16729                ParserRuntimeOptions {
16730                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
16731                    ..ParserRuntimeOptions::default()
16732                },
16733            )
16734            .expect("hook supplies the missing predicate result");
16735
16736        assert_eq!(parser.node(tree).text(), "xy");
16737        assert_eq!(
16738            parser.semantic_hooks.predicates,
16739            vec![(1, 0, 0, Some("y".to_owned()))]
16740        );
16741        assert_eq!(parser.fast_predicate_cache.get(&(1, 0, 0)), Some(&true));
16742    }
16743
16744    #[test]
16745    fn runtime_options_default_preserves_semantic_hook_predicates() {
16746        let atn = predicate_after_token_atn();
16747        let mut parser = mini_parser_with_hooks(
16748            vec![
16749                TestToken::new(1).with_text("x"),
16750                TestToken::new(2).with_text("y"),
16751                TestToken::eof("parser-test", 2, 1, 2),
16752            ],
16753            RejectingPredicateHooks::default(),
16754        );
16755
16756        let result =
16757            parser.parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default());
16758
16759        assert!(
16760            result.is_err(),
16761            "default runtime options must not bypass semantic hooks for predicate ATNs"
16762        );
16763        assert_eq!(
16764            parser.semantic_hooks.predicates,
16765            vec![(1, 0, 0, Some("y".to_owned()))]
16766        );
16767        assert_eq!(parser.fast_predicate_cache.get(&(1, 0, 0)), Some(&false));
16768    }
16769
16770    #[test]
16771    fn semantic_hook_handles_committed_parser_action() {
16772        let atn = token_then_eof_atn();
16773        let mut parser = mini_parser_with_hooks(
16774            vec![
16775                TestToken::new(1).with_text("x"),
16776                TestToken::eof("parser-test", 1, 1, 1),
16777            ],
16778            RecordingHooks::default(),
16779        );
16780        let (tree, _) = parser
16781            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
16782            .expect("rule parses before action hook is tested");
16783
16784        assert!(parser.parser_action_hook(ParserAction::new(42, 0, 0, Some(0)), tree));
16785        assert_eq!(
16786            parser.semantic_hooks.actions,
16787            vec![(42, "x".to_owned(), Some("s".to_owned()))]
16788        );
16789        assert_eq!(
16790            parser.semantic_hooks.action_trees,
16791            [Some("x<EOF>".to_owned())]
16792        );
16793    }
16794
16795    #[test]
16796    fn unhandled_committed_action_fails_loud_under_error_policy() {
16797        // An action offered to the hook that no hook handles (returns false)
16798        // must be recorded and surfaced as `AntlrError::Unsupported` under the
16799        // Error policy, so a `hook`-disposed action is not silently dropped.
16800        let mut parser = mini_parser_with_hooks(vec![TestToken::eof("t", 0, 1, 0)], DecliningHooks);
16801        parser.set_unknown_predicate_policy(UnknownSemanticPolicy::Error);
16802        let tree = parser.rule_node(ParserRuleContext::new(0, -1));
16803
16804        // DecliningHooks::action returns false (unhandled).
16805        assert!(!parser.parser_action_hook(ParserAction::new(42, 0, 0, Some(0)), tree));
16806
16807        let error = parser
16808            .take_unknown_semantic_error()
16809            .expect("an unhandled committed action under Error policy must fail loud");
16810        let AntlrError::Unsupported(message) = error else {
16811            panic!("expected AntlrError::Unsupported, got {error:?}");
16812        };
16813        assert!(
16814            message.contains("unhandled semantic action") && message.contains("state=42"),
16815            "message should name the dropped action coordinate: {message}"
16816        );
16817
16818        // Under the default (assume-true) policy the same miss is not recorded.
16819        let mut lenient =
16820            mini_parser_with_hooks(vec![TestToken::eof("t", 0, 1, 0)], DecliningHooks);
16821        let tree = lenient.rule_node(ParserRuleContext::new(0, -1));
16822        assert!(!lenient.parser_action_hook(ParserAction::new(42, 0, 0, Some(0)), tree));
16823        assert!(lenient.take_unknown_semantic_error().is_none());
16824    }
16825
16826    #[test]
16827    fn translated_predicate_is_unaffected_by_error_policy() {
16828        let atn = predicate_after_token_atn();
16829        let mut parser = mini_parser(vec![
16830            TestToken::new(1).with_text("x"),
16831            TestToken::new(2).with_text("y"),
16832            TestToken::eof("parser-test", 2, 1, 2),
16833        ]);
16834
16835        let (tree, _) = parser
16836            .parse_atn_rule_with_runtime_options(
16837                &atn,
16838                0,
16839                ParserRuntimeOptions {
16840                    predicates: &[(0, 0, ParserPredicate::True)],
16841                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
16842                    ..ParserRuntimeOptions::default()
16843                },
16844            )
16845            .expect("a predicate covered by the table is not an unknown coordinate");
16846
16847        assert_eq!(parser.node(tree).text(), "xy");
16848    }
16849
16850    /// Hooks that decline (`None`) must fall through to the configured policy
16851    /// even when the coordinate carries a [`semir`] `Hook` node, matching the
16852    /// legacy table path. Regression for the `unwrap_or(false)` that silently
16853    /// rejected declined hook nodes and bypassed [`UnknownSemanticPolicy`].
16854    fn hook_predicate_semantics() -> ParserSemantics {
16855        let mut ir = SemIr::new();
16856        let expr = ir.expr(PExpr::Hook(HookId::new(0)));
16857        ParserSemantics {
16858            ir,
16859            predicates: vec![ParserSemanticPredicate {
16860                rule_index: 0,
16861                pred_index: 0,
16862                expr,
16863                failure_message: None,
16864            }],
16865            actions: Vec::new(),
16866        }
16867    }
16868
16869    #[derive(Debug, Default)]
16870    struct DecliningHooks;
16871
16872    impl SemanticHooks for DecliningHooks {}
16873
16874    #[test]
16875    fn semir_hook_none_falls_through_to_assume_true() {
16876        let atn = predicate_after_token_atn();
16877        let semantics = hook_predicate_semantics();
16878        let mut parser = mini_parser_with_hooks(
16879            vec![
16880                TestToken::new(1).with_text("x"),
16881                TestToken::new(2).with_text("y"),
16882                TestToken::eof("parser-test", 2, 1, 2),
16883            ],
16884            DecliningHooks,
16885        );
16886
16887        let (tree, _) = parser
16888            .parse_atn_rule_with_runtime_options(
16889                &atn,
16890                0,
16891                ParserRuntimeOptions {
16892                    semantics: Some(&semantics),
16893                    unknown_predicate_policy: UnknownSemanticPolicy::AssumeTrue,
16894                    ..ParserRuntimeOptions::default()
16895                },
16896            )
16897            .expect("a declined SemIR hook must pass under assume-true");
16898
16899        assert_eq!(parser.node(tree).text(), "xy");
16900    }
16901
16902    #[test]
16903    fn semir_hook_none_falls_through_to_assume_false() {
16904        let atn = predicate_after_token_atn();
16905        let semantics = hook_predicate_semantics();
16906        let mut parser = mini_parser_with_hooks(
16907            vec![
16908                TestToken::new(1).with_text("x"),
16909                TestToken::new(2).with_text("y"),
16910                TestToken::eof("parser-test", 2, 1, 2),
16911            ],
16912            DecliningHooks,
16913        );
16914
16915        let result = parser.parse_atn_rule_with_runtime_options(
16916            &atn,
16917            0,
16918            ParserRuntimeOptions {
16919                semantics: Some(&semantics),
16920                unknown_predicate_policy: UnknownSemanticPolicy::AssumeFalse,
16921                ..ParserRuntimeOptions::default()
16922            },
16923        );
16924
16925        assert!(
16926            result.is_err(),
16927            "a declined SemIR hook must fail the only guarded path under assume-false"
16928        );
16929    }
16930
16931    #[test]
16932    fn semir_hook_none_records_coordinate_under_error_policy() {
16933        let atn = predicate_after_token_atn();
16934        let semantics = hook_predicate_semantics();
16935        let mut parser = mini_parser_with_hooks(
16936            vec![
16937                TestToken::new(1).with_text("x"),
16938                TestToken::new(2).with_text("y"),
16939                TestToken::eof("parser-test", 2, 1, 2),
16940            ],
16941            DecliningHooks,
16942        );
16943
16944        let error = parser
16945            .parse_atn_rule_with_runtime_options(
16946                &atn,
16947                0,
16948                ParserRuntimeOptions {
16949                    semantics: Some(&semantics),
16950                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
16951                    ..ParserRuntimeOptions::default()
16952                },
16953            )
16954            .expect_err("a declined SemIR hook under Error policy must fail the parse");
16955
16956        let AntlrError::Unsupported(message) = error else {
16957            panic!("expected AntlrError::Unsupported, got {error:?}");
16958        };
16959        assert!(
16960            message.contains("unsupported semantic predicate") && message.contains("pred_index=0"),
16961            "message should name the unresolved coordinate: {message}"
16962        );
16963    }
16964
16965    #[test]
16966    fn generated_direct_predicate_honors_installed_policy() {
16967        // The generated recursive-descent path calls
16968        // `parser_semantic_ir_predicate_matches_with_context_and_local` without
16969        // going through `ParserRuntimeOptions`, so the policy must be installed
16970        // via `set_unknown_predicate_policy` (as the generated constructor now
16971        // does). A declining hook must then honor it rather than the default.
16972        let semantics = hook_predicate_semantics();
16973        let context = ParserRuleContext::new(0, -1);
16974
16975        let mut assume_true =
16976            mini_parser_with_hooks(vec![TestToken::eof("t", 0, 1, 0)], DecliningHooks);
16977        assert!(
16978            assume_true.parser_semantic_ir_predicate_matches_with_context_and_local(
16979                &semantics, 0, 0, &context, 0
16980            ),
16981            "default AssumeTrue accepts a declined hook"
16982        );
16983        assert!(assume_true.take_unknown_semantic_error().is_none());
16984
16985        let mut error_policy =
16986            mini_parser_with_hooks(vec![TestToken::eof("t", 0, 1, 0)], DecliningHooks);
16987        error_policy.set_unknown_predicate_policy(UnknownSemanticPolicy::Error);
16988        assert!(
16989            !error_policy.parser_semantic_ir_predicate_matches_with_context_and_local(
16990                &semantics, 0, 0, &context, 0
16991            ),
16992            "Error policy rejects a declined hook on the generated-direct path"
16993        );
16994        let error = error_policy
16995            .take_unknown_semantic_error()
16996            .expect("Error policy records the unresolved coordinate for the generated path");
16997        let AntlrError::Unsupported(message) = error else {
16998            panic!("expected AntlrError::Unsupported, got {error:?}");
16999        };
17000        assert!(message.contains("pred_index=0"), "message: {message}");
17001    }
17002
17003    #[test]
17004    fn parser_rule_start_skips_leading_hidden_tokens() {
17005        let atn = token_then_eof_atn();
17006        let mut parser = mini_parser(vec![
17007            TestToken::new(99)
17008                .with_text(" ")
17009                .with_channel(HIDDEN_CHANNEL),
17010            TestToken::new(1).with_text("x"),
17011            TestToken::eof("parser-test", 2, 1, 2),
17012        ]);
17013
17014        let tree = parser
17015            .parse_atn_rule(&atn, 0)
17016            .expect("artificial parser rule should parse");
17017        let Some(rule) = parser.node(tree).first_rule(0).and_then(Node::as_rule) else {
17018            panic!("rule node should be present");
17019        };
17020        assert_eq!(
17021            rule.start()
17022                .expect("rule should have a start token")
17023                .token_type(),
17024            1
17025        );
17026    }
17027
17028    #[test]
17029    fn parser_action_after_eof_stops_at_eof_token() {
17030        let atn = eof_then_action_atn();
17031        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 0, 1, 0)]);
17032
17033        let (_, actions) = parser
17034            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
17035            .expect("EOF action rule should parse");
17036
17037        assert_eq!(actions.len(), 1);
17038        assert_eq!(actions[0].stop_index(), Some(0));
17039        assert_eq!(
17040            parser.text_interval(actions[0].start_index(), actions[0].stop_index()),
17041            ""
17042        );
17043    }
17044
17045    #[test]
17046    fn after_action_stop_uses_rule_context_stop_not_cursor() {
17047        // A rule that ends right before EOF without matching it (e.g. `a: ID;`
17048        // called from `start: a EOF;`): after matching ID the cursor parks on EOF,
17049        // but the rule did not consume it. The @after stop must follow the rule
17050        // context's recorded stop (ID at index 0), not the cursor's EOF (index 1).
17051        let mut id = TestToken::new(1).with_text("x");
17052        id.set_token_index(0);
17053        let mut eof = TestToken::eof("parser-test", 1, 1, 1);
17054        eof.set_token_index(1);
17055        let mut parser = mini_parser(vec![id.clone(), eof]);
17056        // Advance the cursor onto EOF, as it would be after `a` matched ID.
17057        parser.consume();
17058        assert_eq!(parser.la(1), TOKEN_EOF);
17059
17060        // Rule `a` matched only ID, so its context stop is the ID token (index 0),
17061        // exactly what finish_rule(consumed_eof = false) records.
17062        let mut ctx = ParserRuleContext::new(0, 0);
17063        parser.set_context_stop(
17064            &mut ctx,
17065            parser.token_id_at(0).expect("ID token should be buffered"),
17066        );
17067        let tree = parser.rule_node(ctx);
17068
17069        let current_index = parser.input.index();
17070        // Cursor-only inference would wrongly pick EOF (the parked cursor)...
17071        assert_eq!(parser.after_action_stop_index(current_index), Some(1));
17072        // ...but the tree-aware helper follows the rule context stop (ID).
17073        assert_eq!(
17074            parser.after_action_stop_index_for_tree(tree, current_index),
17075            Some(0)
17076        );
17077    }
17078
17079    #[test]
17080    fn after_action_start_uses_rule_context_start_not_cursor() {
17081        // A rule that begins after leading hidden-channel tokens: the rule context
17082        // start (set by `enter_rule`) is the first visible token, not the raw cursor
17083        // that may still point at the hidden prefix. The @after start must follow
17084        // the context start so `$start`/`$text` excludes the hidden prefix.
17085        let mut parser = mini_parser(vec![
17086            TestToken::new(9)
17087                .with_text(" ")
17088                .with_channel(HIDDEN_CHANNEL),
17089            TestToken::new(9)
17090                .with_text(" ")
17091                .with_channel(HIDDEN_CHANNEL),
17092            TestToken::new(1).with_text("x"),
17093            TestToken::eof("parser-test", 3, 1, 3),
17094        ]);
17095
17096        let mut ctx = ParserRuleContext::new(0, 0);
17097        parser.set_context_start(
17098            &mut ctx,
17099            parser.token_id_at(2).expect("ID token should be buffered"),
17100        );
17101        let tree = parser.rule_node(ctx);
17102
17103        // The raw fallback (pre-rule cursor) would be 0 (the hidden prefix)...
17104        // ...but the tree-aware helper follows the rule context start (index 2).
17105        assert_eq!(parser.after_action_start_index_for_tree(tree, 0), 2);
17106
17107        // With no rule start recorded, it falls back to the provided index.
17108        let empty = parser.rule_node(ParserRuleContext::new(0, 0));
17109        assert_eq!(parser.after_action_start_index_for_tree(empty, 7), 7);
17110    }
17111
17112    fn clean_fast_outcome(index: usize, consumed_eof: bool, marker: u32) -> FastRecognizeOutcome {
17113        FastRecognizeOutcome {
17114            index,
17115            consumed_eof,
17116            diagnostics: DiagnosticSeqId::EMPTY,
17117            deferred_nodes: FastDeferredNodeId::EMPTY,
17118            nodes: NodeSeqId(marker),
17119        }
17120    }
17121
17122    #[test]
17123    fn clean_fast_outcome_dedupe_scans_small_lists_inline() {
17124        let mut outcomes = vec![
17125            clean_fast_outcome(4, false, 0),
17126            clean_fast_outcome(2, false, 1),
17127            clean_fast_outcome(4, false, 2),
17128            clean_fast_outcome(4, true, 3),
17129            clean_fast_outcome(2, false, 4),
17130        ];
17131        let mut scratch = FastOutcomeDedupScratch::default();
17132
17133        let strategy = dedupe_clean_fast_outcomes(&mut outcomes, &mut scratch);
17134
17135        assert_eq!(strategy, FastOutcomeDedupStrategy::Inline);
17136        assert_eq!(
17137            outcomes
17138                .iter()
17139                .map(|outcome| (outcome.index, outcome.consumed_eof, outcome.nodes.0))
17140                .collect::<Vec<_>>(),
17141            vec![(4, false, 0), (2, false, 1), (4, true, 3)]
17142        );
17143        assert!(scratch.dense_words.is_empty());
17144        assert!(scratch.sparse_keys.is_empty());
17145    }
17146
17147    #[test]
17148    fn clean_fast_outcome_dedupe_uses_and_reuses_dense_bitmap() {
17149        let mut scratch = FastOutcomeDedupScratch::default();
17150        let mut outcomes = (100..109)
17151            .flat_map(|index| {
17152                [
17153                    clean_fast_outcome(
17154                        index,
17155                        false,
17156                        u32::try_from(index).expect("test index fits in u32"),
17157                    ),
17158                    clean_fast_outcome(index, false, u32::MAX),
17159                ]
17160            })
17161            .collect();
17162
17163        let strategy = dedupe_clean_fast_outcomes(&mut outcomes, &mut scratch);
17164
17165        assert_eq!(strategy, FastOutcomeDedupStrategy::Dense);
17166        assert_eq!(outcomes.len(), 9);
17167        assert_eq!(outcomes[0].nodes, NodeSeqId(100));
17168        let dense_capacity = scratch.dense_words.capacity();
17169
17170        let mut reused = (1_000..1_009)
17171            .map(|index| {
17172                clean_fast_outcome(
17173                    index,
17174                    false,
17175                    u32::try_from(index).expect("test index fits in u32"),
17176                )
17177            })
17178            .collect();
17179        let strategy = dedupe_clean_fast_outcomes(&mut reused, &mut scratch);
17180
17181        assert_eq!(strategy, FastOutcomeDedupStrategy::Dense);
17182        assert_eq!(reused.len(), 9);
17183        assert_eq!(scratch.dense_words.capacity(), dense_capacity);
17184    }
17185
17186    #[test]
17187    fn clean_fast_outcome_dedupe_uses_and_reuses_sparse_hash() {
17188        let mut scratch = FastOutcomeDedupScratch::default();
17189        let sparse_indexes = [
17190            0, 100_000, 200_000, 300_000, 400_000, 500_000, 600_000, 700_000, 800_000,
17191        ];
17192        let mut outcomes = sparse_indexes
17193            .into_iter()
17194            .chain([400_000])
17195            .enumerate()
17196            .map(|(marker, index)| {
17197                clean_fast_outcome(
17198                    index,
17199                    false,
17200                    u32::try_from(marker).expect("test marker fits in u32"),
17201                )
17202            })
17203            .collect();
17204
17205        let strategy = dedupe_clean_fast_outcomes(&mut outcomes, &mut scratch);
17206
17207        assert_eq!(strategy, FastOutcomeDedupStrategy::Sparse);
17208        assert_eq!(outcomes.len(), sparse_indexes.len());
17209        assert_eq!(outcomes[4].nodes, NodeSeqId(4));
17210        let sparse_capacity = scratch.sparse_keys.capacity();
17211
17212        let mut reused = sparse_indexes
17213            .into_iter()
17214            .map(|index| {
17215                clean_fast_outcome(
17216                    index,
17217                    false,
17218                    u32::try_from(index).expect("test index fits in u32"),
17219                )
17220            })
17221            .collect();
17222        let strategy = dedupe_clean_fast_outcomes(&mut reused, &mut scratch);
17223
17224        assert_eq!(strategy, FastOutcomeDedupStrategy::Sparse);
17225        assert_eq!(reused.len(), sparse_indexes.len());
17226        assert_eq!(scratch.sparse_keys.capacity(), sparse_capacity);
17227    }
17228
17229    #[test]
17230    fn clean_fast_outcome_dedupe_releases_oversized_sparse_hash() {
17231        let mut scratch = FastOutcomeDedupScratch::default();
17232        scratch
17233            .sparse_keys
17234            .reserve(MAX_RETAINED_FAST_OUTCOME_SPARSE_KEYS * 2);
17235        assert!(scratch.sparse_keys.capacity() > MAX_RETAINED_FAST_OUTCOME_SPARSE_KEYS);
17236        let mut outcomes = (0..9)
17237            .map(|index| clean_fast_outcome(index * 100_000, false, index as u32))
17238            .collect();
17239
17240        let strategy = dedupe_clean_fast_outcomes(&mut outcomes, &mut scratch);
17241
17242        assert_eq!(strategy, FastOutcomeDedupStrategy::Sparse);
17243        assert!(scratch.sparse_keys.is_empty());
17244        assert!(scratch.sparse_keys.capacity() <= MAX_RETAINED_FAST_OUTCOME_SPARSE_KEYS);
17245    }
17246
17247    #[test]
17248    fn fast_outcome_selection_respects_sll_tie_order() {
17249        let mut arena = RecognitionArena::default();
17250        let first = FastRecognizeOutcome {
17251            index: 1,
17252            consumed_eof: false,
17253            diagnostics: arena.diagnostic_sequence([ParserDiagnostic {
17254                line: 1,
17255                column: 0,
17256                message: "mismatched input 'x'".to_owned(),
17257            }]),
17258            deferred_nodes: FastDeferredNodeId::EMPTY,
17259            nodes: NodeSeqId::EMPTY,
17260        };
17261        let second = FastRecognizeOutcome {
17262            index: first.index,
17263            consumed_eof: first.consumed_eof,
17264            diagnostics: DiagnosticSeqId::EMPTY,
17265            deferred_nodes: FastDeferredNodeId::EMPTY,
17266            nodes: NodeSeqId::EMPTY,
17267        };
17268
17269        let selected = select_best_fast_outcome(
17270            [first, second].into_iter(),
17271            PredictionMode::Sll,
17272            None,
17273            |_| panic!("caller-follow token probe should not run"),
17274            &arena,
17275        )
17276        .expect("one outcome should be selected");
17277        assert_eq!(arena.diagnostics_len(selected.diagnostics), 1);
17278        let eof_second = FastRecognizeOutcome {
17279            index: second.index,
17280            consumed_eof: true,
17281            diagnostics: DiagnosticSeqId::EMPTY,
17282            deferred_nodes: FastDeferredNodeId::EMPTY,
17283            nodes: NodeSeqId::EMPTY,
17284        };
17285        let selected = select_best_fast_outcome(
17286            [first, eof_second].into_iter(),
17287            PredictionMode::Sll,
17288            None,
17289            |_| panic!("caller-follow token probe should not run"),
17290            &arena,
17291        )
17292        .expect("one outcome should be selected");
17293        assert!(!selected.consumed_eof);
17294        let selected = select_best_fast_outcome(
17295            [first, second].into_iter(),
17296            PredictionMode::Ll,
17297            None,
17298            |_| panic!("caller-follow token probe should not run"),
17299            &arena,
17300        )
17301        .expect("one outcome should be selected");
17302        assert!(selected.diagnostics.is_empty());
17303    }
17304
17305    #[test]
17306    fn recovery_fast_outcome_dedupe_uses_selection_rank() {
17307        let mut arena = RecognitionArena::default();
17308        let first = FastRecognizeOutcome {
17309            index: 3,
17310            consumed_eof: false,
17311            diagnostics: arena.diagnostic_sequence([ParserDiagnostic {
17312                line: 1,
17313                column: 0,
17314                message: "mismatched input 'x' expecting 'a'".to_owned(),
17315            }]),
17316            deferred_nodes: FastDeferredNodeId::EMPTY,
17317            nodes: NodeSeqId::EMPTY,
17318        };
17319        let same_rank = FastRecognizeOutcome {
17320            index: first.index,
17321            consumed_eof: first.consumed_eof,
17322            diagnostics: arena.diagnostic_sequence([ParserDiagnostic {
17323                line: 1,
17324                column: 0,
17325                message: "mismatched input 'x' expecting 'b'".to_owned(),
17326            }]),
17327            deferred_nodes: FastDeferredNodeId::EMPTY,
17328            nodes: NodeSeqId::EMPTY,
17329        };
17330        let better_rank = FastRecognizeOutcome {
17331            index: first.index,
17332            consumed_eof: first.consumed_eof,
17333            diagnostics: arena.diagnostic_sequence([ParserDiagnostic {
17334                line: 1,
17335                column: 0,
17336                message: "missing 'a' at 'x'".to_owned(),
17337            }]),
17338            deferred_nodes: FastDeferredNodeId::EMPTY,
17339            nodes: NodeSeqId::EMPTY,
17340        };
17341        let mut outcomes = vec![first, same_rank, better_rank];
17342
17343        dedupe_fast_outcomes(&mut outcomes, &arena);
17344
17345        assert_eq!(outcomes.len(), 2);
17346        assert_eq!(
17347            arena
17348                .diagnostics(outcomes[0].diagnostics)
17349                .next()
17350                .expect("first diagnostic")
17351                .message,
17352            "mismatched input 'x' expecting 'a'"
17353        );
17354        assert_eq!(
17355            arena
17356                .diagnostics(outcomes[1].diagnostics)
17357                .next()
17358                .expect("second diagnostic")
17359                .message,
17360            "missing 'a' at 'x'"
17361        );
17362    }
17363
17364    #[test]
17365    fn fast_outcome_selection_prefers_generated_caller_follow() {
17366        let arena = RecognitionArena::default();
17367        let earlier = FastRecognizeOutcome {
17368            index: 7,
17369            consumed_eof: false,
17370            diagnostics: DiagnosticSeqId::EMPTY,
17371            deferred_nodes: FastDeferredNodeId::EMPTY,
17372            nodes: NodeSeqId::EMPTY,
17373        };
17374        let later = FastRecognizeOutcome {
17375            index: 8,
17376            consumed_eof: false,
17377            diagnostics: DiagnosticSeqId::EMPTY,
17378            deferred_nodes: FastDeferredNodeId::EMPTY,
17379            nodes: NodeSeqId::EMPTY,
17380        };
17381        let mut follow = TokenBitSet::default();
17382        follow.insert(5);
17383
17384        let selected = select_best_fast_outcome(
17385            [later, earlier].into_iter(),
17386            PredictionMode::Ll,
17387            Some(&follow),
17388            |index| (if index == 7 { 5 } else { TOKEN_EOF }, index == 7, true),
17389            &arena,
17390        )
17391        .expect("one outcome should be selected");
17392        assert_eq!(selected.index, 7);
17393
17394        let selected = select_best_fast_outcome(
17395            [later, earlier].into_iter(),
17396            PredictionMode::Ll,
17397            Some(&follow),
17398            |index| (if index == 7 { 5 } else { TOKEN_EOF }, false, true),
17399            &arena,
17400        )
17401        .expect("one outcome should be selected");
17402        assert_eq!(selected.index, 8);
17403
17404        let indented_next_statement = FastRecognizeOutcome {
17405            index: 9,
17406            consumed_eof: false,
17407            diagnostics: DiagnosticSeqId::EMPTY,
17408            deferred_nodes: FastDeferredNodeId::EMPTY,
17409            nodes: NodeSeqId::EMPTY,
17410        };
17411        let selected = select_best_fast_outcome(
17412            [indented_next_statement, earlier].into_iter(),
17413            PredictionMode::Ll,
17414            Some(&follow),
17415            |index| {
17416                let is_boundary = index == 7;
17417                let is_boundary_gap = matches!(index, 7 | 8);
17418                (
17419                    if index == 7 { 5 } else { TOKEN_EOF },
17420                    is_boundary,
17421                    is_boundary_gap,
17422                )
17423            },
17424            &arena,
17425        )
17426        .expect("one outcome should be selected");
17427        assert_eq!(selected.index, 7);
17428
17429        let continuation = FastRecognizeOutcome {
17430            index: 10,
17431            consumed_eof: false,
17432            diagnostics: DiagnosticSeqId::EMPTY,
17433            deferred_nodes: FastDeferredNodeId::EMPTY,
17434            nodes: NodeSeqId::EMPTY,
17435        };
17436        let selected = select_best_fast_outcome(
17437            [continuation, earlier].into_iter(),
17438            PredictionMode::Ll,
17439            Some(&follow),
17440            |index| {
17441                let is_boundary = matches!(index, 7 | 9);
17442                (
17443                    if index == 7 { 5 } else { TOKEN_EOF },
17444                    is_boundary,
17445                    is_boundary,
17446                )
17447            },
17448            &arena,
17449        )
17450        .expect("one outcome should be selected");
17451        assert_eq!(selected.index, 10);
17452
17453        let selected = select_best_fast_outcome(
17454            [earlier, later].into_iter(),
17455            PredictionMode::Sll,
17456            Some(&follow),
17457            |_| panic!("caller-follow token probe should not run in SLL mode"),
17458            &arena,
17459        )
17460        .expect("one outcome should be selected");
17461        assert_eq!(selected.index, 8);
17462    }
17463
17464    #[test]
17465    fn caller_follow_boundary_text_requires_separator_shape() {
17466        assert!(is_caller_follow_boundary_text(";"));
17467        assert!(is_caller_follow_boundary_text("\n"));
17468        assert!(is_caller_follow_boundary_text("\r\n  "));
17469        assert!(is_caller_follow_boundary_text(";\n"));
17470        assert!(!is_caller_follow_boundary_text("\"\"\"line1\nline2\"\"\""));
17471        assert!(!is_caller_follow_boundary_text("/* line1\nline2 */"));
17472        assert!(!is_caller_follow_boundary_text("identifier"));
17473        assert!(is_caller_follow_boundary_gap_text(" \t "));
17474        assert!(is_caller_follow_boundary_gap_text("\n  "));
17475        assert!(is_caller_follow_boundary_gap_text(";\t"));
17476        assert!(!is_caller_follow_boundary_gap_text(
17477            "\"\"\"line1\nline2\"\"\""
17478        ));
17479        assert!(!is_caller_follow_boundary_gap_text("/* line1\nline2 */"));
17480    }
17481
17482    #[test]
17483    fn caller_follow_token_info_treats_hidden_tokens_as_boundary_gaps() {
17484        let mut parser = mini_parser(vec![
17485            TestToken::new(5).with_text("\n"),
17486            TestToken::new(6)
17487                .with_text("// comment\n")
17488                .with_channel(HIDDEN_CHANNEL),
17489            TestToken::new(1).with_text("x"),
17490            TestToken::eof("parser-test", 1, 2, 0),
17491        ]);
17492
17493        assert_eq!(parser.caller_follow_token_info(0), (5, true, true));
17494        assert_eq!(parser.caller_follow_token_info(1), (6, false, true));
17495        assert_eq!(parser.caller_follow_token_info(2), (1, false, false));
17496    }
17497
17498    #[test]
17499    fn caller_follow_token_info_uses_stream_visible_channel() {
17500        let source = Source {
17501            tokens: vec![
17502                TestToken::new(5).with_text("\n").with_channel(2),
17503                TestToken::new(1).with_text("x").with_channel(2),
17504                TestToken::new(6)
17505                    .with_text("// comment\n")
17506                    .with_channel(HIDDEN_CHANNEL),
17507                TestToken::eof("parser-test", 1, 2, 0),
17508            ],
17509            index: 0,
17510        };
17511        let data = RecognizerData::new(
17512            "Mini.g4",
17513            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
17514        );
17515        let mut parser = BaseParser::new(CommonTokenStream::with_channel(source, 2), data);
17516
17517        assert_eq!(parser.caller_follow_token_info(0), (5, true, true));
17518        assert_eq!(parser.caller_follow_token_info(1), (1, false, false));
17519        assert_eq!(parser.caller_follow_token_info(2), (6, false, true));
17520    }
17521
17522    #[test]
17523    fn reset_per_parse_caches_clears_state_expected_token_cache() {
17524        let atn = token_then_eof_atn();
17525        let mut parser = mini_parser(Vec::new());
17526
17527        let _ = parser.cached_state_expected_token_set(&atn, 0);
17528        assert!(!parser.state_expected_token_cache.is_empty());
17529
17530        parser.reset_per_parse_caches();
17531        assert!(parser.state_expected_token_cache.is_empty());
17532    }
17533
17534    #[test]
17535    fn empty_cycle_cache_survives_reset_and_invalidates_for_a_different_atn() {
17536        let cyclic = epsilon_cycle_atn();
17537        let acyclic = token_then_eof_atn();
17538        let mut parser = mini_parser(Vec::new());
17539
17540        assert!(parser.state_can_reenter_without_consuming(&cyclic, 1));
17541        assert_eq!(
17542            parser.empty_cycle_cache_atn,
17543            Some(SharedAtnCacheKey::for_atn(&cyclic))
17544        );
17545        assert_eq!(parser.empty_cycle_cache[1], Some(true));
17546
17547        parser.reset_per_parse_caches();
17548        assert_eq!(parser.empty_cycle_cache[1], Some(true));
17549        assert!(parser.state_can_reenter_without_consuming(&cyclic, 1));
17550
17551        assert!(!parser.state_can_reenter_without_consuming(&acyclic, 1));
17552        assert_eq!(
17553            parser.empty_cycle_cache_atn,
17554            Some(SharedAtnCacheKey::for_atn(&acyclic))
17555        );
17556        assert_eq!(parser.empty_cycle_cache[1], Some(false));
17557    }
17558
17559    #[test]
17560    fn parser_error_with_empty_expected_set_omits_empty_set_display() {
17561        let source = Source {
17562            tokens: vec![
17563                TestToken::new(1).with_text("x"),
17564                TestToken::eof("parser-test", 1, 1, 1),
17565            ],
17566            index: 0,
17567        };
17568        let data = RecognizerData::new(
17569            "Mini.g4",
17570            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
17571        );
17572        let mut parser = BaseParser::new(CommonTokenStream::new(source), data);
17573        let expected = ExpectedTokens {
17574            index: Some(0),
17575            symbols: BTreeSet::new(),
17576            no_viable: None,
17577        };
17578
17579        let (_, message) = parser.expected_error_message(0, 0, &expected);
17580
17581        assert_eq!(message, "mismatched input 'x'");
17582    }
17583
17584    #[test]
17585    fn eof_rule_stop_index_points_at_eof_token() {
17586        let source = Source {
17587            tokens: vec![
17588                TestToken::new(1).with_text("x"),
17589                TestToken::eof("parser-test", 1, 1, 1),
17590            ],
17591            index: 0,
17592        };
17593        let data = RecognizerData::new(
17594            "Mini.g4",
17595            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
17596        );
17597        let mut parser = BaseParser::new(CommonTokenStream::new(source), data);
17598
17599        assert_eq!(parser.rule_stop_token_index(1, true), Some(1));
17600        assert_eq!(parser.rule_stop_token_index(1, false), Some(0));
17601    }
17602
17603    #[test]
17604    fn generated_parser_action_uses_current_rule_stop_boundary() {
17605        let mut parser = mini_parser(vec![
17606            TestToken::new(1).with_text("x"),
17607            TestToken::eof("parser-test", 1, 1, 1),
17608        ]);
17609
17610        parser.match_token(1).expect("token should match");
17611        let action = parser.parser_action_at_current(7, 0, 0, false);
17612        assert_eq!(action.source_state(), 7);
17613        assert_eq!(action.rule_index(), 0);
17614        assert_eq!(action.start_index(), 0);
17615        assert_eq!(action.stop_index(), Some(0));
17616
17617        parser.match_eof().expect("EOF should match");
17618        let action = parser.parser_action_at_current(8, 0, 0, true);
17619        assert_eq!(action.stop_index(), Some(1));
17620    }
17621
17622    #[test]
17623    fn folds_left_recursive_boundary_into_rule_node() {
17624        let mut arena = RecognitionArena::default();
17625        let first = arena.push_node(ArenaRecognizedNode::Token {
17626            token: TokenId::try_from(0).expect("test token ID"),
17627        });
17628        let boundary = arena.push_node(ArenaRecognizedNode::LeftRecursiveBoundary {
17629            rule_index: 1,
17630            alt_number: 3,
17631        });
17632        let second = arena.push_node(ArenaRecognizedNode::Token {
17633            token: TokenId::try_from(1).expect("test token ID"),
17634        });
17635        let mut nodes = NodeSeqId::EMPTY;
17636        for node in [first, boundary, second].into_iter().rev() {
17637            nodes = arena.prepend(nodes, node);
17638        }
17639
17640        let folded = arena.fold_left_recursive_boundaries(nodes);
17641        let folded_nodes = arena.iter(folded).collect::<Vec<_>>();
17642
17643        assert_eq!(folded_nodes.len(), 2);
17644        let ArenaRecognizedNode::Rule {
17645            rule_index,
17646            invoking_state,
17647            alt_number,
17648            start_index,
17649            stop_index,
17650            children,
17651            ..
17652        } = arena.node(folded_nodes[0])
17653        else {
17654            panic!("first folded node should be a rule");
17655        };
17656        assert_eq!(rule_index, 1);
17657        assert_eq!(invoking_state, -1);
17658        assert_eq!(alt_number, 3);
17659        assert_eq!(start_index, 0);
17660        assert_eq!(stop_index, Some(0));
17661        assert_eq!(arena.iter(children).collect::<Vec<_>>(), [first]);
17662        assert_eq!(arena.node(folded_nodes[1]), arena.node(second));
17663
17664        let stats = arena.stats(folded, DiagnosticSeqId::EMPTY);
17665        assert_eq!(
17666            (stats.total_nodes, stats.live_nodes, stats.dead_nodes),
17667            (4, 3, 1)
17668        );
17669        assert_eq!(
17670            (stats.total_links, stats.live_links, stats.dead_links),
17671            (9, 3, 6)
17672        );
17673    }
17674
17675    #[test]
17676    fn recognition_arena_reports_live_dead_and_retained_capacity() {
17677        let mut arena = RecognitionArena::default();
17678        let token = arena.push_node(ArenaRecognizedNode::Token {
17679            token: TokenId::try_from(0).expect("test token ID"),
17680        });
17681        let extra = arena.push_extra(RecognitionExtra::MissingToken {
17682            token_type: 2,
17683            at_index: 1,
17684            text: "<missing X>".to_owned(),
17685        });
17686        let missing = arena.push_node(ArenaRecognizedNode::MissingToken { extra });
17687        let discarded = arena.push_node(ArenaRecognizedNode::ErrorToken {
17688            token: TokenId::try_from(1).expect("test token ID"),
17689        });
17690        let mut live = NodeSeqId::EMPTY;
17691        live = arena.prepend(live, missing);
17692        live = arena.prepend(live, token);
17693        let _discarded_sequence = arena.prepend(NodeSeqId::EMPTY, discarded);
17694        let live_diagnostics = arena.diagnostic_sequence([ParserDiagnostic {
17695            line: 1,
17696            column: 0,
17697            message: "missing X".to_owned(),
17698        }]);
17699        let _discarded_diagnostics = arena.diagnostic_sequence([ParserDiagnostic {
17700            line: 1,
17701            column: 1,
17702            message: "discarded".to_owned(),
17703        }]);
17704        let deferred_children = arena.deferred_fragment(live);
17705        let _deferred_rule = arena.deferred_rule_node(FastDeferredRule {
17706            rule_index: 0,
17707            invoking_state: -1,
17708            start_index: 0,
17709            stop_index: Some(1),
17710            deferred_children,
17711            children: NodeSeqId::EMPTY,
17712        });
17713
17714        let stats = arena.stats(live, live_diagnostics);
17715
17716        assert_eq!(
17717            (stats.total_nodes, stats.live_nodes, stats.dead_nodes),
17718            (3, 2, 1)
17719        );
17720        assert_eq!(
17721            (stats.total_links, stats.live_links, stats.dead_links),
17722            (5, 3, 2)
17723        );
17724        assert_eq!(
17725            (stats.total_extras, stats.live_extras, stats.dead_extras),
17726            (3, 2, 1)
17727        );
17728        assert!(size_of::<SeqLink>() <= 8);
17729        assert!(size_of::<DiagnosticLink>() <= 8);
17730        assert!(size_of::<FastDeferredNode>() <= 12);
17731        assert!(size_of::<FastDeferredRule>() <= 28);
17732        assert!(size_of::<FastRecognizeOutcome>() <= 24);
17733        let capacities = (
17734            stats.node_capacity,
17735            stats.link_capacity,
17736            stats.extra_capacity,
17737        );
17738        let deferred_capacities = (
17739            arena.deferred_nodes.capacity(),
17740            arena.deferred_rules.capacity(),
17741        );
17742
17743        arena.reset();
17744        let reset = arena.stats(NodeSeqId::EMPTY, DiagnosticSeqId::EMPTY);
17745        assert_eq!(
17746            (reset.total_nodes, reset.total_links, reset.total_extras),
17747            (0, 0, 0)
17748        );
17749        assert_eq!(
17750            (
17751                reset.node_capacity,
17752                reset.link_capacity,
17753                reset.extra_capacity,
17754            ),
17755            capacities
17756        );
17757        assert!(arena.deferred_nodes.is_empty());
17758        assert!(arena.deferred_rules.is_empty());
17759        assert_eq!(
17760            (
17761                arena.deferred_nodes.capacity(),
17762                arena.deferred_rules.capacity(),
17763            ),
17764            deferred_capacities
17765        );
17766    }
17767
17768    #[test]
17769    fn parser_computes_recognition_arena_stats_on_demand() {
17770        let mut parser = mini_parser(Vec::new());
17771        let live = parser
17772            .recognition_arena
17773            .push_node(ArenaRecognizedNode::Token {
17774                token: TokenId::try_from(0).expect("test token ID"),
17775            });
17776        let discarded = parser
17777            .recognition_arena
17778            .push_node(ArenaRecognizedNode::ErrorToken {
17779                token: TokenId::try_from(1).expect("test token ID"),
17780            });
17781        let live_root = parser.recognition_arena.prepend(NodeSeqId::EMPTY, live);
17782        let _discarded_root = parser
17783            .recognition_arena
17784            .prepend(NodeSeqId::EMPTY, discarded);
17785        parser.finish_recognition_arena(live_root, DiagnosticSeqId::EMPTY);
17786
17787        let stats = parser.recognition_arena_stats();
17788
17789        assert_eq!(
17790            (stats.total_nodes, stats.live_nodes, stats.dead_nodes),
17791            (2, 1, 1)
17792        );
17793        assert_eq!(
17794            (stats.total_links, stats.live_links, stats.dead_links),
17795            (2, 1, 1)
17796        );
17797    }
17798
17799    #[test]
17800    fn recognition_arena_drops_capacity_above_retention_limit() {
17801        let mut storage = Vec::<u8>::with_capacity(4);
17802        storage.extend([1, 2, 3]);
17803
17804        reset_arena_vec(&mut storage, 3);
17805
17806        assert!(storage.is_empty());
17807        assert_eq!(storage.capacity(), 0);
17808    }
17809
17810    #[test]
17811    fn recognition_arena_concatenates_diagnostics_in_source_order() {
17812        let mut arena = RecognitionArena::default();
17813        let prefix = arena.diagnostic_sequence([
17814            ParserDiagnostic {
17815                line: 1,
17816                column: 0,
17817                message: "first".to_owned(),
17818            },
17819            ParserDiagnostic {
17820                line: 1,
17821                column: 1,
17822                message: "second".to_owned(),
17823            },
17824        ]);
17825        let suffix = arena.diagnostic_sequence([ParserDiagnostic {
17826            line: 1,
17827            column: 2,
17828            message: "third".to_owned(),
17829        }]);
17830        let extras_before = arena.extras.len();
17831
17832        let combined = arena.concat_diagnostics(prefix, suffix);
17833        let messages = arena
17834            .diagnostics(combined)
17835            .map(|diagnostic| diagnostic.message.as_str())
17836            .collect::<Vec<_>>();
17837
17838        assert_eq!(messages, ["first", "second", "third"]);
17839        assert_eq!(arena.extras.len(), extras_before);
17840    }
17841
17842    #[test]
17843    fn outcome_ties_keep_later_non_recursive_alternative() {
17844        let arena = RecognitionArena::default();
17845        let first = RecognizeOutcome {
17846            index: 1,
17847            consumed_eof: false,
17848            alt_number: 0,
17849            member_values: BTreeMap::new(),
17850            return_values: BTreeMap::new(),
17851            diagnostics: DiagnosticSeqId::EMPTY,
17852            decisions: Vec::new(),
17853            actions: vec![ParserAction::new(1, 0, 0, None)],
17854            nodes: NodeSeqId::EMPTY,
17855        };
17856        let second = RecognizeOutcome {
17857            actions: vec![ParserAction::new(2, 0, 0, None)],
17858            ..first.clone()
17859        };
17860
17861        let selected = select_best_outcome([first, second].into_iter(), PredictionMode::Ll, &arena)
17862            .expect("one outcome should be selected");
17863        assert_eq!(selected.actions[0].source_state(), 2);
17864    }
17865
17866    #[test]
17867    fn outcome_ties_prefer_more_actions_for_non_recursive_paths() {
17868        let arena = RecognitionArena::default();
17869        let first = RecognizeOutcome {
17870            index: 1,
17871            consumed_eof: false,
17872            alt_number: 0,
17873            member_values: BTreeMap::new(),
17874            return_values: BTreeMap::new(),
17875            diagnostics: DiagnosticSeqId::EMPTY,
17876            decisions: Vec::new(),
17877            actions: vec![ParserAction::new(1, 0, 0, None)],
17878            nodes: NodeSeqId::EMPTY,
17879        };
17880        let second = RecognizeOutcome {
17881            actions: vec![
17882                ParserAction::new(2, 0, 0, None),
17883                ParserAction::new(3, 0, 0, None),
17884            ],
17885            ..first.clone()
17886        };
17887
17888        let selected = select_best_outcome([second, first].into_iter(), PredictionMode::Ll, &arena)
17889            .expect("one outcome should be selected");
17890        assert_eq!(selected.actions.len(), 2);
17891    }
17892
17893    #[test]
17894    fn outcome_ties_prefer_later_action_stop_for_greedy_optional_paths() {
17895        let arena = RecognitionArena::default();
17896        let first = RecognizeOutcome {
17897            index: 7,
17898            consumed_eof: false,
17899            alt_number: 0,
17900            member_values: BTreeMap::new(),
17901            return_values: BTreeMap::new(),
17902            diagnostics: DiagnosticSeqId::EMPTY,
17903            decisions: vec![1, 0],
17904            actions: vec![
17905                ParserAction::new(23, 2, 2, Some(4)),
17906                ParserAction::new(23, 2, 0, Some(6)),
17907            ],
17908            nodes: NodeSeqId::EMPTY,
17909        };
17910        let second = RecognizeOutcome {
17911            decisions: vec![0, 1],
17912            actions: vec![
17913                ParserAction::new(23, 2, 2, Some(6)),
17914                ParserAction::new(23, 2, 0, Some(6)),
17915            ],
17916            ..first.clone()
17917        };
17918
17919        let selected = select_best_outcome([first, second].into_iter(), PredictionMode::Ll, &arena)
17920            .expect("one outcome should be selected");
17921        assert_eq!(selected.actions[0].stop_index(), Some(6));
17922    }
17923
17924    #[test]
17925    fn outcome_ties_keep_first_recursive_tree_shape() {
17926        let mut arena = RecognitionArena::default();
17927        let token = arena.push_node(ArenaRecognizedNode::Token {
17928            token: TokenId::try_from(0).expect("test token ID"),
17929        });
17930        let token_children = arena.prepend(NodeSeqId::EMPTY, token);
17931        let inner = arena.push_node(ArenaRecognizedNode::Rule {
17932            rule_index: 1,
17933            invoking_state: -1,
17934            alt_number: 0,
17935            start_index: 0,
17936            stop_index: Some(0),
17937            return_values: None,
17938            children: token_children,
17939        });
17940        let inner_children = arena.prepend(NodeSeqId::EMPTY, inner);
17941        let outer = arena.push_node(ArenaRecognizedNode::Rule {
17942            rule_index: 1,
17943            invoking_state: -1,
17944            alt_number: 0,
17945            start_index: 0,
17946            stop_index: Some(0),
17947            return_values: None,
17948            children: inner_children,
17949        });
17950        let recursive_nodes = arena.prepend(NodeSeqId::EMPTY, outer);
17951        let first = RecognizeOutcome {
17952            index: 1,
17953            consumed_eof: false,
17954            alt_number: 0,
17955            member_values: BTreeMap::new(),
17956            return_values: BTreeMap::new(),
17957            diagnostics: DiagnosticSeqId::EMPTY,
17958            decisions: Vec::new(),
17959            actions: vec![ParserAction::new(1, 0, 0, None)],
17960            nodes: recursive_nodes,
17961        };
17962        let second = RecognizeOutcome {
17963            index: 1,
17964            consumed_eof: false,
17965            alt_number: 0,
17966            member_values: BTreeMap::new(),
17967            return_values: BTreeMap::new(),
17968            diagnostics: DiagnosticSeqId::EMPTY,
17969            decisions: Vec::new(),
17970            actions: vec![ParserAction::new(2, 0, 0, None)],
17971            nodes: recursive_nodes,
17972        };
17973
17974        let selected = select_best_outcome([first, second].into_iter(), PredictionMode::Ll, &arena)
17975            .expect("one outcome should be selected");
17976        assert_eq!(selected.actions[0].source_state(), 1);
17977    }
17978
17979    #[test]
17980    fn sll_outcome_selection_keeps_earlier_recovered_alt() {
17981        let mut arena = RecognitionArena::default();
17982        let recovered_diagnostics = arena.diagnostic_sequence([ParserDiagnostic {
17983            line: 1,
17984            column: 3,
17985            message: "missing 'Y' at '<EOF>'".to_owned(),
17986        }]);
17987        let first_alt = RecognizeOutcome {
17988            index: 2,
17989            consumed_eof: true,
17990            alt_number: 0,
17991            member_values: BTreeMap::new(),
17992            return_values: BTreeMap::new(),
17993            diagnostics: recovered_diagnostics,
17994            decisions: vec![0],
17995            actions: vec![ParserAction::new(1, 0, 0, None)],
17996            nodes: NodeSeqId::EMPTY,
17997        };
17998        let second_alt = RecognizeOutcome {
17999            diagnostics: DiagnosticSeqId::EMPTY,
18000            decisions: vec![1],
18001            actions: vec![ParserAction::new(2, 0, 0, None)],
18002            ..first_alt.clone()
18003        };
18004
18005        let selected = select_best_outcome(
18006            [second_alt, first_alt].into_iter(),
18007            PredictionMode::Sll,
18008            &arena,
18009        )
18010        .expect("one outcome should be selected");
18011        assert_eq!(arena.diagnostics_len(selected.diagnostics), 1);
18012        assert_eq!(selected.decisions, [0]);
18013    }
18014}