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    ParserAtnSimulatorError, ParserSemanticCandidate,
79};
80use crate::atn::parser_atn::{
81    ParserAtn as Atn, ParserAtnState as AtnState, ParserIntervalSet, ParserTransition,
82    ParserTransitionData as Transition, ParserTransitionKind,
83};
84#[cfg(test)]
85use crate::atn::parser_atn::{ParserAtnBuilder, ParserTransitionSpec};
86use crate::char_stream::CharStream;
87use crate::errors::{AntlrError, SyntaxErrorEvent};
88use crate::int_stream::IntStream;
89use crate::lexer::{LexerCustomAction, LexerLifecycleCtx, LexerSemCtx};
90use crate::prediction::SemanticContext;
91use crate::recognizer::{Recognizer, RecognizerData};
92use crate::semir::{self, AStmt, ArithOp, CmpOp, ExprId, HookId, MemberEnv, PExpr, SemIr, StmtId};
93use crate::token::{
94    TOKEN_EOF, Token, TokenId, TokenSource, TokenSourceError, TokenSpec, TokenStore, TokenView,
95};
96use crate::token_stream::CommonTokenStream;
97use crate::tree::{
98    Node, NodeId, ParseTreeCheckpoint, ParseTreeStorage, ParsedFile, ParserRuleContext,
99};
100use crate::vocabulary::Vocabulary;
101
102type ParseTree = NodeId;
103
104/// Upper bound for the recursive metadata recognizer before it treats a path as
105/// non-viable. Long expression-regression descriptors legitimately walk tens
106/// of thousands of ATN edges.
107const RECOGNITION_DEPTH_LIMIT: usize = 32_768;
108/// Preserve the recursive hot path while checking native stack capacity often
109/// enough that one unchecked group cannot cross the protected red zone.
110const FAST_RECOGNIZE_STACK_CHECK_INTERVAL: usize = 8;
111const FAST_RECOGNIZE_RED_ZONE: usize = 1024 * 1024;
112const FAST_RECOGNIZE_STACK_SIZE: usize = 4 * 1024 * 1024;
113/// Generated recursive-descent rule methods map grammar-rule nesting onto
114/// native call depth. Their `_dispatch` boundary samples remaining stack
115/// capacity once per this many rule-context frames, so between two samples at
116/// most this many rule bodies of native growth can occur — far below the
117/// red zone.
118const GENERATED_RULE_STACK_CHECK_INTERVAL: usize = 8;
119/// Whole-rule direct adaptive execution is allowed to give up and fall back to
120/// the existing recognizer. Keep the guard at the same order of magnitude as
121/// speculative recognition so malformed cyclic ATNs cannot spin forever.
122const ADAPTIVE_DIRECT_STEP_LIMIT: usize = RECOGNITION_DEPTH_LIMIT;
123
124/// Runs a generated rule body after ensuring native stack capacity, growing
125/// onto a segmented stack when remaining capacity enters the red zone.
126///
127/// Generated `parse_generated_rule_*_dispatch` methods call this when
128/// [`BaseParser::generated_rule_stack_check_due`] fires so deeply nested input
129/// parses (or reports a syntax error) instead of aborting the process.
130pub fn grow_generated_rule_stack<R>(body: impl FnOnce() -> R) -> R {
131    stacker::maybe_grow(FAST_RECOGNIZE_RED_ZONE, FAST_RECOGNIZE_STACK_SIZE, body)
132}
133
134/// Shared lifecycle and recovery shell for generated parser rules.
135///
136/// This is an implementation detail of `antlr4-rust-gen`, not a stable
137/// hand-written parser API. The binders supplied by generated code keep
138/// grammar-specific locals and steps inline while this macro owns the fixed
139/// dispatch, entry, recovery, and exit state machine.
140#[doc(hidden)]
141#[macro_export]
142macro_rules! __antlr4_rust_generated_rule {
143    (
144        dispatch $parser:ident, $rule:expr, $fatal:path;
145        $body:expr
146    ) => {{
147        if let Some(error) = $parser.base.rule_depth_cap_violation() {
148            return Err($fatal(error));
149        }
150        if let Some(error) = $parser.base.parse_listener_enter_rule($rule) {
151            return Err($fatal(error));
152        }
153        let __listener_result = if $parser.base.generated_rule_stack_check_due() {
154            $crate::grow_generated_rule_stack(|| $body)
155        } else {
156            $body
157        };
158        $parser.base.parse_listener_exit_rule($rule);
159        __listener_result
160    }};
161    (
162        ordinary $parser:ident, $state:expr, $rule:expr, $allow_fallback:expr,
163        $atn:expr, $fatal:path;
164        retry [$($retry:tt)*];
165        bind ($ctx:ident, $rule_start:ident, $consumed_eof:ident, $sync_error:ident);
166        setup { $($setup:tt)* }
167        body { $($body:tt)* }
168        success { $($success:tt)* }
169        recovery { $($recovery:tt)* }
170    ) => {
171        $crate::__antlr4_rust_generated_rule! {
172            @body
173            parser $parser;
174            enter $parser.base.enter_rule($state, $rule);
175            finish finish_rule;
176            abort exit_rule;
177            allow_fallback $allow_fallback;
178            atn $atn;
179            fatal $fatal;
180            retry [$($retry)*];
181            bind ($ctx, $rule_start, $consumed_eof, $sync_error);
182            setup { $($setup)* }
183            body { $($body)* }
184            success { $($success)* }
185            recovery { $($recovery)* }
186        }
187    };
188    (
189        recursive $parser:ident, $state:expr, $rule:expr, $precedence:expr,
190        $allow_fallback:expr, $atn:expr, $fatal:path;
191        retry [$($retry:tt)*];
192        bind ($ctx:ident, $rule_start:ident, $consumed_eof:ident, $sync_error:ident);
193        setup { $($setup:tt)* }
194        body { $($body:tt)* }
195        success { $($success:tt)* }
196        recovery { $($recovery:tt)* }
197    ) => {
198        $crate::__antlr4_rust_generated_rule! {
199            @body
200            parser $parser;
201            enter $parser.base.enter_recursion_rule($state, $rule, $precedence);
202            finish finish_recursion_rule;
203            abort unroll_recursion_context;
204            allow_fallback $allow_fallback;
205            atn $atn;
206            fatal $fatal;
207            retry [$($retry)*];
208            bind ($ctx, $rule_start, $consumed_eof, $sync_error);
209            setup { $($setup)* }
210            body { $($body)* }
211            success { $($success)* }
212            recovery { $($recovery)* }
213        }
214    };
215    (
216        @body
217        parser $parser:ident;
218        enter $enter:expr;
219        finish $finish:ident;
220        abort $abort:ident;
221        allow_fallback $allow_fallback:expr;
222        atn $atn:expr;
223        fatal $fatal:path;
224        retry [$($retry:tt)*];
225        bind ($ctx:ident, $rule_start:ident, $consumed_eof:ident, $sync_error:ident);
226        setup { $($setup:tt)* }
227        body { $($body:tt)* }
228        success { $($success:tt)* }
229        recovery { $($recovery:tt)* }
230    ) => {{
231        let __generated_diagnostic_marker =
232            $parser.base.generated_diagnostics_checkpoint();
233        let mut $ctx = $enter;
234        let $rule_start = $crate::IntStream::index($parser.base.input());
235        $($setup)*
236        let mut $consumed_eof = false;
237        let mut $sync_error: Option<$crate::AntlrError> = None;
238        // The body has its own Result boundary: `?` and `return` exit only this
239        // closure, with errors entering recovery. Parser borrows must not escape it.
240        let __result = (|| -> Result<(), $crate::AntlrError> {
241            $($body)*
242            Ok(())
243        })();
244        match __result {
245            Ok(()) => {
246                $($success)*
247                let __tree = $parser.base.$finish($ctx, $consumed_eof);
248                Ok(__tree)
249            }
250            Err(__error) => {
251                $crate::__antlr4_rust_generated_rule! {
252                    @retry
253                    [$($retry)*]
254                    parser $parser;
255                    marker __generated_diagnostic_marker;
256                    abort $abort;
257                }
258                let __error = if let Some(__sync_error) = $sync_error {
259                    if $allow_fallback {
260                        $parser.base.$abort();
261                        $parser
262                            .base
263                            .rollback_generated_tree(__generated_diagnostic_marker);
264                        $parser.base.record_generated_syntax_error();
265                        return Err($fatal(__sync_error));
266                    }
267                    __sync_error
268                } else {
269                    __error
270                };
271                $parser
272                    .base
273                    .recover_generated_rule(&mut $ctx, $atn, __error);
274                $($recovery)*
275                let __tree = $parser.base.$finish($ctx, $consumed_eof);
276                Ok(__tree)
277            }
278        }
279    }};
280    (
281        @retry
282        [none]
283        parser $parser:ident;
284        marker $marker:ident;
285        abort $abort:ident;
286    ) => {};
287    (
288        @retry
289        [$condition:expr => $retry_error:expr]
290        parser $parser:ident;
291        marker $marker:ident;
292        abort $abort:ident;
293    ) => {
294        if $condition {
295            $parser.base.$abort();
296            $parser.base.restore_generated_diagnostics($marker);
297            return Err($retry_error);
298        }
299    };
300}
301
302/// Receives committed rule enter/exit events during recognition, matching
303/// ANTLR's `addParseListener` contract ([`Parser::add_parse_listener`],
304/// also inherent on [`BaseParser`] and generated parsers).
305///
306/// Events fire on the generated recursive-descent path as rules are entered
307/// and exited, with left-recursive operator loops following upstream's
308/// timing exactly: each loop pass first exits the outgoing iteration
309/// (`recRuleSetPrevCtx`) and then enters the new expansion
310/// (`pushNewRecursionContext` firing `triggerEnterRuleEvent`), so live
311/// listener depth never accumulates across a flat operator chain —
312/// `a + a + … + a` peaks at depth 2 like every ANTLR target. On expansion
313/// events, [`EnterRuleEvent::current`] anchors at the operator-side
314/// lookahead (the token the expansion starts at), whereas Java's
315/// `ctx.start` reaches back to the whole expression's first token — anchor
316/// diagnostics accordingly. Enter events fire in registration order and
317/// exit events in reverse registration order, matching upstream. Enter/exit
318/// calls balance on every completed path, including error recovery and
319/// aborts inside operator loops — with one exception shared with Java: an
320/// ordinary rule's enter that returns `Err` receives no matching exit
321/// (upstream calls `enterRule` outside the generated `try`/`finally`, so a
322/// throwing listener skips `exitRule` the same way). Listener state shared
323/// across parses via `Arc` should be reset after an abort (the unmatched
324/// ordinary-rule enter leaves counters one high).
325///
326/// Divergence from Java to know about: upstream generated rule methods run
327/// only on the committed parse, while this runtime may re-enter a rule while
328/// recovering from a syntax error — such retries deliver additional balanced
329/// enter/exit pairs. Depth counters and resource bounds (the primary use
330/// case) are unaffected; exact once-per-node collectors should prefer the
331/// post-parse tree walker.
332///
333/// `enter_every_rule` is fallible: returning `Err` aborts the parse with
334/// that error. The abort is sticky through rule-level recovery — the parse
335/// fails even when recovery could have produced a tree, mirroring how a
336/// thrown exception escapes ANTLR's `triggerEnterRuleEvent`. Rules the
337/// generator emitted no body for (interpreter-only fallback) do not fire
338/// events; when any parse listener is registered, generated dispatch routes
339/// ATN-preferred rules through their generated bodies so real grammars
340/// observe every rule.
341///
342/// Cost: with no listener registered, dispatch pays one emptiness check per
343/// rule boundary (benchmarked at baseline). With one registered, dispatch
344/// itself is a few percent; on grammars where the generator classified rules
345/// ATN-preferred, the dominant cost is the routing override above — the same
346/// one [`Parser::set_max_rule_depth`] takes — which trades that fast path
347/// for observability. Grammars without ATN-preferred rules (most small DSLs)
348/// pay only the dispatch.
349pub trait ParseListener: Send {
350    /// Called when a generated rule is entered, before its body runs, and
351    /// once per left-recursive operator expansion.
352    ///
353    /// Returning `Err` aborts the parse with the given error.
354    fn enter_every_rule(&mut self, event: &EnterRuleEvent<'_>) -> Result<(), AntlrError>;
355
356    /// Called when a generated rule exits, after its body (and any rule-level
357    /// error recovery) finished, and once per left-recursive operator
358    /// expansion as the rule unrolls.
359    fn exit_every_rule(&mut self, rule_index: usize) {
360        let _ = rule_index;
361    }
362}
363
364/// Boxed listeners forward to their inner implementation, so the boxes
365/// returned by [`Parser::remove_parse_listeners`] can be re-registered
366/// through [`Parser::add_parse_listener`] unchanged.
367impl<T: ParseListener + ?Sized> ParseListener for Box<T> {
368    fn enter_every_rule(&mut self, event: &EnterRuleEvent<'_>) -> Result<(), AntlrError> {
369        (**self).enter_every_rule(event)
370    }
371
372    fn exit_every_rule(&mut self, rule_index: usize) {
373        (**self).exit_every_rule(rule_index);
374    }
375}
376
377/// A rule-entry event delivered to [`ParseListener::enter_every_rule`].
378///
379/// Non-exhaustive so future fields (alt number, invoking state, a context
380/// handle) extend the event without breaking implementors.
381#[derive(Debug)]
382#[non_exhaustive]
383pub struct EnterRuleEvent<'a> {
384    /// Index of the rule being entered (compare against the generated
385    /// `RULE_*` constants).
386    pub rule_index: usize,
387    /// The lookahead token the rule starts at — its line/column/offsets
388    /// anchor listener diagnostics — or `None` at end of input.
389    pub current: Option<TokenView<'a>>,
390}
391
392struct ParseListenerSlot(Box<dyn ParseListener>);
393
394impl std::fmt::Debug for ParseListenerSlot {
395    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
396        f.write_str("ParseListener")
397    }
398}
399/// Probe window for deciding whether clean-pass memo entries are reusable
400/// enough to keep caching. High-cardinality parses mostly produce one-shot
401/// entries; compact ambiguous loops repeatedly hit the same keys.
402const CLEAN_MEMO_PROBE_LIMIT: usize = 4096;
403const CLEAN_MEMO_REPEAT_LIMIT: usize = 8;
404/// Sparse parses periodically reopen the bounded probe so a repeat-heavy
405/// region that starts later in the token stream can promote memoization.
406const CLEAN_MEMO_REPROBE_INTERVAL: usize = 262_144;
407const FAST_RECOGNIZE_VISITING_CAPACITY: usize = 256;
408const FAST_RECOGNIZE_MIN_MEMO_CAPACITY: usize = 256;
409const FAST_RECOGNIZE_MAX_MEMO_CAPACITY: usize = 524_288;
410const FAST_RECOGNIZE_MAX_RETAINED_MEMO_CAPACITY: usize = 65_536;
411
412#[derive(Clone, Copy, Debug, Eq, PartialEq)]
413enum CleanMemoMode {
414    Probe,
415    Promote,
416    Sparse,
417}
418
419fn interval_set_contains(intervals: &[(i32, i32)], symbol: i32) -> bool {
420    intervals
421        .iter()
422        .any(|(start, stop)| (*start..=*stop).contains(&symbol))
423}
424
425fn interval_symbols(intervals: &[(i32, i32)]) -> BTreeSet<i32> {
426    let mut symbols = BTreeSet::new();
427    for (start, stop) in intervals {
428        symbols.extend(*start..=*stop);
429    }
430    symbols
431}
432
433fn interval_complement_symbols(
434    intervals: &[(i32, i32)],
435    min_vocabulary: i32,
436    max_vocabulary: i32,
437) -> BTreeSet<i32> {
438    (min_vocabulary..=max_vocabulary)
439        .filter(|symbol| !interval_set_contains(intervals, *symbol))
440        .collect()
441}
442
443#[cfg(feature = "perf-counters")]
444mod perf_counters {
445    use std::cell::Cell;
446    thread_local! {
447        pub(super) static RFS_CALLS: Cell<u64> = const { Cell::new(0) };
448        pub(super) static RFS_MEMO_HITS: Cell<u64> = const { Cell::new(0) };
449        pub(super) static RFS_MEMO_MISSES: Cell<u64> = const { Cell::new(0) };
450        pub(super) static RFS_VISITING_CYCLE: Cell<u64> = const { Cell::new(0) };
451        pub(super) static MEMO_INSERTED: Cell<u64> = const { Cell::new(0) };
452        pub(super) static OUTCOMES_PUSHED: Cell<u64> = const { Cell::new(0) };
453        pub(super) static OUTCOMES_CLONED: Cell<u64> = const { Cell::new(0) };
454        pub(super) static OUTCOME_DEDUPE_INPUTS: Cell<u64> = const { Cell::new(0) };
455        pub(super) static OUTCOME_DEDUPE_REMOVED: Cell<u64> = const { Cell::new(0) };
456        pub(super) static OUTCOME_DEDUPE_INLINE: Cell<u64> = const { Cell::new(0) };
457        pub(super) static OUTCOME_DEDUPE_DENSE: Cell<u64> = const { Cell::new(0) };
458        pub(super) static OUTCOME_DEDUPE_SPARSE: Cell<u64> = const { Cell::new(0) };
459        pub(super) static OUTCOME_DEDUPE_DENSE_WORDS: Cell<u64> = const { Cell::new(0) };
460    }
461    pub(super) fn inc(c: &'static std::thread::LocalKey<Cell<u64>>, n: u64) {
462        c.with(|v| v.set(v.get() + n));
463    }
464    thread_local! {
465        pub(super) static EPSILON_TRANSITIONS: Cell<u64> = const { Cell::new(0) };
466        pub(super) static RULE_TRANSITIONS: Cell<u64> = const { Cell::new(0) };
467        pub(super) static ATOM_RANGE_TRANSITIONS: Cell<u64> = const { Cell::new(0) };
468        pub(super) static SINGLE_TRANS_BODY: Cell<u64> = const { Cell::new(0) };
469        pub(super) static MULTI_TRANS_BODY: Cell<u64> = const { Cell::new(0) };
470        pub(super) static SINGLE_TRANS_RULE: Cell<u64> = const { Cell::new(0) };
471        pub(super) static SINGLE_TRANS_ATOM: Cell<u64> = const { Cell::new(0) };
472        pub(super) static SINGLE_TRANS_OTHER: Cell<u64> = const { Cell::new(0) };
473        pub(super) static OUTCOMES_RETURN_0: Cell<u64> = const { Cell::new(0) };
474        pub(super) static OUTCOMES_RETURN_1: Cell<u64> = const { Cell::new(0) };
475        pub(super) static OUTCOMES_RETURN_N: Cell<u64> = const { Cell::new(0) };
476    }
477    pub(super) fn snapshot() -> [(&'static str, u64); 24] {
478        [
479            ("rfs_calls", RFS_CALLS.with(Cell::get)),
480            ("rfs_memo_hits", RFS_MEMO_HITS.with(Cell::get)),
481            ("rfs_memo_misses", RFS_MEMO_MISSES.with(Cell::get)),
482            ("rfs_visiting_cycle", RFS_VISITING_CYCLE.with(Cell::get)),
483            ("memo_inserted", MEMO_INSERTED.with(Cell::get)),
484            ("outcomes_pushed", OUTCOMES_PUSHED.with(Cell::get)),
485            ("outcomes_cloned", OUTCOMES_CLONED.with(Cell::get)),
486            (
487                "outcome_dedupe_inputs",
488                OUTCOME_DEDUPE_INPUTS.with(Cell::get),
489            ),
490            (
491                "outcome_dedupe_removed",
492                OUTCOME_DEDUPE_REMOVED.with(Cell::get),
493            ),
494            (
495                "outcome_dedupe_inline",
496                OUTCOME_DEDUPE_INLINE.with(Cell::get),
497            ),
498            ("outcome_dedupe_dense", OUTCOME_DEDUPE_DENSE.with(Cell::get)),
499            (
500                "outcome_dedupe_sparse",
501                OUTCOME_DEDUPE_SPARSE.with(Cell::get),
502            ),
503            (
504                "outcome_dedupe_dense_words",
505                OUTCOME_DEDUPE_DENSE_WORDS.with(Cell::get),
506            ),
507            ("epsilon_transitions", EPSILON_TRANSITIONS.with(Cell::get)),
508            ("rule_transitions", RULE_TRANSITIONS.with(Cell::get)),
509            (
510                "atom_range_transitions",
511                ATOM_RANGE_TRANSITIONS.with(Cell::get),
512            ),
513            ("single_trans_body", SINGLE_TRANS_BODY.with(Cell::get)),
514            ("multi_trans_body", MULTI_TRANS_BODY.with(Cell::get)),
515            ("single_trans_rule", SINGLE_TRANS_RULE.with(Cell::get)),
516            ("single_trans_atom", SINGLE_TRANS_ATOM.with(Cell::get)),
517            ("single_trans_other", SINGLE_TRANS_OTHER.with(Cell::get)),
518            ("outcomes_return_0", OUTCOMES_RETURN_0.with(Cell::get)),
519            ("outcomes_return_1", OUTCOMES_RETURN_1.with(Cell::get)),
520            ("outcomes_return_n", OUTCOMES_RETURN_N.with(Cell::get)),
521        ]
522    }
523    pub fn reset() {
524        RFS_CALLS.with(|c| c.set(0));
525        RFS_MEMO_HITS.with(|c| c.set(0));
526        RFS_MEMO_MISSES.with(|c| c.set(0));
527        RFS_VISITING_CYCLE.with(|c| c.set(0));
528        MEMO_INSERTED.with(|c| c.set(0));
529        OUTCOMES_PUSHED.with(|c| c.set(0));
530        OUTCOMES_CLONED.with(|c| c.set(0));
531        OUTCOME_DEDUPE_INPUTS.with(|c| c.set(0));
532        OUTCOME_DEDUPE_REMOVED.with(|c| c.set(0));
533        OUTCOME_DEDUPE_INLINE.with(|c| c.set(0));
534        OUTCOME_DEDUPE_DENSE.with(|c| c.set(0));
535        OUTCOME_DEDUPE_SPARSE.with(|c| c.set(0));
536        OUTCOME_DEDUPE_DENSE_WORDS.with(|c| c.set(0));
537        EPSILON_TRANSITIONS.with(|c| c.set(0));
538        RULE_TRANSITIONS.with(|c| c.set(0));
539        ATOM_RANGE_TRANSITIONS.with(|c| c.set(0));
540        SINGLE_TRANS_BODY.with(|c| c.set(0));
541        MULTI_TRANS_BODY.with(|c| c.set(0));
542        SINGLE_TRANS_RULE.with(|c| c.set(0));
543        SINGLE_TRANS_ATOM.with(|c| c.set(0));
544        SINGLE_TRANS_OTHER.with(|c| c.set(0));
545        OUTCOMES_RETURN_0.with(|c| c.set(0));
546        OUTCOMES_RETURN_1.with(|c| c.set(0));
547        OUTCOMES_RETURN_N.with(|c| c.set(0));
548    }
549    pub fn dump() {
550        for (name, value) in snapshot() {
551            #[allow(clippy::print_stderr)]
552            {
553                eprintln!("perf {name}={value}");
554            }
555        }
556    }
557}
558
559#[cfg(feature = "perf-counters")]
560pub use perf_counters::{dump as dump_perf_counters, reset as reset_perf_counters};
561/// Preserve lazy lexing for short or failing inputs, but eagerly fill once the
562/// fast recognizer has probed far enough that per-token stream sync dominates.
563/// Sixty-four tokens is a small rule-sized window: it keeps startup lazy while
564/// switching long inputs to the cheaper filled-stream path before large fanout.
565const FAST_RECOGNIZER_DEFERRED_FILL_AT: usize = 64;
566/// Parser semantic action reached while recognizing one ATN path.
567///
568/// Generated parsers use `source_state` to dispatch back to the grammar action
569/// rendered for that ATN action transition. The token interval is the current
570/// rule's input span at the action site, which covers common target templates
571/// such as `$text`. Rule-init actions do not have an ATN action source state,
572/// so they are marked separately and may carry an ATN state for expected-token
573/// rendering.
574#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
575pub struct ParserAction {
576    source_state: usize,
577    rule_index: usize,
578    action_index: Option<usize>,
579    start_index: usize,
580    stop_index: Option<usize>,
581    rule_init: bool,
582    expected_state: Option<usize>,
583}
584
585impl ParserAction {
586    /// Creates an action event for a recognized parser path.
587    pub const fn new(
588        source_state: usize,
589        rule_index: usize,
590        start_index: usize,
591        stop_index: Option<usize>,
592    ) -> Self {
593        Self {
594            source_state,
595            rule_index,
596            action_index: None,
597            start_index,
598            stop_index,
599            rule_init: false,
600            expected_state: None,
601        }
602    }
603
604    /// Creates an indexed action event for a recognized parser path.
605    pub const fn new_indexed(
606        source_state: usize,
607        rule_index: usize,
608        action_index: usize,
609        start_index: usize,
610        stop_index: Option<usize>,
611    ) -> Self {
612        Self {
613            source_state,
614            rule_index,
615            action_index: Some(action_index),
616            start_index,
617            stop_index,
618            rule_init: false,
619            expected_state: None,
620        }
621    }
622
623    /// Creates an action event for a rule-level `@init` action.
624    pub const fn new_rule_init(
625        rule_index: usize,
626        start_index: usize,
627        expected_state: Option<usize>,
628    ) -> Self {
629        Self {
630            source_state: usize::MAX,
631            rule_index,
632            action_index: None,
633            start_index,
634            stop_index: None,
635            rule_init: true,
636            expected_state,
637        }
638    }
639
640    /// ATN state that owns the semantic-action transition.
641    pub const fn source_state(&self) -> usize {
642        self.source_state
643    }
644
645    /// Grammar rule index recorded by the serialized ATN action transition.
646    pub const fn rule_index(&self) -> usize {
647        self.rule_index
648    }
649
650    /// Stable source-order action index in the grammar.
651    pub const fn action_index(&self) -> Option<usize> {
652        self.action_index
653    }
654
655    /// Token-stream index where the active rule began.
656    pub const fn start_index(&self) -> usize {
657        self.start_index
658    }
659
660    /// Last token-stream index consumed before the action was reached.
661    pub const fn stop_index(&self) -> Option<usize> {
662        self.stop_index
663    }
664
665    /// Reports whether this event represents a rule-level `@init` action.
666    pub const fn is_rule_init(&self) -> bool {
667        self.rule_init
668    }
669
670    /// ATN state used to compute expected-token display for this action.
671    pub const fn expected_state(&self) -> Option<usize> {
672        self.expected_state
673    }
674}
675
676/// Runtime view passed to parser semantic hooks.
677///
678/// The context is intentionally read-only with respect to parser structure:
679/// predicates may run speculatively during prediction, and hooks can be called
680/// more than once for paths that are later abandoned. Lookahead methods may
681/// buffer tokens from the underlying token source, matching normal parser
682/// prediction behavior.
683pub struct ParserSemCtx<'a, S>
684where
685    S: TokenSource,
686{
687    input: &'a mut CommonTokenStream<S>,
688    tree_storage: &'a ParseTreeStorage,
689    rule_index: usize,
690    coordinate_index: usize,
691    rule_name: Option<String>,
692    context: Option<&'a ParserRuleContext>,
693    tree: Option<ParseTree>,
694    local_int_arg: Option<(usize, i64)>,
695    member_values: &'a MemberEnv,
696    action: Option<ParserAction>,
697}
698
699impl<S> std::fmt::Debug for ParserSemCtx<'_, S>
700where
701    S: TokenSource,
702{
703    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
704        f.debug_struct("ParserSemCtx")
705            .field("rule_index", &self.rule_index)
706            .field("coordinate_index", &self.coordinate_index)
707            .field("rule_name", &self.rule_name)
708            .field("context", &self.context)
709            .field("tree", &self.tree)
710            .field("local_int_arg", &self.local_int_arg)
711            .field("member_values", &self.member_values)
712            .field("action", &self.action)
713            .finish_non_exhaustive()
714    }
715}
716
717impl<'a, S> ParserSemCtx<'a, S>
718where
719    S: TokenSource,
720{
721    /// Rule index that owns the predicate/action coordinate.
722    #[must_use]
723    pub const fn rule_index(&self) -> usize {
724        self.rule_index
725    }
726
727    /// Rule name that owns the coordinate, when recognizer metadata has it.
728    #[must_use]
729    pub fn rule_name(&self) -> Option<&str> {
730        self.rule_name.as_deref()
731    }
732
733    /// Predicate/action index inside the owning rule. Legacy parser actions
734    /// without source-index metadata report `usize::MAX`.
735    #[must_use]
736    pub const fn coordinate_index(&self) -> usize {
737        self.coordinate_index
738    }
739
740    /// Current token-stream index.
741    #[must_use]
742    pub fn input_index(&self) -> usize {
743        self.input.index()
744    }
745
746    /// Token type at one-based lookahead/lookbehind offset.
747    pub fn la(&mut self, offset: isize) -> i32 {
748        self.input.la(offset)
749    }
750
751    /// Token at one-based lookahead/lookbehind offset.
752    pub fn lt(&self, offset: isize) -> Option<TokenView<'_>> {
753        self.input.lt(offset)
754    }
755
756    /// Borrowing token view for text inspection at a one-based offset.
757    pub fn token_text(&self, offset: isize) -> Option<TokenView<'_>> {
758        self.lt(offset)
759    }
760
761    /// Token at an absolute buffered index, including hidden/custom channels.
762    ///
763    /// Unlike [`Self::lt`], this does not apply the token stream's channel
764    /// filter and does not move its cursor. It is intended for semantic helpers
765    /// such as automatic-semicolon-insertion checks that inspect trivia
766    /// immediately before the current visible token.
767    pub fn token_at(&self, index: usize) -> Option<TokenView<'_>> {
768        self.input.get(index)
769    }
770
771    /// Current generated rule context, when a generated rule predicate supplied
772    /// one.
773    #[must_use]
774    pub const fn context(&self) -> Option<&'a ParserRuleContext> {
775        self.context
776    }
777
778    /// Flat tree storage containing completed children visible to this hook.
779    #[must_use]
780    pub const fn parse_tree_storage(&self) -> &'a ParseTreeStorage {
781        self.tree_storage
782    }
783
784    /// Canonical token store used by completed flat-tree nodes.
785    #[must_use]
786    pub const fn token_store(&self) -> &TokenStore {
787        self.input.token_store()
788    }
789
790    /// Completed parse-tree root ID passed to a replayed action hook.
791    #[must_use]
792    pub const fn tree_id(&self) -> Option<NodeId> {
793        self.tree
794    }
795
796    /// Completed parse tree passed to an action hook, if the action is being
797    /// replayed after recognition.
798    #[must_use]
799    pub fn tree(&self) -> Option<Node<'_>> {
800        self.tree
801            .and_then(|id| self.tree_storage.node(self.input.token_store(), id))
802    }
803
804    /// Integer local argument visible to this predicate coordinate.
805    #[must_use]
806    pub fn local_int_arg(&self) -> Option<i64> {
807        self.local_int_arg.map(|(_, value)| value)
808    }
809
810    /// Integer member value observed on the current speculative path.
811    #[must_use]
812    pub fn member_int(&self, member: usize) -> Option<i64> {
813        self.member_values.scalar(member)
814    }
815
816    /// Top of a stack-valued member slot on the current speculative path;
817    /// `None` when the stack is empty or was never pushed.
818    #[must_use]
819    pub fn member_stack_top(&self, member: usize) -> Option<i64> {
820        self.member_values.stack_top(member)
821    }
822
823    /// Depth of a stack-valued member slot on the current speculative path.
824    #[must_use]
825    pub fn member_stack_len(&self, member: usize) -> usize {
826        self.member_values.stack_len(member)
827    }
828
829    /// Parser action event being replayed, when this context belongs to an
830    /// action hook.
831    #[must_use]
832    pub const fn action(&self) -> Option<ParserAction> {
833        self.action
834    }
835
836    /// Text covered by a parser action event.
837    ///
838    /// Mirrors [`BaseParser::text_interval`] / `$text`: when the stop token is
839    /// EOF the interval ends at the previous *visible* token, so trailing hidden
840    /// tokens (and the EOF marker) are excluded rather than blindly subtracting
841    /// one, which could point at hidden whitespace. `CommonTokenStream::text`
842    /// itself guards `start > stop`, so an empty interval yields `""`.
843    pub fn action_text(&self) -> String {
844        let Some(action) = self.action else {
845            return String::new();
846        };
847        let Some(stop) = action.stop_index() else {
848            return String::new();
849        };
850        let stop = if self
851            .input
852            .get(stop)
853            .is_some_and(|token| token.token_type() == TOKEN_EOF)
854        {
855            let Some(previous) = self.input.previous_visible_token_index(stop) else {
856                return String::new();
857            };
858            previous
859        } else {
860            stop
861        };
862        self.input.text(action.start_index(), stop)
863    }
864}
865
866/// User extension point for parser semantic predicates and actions that the
867/// metadata generator did not translate into built-in runtime metadata.
868///
869/// Returning `None`/`false` says "not handled", so the runtime falls through
870/// to the configured [`UnknownSemanticPolicy`]. Predicate hooks may run during
871/// speculative prediction and must be replay-safe.
872pub trait SemanticHooks {
873    /// Whether generated lexers should route lifecycle callbacks through this
874    /// hook object.
875    ///
876    /// User hook implementations opt in by default. [`NoSemanticHooks`]
877    /// overrides this to keep generated lexers on the direct no-extension
878    /// token path.
879    const ENABLES_LEXER_LIFECYCLE: bool = true;
880
881    /// Whether this hook object may observe parser predicate transitions.
882    ///
883    /// Custom hooks default to conservative predicate handling so the fast
884    /// recognizer does not bypass a `sempred` implementation.
885    fn observes_parser_predicates(&self) -> bool {
886        true
887    }
888
889    /// Whether this hook object may override interpreted parser decisions.
890    ///
891    /// This remains disabled by default so ordinary generated parsers retain
892    /// the fast recognizer path.
893    fn observes_parser_decisions(&self) -> bool {
894        false
895    }
896
897    /// Overrides one interpreted parser decision with a one-based alternative.
898    ///
899    /// Returning `None` leaves normal adaptive prediction in control. Hooks
900    /// that return an alternative own any one-shot or input-index filtering
901    /// they require.
902    fn parser_decision_override(
903        &mut self,
904        decision: usize,
905        input_index: usize,
906        alternative_count: usize,
907    ) -> Option<usize> {
908        let _ = (decision, input_index, alternative_count);
909        None
910    }
911
912    fn sempred<S>(
913        &mut self,
914        ctx: &mut ParserSemCtx<'_, S>,
915        rule_index: usize,
916        pred_index: usize,
917    ) -> Option<bool>
918    where
919        S: TokenSource,
920    {
921        let _ = (ctx, rule_index, pred_index);
922        None
923    }
924
925    fn action<S>(&mut self, ctx: &mut ParserSemCtx<'_, S>, action: ParserAction) -> bool
926    where
927        S: TokenSource,
928    {
929        let _ = (ctx, action);
930        false
931    }
932
933    fn lexer_sempred<I>(
934        &mut self,
935        ctx: &mut LexerSemCtx<'_, I>,
936        rule_index: usize,
937        pred_index: usize,
938    ) -> Option<bool>
939    where
940        I: CharStream,
941    {
942        let _ = (ctx, rule_index, pred_index);
943        None
944    }
945
946    /// Runs a lexer custom action on the committed lexing path. Returns whether
947    /// the hook handled the action.
948    ///
949    /// The action runs post-accept, so `ctx` carries a mutable lexer borrow: a
950    /// hook may change lexer state, including [`LexerSemCtx::set_type`],
951    /// [`LexerSemCtx::set_channel`], mode changes, input consumption, and
952    /// queued prefix tokens, just like the closure-based `custom_action` API.
953    /// (The speculative predicate context in [`Self::lexer_sempred`] is a shared
954    /// borrow, so those mutators are inert there.)
955    fn lexer_action<I>(&mut self, ctx: &mut LexerSemCtx<'_, I>, action: LexerCustomAction) -> bool
956    where
957        I: CharStream,
958    {
959        let _ = (ctx, action);
960        false
961    }
962
963    /// Runs after runtime-owned lexer state has been reset for reuse.
964    ///
965    /// Implementations should clear extension-owned transient state here.
966    fn lexer_reset<I>(&mut self, ctx: &mut LexerLifecycleCtx<'_, I>)
967    where
968        I: CharStream,
969    {
970        let _ = ctx;
971    }
972
973    /// Runs before the runtime returns a queued token or starts a new ATN
974    /// token match.
975    ///
976    /// The callback also runs between internal `skip`/`more` matches, so it
977    /// observes every point where another ATN match may start.
978    fn lexer_before_token<I>(&mut self, ctx: &mut LexerLifecycleCtx<'_, I>)
979    where
980        I: CharStream,
981    {
982        let _ = ctx;
983    }
984
985    /// Runs after the accepted path's portable and custom actions, but before
986    /// the token span is finalized and emitted.
987    ///
988    /// Accepted paths that selected `skip` or `more` are included, and the hook
989    /// may observe or override that pending token type.
990    ///
991    /// This callback has no synthetic ATN coordinate. It therefore also runs
992    /// for accepted rules that contain no action or predicate.
993    fn lexer_after_accept<I>(&mut self, ctx: &mut LexerLifecycleCtx<'_, I>)
994    where
995        I: CharStream,
996    {
997        let _ = ctx;
998    }
999
1000    /// Observes a token after committed lexer actions and portable commands
1001    /// have run and the token has been emitted, immediately before it is
1002    /// returned to the token stream.
1003    ///
1004    /// Hidden and custom-channel tokens are included. `skip` and intermediate
1005    /// `more` matches do not produce callbacks.
1006    fn lexer_token_emitted(&mut self, token: TokenView<'_>) {
1007        let _ = token;
1008    }
1009}
1010
1011/// Default hook object used by parsers that do not need user-supplied
1012/// semantics.
1013#[derive(Clone, Copy, Debug, Default)]
1014pub struct NoSemanticHooks;
1015
1016impl SemanticHooks for NoSemanticHooks {
1017    const ENABLES_LEXER_LIFECYCLE: bool = false;
1018
1019    fn observes_parser_predicates(&self) -> bool {
1020        false
1021    }
1022}
1023
1024/// Parser semantic predicate rendered from a supported target template.
1025///
1026/// The metadata recognizer evaluates these at the token-stream index where the
1027/// predicate transition is reached. Unsupported or absent predicate templates
1028/// remain unconditional so existing generated parsers keep their previous
1029/// behavior unless the generator opts into this table.
1030#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
1031pub enum ParserPredicate {
1032    True,
1033    False,
1034    /// Predicate that always fails and carries ANTLR's `<fail='...'>` message.
1035    FalseWithMessage {
1036        message: &'static str,
1037    },
1038    /// Target-template test helper that reports predicate evaluation before
1039    /// returning the wrapped boolean value.
1040    Invoke {
1041        value: bool,
1042    },
1043    LookaheadTextEquals {
1044        offset: isize,
1045        text: &'static str,
1046    },
1047    LookaheadNotEquals {
1048        offset: isize,
1049        token_type: i32,
1050    },
1051    /// Checks that the last two consumed visible tokens were adjacent in the
1052    /// token stream. Used by C# parser predicates for split operator tokens.
1053    TokenPairAdjacent,
1054    /// Checks a generated parser context child by rule index and text.
1055    ///
1056    /// If the child is absent the predicate succeeds, matching target helpers
1057    /// that treat incomplete or non-matching contexts as non-restrictive.
1058    ContextChildRuleTextNotEquals {
1059        rule_index: usize,
1060        text: &'static str,
1061    },
1062    /// Compares the current rule invocation's integer argument with a literal
1063    /// value from a supported `ValEquals("$i", "...")` target template.
1064    LocalIntEquals {
1065        value: i64,
1066    },
1067    /// Checks ANTLR-style raw predicates like `5 >= $_p` against the current
1068    /// rule invocation's integer argument.
1069    LocalIntLessOrEqual {
1070        value: i64,
1071    },
1072    /// Compares a generated parser integer member modulo a literal value.
1073    MemberModuloEquals {
1074        member: usize,
1075        modulus: i64,
1076        value: i64,
1077        equals: bool,
1078    },
1079    /// Compares a generated parser integer member with a literal value.
1080    MemberEquals {
1081        member: usize,
1082        value: i64,
1083        equals: bool,
1084    },
1085}
1086
1087impl ParserPredicate {
1088    /// Lowers the legacy predicate metadata variant into `SemIR`.
1089    ///
1090    /// This is the compatibility adapter for generated parsers produced while
1091    /// the runtime still emitted closed enum tables. Newer generated parsers
1092    /// emit `SemIR` directly.
1093    pub fn lower_into_semir(self, ir: &mut SemIr) -> ExprId {
1094        match self {
1095            Self::True => ir.expr(PExpr::Bool(true)),
1096            Self::False | Self::FalseWithMessage { .. } => ir.expr(PExpr::Bool(false)),
1097            Self::Invoke { value } => ir.expr(PExpr::EvalTrace(value)),
1098            Self::LookaheadTextEquals { offset, text } => {
1099                let token = ir.expr(PExpr::TokenText(offset));
1100                let text = ir.intern(text);
1101                let text = ir.expr(PExpr::Str(text));
1102                ir.expr(PExpr::Cmp(CmpOp::Eq, token, text))
1103            }
1104            Self::LookaheadNotEquals { offset, token_type } => {
1105                let actual = ir.expr(PExpr::La(offset));
1106                let expected = ir.expr(PExpr::Int(i64::from(token_type)));
1107                ir.expr(PExpr::Cmp(CmpOp::Ne, actual, expected))
1108            }
1109            Self::TokenPairAdjacent => ir.expr(PExpr::TokenIndexAdjacent),
1110            Self::ContextChildRuleTextNotEquals { rule_index, text } => {
1111                let actual = ir.expr(PExpr::CtxRuleText(rule_index));
1112                let expected = ir.intern(text);
1113                let expected = ir.expr(PExpr::Str(expected));
1114                ir.expr(PExpr::Cmp(CmpOp::Ne, actual, expected))
1115            }
1116            Self::LocalIntEquals { value } => local_arg_comparison(ir, CmpOp::Eq, value),
1117            Self::LocalIntLessOrEqual { value } => local_arg_comparison(ir, CmpOp::Le, value),
1118            Self::MemberModuloEquals {
1119                member,
1120                modulus,
1121                value,
1122                equals,
1123            } => {
1124                if modulus == 0 {
1125                    return ir.expr(PExpr::Bool(false));
1126                }
1127                let member = ir.expr(PExpr::Member(member));
1128                let modulus = ir.expr(PExpr::Int(modulus));
1129                let actual = ir.expr(PExpr::Arith(ArithOp::Mod, member, modulus));
1130                let expected = ir.expr(PExpr::Int(value));
1131                ir.expr(PExpr::Cmp(
1132                    if equals { CmpOp::Eq } else { CmpOp::Ne },
1133                    actual,
1134                    expected,
1135                ))
1136            }
1137            Self::MemberEquals {
1138                member,
1139                value,
1140                equals,
1141            } => {
1142                let actual = ir.expr(PExpr::Member(member));
1143                let expected = ir.expr(PExpr::Int(value));
1144                ir.expr(PExpr::Cmp(
1145                    if equals { CmpOp::Eq } else { CmpOp::Ne },
1146                    actual,
1147                    expected,
1148                ))
1149            }
1150        }
1151    }
1152
1153    #[must_use]
1154    pub const fn failure_message(self) -> Option<&'static str> {
1155        match self {
1156            Self::FalseWithMessage { message } => Some(message),
1157            Self::True
1158            | Self::False
1159            | Self::Invoke { .. }
1160            | Self::LookaheadTextEquals { .. }
1161            | Self::LookaheadNotEquals { .. }
1162            | Self::TokenPairAdjacent
1163            | Self::ContextChildRuleTextNotEquals { .. }
1164            | Self::LocalIntEquals { .. }
1165            | Self::LocalIntLessOrEqual { .. }
1166            | Self::MemberModuloEquals { .. }
1167            | Self::MemberEquals { .. } => None,
1168        }
1169    }
1170}
1171
1172fn local_arg_comparison(ir: &mut SemIr, op: CmpOp, value: i64) -> ExprId {
1173    let local = ir.expr(PExpr::LocalArg);
1174    let absent = ir.expr(PExpr::IsNull(local));
1175    let expected = ir.expr(PExpr::Int(value));
1176    let comparison = ir.expr(PExpr::Cmp(op, local, expected));
1177    ir.expr(PExpr::Or([absent, comparison].into()))
1178}
1179
1180/// Policy for semantic predicate coordinates that have no runtime
1181/// implementation.
1182///
1183/// ANTLR grammars may embed target-language predicates that the metadata
1184/// generator could not translate into a [`ParserPredicate`] table entry. When
1185/// recognition reaches such a coordinate the runtime cannot know the grammar
1186/// author's intent, so the caller chooses how to proceed.
1187///
1188/// The default is [`Self::AssumeTrue`], matching the historical behavior of
1189/// this runtime. That default is deprecated and will change to [`Self::Error`]
1190/// in a future minor release; grammars relying on unconditional predicates
1191/// should opt in explicitly.
1192#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
1193pub enum UnknownSemanticPolicy {
1194    /// Treat the predicate as passing, as if it were absent from the grammar.
1195    #[default]
1196    AssumeTrue,
1197    /// Treat the predicate as failing, removing the guarded alternative.
1198    AssumeFalse,
1199    /// Fail the parse with [`AntlrError::Unsupported`] naming every unknown
1200    /// coordinate that recognition evaluated.
1201    Error,
1202}
1203
1204/// Resolves a predicate coordinate that neither a translated table entry nor a
1205/// user hook could answer, applying the active [`UnknownSemanticPolicy`].
1206///
1207/// Under [`UnknownSemanticPolicy::Error`] the coordinate is recorded in `hits`
1208/// so the parse entry can surface every unresolved coordinate afterwards. Both
1209/// the legacy [`ParserPredicate`] path and the [`semir::PExpr::Hook`] path
1210/// funnel through here so a missing implementation is never silently coerced
1211/// to a boolean (design goal G1: never silently mis-parse).
1212fn apply_unknown_predicate_policy(
1213    policy: UnknownSemanticPolicy,
1214    rule_index: usize,
1215    pred_index: usize,
1216    hits: &mut Vec<(usize, usize)>,
1217) -> bool {
1218    match policy {
1219        UnknownSemanticPolicy::AssumeTrue => true,
1220        UnknownSemanticPolicy::AssumeFalse => false,
1221        UnknownSemanticPolicy::Error => {
1222            let coordinate = (rule_index, pred_index);
1223            if !hits.contains(&coordinate) {
1224                hits.push(coordinate);
1225            }
1226            false
1227        }
1228    }
1229}
1230
1231/// Interval-set of expected token types, displayable through a vocabulary —
1232/// the shape ANTLR's `getExpectedTokens().toString(vocabulary)` exposes to
1233/// generated test actions.
1234#[derive(Clone, Debug, Eq, PartialEq)]
1235pub struct ExpectedTokenSet {
1236    symbols: BTreeSet<i32>,
1237}
1238
1239impl ExpectedTokenSet {
1240    /// Formats the set using ANTLR token display names, e.g. `{'a', 'b'}`.
1241    #[must_use]
1242    pub fn to_token_string(&self, vocabulary: &Vocabulary) -> String {
1243        expected_symbols_display(&self.symbols, vocabulary)
1244    }
1245}
1246
1247/// Marker error strategy matching ANTLR's `BailErrorStrategy`.
1248///
1249/// The first syntax error aborts the parse instead of recovering. Generated
1250/// recognizers accept it through `set_error_handler(BailErrorStrategy::new())`.
1251#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
1252pub struct BailErrorStrategy;
1253
1254impl BailErrorStrategy {
1255    #[must_use]
1256    pub const fn new() -> Self {
1257        Self
1258    }
1259}
1260
1261/// Prediction strategy requested by generated parser harnesses.
1262#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1263pub enum PredictionMode {
1264    /// Prefer the clean full-context outcome when alternatives reach the same
1265    /// input position.
1266    Ll,
1267    /// Preserve SLL's first-viable alternative bias at a decision, even when a
1268    /// later full-context alternative could avoid recovery.
1269    Sll,
1270    /// Full LL prediction with exact ambiguity detection for diagnostic runs.
1271    LlExactAmbigDetection,
1272}
1273
1274/// Integer argument metadata for a generated parser rule invocation.
1275///
1276/// ANTLR's serialized ATN does not retain Rust-target rule argument values, so
1277/// the generator records the rule-transition source state and the value that
1278/// should be visible to semantic predicates inside the callee.
1279#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
1280pub struct ParserRuleArg {
1281    /// ATN state containing the rule transition that receives this argument.
1282    pub source_state: usize,
1283    /// Callee rule index for the transition.
1284    pub rule_index: usize,
1285    /// Literal fallback value to expose in the callee.
1286    pub value: i64,
1287    /// Whether the callee should inherit the caller's current integer argument.
1288    pub inherit_local: bool,
1289}
1290
1291/// Integer member mutation attached to an ATN action transition.
1292#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
1293pub struct ParserMemberAction {
1294    /// ATN state containing the action transition.
1295    pub source_state: usize,
1296    /// Generator-assigned integer member id.
1297    pub member: usize,
1298    /// Delta applied when the action is reached on one speculative path.
1299    pub delta: i64,
1300}
1301
1302/// Integer return-value assignment attached to an ATN action transition.
1303///
1304/// Generated parsers use this metadata when target actions assign a simple
1305/// return field such as `$y=1000;`. The interpreter applies it while selecting
1306/// the recognized path so the finished parse tree can answer later
1307/// `$label.y` action templates.
1308#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
1309pub struct ParserReturnAction {
1310    /// ATN state containing the action transition.
1311    pub source_state: usize,
1312    /// Rule index recorded by the serialized action transition.
1313    pub rule_index: usize,
1314    /// Return-field name as it appears in the grammar.
1315    pub name: &'static str,
1316    /// Literal integer value assigned by the action.
1317    pub value: i64,
1318}
1319
1320impl ParserMemberAction {
1321    /// Lowers this speculative member mutation into a `SemIR` action.
1322    pub fn lower_into_semir(self, ir: &mut SemIr) -> ParserSemanticAction {
1323        let delta = ir.expr(PExpr::Int(self.delta));
1324        ParserSemanticAction {
1325            source_state: self.source_state,
1326            rule_index: usize::MAX,
1327            stmt: ir.stmt(AStmt::AddMember(self.member, delta)),
1328            speculative: true,
1329        }
1330    }
1331}
1332
1333impl ParserReturnAction {
1334    /// Lowers this committed return-value assignment into a `SemIR` action.
1335    pub fn lower_into_semir(self, ir: &mut SemIr) -> ParserSemanticAction {
1336        let name = ir.intern(self.name);
1337        let value = ir.expr(PExpr::Int(self.value));
1338        ParserSemanticAction {
1339            source_state: self.source_state,
1340            rule_index: self.rule_index,
1341            stmt: ir.stmt(AStmt::SetReturn(name, value)),
1342            speculative: false,
1343        }
1344    }
1345}
1346
1347/// Parser predicate coordinate lowered into [`SemIr`].
1348#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1349pub struct ParserSemanticPredicate {
1350    /// Serialized rule index that owns this predicate.
1351    pub rule_index: usize,
1352    /// Predicate index inside the owning rule.
1353    pub pred_index: usize,
1354    /// Root expression in the associated [`ParserSemantics::ir`] arena.
1355    pub expr: ExprId,
1356    /// ANTLR `<fail='...'>` message for predicates that intentionally fail.
1357    pub failure_message: Option<&'static str>,
1358}
1359
1360/// Parser action coordinate lowered into [`SemIr`].
1361#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1362pub struct ParserSemanticAction {
1363    /// ATN state containing the action transition.
1364    pub source_state: usize,
1365    /// Serialized rule index recorded by the action transition.
1366    pub rule_index: usize,
1367    /// Root statement in the associated [`ParserSemantics::ir`] arena.
1368    pub stmt: StmtId,
1369    /// Whether this action may run on speculative recognition paths.
1370    pub speculative: bool,
1371}
1372
1373/// Data-driven semantic tables emitted by generated parsers.
1374///
1375/// This is the runtime representation for issue #9's `SemIR` path. Existing
1376/// `ParserPredicate`, `ParserMemberAction`, and `ParserReturnAction` tables
1377/// remain accepted as deprecated adapters for generated code produced before
1378/// this table existed.
1379#[derive(Clone, Debug, Default, Eq, PartialEq)]
1380pub struct ParserSemantics {
1381    pub ir: SemIr,
1382    pub predicates: Vec<ParserSemanticPredicate>,
1383    pub actions: Vec<ParserSemanticAction>,
1384}
1385
1386/// Optional generated-runtime metadata for metadata-driven parser execution.
1387#[derive(Clone, Copy, Debug, Default)]
1388pub struct ParserRuntimeOptions<'a> {
1389    /// Rule indexes whose `@init` actions should run at rule entry or be
1390    /// returned for legacy replay when no semantic hook handles them.
1391    pub init_action_rules: &'a [usize],
1392    /// Stable parser-action indexes keyed by authored ATN source state.
1393    ///
1394    /// A non-empty table selects committed interpreted execution: mapped
1395    /// actions run at their grammar position instead of being replayed after
1396    /// the complete rule has been recognized.
1397    pub action_indices: &'a [(usize, usize)],
1398    /// Whether generated parse-tree contexts should retain alternative numbers.
1399    pub track_alt_numbers: bool,
1400    /// Whether generated typed contexts should retain private dispatch alternatives.
1401    ///
1402    /// Unlike `track_alt_numbers`, this metadata does not affect the public
1403    /// alternative number or parse-tree rendering.
1404    #[doc(hidden)]
1405    pub track_context_alt_numbers: bool,
1406    /// Semantic predicate table keyed by serialized `(rule_index, pred_index)`.
1407    pub predicates: &'a [(usize, usize, ParserPredicate)],
1408    /// `SemIR` predicate/action table emitted by newer generated parsers.
1409    pub semantics: Option<&'a ParserSemantics>,
1410    /// Rule-call integer argument table keyed by ATN source state.
1411    pub rule_args: &'a [ParserRuleArg],
1412    /// Integer member mutations keyed by ATN action source state.
1413    pub member_actions: &'a [ParserMemberAction],
1414    /// Integer return assignments keyed by ATN action source state.
1415    pub return_actions: &'a [ParserReturnAction],
1416    /// How to evaluate semantic predicate coordinates absent from
1417    /// `predicates`.
1418    pub unknown_predicate_policy: UnknownSemanticPolicy,
1419}
1420
1421pub trait Parser: Recognizer {
1422    /// Reports whether generated parser rules should build parse-tree nodes
1423    /// while recognizing input.
1424    fn build_parse_trees(&self) -> bool;
1425
1426    /// Enables or disables parse-tree construction for subsequent rule calls.
1427    fn set_build_parse_trees(&mut self, build: bool);
1428
1429    /// Returns the number of parser syntax errors recorded by committed parse
1430    /// paths so far.
1431    fn number_of_syntax_errors(&self) -> usize {
1432        0
1433    }
1434
1435    /// Reports whether prediction diagnostic-listener messages are emitted
1436    /// during parser ATN recognition.
1437    fn report_diagnostic_errors(&self) -> bool {
1438        false
1439    }
1440
1441    /// Enables or disables ANTLR-style prediction diagnostics for subsequent
1442    /// rule calls.
1443    fn set_report_diagnostic_errors(&mut self, _report: bool) {}
1444
1445    /// Reports the prediction strategy used when selecting among alternatives.
1446    fn prediction_mode(&self) -> PredictionMode {
1447        PredictionMode::Ll
1448    }
1449
1450    /// Sets the prediction strategy for subsequent rule calls.
1451    fn set_prediction_mode(&mut self, _mode: PredictionMode) {}
1452
1453    /// Maximum rule-nesting depth accepted before the parse aborts, or `None`
1454    /// for unlimited (the default).
1455    fn max_rule_depth(&self) -> Option<usize> {
1456        None
1457    }
1458
1459    /// Bounds the rule-nesting depth for subsequent rule calls.
1460    ///
1461    /// Deeply nested input is parsed safely regardless (rule recursion grows
1462    /// onto a segmented stack), but each nesting level still costs CPU and
1463    /// tree memory. Callers parsing untrusted input can cap that work: when
1464    /// the limit is exceeded the parse stops with a positioned syntax error
1465    /// instead of consuming unbounded resources. The measure counts rule
1466    /// frames plus left-recursive operator expansions, matching what an
1467    /// upstream-ANTLR rule-entry listener observes.
1468    ///
1469    /// The cap is enforced by generated recursive-descent rule bodies. When
1470    /// one is set, generated dispatch routes ATN-preferred rules through
1471    /// their generated bodies too, trading that fast path for enforcement.
1472    /// Rules the generator emitted no body for (interpreter-only fallback)
1473    /// do not check the cap.
1474    fn set_max_rule_depth(&mut self, _depth: Option<usize>) {}
1475
1476    /// Registers a listener for committed rule enter/exit events during
1477    /// recognition (ANTLR's `addParseListener`). See [`ParseListener`] for
1478    /// the delivery contract. The default implementation drops the listener;
1479    /// [`BaseParser`] and generated parsers deliver events.
1480    fn add_parse_listener(&mut self, _listener: Box<dyn ParseListener>) {}
1481
1482    /// Removes every registered parse listener and returns them, dropping
1483    /// any sticky abort a removed listener had requested.
1484    fn remove_parse_listeners(&mut self) -> Vec<Box<dyn ParseListener>> {
1485        Vec::new()
1486    }
1487}
1488
1489#[derive(Debug)]
1490struct LeftRecursiveCallerOverlap {
1491    atn_key: SharedAtnCacheKey,
1492    state_number: usize,
1493    symbol: i32,
1494    context_version: usize,
1495    overlaps: bool,
1496}
1497
1498const LEFT_RECURSIVE_CALLER_OVERLAP_CACHE_SIZE: usize = 16;
1499
1500#[derive(Debug)]
1501pub struct BaseParser<S, H = NoSemanticHooks> {
1502    input: CommonTokenStream<S>,
1503    tree: ParseTreeStorage,
1504    data: RecognizerData,
1505    semantic_hooks: H,
1506    decision_override_generation: usize,
1507    build_parse_trees: bool,
1508    syntax_errors: usize,
1509    report_diagnostic_errors: bool,
1510    prediction_mode: PredictionMode,
1511    prediction_diagnostics: Vec<ParserDiagnostic>,
1512    reported_prediction_diagnostics: BTreeSet<(usize, usize, String)>,
1513    generated_parser_diagnostics: Vec<ParserDiagnostic>,
1514    generated_sync_expected: Option<TokenBitSet>,
1515    generated_recovery_error_index: Option<usize>,
1516    generated_recovery_error_states: BTreeSet<isize>,
1517    int_members: MemberEnv,
1518    rule_context_stack: Vec<RuleContextFrame>,
1519    rule_context_version: usize,
1520    left_recursive_caller_overlap_cache:
1521        [Option<LeftRecursiveCallerOverlap>; LEFT_RECURSIVE_CALLER_OVERLAP_CACHE_SIZE],
1522    pending_invoking_states: Vec<isize>,
1523    precedence_stack: Vec<i32>,
1524    /// Predicate side effects are observable in a few target-template tests;
1525    /// speculative recognition may revisit the same coordinate, so replay it
1526    /// once per parser instance.
1527    invoked_predicates: Vec<(usize, usize)>,
1528    /// Bail error strategy: the first syntax error aborts the parse instead of
1529    /// recovering (ANTLR's `BailErrorStrategy`). Generated recognizers set it
1530    /// through `set_error_handler(BailErrorStrategy::new())`.
1531    bail_on_error: bool,
1532    /// Parse listeners receiving committed rule enter/exit events during
1533    /// recognition (ANTLR's `addParseListener`). Empty in the default
1534    /// configuration, and every dispatch site is gated on emptiness so the
1535    /// unused feature costs one predictable branch per rule boundary.
1536    parse_listeners: Vec<ParseListenerSlot>,
1537    /// Sticky abort requested by a parse listener's `enter_every_rule`.
1538    /// Mirrors `rule_depth_error`: rule-level recovery absorbs the error like
1539    /// any rule failure, so the flag stays set until the top-level entry
1540    /// drains it and fails the parse.
1541    parse_listener_abort: Option<AntlrError>,
1542    /// Optional cap on rule-nesting depth for adversarial-input hardening.
1543    /// `None` (default) parses unbounded nesting; `Some(n)` aborts the parse
1544    /// with a positioned syntax error once `n` rule frames are exceeded.
1545    max_rule_depth: Option<usize>,
1546    /// Sticky depth-cap violation. Rule-level recovery would otherwise absorb
1547    /// the error and keep parsing; once set, every subsequent rule entry fails
1548    /// immediately and the top-level entry returns this error even when
1549    /// recovery produced a tree.
1550    rule_depth_error: Option<AntlrError>,
1551    /// Left-recursive expansions currently deepening the parse tree. Each
1552    /// operator iteration wraps the previous context one level deeper without
1553    /// pushing a rule frame, so the depth cap must count these separately —
1554    /// upstream ANTLR fires a rule-entry listener event for exactly this case
1555    /// (`Parser.pushNewRecursionContext` → `triggerEnterRuleEvent`).
1556    recursion_expansions: usize,
1557    /// Per-invocation snapshots of [`Self::recursion_expansions`], pushed by
1558    /// `enter_recursion_rule` and restored by `unroll_recursion_context`, so a
1559    /// finished left-recursive rule releases the depth its expansions added.
1560    recursion_expansion_marks: Vec<usize>,
1561    /// How to evaluate predicate coordinates missing from the active
1562    /// predicate table. Set from [`ParserRuntimeOptions`] at each parse entry.
1563    unknown_predicate_policy: UnknownSemanticPolicy,
1564    /// Unknown predicate coordinates evaluated by the current parse, recorded
1565    /// so [`UnknownSemanticPolicy::Error`] can report them after recognition.
1566    unknown_predicate_hits: Vec<(usize, usize)>,
1567    /// Committed parser action coordinates offered to [`SemanticHooks::action`]
1568    /// that no hook handled, recorded so a generated `hook`/error-disposed
1569    /// action fails loud instead of being silently dropped. Keyed by
1570    /// `(rule_index, source_state)`.
1571    unhandled_action_hits: Vec<(usize, usize)>,
1572    /// Per-parse rule FIRST-set cache keyed by rule start state. This keeps
1573    /// hot rule-transition checks to a vector lookup after the first visit
1574    /// while the thread-local shared ATN cache still owns the cross-parse
1575    /// computed value.
1576    rule_first_set_cache: Vec<Option<Rc<FirstSet>>>,
1577    /// Per-state expected-symbol cache. `state_expected_symbols` walks every
1578    /// epsilon-reachable consuming transition and shows up as a hot loop in
1579    /// `next_recovery_context` and recovery diagnostics on long inputs.
1580    /// Keying on `state_number` and sharing the result through `Rc` removes
1581    /// repeated DFS plus per-call `BTreeSet` allocations.
1582    state_expected_cache: FxHashMap<usize, Rc<BTreeSet<i32>>>,
1583    /// Same expected-symbol cache as a bitset for generated parser sync.
1584    /// Successful parses only need `contains` and union; keeping that path out
1585    /// of `BTreeSet` avoids tree allocation for every nullable loop/optional
1586    /// check and defers deterministic formatting to diagnostics.
1587    state_expected_token_cache: FxHashMap<usize, Rc<TokenBitSet>>,
1588    /// Per-state cache for whether a return state can finish its owning rule
1589    /// without consuming more input. Generated-parser sync uses this to walk
1590    /// parent prediction contexts for nullable exits without paying repeated
1591    /// epsilon-closure searches on every loop or optional decision.
1592    rule_stop_reach_cache: Vec<Option<bool>>,
1593    /// Per-parser interner for `recovery_symbols` sets. Speculative recursion
1594    /// threads the same epsilon-recovery context through hundreds of follow
1595    /// states; sharing `Rc<BTreeSet<i32>>` instances lets clones reduce to a
1596    /// reference bump and lets the memo key hash by pointer.
1597    recovery_symbols_intern: FxHashMap<Rc<BTreeSet<i32>>, Rc<BTreeSet<i32>>>,
1598    /// Per-decision-state look-1 cache. Built lazily so grammars that rarely
1599    /// touch a given decision state still pay no upfront cost; once cached,
1600    /// the recognizer prunes alternatives whose look-1 cannot accept the
1601    /// current lookahead, letting common SLL decisions reduce to a single
1602    /// transition walk instead of a full speculative fan-out.
1603    decision_lookahead_cache: FxHashMap<usize, Rc<DecisionLookahead>>,
1604    /// Caches the LL(1) alt selection per `(state, lookahead_token)`.
1605    /// Each multi-trans visit asks "given this decision state and this
1606    /// lookahead token, which alt do I commit to?" Hitting this cache
1607    /// turns the question into a hashmap probe instead of re-scanning
1608    /// the decision's per-transition FIRST sets every visit.
1609    ll1_decision_cache: FxHashMap<(usize, i32), Option<usize>>,
1610    /// Predicate results shared by the fast recognizer's clean and recovery
1611    /// attempts. The eligible fast path keeps every runtime-provided input
1612    /// fixed, and custom predicate hooks are required to be replay-safe.
1613    fast_predicate_cache: FxHashMap<(usize, usize, usize), bool>,
1614    /// Cache for whether an ATN state can reach itself without consuming
1615    /// input. Only those states need the recursive recognizer's
1616    /// `(state, token-index)` cycle guard. The companion ATN key lets this
1617    /// grammar-static cache survive parser resets without reusing state
1618    /// coordinates after the parser is driven against a different ATN.
1619    empty_cycle_cache: Vec<Option<bool>>,
1620    empty_cycle_cache_atn: Option<SharedAtnCacheKey>,
1621    /// Probe state for deciding whether clean-pass memo entries are worth
1622    /// storing for the current parse.
1623    clean_memo_mode: CleanMemoMode,
1624    clean_memo_probe_seen: FxHashSet<FastRecognizeKey>,
1625    clean_memo_probe_samples: usize,
1626    clean_memo_probe_repeats: usize,
1627    clean_memo_sparse_samples: usize,
1628    /// Reusable cycle and memo storage for one top-level fast recognition.
1629    fast_recognize_scratch: FastRecognizeTopScratch,
1630    /// Reusable direct-index/hash storage for clean speculative endpoints.
1631    fast_outcome_dedup: FastOutcomeDedupScratch,
1632    /// Empty recovery-symbols singleton used as the default at rule entry and
1633    /// after token consumption.
1634    empty_recovery_symbols: Rc<BTreeSet<i32>>,
1635    /// Whether the fast recognizer's FIRST-set prefilter is enabled. The
1636    /// prefilter trims speculative rule calls whose called rule cannot
1637    /// match the current lookahead, but it also bypasses single-token
1638    /// insertion / deletion recovery that ANTLR runs at the rule's first
1639    /// consuming transition. `parse_atn_rule` flips this off and retries
1640    /// when the first pass produces no clean outcome so the runtime can
1641    /// repair inputs the reference parser would have repaired.
1642    fast_first_set_prefilter: bool,
1643    /// Whether the fast recognizer should explore parser error-recovery paths.
1644    /// Public rule parsing starts with this disabled for the common valid-input
1645    /// path and enables it only for the retry that needs ANTLR-style repairs.
1646    fast_recovery_enabled: bool,
1647    /// Whether the fast recognizer should record terminal-token nodes while
1648    /// speculating. Clean valid-input parsing can reconstruct terminals from
1649    /// selected rule spans after recognition, avoiding many speculative
1650    /// nodes that are thrown away with losing paths.
1651    fast_token_nodes_enabled: bool,
1652    /// Whether fast recognition should retain private/public rule alternatives
1653    /// in deferred tree metadata.
1654    fast_track_alt_numbers: bool,
1655    /// Parser-owned append-only storage for speculative recognition output.
1656    /// Each public interpreted-rule entry clears lengths while retaining
1657    /// bounded backing capacities for parser reuse.
1658    recognition_arena: RecognitionArena,
1659    last_recognition_arena_root: NodeSeqId,
1660    last_recognition_arena_diagnostics: DiagnosticSeqId,
1661}
1662
1663/// Rollback marker for speculative generated parser paths.
1664#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1665pub struct GeneratedDiagnosticsCheckpoint {
1666    diagnostics_len: usize,
1667    syntax_errors: usize,
1668    tree: ParseTreeCheckpoint,
1669}
1670
1671/// Storage and reachability counters for the most recent interpreted-rule
1672/// recognition arena.
1673#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
1674pub struct RecognitionArenaStats {
1675    pub total_nodes: usize,
1676    pub live_nodes: usize,
1677    pub dead_nodes: usize,
1678    pub node_capacity: usize,
1679    pub total_links: usize,
1680    pub live_links: usize,
1681    pub dead_links: usize,
1682    pub link_capacity: usize,
1683    pub total_extras: usize,
1684    pub live_extras: usize,
1685    pub dead_extras: usize,
1686    pub extra_capacity: usize,
1687}
1688
1689#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1690struct RuleContextFrame {
1691    rule_index: usize,
1692    invoking_state: isize,
1693}
1694
1695#[derive(Clone, Debug, Eq, PartialEq)]
1696struct RecognizeOutcome {
1697    index: usize,
1698    consumed_eof: bool,
1699    alt_number: usize,
1700    member_values: MemberEnv,
1701    return_values: BTreeMap<String, i64>,
1702    diagnostics: DiagnosticSeqId,
1703    decisions: Vec<usize>,
1704    actions: Vec<ParserAction>,
1705    nodes: NodeSeqId,
1706}
1707
1708#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1709struct FastRecognizeOutcome {
1710    index: usize,
1711    consumed_eof: bool,
1712    diagnostics: DiagnosticSeqId,
1713    deferred_nodes: FastDeferredNodeId,
1714    /// Head of the speculative parse-tree fragment in the parser-owned arena.
1715    /// Copying an outcome copies this compact ID; prepending appends one
1716    /// `SeqLink` without allocating an individual node or list tail.
1717    nodes: NodeSeqId,
1718}
1719
1720#[derive(Debug, Default)]
1721struct FastRecognizeTopScratch {
1722    visiting: FxHashSet<FastRecognizeKey>,
1723    memo: FxHashMap<FastRecognizeKey, Rc<[FastRecognizeOutcome]>>,
1724}
1725
1726impl FastRecognizeTopScratch {
1727    fn prepare(&mut self, memo_capacity: usize) {
1728        self.visiting.clear();
1729        self.visiting.reserve(FAST_RECOGNIZE_VISITING_CAPACITY);
1730        self.memo.clear();
1731        self.memo.reserve(memo_capacity);
1732    }
1733
1734    fn release_oversized_memo(&mut self) {
1735        self.memo.clear();
1736        if self.memo.capacity() > FAST_RECOGNIZE_MAX_RETAINED_MEMO_CAPACITY {
1737            self.memo = FxHashMap::default();
1738        }
1739    }
1740}
1741
1742fn fast_recognize_memo_capacity(buffered_tokens: usize) -> usize {
1743    buffered_tokens.saturating_mul(8).clamp(
1744        FAST_RECOGNIZE_MIN_MEMO_CAPACITY,
1745        FAST_RECOGNIZE_MAX_MEMO_CAPACITY,
1746    )
1747}
1748
1749#[derive(Debug, Default)]
1750struct FastOutcomeDedupScratch {
1751    dense_words: Vec<u64>,
1752    touched_dense_words: Vec<u32>,
1753    sparse_keys: FxHashSet<(usize, bool)>,
1754}
1755
1756/// Handle into the parser-owned deferred tree rope.
1757///
1758/// The sentinel keeps outcomes and repetition paths compact without an
1759/// `Option` discriminant or per-node reference counting.
1760#[repr(transparent)]
1761#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1762struct FastDeferredNodeId(u32);
1763
1764impl FastDeferredNodeId {
1765    const EMPTY: Self = Self(u32::MAX);
1766
1767    const fn is_empty(self) -> bool {
1768        self.0 == Self::EMPTY.0
1769    }
1770}
1771
1772impl Default for FastDeferredNodeId {
1773    fn default() -> Self {
1774        Self::EMPTY
1775    }
1776}
1777
1778#[repr(transparent)]
1779#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1780struct FastDeferredRuleId(u32);
1781
1782/// One immutable deferred-tree rope record in `RecognitionArena`.
1783#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1784enum FastDeferredNode {
1785    Fragment(NodeSeqId),
1786    Rule(FastDeferredRuleId),
1787    Alternative(u32),
1788    LeftRecursiveBoundary {
1789        rule_index: u32,
1790    },
1791    Concat {
1792        prefix: FastDeferredNodeId,
1793        suffix: FastDeferredNodeId,
1794    },
1795}
1796
1797#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1798struct FastDeferredRule {
1799    rule_index: u32,
1800    invoking_state: i32,
1801    start_index: u32,
1802    stop_index: Option<u32>,
1803    deferred_children: FastDeferredNodeId,
1804    children: NodeSeqId,
1805}
1806
1807#[repr(transparent)]
1808#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1809struct RecognizedNodeId(u32);
1810
1811#[repr(transparent)]
1812#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1813struct NodeSeqId(u32);
1814
1815impl NodeSeqId {
1816    const EMPTY: Self = Self(u32::MAX);
1817
1818    const fn is_empty(self) -> bool {
1819        self.0 == Self::EMPTY.0
1820    }
1821}
1822
1823impl Default for NodeSeqId {
1824    fn default() -> Self {
1825        Self::EMPTY
1826    }
1827}
1828
1829#[repr(transparent)]
1830#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1831struct DiagnosticSeqId(u32);
1832
1833impl DiagnosticSeqId {
1834    const EMPTY: Self = Self(u32::MAX);
1835
1836    const fn is_empty(self) -> bool {
1837        self.0 == Self::EMPTY.0
1838    }
1839}
1840
1841impl Default for DiagnosticSeqId {
1842    fn default() -> Self {
1843        Self::EMPTY
1844    }
1845}
1846
1847#[repr(transparent)]
1848#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1849struct RecognitionExtraId(u32);
1850
1851#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
1852struct SeqLink {
1853    head: RecognizedNodeId,
1854    tail: NodeSeqId,
1855}
1856
1857#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
1858struct DiagnosticLink {
1859    head: RecognitionExtraId,
1860    tail: DiagnosticSeqId,
1861}
1862
1863struct ArenaRuleSpec {
1864    rule_index: usize,
1865    invoking_state: isize,
1866    alt_number: usize,
1867    start_index: usize,
1868    stop_index: Option<usize>,
1869    return_values: BTreeMap<String, i64>,
1870    children: NodeSeqId,
1871}
1872
1873/// Compact speculative node record. Common records contain only IDs and
1874/// scalars; missing-token text and generated return values live in `extras`.
1875#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
1876enum ArenaRecognizedNode {
1877    Token {
1878        token: TokenId,
1879    },
1880    ErrorToken {
1881        token: TokenId,
1882    },
1883    MissingToken {
1884        extra: RecognitionExtraId,
1885    },
1886    Rule {
1887        rule_index: u32,
1888        invoking_state: i32,
1889        alt_number: u32,
1890        start_index: u32,
1891        stop_index: Option<u32>,
1892        return_values: Option<RecognitionExtraId>,
1893        children: NodeSeqId,
1894    },
1895    /// Marker emitted at a precedence-rule loop entry where ANTLR would call
1896    /// `pushNewRecursionContext`. Folded into a wrapper rule node before the
1897    /// public rule entry hands the tree to the caller.
1898    LeftRecursiveBoundary {
1899        rule_index: u32,
1900        alt_number: u32,
1901    },
1902}
1903
1904#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
1905enum RecognitionExtra {
1906    MissingToken {
1907        token_type: i32,
1908        at_index: u32,
1909        text: String,
1910    },
1911    ReturnValues(BTreeMap<String, i64>),
1912    Diagnostic(ParserDiagnostic),
1913}
1914
1915#[derive(Debug, Default)]
1916struct RecognitionArena {
1917    nodes: Vec<ArenaRecognizedNode>,
1918    seq_links: Vec<SeqLink>,
1919    diagnostic_links: Vec<DiagnosticLink>,
1920    extras: Vec<RecognitionExtra>,
1921    deferred_nodes: Vec<FastDeferredNode>,
1922    deferred_rules: Vec<FastDeferredRule>,
1923}
1924
1925// Preserve normal parser reuse while preventing one pathological parse from
1926// pinning an arbitrarily large arena for the parser's remaining lifetime.
1927const MAX_RETAINED_RECOGNITION_NODES: usize = 131_072;
1928const MAX_RETAINED_RECOGNITION_SEQUENCE_LINKS: usize = 262_144;
1929const MAX_RETAINED_RECOGNITION_DIAGNOSTIC_LINKS: usize = 65_536;
1930const MAX_RETAINED_RECOGNITION_EXTRAS: usize = 32_768;
1931const MAX_RETAINED_FAST_DEFERRED_NODES: usize = 262_144;
1932const MAX_RETAINED_FAST_DEFERRED_RULES: usize = 131_072;
1933
1934impl RecognitionArena {
1935    fn reset(&mut self) {
1936        reset_arena_vec(&mut self.nodes, MAX_RETAINED_RECOGNITION_NODES);
1937        reset_arena_vec(&mut self.seq_links, MAX_RETAINED_RECOGNITION_SEQUENCE_LINKS);
1938        reset_arena_vec(
1939            &mut self.diagnostic_links,
1940            MAX_RETAINED_RECOGNITION_DIAGNOSTIC_LINKS,
1941        );
1942        reset_arena_vec(&mut self.extras, MAX_RETAINED_RECOGNITION_EXTRAS);
1943        reset_arena_vec(&mut self.deferred_nodes, MAX_RETAINED_FAST_DEFERRED_NODES);
1944        reset_arena_vec(&mut self.deferred_rules, MAX_RETAINED_FAST_DEFERRED_RULES);
1945    }
1946
1947    fn push_node(&mut self, node: ArenaRecognizedNode) -> RecognizedNodeId {
1948        let id = RecognizedNodeId(
1949            u32::try_from(self.nodes.len()).expect("recognition node arena fits in u32"),
1950        );
1951        self.nodes.push(node);
1952        id
1953    }
1954
1955    fn push_extra(&mut self, extra: RecognitionExtra) -> RecognitionExtraId {
1956        let id = RecognitionExtraId(
1957            u32::try_from(self.extras.len()).expect("recognition extra arena fits in u32"),
1958        );
1959        self.extras.push(extra);
1960        id
1961    }
1962
1963    fn prepend(&mut self, tail: NodeSeqId, head: RecognizedNodeId) -> NodeSeqId {
1964        let id = NodeSeqId(
1965            u32::try_from(self.seq_links.len()).expect("node sequence arena fits in u32"),
1966        );
1967        self.seq_links.push(SeqLink { head, tail });
1968        id
1969    }
1970
1971    fn push_deferred_node(&mut self, node: FastDeferredNode) -> FastDeferredNodeId {
1972        let id = FastDeferredNodeId(
1973            u32::try_from(self.deferred_nodes.len()).expect("deferred node arena fits in u32"),
1974        );
1975        self.deferred_nodes.push(node);
1976        id
1977    }
1978
1979    fn push_deferred_rule(&mut self, rule: FastDeferredRule) -> FastDeferredRuleId {
1980        let id = FastDeferredRuleId(
1981            u32::try_from(self.deferred_rules.len()).expect("deferred rule arena fits in u32"),
1982        );
1983        self.deferred_rules.push(rule);
1984        id
1985    }
1986
1987    fn deferred_fragment(&mut self, nodes: NodeSeqId) -> FastDeferredNodeId {
1988        if nodes.is_empty() {
1989            FastDeferredNodeId::EMPTY
1990        } else {
1991            self.push_deferred_node(FastDeferredNode::Fragment(nodes))
1992        }
1993    }
1994
1995    fn deferred_rule_node(&mut self, rule: FastDeferredRule) -> FastDeferredNodeId {
1996        let rule = self.push_deferred_rule(rule);
1997        self.push_deferred_node(FastDeferredNode::Rule(rule))
1998    }
1999
2000    fn deferred_alternative(&mut self, alt_number: usize) -> FastDeferredNodeId {
2001        self.push_deferred_node(FastDeferredNode::Alternative(
2002            u32::try_from(alt_number).expect("alternative number fits in u32"),
2003        ))
2004    }
2005
2006    fn deferred_left_recursive_boundary(&mut self, rule_index: usize) -> FastDeferredNodeId {
2007        self.push_deferred_node(FastDeferredNode::LeftRecursiveBoundary {
2008            rule_index: u32::try_from(rule_index).expect("rule index fits in u32"),
2009        })
2010    }
2011
2012    fn concat_deferred_nodes(
2013        &mut self,
2014        prefix: FastDeferredNodeId,
2015        suffix: FastDeferredNodeId,
2016    ) -> FastDeferredNodeId {
2017        if prefix.is_empty() {
2018            return suffix;
2019        }
2020        if suffix.is_empty() {
2021            return prefix;
2022        }
2023        self.push_deferred_node(FastDeferredNode::Concat { prefix, suffix })
2024    }
2025
2026    fn deferred_node(&self, id: FastDeferredNodeId) -> FastDeferredNode {
2027        self.deferred_nodes[id.0 as usize]
2028    }
2029
2030    fn deferred_rule(&self, id: FastDeferredRuleId) -> FastDeferredRule {
2031        self.deferred_rules[id.0 as usize]
2032    }
2033
2034    fn prepend_diagnostic(
2035        &mut self,
2036        tail: DiagnosticSeqId,
2037        diagnostic: ParserDiagnostic,
2038    ) -> DiagnosticSeqId {
2039        let head = self.push_extra(RecognitionExtra::Diagnostic(diagnostic));
2040        self.prepend_diagnostic_id(tail, head)
2041    }
2042
2043    fn prepend_diagnostic_id(
2044        &mut self,
2045        tail: DiagnosticSeqId,
2046        head: RecognitionExtraId,
2047    ) -> DiagnosticSeqId {
2048        let id = DiagnosticSeqId(
2049            u32::try_from(self.diagnostic_links.len())
2050                .expect("diagnostic sequence arena fits in u32"),
2051        );
2052        self.diagnostic_links.push(DiagnosticLink { head, tail });
2053        id
2054    }
2055
2056    fn concat_diagnostics(
2057        &mut self,
2058        prefix: DiagnosticSeqId,
2059        mut suffix: DiagnosticSeqId,
2060    ) -> DiagnosticSeqId {
2061        if prefix.is_empty() {
2062            return suffix;
2063        }
2064        if suffix.is_empty() {
2065            return prefix;
2066        }
2067        let mut reversed = DiagnosticSeqId::EMPTY;
2068        let mut cursor = prefix;
2069        while let Some(link) = self.diagnostic_link(cursor) {
2070            reversed = self.prepend_diagnostic_id(reversed, link.head);
2071            cursor = link.tail;
2072        }
2073        while let Some(link) = self.diagnostic_link(reversed) {
2074            suffix = self.prepend_diagnostic_id(suffix, link.head);
2075            reversed = link.tail;
2076        }
2077        suffix
2078    }
2079
2080    #[cfg(test)]
2081    fn diagnostic_sequence(
2082        &mut self,
2083        diagnostics: impl IntoIterator<Item = ParserDiagnostic>,
2084    ) -> DiagnosticSeqId {
2085        let diagnostics = diagnostics.into_iter().collect::<Vec<_>>();
2086        let mut sequence = DiagnosticSeqId::EMPTY;
2087        for diagnostic in diagnostics.into_iter().rev() {
2088            sequence = self.prepend_diagnostic(sequence, diagnostic);
2089        }
2090        sequence
2091    }
2092
2093    fn node(&self, id: RecognizedNodeId) -> ArenaRecognizedNode {
2094        self.nodes[id.0 as usize]
2095    }
2096
2097    fn set_boundary_alt_number(&mut self, id: RecognizedNodeId, alt_number: u32) {
2098        let ArenaRecognizedNode::LeftRecursiveBoundary {
2099            alt_number: stored, ..
2100        } = &mut self.nodes[id.0 as usize]
2101        else {
2102            unreachable!("deferred boundary must materialize as a boundary node");
2103        };
2104        *stored = alt_number;
2105    }
2106
2107    fn extra(&self, id: RecognitionExtraId) -> &RecognitionExtra {
2108        &self.extras[id.0 as usize]
2109    }
2110
2111    fn link(&self, id: NodeSeqId) -> Option<SeqLink> {
2112        (!id.is_empty()).then(|| self.seq_links[id.0 as usize])
2113    }
2114
2115    fn diagnostic_link(&self, id: DiagnosticSeqId) -> Option<DiagnosticLink> {
2116        (!id.is_empty()).then(|| self.diagnostic_links[id.0 as usize])
2117    }
2118
2119    const fn iter(&self, sequence: NodeSeqId) -> NodeSeqIter<'_> {
2120        NodeSeqIter {
2121            arena: self,
2122            cursor: sequence,
2123        }
2124    }
2125
2126    const fn diagnostics(&self, sequence: DiagnosticSeqId) -> DiagnosticSeqIter<'_> {
2127        DiagnosticSeqIter {
2128            arena: self,
2129            cursor: sequence,
2130        }
2131    }
2132
2133    fn diagnostics_len(&self, sequence: DiagnosticSeqId) -> usize {
2134        self.diagnostics(sequence).count()
2135    }
2136
2137    fn diagnostics_recovery_rank(&self, sequence: DiagnosticSeqId) -> usize {
2138        self.diagnostics(sequence)
2139            .filter(|diagnostic| {
2140                diagnostic.message.starts_with("mismatched input ")
2141                    && !diagnostic.message.starts_with("mismatched input '<EOF>' ")
2142            })
2143            .count()
2144    }
2145
2146    fn compare_diagnostics(&self, left: DiagnosticSeqId, right: DiagnosticSeqId) -> Ordering {
2147        self.diagnostics(left).cmp(self.diagnostics(right))
2148    }
2149
2150    fn sequence_len(&self, sequence: NodeSeqId) -> usize {
2151        self.iter(sequence).count()
2152    }
2153
2154    fn sequence_has_left_recursive_boundary(&self, sequence: NodeSeqId) -> bool {
2155        self.iter(sequence).any(|node| match self.node(node) {
2156            ArenaRecognizedNode::LeftRecursiveBoundary { .. } => true,
2157            ArenaRecognizedNode::Rule { children, .. } => {
2158                self.sequence_has_left_recursive_boundary(children)
2159            }
2160            ArenaRecognizedNode::Token { .. }
2161            | ArenaRecognizedNode::ErrorToken { .. }
2162            | ArenaRecognizedNode::MissingToken { .. } => false,
2163        })
2164    }
2165
2166    fn sequence_has_direct_boundary(&self, sequence: NodeSeqId) -> bool {
2167        self.iter(sequence).any(|node| {
2168            matches!(
2169                self.node(node),
2170                ArenaRecognizedNode::LeftRecursiveBoundary { .. }
2171            )
2172        })
2173    }
2174
2175    fn sequence_has_explicit_token(&self, sequence: NodeSeqId) -> bool {
2176        self.iter(sequence).any(|node| {
2177            matches!(
2178                self.node(node),
2179                ArenaRecognizedNode::Token { .. }
2180                    | ArenaRecognizedNode::ErrorToken { .. }
2181                    | ArenaRecognizedNode::MissingToken { .. }
2182            )
2183        })
2184    }
2185
2186    fn node_start_index(&self, node: RecognizedNodeId) -> Option<usize> {
2187        match self.node(node) {
2188            ArenaRecognizedNode::Token { token } | ArenaRecognizedNode::ErrorToken { token } => {
2189                Some(token.index())
2190            }
2191            ArenaRecognizedNode::MissingToken { extra } => {
2192                let RecognitionExtra::MissingToken { at_index, .. } = self.extra(extra) else {
2193                    unreachable!("missing-token node must reference missing-token extra");
2194                };
2195                Some(*at_index as usize)
2196            }
2197            ArenaRecognizedNode::Rule { start_index, .. } => Some(start_index as usize),
2198            ArenaRecognizedNode::LeftRecursiveBoundary { .. } => None,
2199        }
2200    }
2201
2202    fn node_stop_index(&self, node: RecognizedNodeId) -> Option<usize> {
2203        match self.node(node) {
2204            ArenaRecognizedNode::Token { token } | ArenaRecognizedNode::ErrorToken { token } => {
2205                Some(token.index())
2206            }
2207            ArenaRecognizedNode::MissingToken { extra } => {
2208                let RecognitionExtra::MissingToken { at_index, .. } = self.extra(extra) else {
2209                    unreachable!("missing-token node must reference missing-token extra");
2210                };
2211                (*at_index as usize).checked_sub(1)
2212            }
2213            ArenaRecognizedNode::Rule { stop_index, .. } => stop_index.map(|index| index as usize),
2214            ArenaRecognizedNode::LeftRecursiveBoundary { .. } => None,
2215        }
2216    }
2217
2218    fn node_span(&self, node: RecognizedNodeId) -> Option<(usize, Option<usize>)> {
2219        let start = self.node_start_index(node)?;
2220        let stop = self.node_stop_index(node);
2221        Some((start, stop))
2222    }
2223
2224    fn sequence_start_index(&self, sequence: NodeSeqId) -> Option<usize> {
2225        self.iter(sequence)
2226            .find_map(|node| self.node_start_index(node))
2227    }
2228
2229    fn sequence_stop_index(&self, sequence: NodeSeqId) -> Option<usize> {
2230        let mut stop = None;
2231        for node in self.iter(sequence) {
2232            if let Some(index) = self.node_stop_index(node) {
2233                stop = Some(index);
2234            }
2235        }
2236        stop
2237    }
2238
2239    fn sequence_needs_stable_tie(&self, sequence: NodeSeqId) -> bool {
2240        self.iter(sequence)
2241            .any(|node| self.node_needs_stable_tie(node))
2242    }
2243
2244    fn node_needs_stable_tie(&self, node: RecognizedNodeId) -> bool {
2245        match self.node(node) {
2246            ArenaRecognizedNode::Token { .. }
2247            | ArenaRecognizedNode::ErrorToken { .. }
2248            | ArenaRecognizedNode::MissingToken { .. } => false,
2249            ArenaRecognizedNode::LeftRecursiveBoundary { .. } => true,
2250            ArenaRecognizedNode::Rule {
2251                rule_index,
2252                children,
2253                ..
2254            } => self.iter(children).any(|child| {
2255                matches!(
2256                    self.node(child),
2257                    ArenaRecognizedNode::Rule {
2258                        rule_index: child_rule,
2259                        ..
2260                    } if child_rule == rule_index
2261                ) || self.node_needs_stable_tie(child)
2262            }),
2263        }
2264    }
2265
2266    fn compare_sequences(&self, mut left: NodeSeqId, mut right: NodeSeqId) -> Ordering {
2267        loop {
2268            match (self.link(left), self.link(right)) {
2269                (Some(left_link), Some(right_link)) => {
2270                    let order = self.compare_nodes(left_link.head, right_link.head);
2271                    if order != Ordering::Equal {
2272                        return order;
2273                    }
2274                    left = left_link.tail;
2275                    right = right_link.tail;
2276                }
2277                (None, None) => return Ordering::Equal,
2278                (None, Some(_)) => return Ordering::Less,
2279                (Some(_), None) => return Ordering::Greater,
2280            }
2281        }
2282    }
2283
2284    fn compare_nodes(&self, left: RecognizedNodeId, right: RecognizedNodeId) -> Ordering {
2285        let left = self.node(left);
2286        let right = self.node(right);
2287        match (left, right) {
2288            (
2289                ArenaRecognizedNode::Token { token: left },
2290                ArenaRecognizedNode::Token { token: right },
2291            )
2292            | (
2293                ArenaRecognizedNode::ErrorToken { token: left },
2294                ArenaRecognizedNode::ErrorToken { token: right },
2295            ) => left.cmp(&right),
2296            (
2297                ArenaRecognizedNode::MissingToken { extra: left },
2298                ArenaRecognizedNode::MissingToken { extra: right },
2299            ) => self.extra(left).cmp(self.extra(right)),
2300            (
2301                ArenaRecognizedNode::Rule {
2302                    rule_index: left_rule,
2303                    invoking_state: left_invoking,
2304                    alt_number: left_alt,
2305                    start_index: left_start,
2306                    stop_index: left_stop,
2307                    return_values: left_returns,
2308                    children: left_children,
2309                },
2310                ArenaRecognizedNode::Rule {
2311                    rule_index: right_rule,
2312                    invoking_state: right_invoking,
2313                    alt_number: right_alt,
2314                    start_index: right_start,
2315                    stop_index: right_stop,
2316                    return_values: right_returns,
2317                    children: right_children,
2318                },
2319            ) => (left_rule, left_invoking, left_alt, left_start, left_stop)
2320                .cmp(&(
2321                    right_rule,
2322                    right_invoking,
2323                    right_alt,
2324                    right_start,
2325                    right_stop,
2326                ))
2327                .then_with(|| {
2328                    left_returns
2329                        .map(|id| self.extra(id))
2330                        .cmp(&right_returns.map(|id| self.extra(id)))
2331                })
2332                .then_with(|| self.compare_sequences(left_children, right_children)),
2333            (
2334                ArenaRecognizedNode::LeftRecursiveBoundary {
2335                    rule_index: left_rule,
2336                    alt_number: left_alt,
2337                },
2338                ArenaRecognizedNode::LeftRecursiveBoundary {
2339                    rule_index: right_rule,
2340                    alt_number: right_alt,
2341                },
2342            ) => (left_rule, left_alt).cmp(&(right_rule, right_alt)),
2343            (left, right) => recognition_node_kind(&left).cmp(&recognition_node_kind(&right)),
2344        }
2345    }
2346
2347    fn reverse_sequence(&mut self, mut sequence: NodeSeqId) -> NodeSeqId {
2348        let mut reversed = NodeSeqId::EMPTY;
2349        while let Some(link) = self.link(sequence) {
2350            reversed = self.prepend(reversed, link.head);
2351            sequence = link.tail;
2352        }
2353        reversed
2354    }
2355
2356    fn fold_left_recursive_boundaries(&mut self, mut sequence: NodeSeqId) -> NodeSeqId {
2357        if !self.sequence_has_direct_boundary(sequence) {
2358            return sequence;
2359        }
2360        let mut reversed = NodeSeqId::EMPTY;
2361        while let Some(link) = self.link(sequence) {
2362            match self.node(link.head) {
2363                ArenaRecognizedNode::LeftRecursiveBoundary {
2364                    rule_index,
2365                    alt_number,
2366                } => {
2367                    if !reversed.is_empty() {
2368                        let children = self.reverse_sequence(reversed);
2369                        let start_index = self.sequence_start_index(children).unwrap_or_default();
2370                        let stop_index = self.sequence_stop_index(children);
2371                        let rule = self.push_node(ArenaRecognizedNode::Rule {
2372                            rule_index,
2373                            invoking_state: -1,
2374                            alt_number,
2375                            start_index: u32::try_from(start_index)
2376                                .expect("left-recursive start index fits in u32"),
2377                            stop_index: stop_index.map(|index| {
2378                                u32::try_from(index).expect("left-recursive stop index fits in u32")
2379                            }),
2380                            return_values: None,
2381                            children,
2382                        });
2383                        reversed = self.prepend(NodeSeqId::EMPTY, rule);
2384                    }
2385                }
2386                _ => {
2387                    reversed = self.prepend(reversed, link.head);
2388                }
2389            }
2390            sequence = link.tail;
2391        }
2392        self.reverse_sequence(reversed)
2393    }
2394
2395    fn stats(&self, root: NodeSeqId, diagnostics: DiagnosticSeqId) -> RecognitionArenaStats {
2396        let mut live_nodes = vec![false; self.nodes.len()];
2397        let mut live_links = vec![false; self.seq_links.len()];
2398        let mut live_diagnostic_links = vec![false; self.diagnostic_links.len()];
2399        let mut live_extras = vec![false; self.extras.len()];
2400        let mut pending = vec![root];
2401        while let Some(mut sequence) = pending.pop() {
2402            while let Some(link) = self.link(sequence) {
2403                let link_index = sequence.0 as usize;
2404                if live_links[link_index] {
2405                    break;
2406                }
2407                live_links[link_index] = true;
2408                let node_index = link.head.0 as usize;
2409                if !live_nodes[node_index] {
2410                    live_nodes[node_index] = true;
2411                    match self.node(link.head) {
2412                        ArenaRecognizedNode::MissingToken { extra } => {
2413                            live_extras[extra.0 as usize] = true;
2414                        }
2415                        ArenaRecognizedNode::Rule {
2416                            return_values,
2417                            children,
2418                            ..
2419                        } => {
2420                            if let Some(extra) = return_values {
2421                                live_extras[extra.0 as usize] = true;
2422                            }
2423                            pending.push(children);
2424                        }
2425                        ArenaRecognizedNode::Token { .. }
2426                        | ArenaRecognizedNode::ErrorToken { .. }
2427                        | ArenaRecognizedNode::LeftRecursiveBoundary { .. } => {}
2428                    }
2429                }
2430                sequence = link.tail;
2431            }
2432        }
2433        let mut diagnostics = diagnostics;
2434        while let Some(link) = self.diagnostic_link(diagnostics) {
2435            let link_index = diagnostics.0 as usize;
2436            if live_diagnostic_links[link_index] {
2437                break;
2438            }
2439            live_diagnostic_links[link_index] = true;
2440            live_extras[link.head.0 as usize] = true;
2441            diagnostics = link.tail;
2442        }
2443        let live_node_count = live_nodes.into_iter().filter(|live| *live).count();
2444        let live_link_count = live_links.into_iter().filter(|live| *live).count()
2445            + live_diagnostic_links
2446                .into_iter()
2447                .filter(|live| *live)
2448                .count();
2449        let live_extra_count = live_extras.into_iter().filter(|live| *live).count();
2450        let total_links = self.seq_links.len() + self.diagnostic_links.len();
2451        RecognitionArenaStats {
2452            total_nodes: self.nodes.len(),
2453            live_nodes: live_node_count,
2454            dead_nodes: self.nodes.len().saturating_sub(live_node_count),
2455            node_capacity: self.nodes.capacity(),
2456            total_links,
2457            live_links: live_link_count,
2458            dead_links: total_links.saturating_sub(live_link_count),
2459            link_capacity: self.seq_links.capacity() + self.diagnostic_links.capacity(),
2460            total_extras: self.extras.len(),
2461            live_extras: live_extra_count,
2462            dead_extras: self.extras.len().saturating_sub(live_extra_count),
2463            extra_capacity: self.extras.capacity(),
2464        }
2465    }
2466}
2467
2468fn reset_arena_vec<T>(storage: &mut Vec<T>, max_retained_capacity: usize) {
2469    if storage.capacity() > max_retained_capacity {
2470        *storage = Vec::new();
2471    } else {
2472        storage.clear();
2473    }
2474}
2475
2476const fn recognition_node_kind(node: &ArenaRecognizedNode) -> u8 {
2477    match node {
2478        ArenaRecognizedNode::Token { .. } => 0,
2479        ArenaRecognizedNode::ErrorToken { .. } => 1,
2480        ArenaRecognizedNode::MissingToken { .. } => 2,
2481        ArenaRecognizedNode::Rule { .. } => 3,
2482        ArenaRecognizedNode::LeftRecursiveBoundary { .. } => 4,
2483    }
2484}
2485
2486struct NodeSeqIter<'a> {
2487    arena: &'a RecognitionArena,
2488    cursor: NodeSeqId,
2489}
2490
2491impl Iterator for NodeSeqIter<'_> {
2492    type Item = RecognizedNodeId;
2493
2494    fn next(&mut self) -> Option<Self::Item> {
2495        let link = self.arena.link(self.cursor)?;
2496        self.cursor = link.tail;
2497        Some(link.head)
2498    }
2499}
2500
2501struct DiagnosticSeqIter<'a> {
2502    arena: &'a RecognitionArena,
2503    cursor: DiagnosticSeqId,
2504}
2505
2506impl<'a> Iterator for DiagnosticSeqIter<'a> {
2507    type Item = &'a ParserDiagnostic;
2508
2509    fn next(&mut self) -> Option<Self::Item> {
2510        let link = self.arena.diagnostic_link(self.cursor)?;
2511        self.cursor = link.tail;
2512        let RecognitionExtra::Diagnostic(diagnostic) = self.arena.extra(link.head) else {
2513            unreachable!("diagnostic link must reference diagnostic extra");
2514        };
2515        Some(diagnostic)
2516    }
2517}
2518
2519#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
2520struct ParserDiagnostic {
2521    line: usize,
2522    column: usize,
2523    message: String,
2524    /// Token the diagnostic is anchored to, resolved to a view when the
2525    /// diagnostic is dispatched to error listeners. `None` when no token
2526    /// exists (synthetic positions, lexer-originated messages).
2527    offending: Option<TokenId>,
2528}
2529
2530#[derive(Clone, Debug, Default, Eq, PartialEq)]
2531struct ExpectedTokens {
2532    index: Option<usize>,
2533    symbols: BTreeSet<i32>,
2534    no_viable: Option<NoViableAlternative>,
2535}
2536
2537#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2538struct NoViableAlternative {
2539    start_index: usize,
2540    error_index: usize,
2541}
2542
2543impl ExpectedTokens {
2544    /// Records the expected symbols for the farthest token index reached by any
2545    /// failed ATN path.
2546    fn record_transition(
2547        &mut self,
2548        index: usize,
2549        transition: ParserTransition<'_>,
2550        max_token_type: i32,
2551    ) {
2552        let symbols = transition_expected_symbols(transition, max_token_type);
2553        match self.index {
2554            Some(current) if index < current => {}
2555            Some(current) if index == current => self.symbols.extend(symbols),
2556            _ => {
2557                self.index = Some(index);
2558                self.symbols = symbols;
2559            }
2560        }
2561    }
2562
2563    /// Records an ambiguous decision that failed after consuming a shared
2564    /// prefix, which ANTLR reports as `no viable alternative`.
2565    const fn record_no_viable(&mut self, start_index: usize, error_index: usize) {
2566        match self.no_viable {
2567            Some(current) if error_index < current.error_index => {}
2568            _ => {
2569                self.no_viable = Some(NoViableAlternative {
2570                    start_index,
2571                    error_index,
2572                });
2573            }
2574        }
2575    }
2576}
2577
2578/// Compact token-type set for parser-internal FIRST/lookahead caches.
2579///
2580/// Public diagnostics still use `BTreeSet<i32>` for deterministic formatting,
2581/// but the hot recognizer path mostly needs `contains` and set union over
2582/// small token ids. A bitset avoids tree traversal and per-symbol allocation
2583/// while keeping conversion to `BTreeSet` at recovery/reporting boundaries.
2584#[derive(Clone, Debug, Default, Eq, PartialEq)]
2585struct TokenBitSet {
2586    words: Vec<u64>,
2587}
2588
2589impl TokenBitSet {
2590    fn insert(&mut self, symbol: i32) {
2591        let Some(slot) = token_bit_slot(symbol) else {
2592            return;
2593        };
2594        let word = slot / u64::BITS as usize;
2595        if word >= self.words.len() {
2596            self.words.resize(word + 1, 0);
2597        }
2598        self.words[word] |= 1_u64 << (slot % u64::BITS as usize);
2599    }
2600
2601    fn extend_range(&mut self, start: i32, stop: i32) {
2602        let (start, stop) = if start <= stop {
2603            (start, stop)
2604        } else {
2605            (stop, start)
2606        };
2607        if start <= TOKEN_EOF && stop >= TOKEN_EOF {
2608            self.insert(TOKEN_EOF);
2609        }
2610        let positive_start = start.max(1);
2611        if positive_start > stop {
2612            return;
2613        }
2614        let Some(start_slot) = token_bit_slot(positive_start) else {
2615            return;
2616        };
2617        let Some(stop_slot) = token_bit_slot(stop) else {
2618            return;
2619        };
2620        self.extend_slot_range(start_slot, stop_slot);
2621    }
2622
2623    fn extend_slot_range(&mut self, start_slot: usize, stop_slot: usize) {
2624        if start_slot > stop_slot {
2625            return;
2626        }
2627        let start_word = start_slot / u64::BITS as usize;
2628        let stop_word = stop_slot / u64::BITS as usize;
2629        if stop_word >= self.words.len() {
2630            self.words.resize(stop_word + 1, 0);
2631        }
2632        let start_offset = start_slot % u64::BITS as usize;
2633        let stop_offset = stop_slot % u64::BITS as usize;
2634        if start_word == stop_word {
2635            self.words[start_word] |=
2636                (!0_u64 << start_offset) & (!0_u64 >> (u64::BITS as usize - 1 - stop_offset));
2637            return;
2638        }
2639        self.words[start_word] |= !0_u64 << start_offset;
2640        for word in &mut self.words[(start_word + 1)..stop_word] {
2641            *word = !0_u64;
2642        }
2643        self.words[stop_word] |= !0_u64 >> (u64::BITS as usize - 1 - stop_offset);
2644    }
2645
2646    fn extend_iter(&mut self, symbols: impl IntoIterator<Item = i32>) {
2647        for symbol in symbols {
2648            self.insert(symbol);
2649        }
2650    }
2651
2652    fn extend_from(&mut self, other: &Self) {
2653        if other.words.len() > self.words.len() {
2654            self.words.resize(other.words.len(), 0);
2655        }
2656        for (left, right) in self.words.iter_mut().zip(&other.words) {
2657            *left |= *right;
2658        }
2659    }
2660
2661    fn contains(&self, symbol: i32) -> bool {
2662        let Some(slot) = token_bit_slot(symbol) else {
2663            return false;
2664        };
2665        let word = slot / u64::BITS as usize;
2666        self.words
2667            .get(word)
2668            .is_some_and(|bits| bits & (1_u64 << (slot % u64::BITS as usize)) != 0)
2669    }
2670
2671    fn is_empty(&self) -> bool {
2672        self.words.iter().all(|word| *word == 0)
2673    }
2674
2675    fn symbols(&self) -> impl Iterator<Item = i32> + '_ {
2676        self.words
2677            .iter()
2678            .copied()
2679            .enumerate()
2680            .flat_map(|(word_index, mut bits)| {
2681                std::iter::from_fn(move || {
2682                    while bits != 0 {
2683                        let bit = bits.trailing_zeros() as usize;
2684                        bits &= bits - 1;
2685                        if let Some(symbol) =
2686                            token_bit_symbol(word_index * u64::BITS as usize + bit)
2687                        {
2688                            return Some(symbol);
2689                        }
2690                    }
2691                    None
2692                })
2693            })
2694    }
2695
2696    fn extend_btree_set(&self, target: &mut BTreeSet<i32>) {
2697        target.extend(self.symbols());
2698    }
2699
2700    fn to_btree_set(&self) -> BTreeSet<i32> {
2701        let mut out = BTreeSet::new();
2702        self.extend_btree_set(&mut out);
2703        out
2704    }
2705}
2706
2707fn token_bit_slot(symbol: i32) -> Option<usize> {
2708    if symbol == TOKEN_EOF {
2709        Some(0)
2710    } else if symbol > 0 {
2711        usize::try_from(symbol).ok()
2712    } else {
2713        None
2714    }
2715}
2716
2717fn token_bit_symbol(slot: usize) -> Option<i32> {
2718    if slot == 0 {
2719        Some(TOKEN_EOF)
2720    } else {
2721        i32::try_from(slot).ok()
2722    }
2723}
2724
2725/// Converts one consuming transition into the token types that would satisfy it
2726/// for diagnostic reporting.
2727fn transition_expected_symbols(
2728    transition: ParserTransition<'_>,
2729    max_token_type: i32,
2730) -> BTreeSet<i32> {
2731    let mut symbols = BTreeSet::new();
2732    match &transition.data() {
2733        Transition::Atom { label, .. } => {
2734            symbols.insert(*label);
2735        }
2736        Transition::Range { start, stop, .. } => {
2737            symbols.extend(*start..=*stop);
2738        }
2739        Transition::Set { set, .. } => {
2740            for (start, stop) in set.ranges() {
2741                symbols.extend(start..=stop);
2742            }
2743        }
2744        Transition::NotSet { set, .. } => {
2745            symbols.extend((1..=max_token_type).filter(|symbol| !set.contains(*symbol)));
2746        }
2747        Transition::Wildcard { .. } => {
2748            symbols.extend(1..=max_token_type);
2749        }
2750        Transition::Epsilon { .. }
2751        | Transition::Rule { .. }
2752        | Transition::Predicate { .. }
2753        | Transition::Action { .. }
2754        | Transition::Precedence { .. } => {}
2755    }
2756    symbols
2757}
2758
2759fn transition_expected_token_set(
2760    transition: ParserTransition<'_>,
2761    max_token_type: i32,
2762) -> TokenBitSet {
2763    let mut symbols = TokenBitSet::default();
2764    match &transition.data() {
2765        Transition::Atom { label, .. } => {
2766            symbols.insert(*label);
2767        }
2768        Transition::Range { start, stop, .. } => {
2769            symbols.extend_range(*start, *stop);
2770        }
2771        Transition::Set { set, .. } => {
2772            for (start, stop) in set.ranges() {
2773                symbols.extend_range(start, stop);
2774            }
2775        }
2776        Transition::NotSet { set, .. } => {
2777            symbols.extend_iter((1..=max_token_type).filter(|symbol| !set.contains(*symbol)));
2778        }
2779        Transition::Wildcard { .. } => {
2780            symbols.extend_range(1, max_token_type);
2781        }
2782        Transition::Epsilon { .. }
2783        | Transition::Rule { .. }
2784        | Transition::Predicate { .. }
2785        | Transition::Action { .. }
2786        | Transition::Precedence { .. } => {}
2787    }
2788    symbols
2789}
2790
2791/// Returns the consuming-token expectations reachable from an ATN state through
2792/// epsilon transitions. Recovery diagnostics need this closure so alternatives
2793/// and loop exits report the same expectation set ANTLR users see.
2794fn state_expected_symbols(atn: &Atn, state_number: usize) -> BTreeSet<i32> {
2795    let mut symbols = BTreeSet::new();
2796    let mut stack = vec![state_number];
2797    let mut visited = BTreeSet::new();
2798    while let Some(current) = stack.pop() {
2799        if !visited.insert(current) {
2800            continue;
2801        }
2802        let Some(state) = atn.state(current) else {
2803            continue;
2804        };
2805        for transition in &state.transitions() {
2806            let transition_symbols = transition_expected_symbols(transition, atn.max_token_type());
2807            if transition_symbols.is_empty() {
2808                if transition.is_epsilon() {
2809                    stack.push(transition.target());
2810                }
2811            } else {
2812                symbols.extend(transition_symbols);
2813            }
2814        }
2815    }
2816    symbols
2817}
2818
2819fn state_expected_token_set(atn: &Atn, state_number: usize) -> TokenBitSet {
2820    let mut symbols = TokenBitSet::default();
2821    let mut stack = vec![state_number];
2822    let mut visited = BTreeSet::new();
2823    while let Some(current) = stack.pop() {
2824        if !visited.insert(current) {
2825            continue;
2826        }
2827        let Some(state) = atn.state(current) else {
2828            continue;
2829        };
2830        for transition in &state.transitions() {
2831            let transition_symbols =
2832                transition_expected_token_set(transition, atn.max_token_type());
2833            if transition_symbols.is_empty() {
2834                if transition.is_epsilon() {
2835                    stack.push(transition.target());
2836                }
2837            } else {
2838                symbols.extend_from(&transition_symbols);
2839            }
2840        }
2841    }
2842    symbols
2843}
2844
2845fn state_can_reach_rule_stop(atn: &Atn, state_number: usize) -> bool {
2846    let Some(rule_index) = atn.state(state_number).and_then(AtnState::rule_index) else {
2847        return false;
2848    };
2849    let Some(stop_state) = atn.rule_to_stop_state().get(rule_index) else {
2850        return false;
2851    };
2852    epsilon_reaches_state(atn, state_number, stop_state)
2853}
2854
2855fn epsilon_reaches_state(atn: &Atn, start: usize, target: usize) -> bool {
2856    let mut stack = vec![start];
2857    let mut visited = BTreeSet::new();
2858    while let Some(current) = stack.pop() {
2859        if current == target {
2860            return true;
2861        }
2862        if !visited.insert(current) {
2863            continue;
2864        }
2865        let Some(state) = atn.state(current) else {
2866            continue;
2867        };
2868        stack.extend(
2869            state
2870                .transitions()
2871                .iter()
2872                .filter(|transition| transition.is_epsilon())
2873                .map(ParserTransition::target),
2874        );
2875    }
2876    false
2877}
2878
2879/// FIRST set for a rule entry plus whether the rule is nullable.
2880///
2881/// Walks epsilon, predicate, action, and rule-call transitions until it finds
2882/// a consuming transition or reaches the rule's stop state. Used by the fast
2883/// recognizer to skip rule alternatives whose first-consumed token cannot
2884/// possibly match the current lookahead.
2885#[derive(Clone, Debug, Default, Eq, PartialEq)]
2886struct FirstSet {
2887    symbols: TokenBitSet,
2888    nullable: bool,
2889}
2890
2891/// Per-parser cache of FIRST sets computed during recognition. The fast path
2892/// consults this on every speculative `Transition::Rule` encounter, so the
2893/// computation must amortize across all of those calls — the FIRST set is a
2894/// pure function of the ATN, not of the input position. Cached entries are
2895/// shared via `Rc` so the recognizer never deep-copies the underlying
2896/// `BTreeSet<i32>`.
2897type FirstSetCache = FxHashMap<(usize, usize), Rc<FirstSet>>;
2898
2899// Thread-local FIRST-set caches keyed by the ATN pointer. The FIRST set
2900// and decision-lookahead entries are purely functions of the grammar's
2901// ATN, so caching across parses lets repeated parsing of the same grammar
2902// (the common case for a CLI tool or language server) avoid redoing the
2903// closure work. Generated parsers hand us a `&'static Atn` whose address
2904// is stable, which is what we hash on.
2905type DecisionLookaheadCache = FxHashMap<usize, Rc<DecisionLookahead>>;
2906
2907#[derive(Debug, Default)]
2908struct LeftRecursiveOperatorLookahead {
2909    /// Operator alts whose token-prefix is fully matched by this one symbol
2910    /// (then only epsilons/actions remain before the recursive RHS call).
2911    /// Safe for one-token loop-enter fast path.
2912    single_token: TokenBitSet,
2913    /// Operator alts that start with this symbol but still require more tokens
2914    /// before the operand. Must not force enter from one-token lookahead when a
2915    /// shorter operator shares the prefix; `StarLoopEntry` adaptive prediction
2916    /// has to weigh the exit alt as well.
2917    multi_token_prefix: TokenBitSet,
2918    predicate_dependent: TokenBitSet,
2919}
2920
2921#[derive(Default)]
2922struct SharedAtnCache {
2923    first_set: FirstSetCache,
2924    decision_lookahead: DecisionLookaheadCache,
2925    left_recursive_operator_lookahead: FxHashMap<(usize, i32), Rc<LeftRecursiveOperatorLookahead>>,
2926    state_before_stop_lookahead: FxHashMap<(usize, usize), Rc<StateBeforeStopLookahead>>,
2927    state_expected_tokens: FxHashMap<usize, Rc<TokenBitSet>>,
2928    rule_stop_reach: FxHashMap<usize, bool>,
2929    observable_action_transitions: Option<bool>,
2930    predicate_transitions: Option<bool>,
2931}
2932
2933thread_local! {
2934    static SHARED_ATN_CACHES: RefCell<FxHashMap<SharedAtnCacheKey, SharedAtnCache>> =
2935        RefCell::new(FxHashMap::default());
2936}
2937
2938/// Compound key for `SHARED_ATN_CACHES`.
2939///
2940/// Generated parsers feed us a `&'static Atn` from a `OnceLock<Atn>`, so the
2941/// pointer identifies one grammar for the program's lifetime. For the
2942/// non-`'static` case (a dropped `Atn` whose allocation is later reused),
2943/// the secondary fields below catch the pointer collision: a new grammar
2944/// would need to match all of `(states ptr, states len, max_token_type)` to
2945/// be mistaken for the dropped one. That combination changing under us
2946/// without a rebuild is implausible enough to treat as a bug; bundling them
2947/// into the key is otherwise a few extra bytes per lookup.
2948#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
2949struct SharedAtnCacheKey {
2950    atn: usize,
2951    states: usize,
2952    state_count: usize,
2953    max_token_type: i32,
2954}
2955
2956impl SharedAtnCacheKey {
2957    fn for_atn(atn: &Atn) -> Self {
2958        let (states, state_count) = atn.storage_identity();
2959        Self {
2960            atn: std::ptr::from_ref::<Atn>(atn) as usize,
2961            states,
2962            state_count,
2963            max_token_type: atn.max_token_type(),
2964        }
2965    }
2966}
2967
2968fn with_shared_first_set_cache<R>(atn: &Atn, f: impl FnOnce(&mut FirstSetCache) -> R) -> R {
2969    SHARED_ATN_CACHES.with(|cell| {
2970        let key = SharedAtnCacheKey::for_atn(atn);
2971        let mut map = cell.borrow_mut();
2972        let cache = map.entry(key).or_default();
2973        f(&mut cache.first_set)
2974    })
2975}
2976
2977fn with_shared_atn_caches<R>(atn: &Atn, f: impl FnOnce(&mut SharedAtnCache) -> R) -> R {
2978    SHARED_ATN_CACHES.with(|cell| {
2979        let key = SharedAtnCacheKey::for_atn(atn);
2980        let mut map = cell.borrow_mut();
2981        let cache = map.entry(key).or_default();
2982        f(cache)
2983    })
2984}
2985
2986/// Per-decision-state cached look-1 sets for each outgoing transition.
2987///
2988/// At a multi-alternative state, the recognizer would otherwise speculatively
2989/// walk every alternative even when only one can possibly accept the current
2990/// lookahead. Caching the look-1 set per transition lets us prune the
2991/// non-viable transitions before recursing — the same SLL prediction trick
2992/// the reference ANTLR runtime uses, just expressed as a `(state, lookahead)`
2993/// filter rather than a full DFA.
2994#[derive(Debug, Default)]
2995struct DecisionLookahead {
2996    transitions: Vec<TransitionLookSet>,
2997}
2998
2999/// Look-1 information for one outgoing transition.
3000///
3001/// `nullable` mirrors `FirstSet::nullable` and is true when the transition
3002/// can reach the rule stop without consuming a token (e.g. an empty alt).
3003/// Nullable transitions cannot be pruned: they may still be the right path
3004/// when the lookahead consumes nothing further inside the current rule.
3005#[derive(Clone, Debug, Default)]
3006struct TransitionLookSet {
3007    symbols: TokenBitSet,
3008    nullable: bool,
3009}
3010
3011/// Mutable bookkeeping shared across one FIRST-set computation. Bundling the
3012/// rarely-touched fields keeps the recursive helpers below the function-arity
3013/// lint and lets every nested call thread the same cache and cycle guards.
3014struct FirstSetCtx<'a> {
3015    cache: &'a mut FirstSetCache,
3016    in_progress: BTreeSet<(usize, usize)>,
3017    hit_cycle: bool,
3018}
3019
3020/// Returns the FIRST set for the (rule entry, rule stop) pair, populating the
3021/// shared cache and tolerating recursive nullable rule chains. Mutually
3022/// recursive rules cannot stack-overflow because callers in flight are tracked
3023/// in `ctx.in_progress`; revisits return without recursing, and the partial
3024/// result is cached only when no cycle was detected during its computation.
3025///
3026/// On a cache hit the returned `Rc` is shared with the recognizer so subsequent
3027/// rule-call probes only pay a reference bump.
3028fn rule_first_set(
3029    atn: &Atn,
3030    target: usize,
3031    rule_stop_state: usize,
3032    cache: &mut FirstSetCache,
3033) -> Rc<FirstSet> {
3034    if let Some(cached) = cache.get(&(target, rule_stop_state)) {
3035        return Rc::clone(cached);
3036    }
3037    let mut ctx = FirstSetCtx {
3038        cache,
3039        in_progress: BTreeSet::new(),
3040        hit_cycle: false,
3041    };
3042    rule_first_set_cached(atn, target, rule_stop_state, &mut ctx)
3043}
3044
3045fn rule_first_set_cached(
3046    atn: &Atn,
3047    target: usize,
3048    rule_stop_state: usize,
3049    ctx: &mut FirstSetCtx<'_>,
3050) -> Rc<FirstSet> {
3051    let key = (target, rule_stop_state);
3052    if let Some(cached) = ctx.cache.get(&key) {
3053        return Rc::clone(cached);
3054    }
3055    if !ctx.in_progress.insert(key) {
3056        // Cycle: a caller above is already computing this entry. Return an
3057        // empty FIRST set; that caller's traversal supplies the contributions
3058        // from the rule's other alternatives.
3059        return Rc::new(FirstSet::default());
3060    }
3061    let saved_hit_cycle = ctx.hit_cycle;
3062    ctx.hit_cycle = false;
3063    let mut first = FirstSet::default();
3064    let mut visited = BTreeSet::new();
3065    rule_first_set_inner(atn, target, rule_stop_state, ctx, &mut visited, &mut first);
3066    ctx.in_progress.remove(&key);
3067    let entry = Rc::new(first);
3068    if !ctx.hit_cycle {
3069        ctx.cache.insert(key, Rc::clone(&entry));
3070    }
3071    ctx.hit_cycle = saved_hit_cycle || ctx.hit_cycle;
3072    entry
3073}
3074
3075/// Returns the look-1 set for traversing `transition` while still inside the
3076/// current `rule_stop_state`. Used by the multi-alternative prefilter, which
3077/// prunes transitions whose look-1 cannot accept the current lookahead.
3078fn transition_first_set(
3079    atn: &Atn,
3080    transition: ParserTransition<'_>,
3081    rule_stop_state: usize,
3082    cache: &mut FirstSetCache,
3083) -> TransitionLookSet {
3084    match &transition.data() {
3085        Transition::Atom { label, .. } => {
3086            let mut symbols = TokenBitSet::default();
3087            symbols.insert(*label);
3088            TransitionLookSet {
3089                symbols,
3090                nullable: false,
3091            }
3092        }
3093        Transition::Range { start, stop, .. } => {
3094            let mut symbols = TokenBitSet::default();
3095            symbols.extend_range(*start, *stop);
3096            TransitionLookSet {
3097                symbols,
3098                nullable: false,
3099            }
3100        }
3101        Transition::Set { set, .. } => {
3102            let mut symbols = TokenBitSet::default();
3103            for (start, stop) in set.ranges() {
3104                symbols.extend_range(start, stop);
3105            }
3106            TransitionLookSet {
3107                symbols,
3108                nullable: false,
3109            }
3110        }
3111        Transition::NotSet { set, .. } => {
3112            let max = atn.max_token_type();
3113            let mut symbols = TokenBitSet::default();
3114            symbols.extend_iter((1..=max).filter(|symbol| !set.contains(*symbol)));
3115            TransitionLookSet {
3116                symbols,
3117                nullable: false,
3118            }
3119        }
3120        Transition::Wildcard { .. } => {
3121            let mut symbols = TokenBitSet::default();
3122            symbols.extend_range(1, atn.max_token_type());
3123            TransitionLookSet {
3124                symbols,
3125                nullable: false,
3126            }
3127        }
3128        Transition::Epsilon { target }
3129        | Transition::Action { target, .. }
3130        | Transition::Predicate { target, .. }
3131        | Transition::Precedence { target, .. } => {
3132            // Walk the closure starting at `target` until a consuming transition
3133            // is reached or the rule stop state is hit.
3134            let first = rule_first_set(atn, *target, rule_stop_state, cache);
3135            TransitionLookSet {
3136                symbols: first.symbols.clone(),
3137                nullable: first.nullable,
3138            }
3139        }
3140        Transition::Rule {
3141            target,
3142            rule_index,
3143            follow_state,
3144            ..
3145        } => {
3146            let Some(child_stop) = atn.rule_to_stop_state().get(*rule_index) else {
3147                return TransitionLookSet::default();
3148            };
3149            let child = rule_first_set(atn, *target, child_stop, cache);
3150            let mut symbols = child.symbols.clone();
3151            let nullable = if child.nullable {
3152                let follow = rule_first_set(atn, *follow_state, rule_stop_state, cache);
3153                symbols.extend_from(&follow.symbols);
3154                follow.nullable
3155            } else {
3156                false
3157            };
3158            TransitionLookSet { symbols, nullable }
3159        }
3160    }
3161}
3162
3163/// Reports whether `transition` can be pruned at a multi-alt state because
3164/// its cached look-1 cannot accept the current lookahead.
3165///
3166/// Pruning runs only for non-consuming transitions (Epsilon/Action/Predicate/
3167/// Rule/Precedence) so consuming transitions still reach the
3168/// `matches`+recovery path that surfaces single-token deletion / insertion
3169/// repairs and ANTLR-compatible expected-token sets. When a non-consuming
3170/// transition is pruned, its FIRST set is folded into `expected` so failed
3171/// parses produce the same `mismatched input ... expecting ...` diagnostic
3172/// the no-prefilter baseline would emit.
3173/// Returns the unique alt index (0-based) when `symbol` falls into exactly
3174/// one transition's FIRST set and no transition is nullable. Used as an
3175/// LL(1) commit point: when prediction is unambiguous from the lookahead
3176/// alone, the recursive recognizer can skip every other alt without paying
3177/// for the per-transition filter probe.
3178///
3179/// `None` signals the caller to fall back to per-transition lookahead
3180/// filtering. Returning `Some` for an alt whose transition cannot actually
3181/// match would prune the only viable parse path; this is why we require
3182/// strict disjointness *and* no nullable transitions in the decision.
3183fn ll1_unique_alt(entry: &DecisionLookahead, symbol: i32) -> Option<usize> {
3184    let mut chosen: Option<usize> = None;
3185    for (index, transition) in entry.transitions.iter().enumerate() {
3186        if transition.nullable {
3187            return None;
3188        }
3189        if transition.symbols.contains(symbol) {
3190            if chosen.is_some() {
3191                return None;
3192            }
3193            chosen = Some(index);
3194        }
3195    }
3196    chosen
3197}
3198
3199/// Returns the unique greedy alt index (0-based) selected by the current
3200/// lookahead.
3201///
3202/// The shortcut is intentionally conservative around nullable exits. If the
3203/// current symbol can start a consuming alternative and an empty alternative is
3204/// also present, one-token lookahead is not enough to know whether the symbol
3205/// belongs to the current construct or to its caller's follow set. `None`
3206/// signals the caller to fall back to adaptive prediction.
3207fn ll1_greedy_alt(entry: &DecisionLookahead, symbol: i32, non_greedy: bool) -> Option<usize> {
3208    let mut matching_non_nullable_alt = None;
3209    let mut nullable_alt = None;
3210    for (index, transition) in entry.transitions.iter().enumerate() {
3211        if transition.nullable {
3212            if nullable_alt.is_some() {
3213                return None;
3214            }
3215            nullable_alt = Some(index);
3216        }
3217        if transition.symbols.contains(symbol) {
3218            if transition.nullable {
3219                continue;
3220            }
3221            if matching_non_nullable_alt.is_some() {
3222                return None;
3223            }
3224            matching_non_nullable_alt = Some(index);
3225        }
3226    }
3227    if matching_non_nullable_alt.is_some() && nullable_alt.is_some() {
3228        return None;
3229    }
3230    if non_greedy {
3231        nullable_alt.or(matching_non_nullable_alt)
3232    } else {
3233        matching_non_nullable_alt.or(nullable_alt)
3234    }
3235}
3236
3237fn should_skip_via_lookahead(
3238    transition_kind: ParserTransitionKind,
3239    transition_index: usize,
3240    lookahead_filter: Option<&(i32, Rc<DecisionLookahead>)>,
3241    index: usize,
3242    record_expected: bool,
3243    expected: &mut ExpectedTokens,
3244) -> bool {
3245    let prune_non_consuming = matches!(
3246        transition_kind,
3247        ParserTransitionKind::Epsilon
3248            | ParserTransitionKind::Action
3249            | ParserTransitionKind::Predicate
3250            | ParserTransitionKind::Rule
3251            | ParserTransitionKind::Precedence
3252    );
3253    if !prune_non_consuming {
3254        return false;
3255    }
3256    let Some((symbol, entry)) = lookahead_filter else {
3257        return false;
3258    };
3259    let Some(set) = entry.transitions.get(transition_index) else {
3260        return false;
3261    };
3262    if set.symbols.contains(*symbol) || set.nullable {
3263        return false;
3264    }
3265    if record_expected && !set.symbols.is_empty() {
3266        record_pruned_transition_expected(set, index, expected);
3267    }
3268    true
3269}
3270
3271fn should_skip_rule_via_first_set(
3272    first: &FirstSet,
3273    symbol: i32,
3274    record_expected: bool,
3275    index: usize,
3276    expected: &mut ExpectedTokens,
3277) -> bool {
3278    if first.nullable || first.symbols.contains(symbol) {
3279        return false;
3280    }
3281    if record_expected && !first.symbols.is_empty() {
3282        record_token_bit_expected(&first.symbols, index, expected);
3283    }
3284    true
3285}
3286
3287fn record_token_bit_expected(symbols: &TokenBitSet, index: usize, expected: &mut ExpectedTokens) {
3288    match expected.index {
3289        Some(current) if index < current => {}
3290        Some(current) if index == current => {
3291            symbols.extend_btree_set(&mut expected.symbols);
3292        }
3293        _ => {
3294            expected.index = Some(index);
3295            expected.symbols = symbols.to_btree_set();
3296        }
3297    }
3298}
3299
3300/// Folds a pruned transition's FIRST set into the farthest-expected accumulator.
3301fn record_pruned_transition_expected(
3302    set: &TransitionLookSet,
3303    index: usize,
3304    expected: &mut ExpectedTokens,
3305) {
3306    match expected.index {
3307        Some(current) if index < current => {}
3308        Some(current) if index == current => {
3309            set.symbols.extend_btree_set(&mut expected.symbols);
3310        }
3311        _ => {
3312            expected.index = Some(index);
3313            expected.symbols = set.symbols.to_btree_set();
3314        }
3315    }
3316}
3317
3318fn rule_first_set_inner(
3319    atn: &Atn,
3320    state_number: usize,
3321    rule_stop_state: usize,
3322    ctx: &mut FirstSetCtx<'_>,
3323    visited: &mut BTreeSet<usize>,
3324    first: &mut FirstSet,
3325) {
3326    if !visited.insert(state_number) {
3327        return;
3328    }
3329    if state_number == rule_stop_state {
3330        first.nullable = true;
3331        return;
3332    }
3333    let Some(state) = atn.state(state_number) else {
3334        return;
3335    };
3336    for transition in &state.transitions() {
3337        let transition_symbols = transition_expected_symbols(transition, atn.max_token_type());
3338        if !transition_symbols.is_empty() {
3339            first.symbols.extend_iter(transition_symbols);
3340            continue;
3341        }
3342        match &transition.data() {
3343            Transition::Epsilon { target }
3344            | Transition::Action { target, .. }
3345            | Transition::Predicate { target, .. }
3346            | Transition::Precedence { target, .. } => {
3347                rule_first_set_inner(atn, *target, rule_stop_state, ctx, visited, first);
3348            }
3349            Transition::Rule {
3350                target,
3351                rule_index,
3352                follow_state,
3353                ..
3354            } => {
3355                let Some(child_stop) = atn.rule_to_stop_state().get(*rule_index) else {
3356                    continue;
3357                };
3358                let child_key = (*target, child_stop);
3359                if ctx.in_progress.contains(&child_key) && !ctx.cache.contains_key(&child_key) {
3360                    ctx.hit_cycle = true;
3361                }
3362                let child = rule_first_set_cached(atn, *target, child_stop, ctx);
3363                first.symbols.extend_from(&child.symbols);
3364                if child.nullable {
3365                    rule_first_set_inner(atn, *follow_state, rule_stop_state, ctx, visited, first);
3366                }
3367            }
3368            Transition::Atom { .. }
3369            | Transition::Range { .. }
3370            | Transition::Set { .. }
3371            | Transition::NotSet { .. }
3372            | Transition::Wildcard { .. } => {}
3373        }
3374    }
3375}
3376
3377/// Returns token types that can resume parsing from `state_number` after a
3378/// failed child rule, following rule calls as well as epsilon transitions.
3379fn state_sync_symbols(atn: &Atn, state_number: usize, stop_state: usize) -> BTreeSet<i32> {
3380    let mut symbols = BTreeSet::new();
3381    state_sync_symbols_inner(
3382        atn,
3383        state_number,
3384        stop_state,
3385        &mut BTreeSet::new(),
3386        &mut symbols,
3387    );
3388    symbols
3389}
3390
3391/// Walks epsilon-like continuations from a parent follow state until it finds
3392/// consuming tokens that can anchor recovery, or EOF if the parent rule can end.
3393fn state_sync_symbols_inner(
3394    atn: &Atn,
3395    state_number: usize,
3396    stop_state: usize,
3397    visited: &mut BTreeSet<usize>,
3398    symbols: &mut BTreeSet<i32>,
3399) {
3400    if !visited.insert(state_number) {
3401        return;
3402    }
3403    if state_number == stop_state {
3404        symbols.insert(TOKEN_EOF);
3405        return;
3406    }
3407    let Some(state) = atn.state(state_number) else {
3408        return;
3409    };
3410    for transition in &state.transitions() {
3411        let transition_symbols = transition_expected_symbols(transition, atn.max_token_type());
3412        if transition_symbols.is_empty() {
3413            match &transition.data() {
3414                Transition::Rule { target, .. }
3415                | Transition::Epsilon { target }
3416                | Transition::Action { target, .. }
3417                | Transition::Predicate { target, .. }
3418                | Transition::Precedence { target, .. } => {
3419                    state_sync_symbols_inner(atn, *target, stop_state, visited, symbols);
3420                }
3421                Transition::Atom { .. }
3422                | Transition::Range { .. }
3423                | Transition::Set { .. }
3424                | Transition::NotSet { .. }
3425                | Transition::Wildcard { .. } => {}
3426            }
3427        } else {
3428            symbols.extend(transition_symbols);
3429        }
3430    }
3431}
3432
3433#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
3434struct OperatorSymbolReachability {
3435    /// One token completes an unconditional operator token-prefix.
3436    single_token: bool,
3437    /// An unconditional operator path requires more tokens before its operand.
3438    multi_token: bool,
3439    /// At least one matching operator path depends on a semantic predicate.
3440    predicate_dependent: bool,
3441}
3442
3443impl OperatorSymbolReachability {
3444    const ADAPTIVE_FALLBACK: Self = Self {
3445        single_token: false,
3446        multi_token: false,
3447        predicate_dependent: true,
3448    };
3449
3450    const fn single_token(predicate_dependent: bool) -> Self {
3451        if predicate_dependent {
3452            Self {
3453                single_token: false,
3454                multi_token: false,
3455                predicate_dependent: true,
3456            }
3457        } else {
3458            Self {
3459                single_token: true,
3460                multi_token: false,
3461                predicate_dependent: false,
3462            }
3463        }
3464    }
3465
3466    const fn multi_token(predicate_dependent: bool) -> Self {
3467        if predicate_dependent {
3468            Self {
3469                single_token: false,
3470                multi_token: false,
3471                predicate_dependent: true,
3472            }
3473        } else {
3474            Self {
3475                single_token: false,
3476                multi_token: true,
3477                predicate_dependent: false,
3478            }
3479        }
3480    }
3481
3482    const fn union(self, other: Self) -> Self {
3483        Self {
3484            single_token: self.single_token || other.single_token,
3485            multi_token: self.multi_token || other.multi_token,
3486            predicate_dependent: self.predicate_dependent || other.predicate_dependent,
3487        }
3488    }
3489}
3490
3491#[derive(Clone, Copy)]
3492struct OperatorReachabilityRequest {
3493    symbol: i32,
3494    precedence: i32,
3495    predicate_dependent: bool,
3496    operator_rule_index: usize,
3497}
3498
3499#[derive(Clone, Copy, Debug)]
3500struct OperatorRuleContinuation {
3501    stop_state: usize,
3502    follow_state: usize,
3503    return_precedence: i32,
3504}
3505
3506struct NullablePrecedenceCtx {
3507    cache: FxHashMap<(usize, usize, i32, bool), bool>,
3508    in_progress: BTreeSet<(usize, usize, i32, bool)>,
3509    hit_cycle: bool,
3510}
3511
3512fn state_is_nullable_with_precedence(
3513    atn: &Atn,
3514    state_number: usize,
3515    stop_state_number: usize,
3516    precedence: i32,
3517    allow_predicates: bool,
3518    ctx: &mut NullablePrecedenceCtx,
3519) -> bool {
3520    let saved_hit_cycle = ctx.hit_cycle;
3521    ctx.hit_cycle = false;
3522    let nullable = state_is_nullable_with_precedence_cached(
3523        atn,
3524        state_number,
3525        stop_state_number,
3526        precedence,
3527        allow_predicates,
3528        ctx,
3529    );
3530    ctx.hit_cycle = saved_hit_cycle;
3531    nullable
3532}
3533
3534fn state_is_nullable_with_precedence_cached(
3535    atn: &Atn,
3536    state_number: usize,
3537    stop_state_number: usize,
3538    precedence: i32,
3539    allow_predicates: bool,
3540    ctx: &mut NullablePrecedenceCtx,
3541) -> bool {
3542    if state_number == stop_state_number {
3543        return true;
3544    }
3545    let key = (
3546        state_number,
3547        stop_state_number,
3548        precedence,
3549        allow_predicates,
3550    );
3551    if let Some(cached) = ctx.cache.get(&key) {
3552        return *cached;
3553    }
3554    if !ctx.in_progress.insert(key) {
3555        ctx.hit_cycle = true;
3556        return false;
3557    }
3558    let saved_hit_cycle = ctx.hit_cycle;
3559    ctx.hit_cycle = false;
3560    let nullable = atn.state(state_number).is_some_and(|state| {
3561        state
3562            .transitions()
3563            .iter()
3564            .any(|transition| match &transition.data() {
3565                Transition::Rule {
3566                    target,
3567                    rule_index,
3568                    follow_state,
3569                    precedence: rule_precedence,
3570                } => {
3571                    let Some(child_stop) = atn.rule_to_stop_state().get(*rule_index) else {
3572                        return false;
3573                    };
3574                    state_is_nullable_with_precedence_cached(
3575                        atn,
3576                        *target,
3577                        child_stop,
3578                        *rule_precedence,
3579                        allow_predicates,
3580                        ctx,
3581                    ) && state_is_nullable_with_precedence_cached(
3582                        atn,
3583                        *follow_state,
3584                        stop_state_number,
3585                        precedence,
3586                        allow_predicates,
3587                        ctx,
3588                    )
3589                }
3590                Transition::Epsilon { target } | Transition::Action { target, .. } => {
3591                    state_is_nullable_with_precedence_cached(
3592                        atn,
3593                        *target,
3594                        stop_state_number,
3595                        precedence,
3596                        allow_predicates,
3597                        ctx,
3598                    )
3599                }
3600                Transition::Predicate { target, .. } if allow_predicates => {
3601                    state_is_nullable_with_precedence_cached(
3602                        atn,
3603                        *target,
3604                        stop_state_number,
3605                        precedence,
3606                        allow_predicates,
3607                        ctx,
3608                    )
3609                }
3610                Transition::Precedence {
3611                    target,
3612                    precedence: transition_precedence,
3613                } if *transition_precedence >= precedence => {
3614                    state_is_nullable_with_precedence_cached(
3615                        atn,
3616                        *target,
3617                        stop_state_number,
3618                        precedence,
3619                        allow_predicates,
3620                        ctx,
3621                    )
3622                }
3623                Transition::Atom { .. }
3624                | Transition::Range { .. }
3625                | Transition::Set { .. }
3626                | Transition::NotSet { .. }
3627                | Transition::Wildcard { .. }
3628                | Transition::Predicate { .. }
3629                | Transition::Precedence { .. } => false,
3630            })
3631    });
3632    ctx.in_progress.remove(&key);
3633    if !ctx.hit_cycle {
3634        ctx.cache.insert(key, nullable);
3635    }
3636    ctx.hit_cycle = saved_hit_cycle || ctx.hit_cycle;
3637    nullable
3638}
3639
3640/// Classifies what remains after the operator's first token is matched.
3641fn state_operator_token_prefix_reachability(
3642    atn: &Atn,
3643    state_number: usize,
3644    request: OperatorReachabilityRequest,
3645    continuations: &[OperatorRuleContinuation],
3646    visited: &mut BTreeSet<(usize, i32, bool)>,
3647) -> OperatorSymbolReachability {
3648    let key = (
3649        state_number,
3650        request.precedence,
3651        request.predicate_dependent,
3652    );
3653    if !visited.insert(key) {
3654        // Recursive helper rules can grow the return stack without consuming
3655        // input. Delegate cycles to adaptive prediction instead of forcing a
3656        // potentially incomplete one-token answer.
3657        return OperatorSymbolReachability::ADAPTIVE_FALLBACK;
3658    }
3659    if let Some((continuation, remaining)) = continuations.split_last()
3660        && state_number == continuation.stop_state
3661    {
3662        let result = state_operator_token_prefix_reachability(
3663            atn,
3664            continuation.follow_state,
3665            OperatorReachabilityRequest {
3666                precedence: continuation.return_precedence,
3667                ..request
3668            },
3669            remaining,
3670            visited,
3671        );
3672        visited.remove(&key);
3673        return result;
3674    }
3675    let Some(state) = atn.state(state_number) else {
3676        visited.remove(&key);
3677        return OperatorSymbolReachability::default();
3678    };
3679    let completes_operator = match state.kind() {
3680        AtnStateKind::RuleStop => continuations.is_empty(),
3681        AtnStateKind::StarLoopBack
3682        | AtnStateKind::StarLoopEntry
3683        | AtnStateKind::PlusLoopBack
3684        | AtnStateKind::LoopEnd => state.rule_index() == Some(request.operator_rule_index),
3685        _ => false,
3686    };
3687    if completes_operator {
3688        visited.remove(&key);
3689        return OperatorSymbolReachability::single_token(request.predicate_dependent);
3690    }
3691    let mut reachability = OperatorSymbolReachability::default();
3692    for transition in &state.transitions() {
3693        let transition_reachability = match &transition.data() {
3694            Transition::Rule { rule_index, .. } if *rule_index == request.operator_rule_index => {
3695                OperatorSymbolReachability::single_token(request.predicate_dependent)
3696            }
3697            Transition::Rule {
3698                target,
3699                rule_index,
3700                follow_state,
3701                precedence: rule_precedence,
3702            } => {
3703                let Some(child_stop) = atn.rule_to_stop_state().get(*rule_index) else {
3704                    continue;
3705                };
3706                let mut nested = continuations.to_vec();
3707                nested.push(OperatorRuleContinuation {
3708                    stop_state: child_stop,
3709                    follow_state: *follow_state,
3710                    return_precedence: request.precedence,
3711                });
3712                state_operator_token_prefix_reachability(
3713                    atn,
3714                    *target,
3715                    OperatorReachabilityRequest {
3716                        precedence: *rule_precedence,
3717                        ..request
3718                    },
3719                    &nested,
3720                    visited,
3721                )
3722            }
3723            Transition::Epsilon { target } | Transition::Action { target, .. } => {
3724                state_operator_token_prefix_reachability(
3725                    atn,
3726                    *target,
3727                    request,
3728                    continuations,
3729                    visited,
3730                )
3731            }
3732            Transition::Precedence {
3733                target,
3734                precedence: transition_precedence,
3735            } => {
3736                if *transition_precedence < request.precedence {
3737                    OperatorSymbolReachability::default()
3738                } else {
3739                    state_operator_token_prefix_reachability(
3740                        atn,
3741                        *target,
3742                        request,
3743                        continuations,
3744                        visited,
3745                    )
3746                }
3747            }
3748            Transition::Predicate { target, .. } => state_operator_token_prefix_reachability(
3749                atn,
3750                *target,
3751                OperatorReachabilityRequest {
3752                    predicate_dependent: true,
3753                    ..request
3754                },
3755                continuations,
3756                visited,
3757            ),
3758            Transition::Atom { .. }
3759            | Transition::Range { .. }
3760            | Transition::Set { .. }
3761            | Transition::NotSet { .. }
3762            | Transition::Wildcard { .. } => {
3763                OperatorSymbolReachability::multi_token(request.predicate_dependent)
3764            }
3765        };
3766        reachability = reachability.union(transition_reachability);
3767    }
3768    visited.remove(&key);
3769    reachability
3770}
3771
3772fn state_can_reach_symbol_with_precedence(
3773    atn: &Atn,
3774    state_number: usize,
3775    request: OperatorReachabilityRequest,
3776    nullable_ctx: &mut NullablePrecedenceCtx,
3777    continuations: &mut Vec<OperatorRuleContinuation>,
3778    visited: &mut BTreeSet<(usize, i32, bool)>,
3779) -> OperatorSymbolReachability {
3780    let key = (
3781        state_number,
3782        request.precedence,
3783        request.predicate_dependent,
3784    );
3785    if !visited.insert(key) {
3786        return OperatorSymbolReachability::ADAPTIVE_FALLBACK;
3787    }
3788    let Some(state) = atn.state(state_number) else {
3789        visited.remove(&key);
3790        return OperatorSymbolReachability::default();
3791    };
3792    let mut reachability = OperatorSymbolReachability::default();
3793    for transition in &state.transitions() {
3794        if transition.matches(request.symbol, 1, atn.max_token_type()) {
3795            reachability = reachability.union(state_operator_token_prefix_reachability(
3796                atn,
3797                transition.target(),
3798                request,
3799                continuations,
3800                &mut BTreeSet::new(),
3801            ));
3802            continue;
3803        }
3804        let transition_reachability = match &transition.data() {
3805            Transition::Rule {
3806                target,
3807                rule_index,
3808                follow_state,
3809                precedence: rule_precedence,
3810            } => {
3811                let Some(child_stop) = atn.rule_to_stop_state().get(*rule_index) else {
3812                    continue;
3813                };
3814                continuations.push(OperatorRuleContinuation {
3815                    stop_state: child_stop,
3816                    follow_state: *follow_state,
3817                    return_precedence: request.precedence,
3818                });
3819                let mut result = state_can_reach_symbol_with_precedence(
3820                    atn,
3821                    *target,
3822                    OperatorReachabilityRequest {
3823                        precedence: *rule_precedence,
3824                        ..request
3825                    },
3826                    nullable_ctx,
3827                    continuations,
3828                    visited,
3829                );
3830                continuations.pop();
3831                if state_is_nullable_with_precedence(
3832                    atn,
3833                    *target,
3834                    child_stop,
3835                    *rule_precedence,
3836                    true,
3837                    nullable_ctx,
3838                ) {
3839                    let child_predicate_dependent = request.predicate_dependent
3840                        || !state_is_nullable_with_precedence(
3841                            atn,
3842                            *target,
3843                            child_stop,
3844                            *rule_precedence,
3845                            false,
3846                            nullable_ctx,
3847                        );
3848                    result = result.union(state_can_reach_symbol_with_precedence(
3849                        atn,
3850                        *follow_state,
3851                        OperatorReachabilityRequest {
3852                            predicate_dependent: child_predicate_dependent,
3853                            ..request
3854                        },
3855                        nullable_ctx,
3856                        continuations,
3857                        visited,
3858                    ));
3859                }
3860                result
3861            }
3862            Transition::Epsilon { target }
3863            | Transition::Action { target, .. }
3864            | Transition::Precedence { target, .. } => {
3865                if matches!(
3866                    &transition.data(),
3867                    Transition::Precedence {
3868                        precedence: transition_precedence,
3869                        ..
3870                    } if *transition_precedence < request.precedence
3871                ) {
3872                    continue;
3873                }
3874                state_can_reach_symbol_with_precedence(
3875                    atn,
3876                    *target,
3877                    request,
3878                    nullable_ctx,
3879                    continuations,
3880                    visited,
3881                )
3882            }
3883            Transition::Predicate { target, .. } => state_can_reach_symbol_with_precedence(
3884                atn,
3885                *target,
3886                OperatorReachabilityRequest {
3887                    predicate_dependent: true,
3888                    ..request
3889                },
3890                nullable_ctx,
3891                continuations,
3892                visited,
3893            ),
3894            Transition::Atom { .. }
3895            | Transition::Range { .. }
3896            | Transition::Set { .. }
3897            | Transition::NotSet { .. }
3898            | Transition::Wildcard { .. } => OperatorSymbolReachability::default(),
3899        };
3900        reachability = reachability.union(transition_reachability);
3901    }
3902    visited.remove(&key);
3903    reachability
3904}
3905
3906fn left_recursive_operator_lookahead(
3907    atn: &Atn,
3908    state_number: usize,
3909    precedence: i32,
3910) -> LeftRecursiveOperatorLookahead {
3911    let Some(state) = atn.state(state_number) else {
3912        return LeftRecursiveOperatorLookahead::default();
3913    };
3914    let Some(operator_rule_index) = state.rule_index() else {
3915        return LeftRecursiveOperatorLookahead::default();
3916    };
3917    let mut lookahead = LeftRecursiveOperatorLookahead::default();
3918    let mut nullable_ctx = NullablePrecedenceCtx {
3919        cache: FxHashMap::default(),
3920        in_progress: BTreeSet::new(),
3921        hit_cycle: false,
3922    };
3923    for transition in &state.transitions() {
3924        let target = transition.target();
3925        if atn
3926            .state(target)
3927            .is_some_and(|state| state.kind() == AtnStateKind::LoopEnd)
3928        {
3929            continue;
3930        }
3931        for symbol in 1..=atn.max_token_type() {
3932            let reachability = state_can_reach_symbol_with_precedence(
3933                atn,
3934                target,
3935                OperatorReachabilityRequest {
3936                    symbol,
3937                    precedence,
3938                    predicate_dependent: false,
3939                    operator_rule_index,
3940                },
3941                &mut nullable_ctx,
3942                &mut Vec::new(),
3943                &mut BTreeSet::new(),
3944            );
3945            if reachability.single_token {
3946                lookahead.single_token.insert(symbol);
3947            }
3948            if reachability.multi_token {
3949                lookahead.multi_token_prefix.insert(symbol);
3950            }
3951            if reachability.predicate_dependent {
3952                lookahead.predicate_dependent.insert(symbol);
3953            }
3954        }
3955    }
3956    lookahead
3957}
3958
3959#[derive(Debug, Default)]
3960struct StateBeforeStopLookahead {
3961    symbols: TokenBitSet,
3962    reaches_context_boundary: bool,
3963}
3964
3965fn state_before_stop_lookahead(
3966    atn: &Atn,
3967    state_number: usize,
3968    stop_state_number: usize,
3969) -> Rc<StateBeforeStopLookahead> {
3970    with_shared_atn_caches(atn, |cache| {
3971        let key = (state_number, stop_state_number);
3972        if let Some(cached) = cache.state_before_stop_lookahead.get(&key) {
3973            return Rc::clone(cached);
3974        }
3975        let mut lookahead = StateBeforeStopLookahead::default();
3976        state_before_stop_lookahead_inner(
3977            atn,
3978            state_number,
3979            stop_state_number,
3980            &mut BTreeSet::new(),
3981            &mut cache.first_set,
3982            &mut lookahead,
3983        );
3984        let lookahead = Rc::new(lookahead);
3985        cache
3986            .state_before_stop_lookahead
3987            .insert(key, Rc::clone(&lookahead));
3988        lookahead
3989    })
3990}
3991
3992fn state_before_stop_lookahead_inner(
3993    atn: &Atn,
3994    state_number: usize,
3995    stop_state_number: usize,
3996    visited: &mut BTreeSet<usize>,
3997    first_set_cache: &mut FirstSetCache,
3998    lookahead: &mut StateBeforeStopLookahead,
3999) {
4000    if state_number == stop_state_number {
4001        lookahead.reaches_context_boundary = true;
4002        return;
4003    }
4004    if !visited.insert(state_number) {
4005        return;
4006    }
4007    let Some(state) = atn.state(state_number) else {
4008        return;
4009    };
4010    if state.kind() == AtnStateKind::RuleStop {
4011        lookahead.reaches_context_boundary = true;
4012        return;
4013    }
4014    for transition in &state.transitions() {
4015        match &transition.data() {
4016            Transition::Epsilon { target }
4017            | Transition::Action { target, .. }
4018            | Transition::Predicate { target, .. }
4019            | Transition::Precedence { target, .. } => {
4020                state_before_stop_lookahead_inner(
4021                    atn,
4022                    *target,
4023                    stop_state_number,
4024                    visited,
4025                    first_set_cache,
4026                    lookahead,
4027                );
4028            }
4029            Transition::Rule {
4030                target,
4031                rule_index,
4032                follow_state,
4033                ..
4034            } => {
4035                let Some(child_stop) = atn.rule_to_stop_state().get(*rule_index) else {
4036                    continue;
4037                };
4038                let child = rule_first_set(atn, *target, child_stop, first_set_cache);
4039                lookahead.symbols.extend_from(&child.symbols);
4040                if child.nullable {
4041                    state_before_stop_lookahead_inner(
4042                        atn,
4043                        *follow_state,
4044                        stop_state_number,
4045                        visited,
4046                        first_set_cache,
4047                        lookahead,
4048                    );
4049                }
4050            }
4051            Transition::Atom { .. }
4052            | Transition::Range { .. }
4053            | Transition::Set { .. }
4054            | Transition::NotSet { .. }
4055            | Transition::Wildcard { .. } => {
4056                lookahead.symbols.extend_iter(transition_expected_symbols(
4057                    transition,
4058                    atn.max_token_type(),
4059                ));
4060            }
4061        }
4062    }
4063}
4064
4065fn caller_context_can_match_symbol_before_state(
4066    atn: &Atn,
4067    return_states: impl DoubleEndedIterator<Item = usize>,
4068    stop_state_number: usize,
4069    symbol: i32,
4070) -> bool {
4071    for return_state in return_states.rev() {
4072        let lookahead = state_before_stop_lookahead(atn, return_state, stop_state_number);
4073        if lookahead.symbols.contains(symbol) {
4074            return true;
4075        }
4076        if !lookahead.reaches_context_boundary {
4077            return false;
4078        }
4079    }
4080    false
4081}
4082
4083/// Carries recovery expectations and their restart state through epsilon-only
4084/// paths. ANTLR can report and repair at the decision state even when the
4085/// failed consuming transition is nested under block or loop epsilon edges.
4086fn next_recovery_context(
4087    atn: &Atn,
4088    state: AtnState<'_>,
4089    inherited: &BTreeSet<i32>,
4090    inherited_state: Option<usize>,
4091) -> (BTreeSet<i32>, Option<usize>) {
4092    let state_symbols = state_expected_symbols(atn, state.state_number());
4093    if state.transitions().len() > 1 && !state_symbols.is_empty() {
4094        let mut symbols = state_symbols;
4095        symbols.extend(inherited.iter().copied());
4096        return (symbols, Some(state.state_number()));
4097    }
4098    (inherited.clone(), inherited_state)
4099}
4100
4101fn recovery_expected_symbols(
4102    atn: &Atn,
4103    state_number: usize,
4104    inherited: &BTreeSet<i32>,
4105) -> BTreeSet<i32> {
4106    let mut symbols = state_expected_symbols(atn, state_number);
4107    symbols.extend(inherited.iter().copied());
4108    symbols
4109}
4110
4111/// Fast-recognizer variant of [`next_recovery_context`] that reuses the
4112/// parser's cached state-expected-symbols sets and the inherited `Rc`
4113/// without copying when the state cannot widen recovery.
4114fn fast_next_recovery_context<S, H>(
4115    parser: &mut BaseParser<S, H>,
4116    atn: &Atn,
4117    state: AtnState<'_>,
4118    inherited: &Rc<BTreeSet<i32>>,
4119    inherited_state: Option<usize>,
4120) -> (Rc<BTreeSet<i32>>, Option<usize>)
4121where
4122    S: TokenSource,
4123    H: SemanticHooks,
4124{
4125    if state.transitions().len() <= 1 {
4126        return (Rc::clone(inherited), inherited_state);
4127    }
4128    let state_symbols = parser.cached_state_expected_symbols(atn, state.state_number());
4129    if state_symbols.is_empty() {
4130        return (Rc::clone(inherited), inherited_state);
4131    }
4132    if inherited.is_empty() {
4133        return (state_symbols, Some(state.state_number()));
4134    }
4135    if Rc::ptr_eq(&state_symbols, inherited) {
4136        return (state_symbols, Some(state.state_number()));
4137    }
4138    let mut combined = (*state_symbols).clone();
4139    combined.extend(inherited.iter().copied());
4140    (
4141        parser.intern_recovery_symbols(combined),
4142        Some(state.state_number()),
4143    )
4144}
4145
4146/// Fast-recognizer variant of [`recovery_expected_symbols`] that reuses the
4147/// cached state-expected-symbols and avoids cloning when no widening is
4148/// needed.
4149fn fast_recovery_expected_symbols<S, H>(
4150    parser: &mut BaseParser<S, H>,
4151    atn: &Atn,
4152    state_number: usize,
4153    inherited: &Rc<BTreeSet<i32>>,
4154) -> Rc<BTreeSet<i32>>
4155where
4156    S: TokenSource,
4157    H: SemanticHooks,
4158{
4159    let cached = parser.cached_state_expected_symbols(atn, state_number);
4160    if inherited.is_empty() {
4161        return cached;
4162    }
4163    if cached.is_empty() {
4164        return Rc::clone(inherited);
4165    }
4166    if Rc::ptr_eq(&cached, inherited) {
4167        return cached;
4168    }
4169    let mut combined = (*cached).clone();
4170    combined.extend(inherited.iter().copied());
4171    parser.intern_recovery_symbols(combined)
4172}
4173
4174struct ParserTableSemCtx<'a> {
4175    member_values: &'a mut MemberEnv,
4176    return_values: &'a mut BTreeMap<String, i64>,
4177}
4178
4179impl semir::PredContext for ParserTableSemCtx<'_> {
4180    type TokenText<'a>
4181        = &'a str
4182    where
4183        Self: 'a;
4184
4185    fn la(&mut self, _offset: isize) -> i64 {
4186        i64::from(TOKEN_EOF)
4187    }
4188
4189    fn token_text(&mut self, _offset: isize) -> Option<Self::TokenText<'_>> {
4190        None
4191    }
4192
4193    fn token_index_adjacent(&mut self) -> bool {
4194        false
4195    }
4196
4197    fn ctx_rule_text(&self, _rule_index: usize) -> Option<String> {
4198        None
4199    }
4200
4201    fn member(&self, member: usize) -> Option<i64> {
4202        Some(self.member_values.scalar(member).unwrap_or_default())
4203    }
4204
4205    fn member_top(&self, member: usize) -> Option<i64> {
4206        self.member_values.stack_top(member)
4207    }
4208
4209    fn member_len(&self, member: usize) -> usize {
4210        self.member_values.stack_len(member)
4211    }
4212
4213    fn local_arg(&self) -> Option<i64> {
4214        None
4215    }
4216
4217    fn column(&self) -> Option<i64> {
4218        None
4219    }
4220
4221    fn token_start_column(&self) -> Option<i64> {
4222        None
4223    }
4224
4225    fn token_text_so_far(&self) -> Option<String> {
4226        None
4227    }
4228
4229    fn hook(&mut self, _hook: HookId) -> bool {
4230        false
4231    }
4232}
4233
4234impl semir::ActContext for ParserTableSemCtx<'_> {
4235    fn set_member(&mut self, member: usize, value: i64) {
4236        self.member_values.set_scalar(member, value);
4237    }
4238
4239    fn push_member(&mut self, member: usize, value: i64) {
4240        self.member_values.push_stack(member, value);
4241    }
4242
4243    fn pop_member(&mut self, member: usize) -> Option<i64> {
4244        self.member_values.pop_stack(member)
4245    }
4246
4247    fn set_return(&mut self, name: &str, value: i64) {
4248        self.return_values.insert(name.to_owned(), value);
4249    }
4250
4251    fn action_hook(&mut self, _hook: HookId) {}
4252}
4253
4254/// Applies generated integer-member side effects to one speculative path.
4255fn apply_member_actions(
4256    source_state: usize,
4257    actions: &[ParserMemberAction],
4258    semantics: Option<&ParserSemantics>,
4259    values: &mut MemberEnv,
4260) {
4261    for action in actions
4262        .iter()
4263        .filter(|action| action.source_state == source_state)
4264    {
4265        values.add_scalar(action.member, action.delta);
4266    }
4267    let Some(semantics) = semantics else {
4268        return;
4269    };
4270    let mut return_values = BTreeMap::new();
4271    let mut ctx = ParserTableSemCtx {
4272        member_values: values,
4273        return_values: &mut return_values,
4274    };
4275    for action in semantics
4276        .actions
4277        .iter()
4278        .filter(|action| action.source_state == source_state && action.speculative)
4279    {
4280        semir::exec_stmt(&semantics.ir, action.stmt, &mut ctx);
4281    }
4282}
4283
4284/// Returns the speculative member state after replaying one ATN action state.
4285fn member_values_after_action(
4286    source_state: usize,
4287    actions: &[ParserMemberAction],
4288    semantics: Option<&ParserSemantics>,
4289    values: &MemberEnv,
4290) -> MemberEnv {
4291    let mut values = values.clone();
4292    apply_member_actions(source_state, actions, semantics, &mut values);
4293    values
4294}
4295
4296/// Returns the speculative rule-return state after replaying one ATN action.
4297fn return_values_after_action(
4298    source_state: usize,
4299    rule_index: usize,
4300    actions: &[ParserReturnAction],
4301    semantics: Option<&ParserSemantics>,
4302    values: &BTreeMap<String, i64>,
4303) -> BTreeMap<String, i64> {
4304    let mut values = values.clone();
4305    for action in actions
4306        .iter()
4307        .filter(|action| action.source_state == source_state && action.rule_index == rule_index)
4308    {
4309        values.insert(action.name.to_owned(), action.value);
4310    }
4311    if let Some(semantics) = semantics {
4312        let mut member_values = MemberEnv::new();
4313        let mut ctx = ParserTableSemCtx {
4314            member_values: &mut member_values,
4315            return_values: &mut values,
4316        };
4317        for action in semantics.actions.iter().filter(|action| {
4318            action.source_state == source_state
4319                && action.rule_index == rule_index
4320                && !action.speculative
4321        }) {
4322            semir::exec_stmt(&semantics.ir, action.stmt, &mut ctx);
4323        }
4324    }
4325    values
4326}
4327
4328/// Resolves the integer argument visible to a child rule invocation.
4329fn rule_local_int_arg(
4330    rule_args: &[ParserRuleArg],
4331    source_state: usize,
4332    rule_index: usize,
4333    local_int_arg: Option<(usize, i64)>,
4334) -> Option<(usize, i64)> {
4335    rule_args
4336        .iter()
4337        .find(|arg| arg.source_state == source_state && arg.rule_index == rule_index)
4338        .map(|arg| {
4339            let value = if arg.inherit_local {
4340                local_int_arg.map_or(arg.value, |(_, value)| value)
4341            } else {
4342                arg.value
4343            };
4344            (rule_index, value)
4345        })
4346}
4347
4348/// Builds the terminal recognition outcome for a path that reached its stop
4349/// state.
4350fn stop_outcome(
4351    index: usize,
4352    consumed_eof: bool,
4353    rule_alt_number: usize,
4354    member_values: MemberEnv,
4355    return_values: BTreeMap<String, i64>,
4356) -> Vec<RecognizeOutcome> {
4357    vec![RecognizeOutcome {
4358        index,
4359        consumed_eof,
4360        alt_number: rule_alt_number,
4361        member_values,
4362        return_values,
4363        diagnostics: DiagnosticSeqId::EMPTY,
4364        decisions: Vec::new(),
4365        actions: Vec::new(),
4366        nodes: NodeSeqId::EMPTY,
4367    }]
4368}
4369
4370fn atn_has_observable_action_transitions(atn: &Atn) -> bool {
4371    with_shared_atn_caches(atn, |cache| {
4372        *cache.observable_action_transitions.get_or_insert_with(|| {
4373            atn.states().any(|state| {
4374                state.transitions().iter().any(|transition| {
4375                    matches!(
4376                        &transition.data(),
4377                        Transition::Action {
4378                            action_index: Some(_),
4379                            ..
4380                        }
4381                    )
4382                })
4383            })
4384        })
4385    })
4386}
4387
4388fn atn_has_predicate_transitions(atn: &Atn) -> bool {
4389    with_shared_atn_caches(atn, |cache| {
4390        *cache.predicate_transitions.get_or_insert_with(|| {
4391            atn.states().any(|state| {
4392                state
4393                    .transitions()
4394                    .iter()
4395                    .any(|transition| matches!(&transition.data(), Transition::Predicate { .. }))
4396            })
4397        })
4398    })
4399}
4400
4401/// Reports whether predicates are the only observable semantics the fast
4402/// recognizer must preserve. Without path-local actions, arguments, or return
4403/// state, repeated evaluation at one coordinate and input index receives the
4404/// same runtime context.
4405fn can_use_fast_predicate_recognizer(atn: &Atn, options: &ParserRuntimeOptions<'_>) -> bool {
4406    options.init_action_rules.is_empty()
4407        && options.action_indices.is_empty()
4408        && !options.track_alt_numbers
4409        && options
4410            .predicates
4411            .iter()
4412            .all(|(_, _, predicate)| predicate.failure_message().is_none())
4413        && options.semantics.is_none_or(|semantics| {
4414            semantics.actions.is_empty()
4415                && semantics
4416                    .predicates
4417                    .iter()
4418                    .all(|predicate| predicate.failure_message.is_none())
4419        })
4420        && options.rule_args.is_empty()
4421        && options.member_actions.is_empty()
4422        && options.return_actions.is_empty()
4423        && !atn_has_observable_action_transitions(atn)
4424}
4425
4426#[derive(Clone, Debug, Eq, PartialEq)]
4427struct RecognizeRequest<'a> {
4428    state_number: usize,
4429    stop_state: usize,
4430    index: usize,
4431    rule_start_index: usize,
4432    decision_start_index: Option<usize>,
4433    init_action_rules: &'a BTreeSet<usize>,
4434    predicates: &'a [(usize, usize, ParserPredicate)],
4435    semantics: Option<&'a ParserSemantics>,
4436    rule_args: &'a [ParserRuleArg],
4437    member_actions: &'a [ParserMemberAction],
4438    return_actions: &'a [ParserReturnAction],
4439    local_int_arg: Option<(usize, i64)>,
4440    member_values: MemberEnv,
4441    return_values: BTreeMap<String, i64>,
4442    rule_alt_number: usize,
4443    track_alt_numbers: bool,
4444    consumed_eof: bool,
4445    committed_decision: bool,
4446    /// Current left-recursive precedence threshold, matching ANTLR's
4447    /// `precpred(_ctx, k)` check for generated precedence rules.
4448    precedence: i32,
4449    depth: usize,
4450    recovery_symbols: BTreeSet<i32>,
4451    recovery_state: Option<usize>,
4452}
4453
4454#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
4455struct RecognizeKey {
4456    state_number: usize,
4457    stop_state: usize,
4458    index: usize,
4459    rule_start_index: usize,
4460    decision_start_index: Option<usize>,
4461    local_int_arg: Option<(usize, i64)>,
4462    member_values: MemberEnv,
4463    return_values: BTreeMap<String, i64>,
4464    rule_alt_number: usize,
4465    track_alt_numbers: bool,
4466    consumed_eof: bool,
4467    committed_decision: bool,
4468    precedence: i32,
4469    recovery_symbols: BTreeSet<i32>,
4470    recovery_state: Option<usize>,
4471}
4472
4473#[derive(Clone, Debug, Eq, PartialEq)]
4474struct EpsilonActionStep {
4475    source_state: usize,
4476    target: usize,
4477    action_rule_index: Option<usize>,
4478    action_index: Option<usize>,
4479    left_recursive_boundary: Option<usize>,
4480    decision: Option<usize>,
4481    decision_start_index: Option<usize>,
4482    alt_number: usize,
4483    recovery_symbols: BTreeSet<i32>,
4484    recovery_state: Option<usize>,
4485}
4486
4487struct RecognizeScratch<'a> {
4488    visiting: &'a mut BTreeSet<RecognizeKey>,
4489    memo: &'a mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
4490    expected: &'a mut ExpectedTokens,
4491}
4492
4493#[derive(Clone, Debug, Eq, PartialEq)]
4494struct FastRecognizeRequest {
4495    state_number: usize,
4496    stop_state: usize,
4497    index: usize,
4498    rule_start_index: usize,
4499    decision_start_index: Option<usize>,
4500    precedence: i32,
4501    depth: usize,
4502    recovery_symbols: Rc<BTreeSet<i32>>,
4503    recovery_state: Option<usize>,
4504}
4505
4506#[derive(Clone, Copy, Debug, Eq, PartialEq)]
4507struct FastRecognizeTopRequest {
4508    start_state: usize,
4509    stop_state: usize,
4510    start_index: usize,
4511    precedence: i32,
4512    caller_follow_state: Option<usize>,
4513}
4514
4515#[derive(Clone, Copy, Debug)]
4516struct FastPredicateContext<'a> {
4517    predicates: &'a [(usize, usize, ParserPredicate)],
4518    semantics: Option<&'a ParserSemantics>,
4519    member_values: &'a MemberEnv,
4520}
4521
4522#[derive(Clone, Copy, Debug, Default)]
4523struct AltNumberTracking {
4524    public: bool,
4525    context: bool,
4526}
4527
4528impl AltNumberTracking {
4529    const fn any(self) -> bool {
4530        self.public || self.context
4531    }
4532}
4533
4534struct FastRecognizeScratch<'a, 'b> {
4535    predicate_context: Option<FastPredicateContext<'a>>,
4536    visiting: &'b mut FxHashSet<FastRecognizeKey>,
4537    memo: &'b mut FxHashMap<FastRecognizeKey, Rc<[FastRecognizeOutcome]>>,
4538    expected: &'b mut ExpectedTokens,
4539    native_depth: usize,
4540}
4541
4542#[derive(Clone, Copy, Debug)]
4543struct FastRepetitionShape {
4544    enter_target: usize,
4545    exit_target: usize,
4546    body_stop_state: usize,
4547    enter_transition_index: usize,
4548    exit_transition_index: usize,
4549}
4550
4551#[derive(Clone, Copy, Debug)]
4552struct FastRepetitionPath {
4553    index: usize,
4554    deferred_nodes: FastDeferredNodeId,
4555    diagnostics: DiagnosticSeqId,
4556    consumed_eof: bool,
4557}
4558
4559enum FastRepetitionWork {
4560    Enter(FastRepetitionPath),
4561    Exit(FastRepetitionPath),
4562}
4563
4564/// Dense entered/exited coordinate sets for one repetition walk.
4565///
4566/// The start coordinate stays inline so short loops avoid a heap allocation;
4567/// later token indexes use one byte each instead of two hash-table entries.
4568struct FastRepetitionCoordinates {
4569    base_index: usize,
4570    base_state: u8,
4571    later_states: Vec<u8>,
4572}
4573
4574impl FastRepetitionCoordinates {
4575    const ENTERED: u8 = 0;
4576    const EXITED: u8 = 2;
4577
4578    const fn new(base_index: usize) -> Self {
4579        Self {
4580            base_index,
4581            base_state: 0,
4582            later_states: Vec::new(),
4583        }
4584    }
4585
4586    fn insert_entered(&mut self, path: FastRepetitionPath) -> bool {
4587        self.insert(path.index, path.consumed_eof, Self::ENTERED)
4588    }
4589
4590    fn insert_exited(&mut self, path: FastRepetitionPath) -> bool {
4591        self.insert(path.index, path.consumed_eof, Self::EXITED)
4592    }
4593
4594    fn insert(&mut self, index: usize, consumed_eof: bool, base_bit: u8) -> bool {
4595        let Some(offset) = index.checked_sub(self.base_index) else {
4596            return false;
4597        };
4598        let state = if offset == 0 {
4599            &mut self.base_state
4600        } else {
4601            if self.later_states.len() < offset {
4602                self.later_states.resize(offset, 0);
4603            }
4604            &mut self.later_states[offset - 1]
4605        };
4606        let bit = 1 << (base_bit + u8::from(consumed_eof));
4607        let is_new = *state & bit == 0;
4608        *state |= bit;
4609        is_new
4610    }
4611}
4612
4613fn fast_repetition_shape(atn: &Atn, state: AtnState<'_>) -> Option<FastRepetitionShape> {
4614    if state.precedence_rule_decision()
4615        || !matches!(
4616            state.kind(),
4617            AtnStateKind::StarLoopEntry | AtnStateKind::PlusLoopBack
4618        )
4619        || state.transitions().len() != 2
4620    {
4621        return None;
4622    }
4623    let mut enter = None;
4624    let mut exit = None;
4625    for (index, transition) in state.transitions().iter().enumerate() {
4626        if transition.kind() != ParserTransitionKind::Epsilon {
4627            return None;
4628        }
4629        let target = transition.target();
4630        if atn
4631            .state(target)
4632            .is_some_and(|target_state| target_state.kind() == AtnStateKind::LoopEnd)
4633        {
4634            if exit.replace((index, target)).is_some() {
4635                return None;
4636            }
4637        } else if enter.replace((index, target)).is_some() {
4638            return None;
4639        }
4640    }
4641    let (enter_transition_index, enter_target) = enter?;
4642    let (exit_transition_index, exit_target) = exit?;
4643    let body_stop_state = if state.kind() == AtnStateKind::StarLoopEntry {
4644        atn.state(exit_target)?.loop_back_state()?
4645    } else {
4646        state.state_number()
4647    };
4648    Some(FastRepetitionShape {
4649        enter_target,
4650        exit_target,
4651        body_stop_state,
4652        enter_transition_index,
4653        exit_transition_index,
4654    })
4655}
4656
4657fn push_fast_repetition_work(
4658    work: &mut Vec<FastRepetitionWork>,
4659    shape: FastRepetitionShape,
4660    path: FastRepetitionPath,
4661    lookahead: Option<&DecisionLookahead>,
4662    symbol: i32,
4663) {
4664    // Match the normal recognizer's FIRST-set pruning before queueing work.
4665    // Ambiguous body paths still share the coordinate bitmap below.
4666    let transition_is_viable = |transition_index: usize| {
4667        let Some(entry) = lookahead else {
4668            return true;
4669        };
4670        let Some(transition) = entry.transitions.get(transition_index) else {
4671            return true;
4672        };
4673        transition.nullable || transition.symbols.contains(symbol)
4674    };
4675    let enter_is_viable = transition_is_viable(shape.enter_transition_index);
4676    let exit_is_viable = transition_is_viable(shape.exit_transition_index);
4677    if shape.enter_transition_index < shape.exit_transition_index {
4678        if exit_is_viable {
4679            work.push(FastRepetitionWork::Exit(path));
4680        }
4681        if enter_is_viable {
4682            work.push(FastRepetitionWork::Enter(path));
4683        }
4684    } else {
4685        if enter_is_viable {
4686            work.push(FastRepetitionWork::Enter(path));
4687        }
4688        if exit_is_viable {
4689            work.push(FastRepetitionWork::Exit(path));
4690        }
4691    }
4692}
4693
4694/// Memo key for the fast recognizer. `recovery_symbols` must come from
4695/// `intern_recovery_symbols` or `empty_recovery_symbols` before it reaches this
4696/// key, so equal sets share one allocation and the key can store that
4697/// allocation's address instead of cloning an `Rc` and walking the full
4698/// `BTreeSet`. Bypassing the interner would turn content-equal recovery sets
4699/// into distinct cache coordinates.
4700#[derive(Clone, Debug)]
4701struct FastRecognizeKey {
4702    state_number: usize,
4703    stop_state: usize,
4704    index: usize,
4705    rule_start_index: usize,
4706    decision_start_index: Option<usize>,
4707    precedence: i32,
4708    recovery_symbols_id: usize,
4709    recovery_state: Option<usize>,
4710}
4711
4712impl PartialEq for FastRecognizeKey {
4713    fn eq(&self, other: &Self) -> bool {
4714        if self.state_number != other.state_number
4715            || self.stop_state != other.stop_state
4716            || self.index != other.index
4717            || self.rule_start_index != other.rule_start_index
4718            || self.decision_start_index != other.decision_start_index
4719            || self.precedence != other.precedence
4720            || self.recovery_state != other.recovery_state
4721            || self.recovery_symbols_id != other.recovery_symbols_id
4722        {
4723            return false;
4724        }
4725        true
4726    }
4727}
4728
4729impl Eq for FastRecognizeKey {}
4730
4731impl Hash for FastRecognizeKey {
4732    fn hash<H: Hasher>(&self, hasher: &mut H) {
4733        self.state_number.hash(hasher);
4734        self.stop_state.hash(hasher);
4735        self.index.hash(hasher);
4736        self.rule_start_index.hash(hasher);
4737        self.decision_start_index.hash(hasher);
4738        self.precedence.hash(hasher);
4739        self.recovery_state.hash(hasher);
4740        self.recovery_symbols_id.hash(hasher);
4741    }
4742}
4743
4744struct FastRecoveryRequest<'a, 'b> {
4745    atn: &'a Atn,
4746    transition: ParserTransition<'a>,
4747    expected_symbols: Rc<BTreeSet<i32>>,
4748    target: usize,
4749    request: FastRecognizeRequest,
4750    visiting: &'b mut FxHashSet<FastRecognizeKey>,
4751    memo: &'b mut FxHashMap<FastRecognizeKey, Rc<[FastRecognizeOutcome]>>,
4752    expected: &'b mut ExpectedTokens,
4753}
4754
4755struct FastCurrentTokenDeletionRequest<'a, 'b> {
4756    atn: &'a Atn,
4757    expected_symbols: Rc<BTreeSet<i32>>,
4758    request: FastRecognizeRequest,
4759    visiting: &'b mut FxHashSet<FastRecognizeKey>,
4760    memo: &'b mut FxHashMap<FastRecognizeKey, Rc<[FastRecognizeOutcome]>>,
4761    expected: &'b mut ExpectedTokens,
4762}
4763
4764#[derive(Clone, Copy)]
4765struct FastChildRuleFailureRecoveryRequest<'a> {
4766    atn: &'a Atn,
4767    rule_index: usize,
4768    start_index: usize,
4769    follow_state: usize,
4770    stop_state: usize,
4771    expected: &'a ExpectedTokens,
4772}
4773
4774struct RecoveryRequest<'a, 'b> {
4775    atn: &'a Atn,
4776    transition: ParserTransition<'a>,
4777    expected_symbols: BTreeSet<i32>,
4778    target: usize,
4779    request: RecognizeRequest<'a>,
4780    visiting: &'b mut BTreeSet<RecognizeKey>,
4781    memo: &'b mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
4782    expected: &'b mut ExpectedTokens,
4783}
4784
4785struct CurrentTokenDeletionRequest<'a, 'b> {
4786    atn: &'a Atn,
4787    expected_symbols: BTreeSet<i32>,
4788    request: RecognizeRequest<'a>,
4789    visiting: &'b mut BTreeSet<RecognizeKey>,
4790    memo: &'b mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
4791    expected: &'b mut ExpectedTokens,
4792}
4793
4794/// Carries the state needed after the normal token-recovery strategies fail
4795/// for a consuming transition.
4796struct ConsumingFailureFallback<'a> {
4797    atn: &'a Atn,
4798    target: usize,
4799    request: RecognizeRequest<'a>,
4800    symbol: i32,
4801    expected_symbols: BTreeSet<i32>,
4802    decision_start_index: Option<usize>,
4803    decision: Option<usize>,
4804}
4805
4806/// Captures the parent-rule context needed when a called rule fails before it
4807/// can produce a normal outcome.
4808struct ChildRuleFailureRecovery<'a> {
4809    atn: &'a Atn,
4810    rule_index: usize,
4811    start_index: usize,
4812    follow_state: usize,
4813    stop_state: usize,
4814    member_values: MemberEnv,
4815    expected: &'a ExpectedTokens,
4816}
4817
4818/// Bundles the context needed to evaluate one semantic predicate transition.
4819#[derive(Clone, Copy, Debug)]
4820struct PredicateEval<'a> {
4821    index: usize,
4822    rule_index: usize,
4823    pred_index: usize,
4824    predicates: &'a [(usize, usize, ParserPredicate)],
4825    semantics: Option<&'a ParserSemantics>,
4826    context: Option<&'a ParserRuleContext>,
4827    local_int_arg: Option<(usize, i64)>,
4828    member_values: &'a MemberEnv,
4829}
4830
4831#[derive(Clone, Copy, Debug)]
4832struct ParserSemanticHookRequest<'a> {
4833    index: usize,
4834    rule_index: usize,
4835    pred_index: usize,
4836    context: Option<&'a ParserRuleContext>,
4837    local_int_arg: Option<(usize, i64)>,
4838    member_values: &'a MemberEnv,
4839}
4840
4841/// Predicate-evaluation context over the recognizer's speculative state.
4842///
4843/// This sits in the prediction hot loop, so everything is borrowed: member
4844/// state read-only from the current speculative path and the rule name
4845/// straight from recognizer metadata. Predicates are pure by construction
4846/// ([`semir::PExpr`] has no mutating node); statement execution uses
4847/// [`ParserTableSemCtx`] (speculative member/return replay) and
4848/// [`BaseParser::parser_action_hook`] (committed action hooks) instead.
4849struct ParserSemIrCtx<'a, S, H>
4850where
4851    S: TokenSource,
4852    H: SemanticHooks,
4853{
4854    input: &'a mut CommonTokenStream<S>,
4855    tree_storage: &'a ParseTreeStorage,
4856    semantic_hooks: &'a mut H,
4857    rule_index: usize,
4858    coordinate_index: usize,
4859    rule_name: Option<&'a str>,
4860    context: Option<&'a ParserRuleContext>,
4861    local_int_arg: Option<(usize, i64)>,
4862    member_values: &'a MemberEnv,
4863    invoked_predicates: &'a mut Vec<(usize, usize)>,
4864    /// Policy applied when a [`semir::PExpr::Hook`] node's user hook declines
4865    /// (`None`); keeps the fail-loud fallback chain identical to the legacy
4866    /// table path instead of coercing the miss to `false`.
4867    unknown_predicate_policy: UnknownSemanticPolicy,
4868    unknown_predicate_hits: &'a mut Vec<(usize, usize)>,
4869}
4870
4871impl<S, H> semir::PredContext for ParserSemIrCtx<'_, S, H>
4872where
4873    S: TokenSource,
4874    H: SemanticHooks,
4875{
4876    type TokenText<'a>
4877        = TokenView<'a>
4878    where
4879        Self: 'a;
4880
4881    fn la(&mut self, offset: isize) -> i64 {
4882        i64::from(self.input.la(offset))
4883    }
4884
4885    fn token_text(&mut self, offset: isize) -> Option<Self::TokenText<'_>> {
4886        self.input.lt(offset)
4887    }
4888
4889    fn token_index_adjacent(&mut self) -> bool {
4890        let Some(first) = self.input.lt_id(-2).map(TokenId::index) else {
4891            return false;
4892        };
4893        let Some(second) = self.input.lt_id(-1).map(TokenId::index) else {
4894            return false;
4895        };
4896        first + 1 == second
4897    }
4898
4899    fn ctx_rule_text(&self, rule_index: usize) -> Option<String> {
4900        self.context.and_then(|context| {
4901            context
4902                .child_rules(self.tree_storage, self.input.token_store(), rule_index)
4903                .next()
4904                .map(crate::tree::RuleNodeView::text)
4905        })
4906    }
4907
4908    fn member(&self, member: usize) -> Option<i64> {
4909        Some(self.member_values.scalar(member).unwrap_or_default())
4910    }
4911
4912    fn member_top(&self, member: usize) -> Option<i64> {
4913        self.member_values.stack_top(member)
4914    }
4915
4916    fn member_len(&self, member: usize) -> usize {
4917        self.member_values.stack_len(member)
4918    }
4919
4920    fn local_arg(&self) -> Option<i64> {
4921        self.local_int_arg.map(|(_, value)| value)
4922    }
4923
4924    fn column(&self) -> Option<i64> {
4925        None
4926    }
4927
4928    fn token_start_column(&self) -> Option<i64> {
4929        None
4930    }
4931
4932    fn token_text_so_far(&self) -> Option<String> {
4933        None
4934    }
4935
4936    fn hook(&mut self, _hook: HookId) -> bool {
4937        let mut ctx = ParserSemCtx {
4938            input: &mut *self.input,
4939            tree_storage: self.tree_storage,
4940            rule_index: self.rule_index,
4941            coordinate_index: self.coordinate_index,
4942            rule_name: self.rule_name.map(str::to_owned),
4943            context: self.context,
4944            tree: None,
4945            local_int_arg: self.local_int_arg,
4946            member_values: self.member_values,
4947            action: None,
4948        };
4949        match self
4950            .semantic_hooks
4951            .sempred(&mut ctx, self.rule_index, self.coordinate_index)
4952        {
4953            Some(result) => result,
4954            // No hook answered this coordinate: fall through to the configured
4955            // policy instead of silently rejecting the alternative, matching the
4956            // legacy table path's dispatch chain (hook → policy).
4957            None => apply_unknown_predicate_policy(
4958                self.unknown_predicate_policy,
4959                self.rule_index,
4960                self.coordinate_index,
4961                self.unknown_predicate_hits,
4962            ),
4963        }
4964    }
4965
4966    fn trace_bool(&mut self, value: bool) -> bool {
4967        let key = (self.rule_index, self.coordinate_index);
4968        if !self.invoked_predicates.contains(&key) {
4969            self.invoked_predicates.push(key);
4970            use std::io::Write as _;
4971            let mut stdout = std::io::stdout().lock();
4972            let _ = writeln!(stdout, "eval={value}");
4973        }
4974        value
4975    }
4976}
4977
4978/// Captures predicate-failure recovery metadata for fail-option predicates.
4979struct PredicateFailureRecovery<'a> {
4980    rule_index: usize,
4981    index: usize,
4982    message: &'a str,
4983    member_values: MemberEnv,
4984    return_values: BTreeMap<String, i64>,
4985    rule_alt_number: usize,
4986}
4987
4988#[derive(Debug)]
4989enum DirectAdaptiveParseControl {
4990    Fallback(DirectAdaptiveFallback),
4991}
4992
4993#[derive(Clone, Copy, Debug, Eq, PartialEq)]
4994enum DirectAdaptiveFallback {
4995    Action,
4996    InvalidAlt,
4997    LeftRecursiveBoundary,
4998    MissingAtn,
4999    NoTransition,
5000    Predicate,
5001    Prediction,
5002    Precedence,
5003    RuleStop,
5004    SemanticContext,
5005    StepLimit,
5006    TokenMismatch,
5007    UnknownDecision,
5008}
5009
5010type DirectAdaptiveParseResult<T> = Result<T, DirectAdaptiveParseControl>;
5011
5012struct DirectAdaptiveParser<'atn, 'sim, S, H = NoSemanticHooks>
5013where
5014    S: TokenSource,
5015    H: SemanticHooks,
5016{
5017    parser: &'sim mut BaseParser<S, H>,
5018    atn: &'atn Atn,
5019    simulator: &'sim mut ParserAtnSimulator<'atn>,
5020    decision_by_state: Vec<Option<usize>>,
5021    steps: usize,
5022}
5023
5024struct CommittedAtnParser<'atn, 'sim, 'options, S, H = NoSemanticHooks>
5025where
5026    S: TokenSource,
5027    H: SemanticHooks,
5028{
5029    parser: &'sim mut BaseParser<S, H>,
5030    atn: &'atn Atn,
5031    simulator: ParserAtnSimulator<'atn>,
5032    options: ParserRuntimeOptions<'options>,
5033    decision_by_state: Vec<Option<usize>>,
5034    action_index_by_state: FxHashMap<usize, usize>,
5035    deferred_actions: Vec<ParserAction>,
5036}
5037
5038struct CommittedRuleOutcome {
5039    tree: ParseTree,
5040    consumed_eof: bool,
5041}
5042
5043struct CommittedDecisionContext<'a> {
5044    precedence: i32,
5045    local_int_arg: Option<(usize, i64)>,
5046    context: &'a mut ParserRuleContext,
5047    entered_loops: &'a mut BTreeSet<usize>,
5048}
5049
5050/// Outcome of a generated token / set / not-set match that may recover.
5051///
5052/// Generated parsers append `children` to the current rule context. `consumed_eof`
5053/// reports whether the match actually consumed a real EOF terminal — it is true
5054/// only on a successful match (or single-token deletion that lands on EOF), and
5055/// always false on single-token insertion, which synthesizes a missing token and
5056/// consumes nothing. Generated code feeds this into `finish_rule`'s
5057/// `consumed_eof`, so the rule stop token is recorded as EOF only when EOF was
5058/// truly matched, matching ANTLR's `matchedEOF` semantics.
5059#[derive(Clone, Debug, Eq, PartialEq)]
5060pub struct GeneratedMatch {
5061    children: GeneratedMatchChildren,
5062    consumed_eof: bool,
5063}
5064
5065#[derive(Clone, Copy)]
5066enum GeneratedExpectedSymbols<'a> {
5067    Tree(&'a BTreeSet<i32>),
5068    TokenSet(ParserIntervalSet<'a>),
5069    TokenSetComplement {
5070        set: ParserIntervalSet<'a>,
5071        min_vocabulary: i32,
5072        max_vocabulary: i32,
5073    },
5074}
5075
5076impl GeneratedExpectedSymbols<'_> {
5077    fn is_empty(self) -> bool {
5078        match self {
5079            Self::Tree(symbols) => symbols.is_empty(),
5080            Self::TokenSet(set) => set.is_empty(),
5081            Self::TokenSetComplement {
5082                set,
5083                min_vocabulary,
5084                max_vocabulary,
5085            } => (min_vocabulary..=max_vocabulary).all(|symbol| set.contains(symbol)),
5086        }
5087    }
5088
5089    fn first(self) -> Option<i32> {
5090        match self {
5091            Self::Tree(symbols) => symbols.iter().next().copied(),
5092            Self::TokenSet(set) => set.ranges().next().map(|(start, _)| start),
5093            Self::TokenSetComplement {
5094                set,
5095                min_vocabulary,
5096                max_vocabulary,
5097            } => (min_vocabulary..=max_vocabulary).find(|symbol| !set.contains(*symbol)),
5098        }
5099    }
5100
5101    fn display(self, vocabulary: &Vocabulary) -> String {
5102        match self {
5103            Self::Tree(symbols) => expected_symbols_display(symbols, vocabulary),
5104            Self::TokenSet(set) => expected_symbols_display_iter(
5105                set.ranges().flat_map(|(start, stop)| start..=stop),
5106                vocabulary,
5107            ),
5108            Self::TokenSetComplement {
5109                set,
5110                min_vocabulary,
5111                max_vocabulary,
5112            } => expected_symbols_display_iter(
5113                (min_vocabulary..=max_vocabulary).filter(|symbol| !set.contains(*symbol)),
5114                vocabulary,
5115            ),
5116        }
5117    }
5118}
5119
5120#[derive(Clone, Debug, Eq, PartialEq)]
5121enum GeneratedMatchChildren {
5122    One(ParseTree),
5123    Many(Vec<ParseTree>),
5124}
5125
5126struct GeneratedMatchChildrenIntoIter {
5127    one: Option<ParseTree>,
5128    many: Option<std::vec::IntoIter<ParseTree>>,
5129}
5130
5131impl Iterator for GeneratedMatchChildrenIntoIter {
5132    type Item = ParseTree;
5133
5134    fn next(&mut self) -> Option<Self::Item> {
5135        self.one
5136            .take()
5137            .or_else(|| self.many.as_mut().and_then(Iterator::next))
5138    }
5139}
5140
5141impl GeneratedMatch {
5142    /// Parse-tree children produced by the match (the matched terminal, an
5143    /// error node plus deleted-then-matched terminal, or a single missing-token
5144    /// error node).
5145    #[must_use]
5146    pub fn children(&self) -> &[ParseTree] {
5147        match &self.children {
5148            GeneratedMatchChildren::One(child) => std::slice::from_ref(child),
5149            GeneratedMatchChildren::Many(children) => children,
5150        }
5151    }
5152
5153    /// Consumes the result, returning the children for appending to the rule
5154    /// context.
5155    #[must_use]
5156    pub fn into_children(self) -> Vec<ParseTree> {
5157        match self.children {
5158            GeneratedMatchChildren::One(child) => vec![child],
5159            GeneratedMatchChildren::Many(children) => children,
5160        }
5161    }
5162
5163    /// Consumes the match without allocating for the common single-child case.
5164    pub fn into_child_iter(self) -> impl Iterator<Item = ParseTree> {
5165        match self.children {
5166            GeneratedMatchChildren::One(child) => GeneratedMatchChildrenIntoIter {
5167                one: Some(child),
5168                many: None,
5169            },
5170            GeneratedMatchChildren::Many(children) => GeneratedMatchChildrenIntoIter {
5171                one: None,
5172                many: Some(children.into_iter()),
5173            },
5174        }
5175    }
5176
5177    /// Whether a real EOF terminal was consumed by this match.
5178    #[must_use]
5179    pub const fn consumed_eof(&self) -> bool {
5180        self.consumed_eof
5181    }
5182}
5183
5184impl<S> BaseParser<S, NoSemanticHooks>
5185where
5186    S: TokenSource,
5187{
5188    /// Creates a parser base over a buffered token stream and recognizer
5189    /// metadata.
5190    pub fn new(input: CommonTokenStream<S>, data: RecognizerData) -> Self {
5191        Self::with_semantic_hooks(input, data, NoSemanticHooks)
5192    }
5193}
5194
5195impl<S, H> BaseParser<S, H>
5196where
5197    S: TokenSource,
5198    H: SemanticHooks,
5199{
5200    /// Creates a parser base with caller-owned semantic hooks.
5201    pub fn with_semantic_hooks(
5202        input: CommonTokenStream<S>,
5203        data: RecognizerData,
5204        semantic_hooks: H,
5205    ) -> Self {
5206        Self {
5207            input,
5208            tree: ParseTreeStorage::new(),
5209            data,
5210            semantic_hooks,
5211            decision_override_generation: 0,
5212            build_parse_trees: true,
5213            syntax_errors: 0,
5214            report_diagnostic_errors: false,
5215            prediction_mode: PredictionMode::Ll,
5216            prediction_diagnostics: Vec::new(),
5217            reported_prediction_diagnostics: BTreeSet::new(),
5218            generated_parser_diagnostics: Vec::new(),
5219            generated_sync_expected: None,
5220            generated_recovery_error_index: None,
5221            generated_recovery_error_states: BTreeSet::new(),
5222            int_members: MemberEnv::new(),
5223            rule_context_stack: Vec::new(),
5224            rule_context_version: 0,
5225            left_recursive_caller_overlap_cache: std::array::from_fn(|_| None),
5226            pending_invoking_states: Vec::new(),
5227            precedence_stack: vec![0],
5228            invoked_predicates: Vec::new(),
5229            bail_on_error: false,
5230            parse_listeners: Vec::new(),
5231            parse_listener_abort: None,
5232            max_rule_depth: None,
5233            rule_depth_error: None,
5234            recursion_expansions: 0,
5235            recursion_expansion_marks: Vec::new(),
5236            unknown_predicate_policy: UnknownSemanticPolicy::default(),
5237            unknown_predicate_hits: Vec::new(),
5238            unhandled_action_hits: Vec::new(),
5239            rule_first_set_cache: Vec::new(),
5240            state_expected_cache: FxHashMap::default(),
5241            state_expected_token_cache: FxHashMap::default(),
5242            rule_stop_reach_cache: Vec::new(),
5243            recovery_symbols_intern: FxHashMap::default(),
5244            decision_lookahead_cache: FxHashMap::default(),
5245            ll1_decision_cache: FxHashMap::default(),
5246            fast_predicate_cache: FxHashMap::default(),
5247            empty_cycle_cache: Vec::new(),
5248            empty_cycle_cache_atn: None,
5249            clean_memo_mode: CleanMemoMode::Probe,
5250            clean_memo_probe_seen: FxHashSet::default(),
5251            clean_memo_probe_samples: 0,
5252            clean_memo_probe_repeats: 0,
5253            clean_memo_sparse_samples: 0,
5254            fast_recognize_scratch: FastRecognizeTopScratch::default(),
5255            fast_outcome_dedup: FastOutcomeDedupScratch::default(),
5256            empty_recovery_symbols: Rc::new(BTreeSet::new()),
5257            fast_first_set_prefilter: true,
5258            fast_recovery_enabled: true,
5259            fast_token_nodes_enabled: true,
5260            fast_track_alt_numbers: false,
5261            recognition_arena: RecognitionArena::default(),
5262            last_recognition_arena_root: NodeSeqId::EMPTY,
5263            last_recognition_arena_diagnostics: DiagnosticSeqId::EMPTY,
5264        }
5265    }
5266
5267    pub const fn input(&mut self) -> &mut CommonTokenStream<S> {
5268        &mut self.input
5269    }
5270
5271    /// Fully resets parser-owned state and rewinds the current token stream.
5272    ///
5273    /// Parser configuration, semantic hooks, learned DFA tables, and
5274    /// grammar-owned member values are retained.
5275    pub fn reset(&mut self) {
5276        self.input.seek(0);
5277        self.tree.reset();
5278        self.data.set_state(-1);
5279        self.syntax_errors = 0;
5280        self.prediction_diagnostics.clear();
5281        self.reported_prediction_diagnostics.clear();
5282        self.generated_parser_diagnostics.clear();
5283        self.generated_sync_expected = None;
5284        self.reset_generated_recovery_state();
5285        self.rule_context_stack.clear();
5286        self.advance_rule_context_version();
5287        self.left_recursive_caller_overlap_cache = std::array::from_fn(|_| None);
5288        self.pending_invoking_states.clear();
5289        self.precedence_stack.clear();
5290        self.precedence_stack.push(0);
5291        self.invoked_predicates.clear();
5292        self.decision_override_generation = 0;
5293        self.unknown_predicate_hits.clear();
5294        self.unhandled_action_hits.clear();
5295        self.parse_listener_abort = None;
5296        self.rule_depth_error = None;
5297        self.recursion_expansions = 0;
5298        self.recursion_expansion_marks.clear();
5299        self.reset_per_parse_caches();
5300        self.fast_first_set_prefilter = true;
5301        self.fast_recovery_enabled = true;
5302        self.fast_token_nodes_enabled = self.build_parse_trees;
5303        self.fast_track_alt_numbers = false;
5304        self.reset_recognition_arena();
5305    }
5306
5307    /// Replaces the buffered token stream and fully resets this parser.
5308    pub fn set_token_stream(&mut self, input: CommonTokenStream<S>) {
5309        self.input = input;
5310        self.reset();
5311    }
5312
5313    /// Installs the policy for predicate coordinates that no translated table
5314    /// entry or user hook resolves.
5315    ///
5316    /// The interpreter fallback sets this per parse from [`ParserRuntimeOptions`],
5317    /// but generated recursive-descent rules evaluate predicates directly
5318    /// (`parser_semantic_ir_predicate_matches_with_context_and_local`) without
5319    /// going through those options. Generated parser constructors call this so
5320    /// the generated-direct path honors `--sem-unknown` too, instead of leaving
5321    /// the field at its `AssumeTrue` default and silently accepting an
5322    /// unimplemented hook predicate.
5323    pub const fn set_unknown_predicate_policy(&mut self, policy: UnknownSemanticPolicy) {
5324        self.unknown_predicate_policy = policy;
5325    }
5326
5327    /// Reports any unknown predicate coordinate the generated-direct path
5328    /// recorded under [`UnknownSemanticPolicy::Error`], as an
5329    /// [`AntlrError::Unsupported`]. Generated parser entry points call this
5330    /// after a rule completes so the fail-loud policy surfaces on the
5331    /// generated path the same way the interpreter entry surfaces it.
5332    #[must_use]
5333    pub fn take_unknown_semantic_error(&mut self) -> Option<AntlrError> {
5334        let error = self.unknown_semantic_error();
5335        self.unknown_predicate_hits.clear();
5336        self.unhandled_action_hits.clear();
5337        error
5338    }
5339
5340    /// Drops any fail-loud semantic coordinates recorded by a previous parse.
5341    ///
5342    /// Generated parsers call this at the true top-level entry so a parser
5343    /// reused after a fail-loud (or recovered) parse starts clean, without
5344    /// clearing hits mid-parse where a generated parent still needs a child's
5345    /// recorded coordinate to survive to the top-level boundary.
5346    pub fn reset_unknown_semantic_hits(&mut self) {
5347        self.unknown_predicate_hits.clear();
5348        self.unhandled_action_hits.clear();
5349    }
5350
5351    /// Returns the token stream owned by this parser.
5352    #[must_use]
5353    pub const fn token_stream(&self) -> &CommonTokenStream<S> {
5354        &self.input
5355    }
5356
5357    /// Returns the token stream for source replacement or in-place re-feeding.
5358    #[must_use]
5359    pub const fn token_stream_mut(&mut self) -> &mut CommonTokenStream<S> {
5360        &mut self.input
5361    }
5362
5363    /// Returns the canonical token store referenced by parse trees.
5364    #[must_use]
5365    pub const fn token_store(&self) -> &TokenStore {
5366        self.input.token_store()
5367    }
5368
5369    /// Returns the flat CST storage populated by completed rules.
5370    #[must_use]
5371    pub const fn parse_tree_storage(&self) -> &ParseTreeStorage {
5372        &self.tree
5373    }
5374
5375    /// Resolves a compact parse-tree ID into a borrowing node view.
5376    #[must_use]
5377    pub fn node(&self, id: NodeId) -> Node<'_> {
5378        self.tree
5379            .node(self.input.token_store(), id)
5380            .expect("parser-produced node ID should remain valid")
5381    }
5382
5383    /// Consumes this parser and returns its token stream.
5384    #[must_use]
5385    pub fn into_token_stream(self) -> CommonTokenStream<S> {
5386        self.input
5387    }
5388
5389    /// Consumes this parser and returns its canonical token store.
5390    #[must_use]
5391    pub fn into_token_store(self) -> TokenStore {
5392        self.input.into_token_store()
5393    }
5394
5395    /// Consumes the parser and pairs its token store and flat CST with `root`.
5396    #[must_use]
5397    pub fn into_parsed_file(self, root: NodeId) -> ParsedFile {
5398        ParsedFile::new(self.input.into_token_store(), self.tree, root)
5399    }
5400
5401    /// Returns the number of parser syntax errors recorded by committed parse
5402    /// paths so far.
5403    pub const fn number_of_syntax_errors(&self) -> usize {
5404        self.syntax_errors
5405    }
5406
5407    /// Computes reachability and retained-capacity counters for the most recent
5408    /// interpreted-rule recognition arena.
5409    ///
5410    /// The reachability scan is linear in the arena size and is deferred until
5411    /// this instrumentation method is called.
5412    #[must_use]
5413    pub fn recognition_arena_stats(&self) -> RecognitionArenaStats {
5414        self.recognition_arena.stats(
5415            self.last_recognition_arena_root,
5416            self.last_recognition_arena_diagnostics,
5417        )
5418    }
5419
5420    /// Records a syntax error that generated parser code returns as fatal before
5421    /// it can recover into the current rule context.
5422    pub const fn record_generated_syntax_error(&mut self) {
5423        self.record_syntax_errors(1);
5424    }
5425
5426    const fn record_syntax_errors(&mut self, count: usize) {
5427        self.syntax_errors = self.syntax_errors.saturating_add(count);
5428    }
5429
5430    /// Returns whether no interpreted rule context or generated invocation is active.
5431    const fn is_top_level_entry(&self) -> bool {
5432        self.rule_context_stack.is_empty() && self.pending_invoking_states.is_empty()
5433    }
5434
5435    /// Emits diagnostics buffered by the token stream while generated parser
5436    /// code was fetching lexer tokens directly.
5437    pub fn report_token_source_errors(&mut self) {
5438        let errors = self.input.drain_source_errors();
5439        self.dispatch_token_source_errors(&errors);
5440    }
5441
5442    /// Captures generated-parser diagnostics and syntax-error count before a
5443    /// speculative generated rule path.
5444    pub const fn generated_diagnostics_checkpoint(&self) -> GeneratedDiagnosticsCheckpoint {
5445        GeneratedDiagnosticsCheckpoint {
5446            diagnostics_len: self.generated_parser_diagnostics.len(),
5447            syntax_errors: self.syntax_errors,
5448            tree: self.tree.checkpoint(),
5449        }
5450    }
5451
5452    /// Restores generated-parser diagnostics after a speculative rule path failed.
5453    pub fn restore_generated_diagnostics(&mut self, marker: GeneratedDiagnosticsCheckpoint) {
5454        self.generated_parser_diagnostics
5455            .truncate(marker.diagnostics_len);
5456        self.syntax_errors = marker.syntax_errors;
5457        self.rollback_generated_tree(marker);
5458    }
5459
5460    /// Rolls back generated tree state while retaining committed diagnostics.
5461    ///
5462    /// Fatal public entries use this after an earlier child recovery: the
5463    /// partial tree is discarded, but ANTLR has already committed the child's
5464    /// diagnostic and syntax-error count.
5465    pub fn rollback_generated_tree(&mut self, marker: GeneratedDiagnosticsCheckpoint) {
5466        self.generated_sync_expected = None;
5467        self.tree.rollback(marker.tree);
5468    }
5469
5470    /// Emits diagnostics recorded by committed generated parser recovery.
5471    pub fn report_generated_parser_diagnostics(&mut self) {
5472        let parser_diagnostics = std::mem::take(&mut self.generated_parser_diagnostics);
5473        let token_errors = self.input.drain_source_errors();
5474        self.dispatch_generated_diagnostics(&parser_diagnostics, &token_errors);
5475    }
5476
5477    fn syntax_error_event<'a>(
5478        &'a self,
5479        offending: Option<TokenId>,
5480        line: usize,
5481        column: usize,
5482        message: &'a str,
5483        error: Option<&'a AntlrError>,
5484    ) -> SyntaxErrorEvent<'a> {
5485        let offending = offending.and_then(|token| self.token_store().view(token));
5486        SyntaxErrorEvent {
5487            offending,
5488            line,
5489            column,
5490            span: offending.and_then(|token| token.byte_span()),
5491            message,
5492            error,
5493        }
5494    }
5495
5496    /// Emits a fatal parser error after an entry-rule parse commits to returning it.
5497    ///
5498    /// Generated parsers call this only at their public entry boundary. Nested
5499    /// failures remain silent until generated recovery commits and buffers them.
5500    pub fn report_unrecovered_parser_error(&self, error: &AntlrError) {
5501        let AntlrError::ParserError {
5502            line,
5503            column,
5504            message,
5505            offending,
5506        } = error
5507        else {
5508            return;
5509        };
5510        self.notify_error_listeners(self.syntax_error_event(
5511            *offending,
5512            *line,
5513            *column,
5514            message,
5515            Some(error),
5516        ));
5517    }
5518
5519    fn dispatch_parser_diagnostic(&self, diagnostic: &ParserDiagnostic) {
5520        self.notify_error_listeners(self.syntax_error_event(
5521            diagnostic.offending,
5522            diagnostic.line,
5523            diagnostic.column,
5524            &diagnostic.message,
5525            None,
5526        ));
5527    }
5528
5529    fn dispatch_parser_diagnostics<'a>(
5530        &self,
5531        diagnostics: impl IntoIterator<Item = &'a ParserDiagnostic>,
5532    ) {
5533        for diagnostic in diagnostics {
5534            self.dispatch_parser_diagnostic(diagnostic);
5535        }
5536    }
5537
5538    fn dispatch_token_source_error(&self, source_error: &TokenSourceError) {
5539        if self.input.token_source().report_error(source_error) {
5540            return;
5541        }
5542        // Lexer errors have no offending token: the failure is that no token
5543        // could be produced, matching ANTLR's null offendingSymbol.
5544        self.notify_error_listeners(source_error.into());
5545    }
5546
5547    fn dispatch_token_source_errors(&self, errors: &[TokenSourceError]) {
5548        for error in errors {
5549            self.dispatch_token_source_error(error);
5550        }
5551    }
5552
5553    /// Dispatches generated parser and lexer diagnostics in the same
5554    /// source-position order as ANTLR's lazy token stream reports them.
5555    fn dispatch_generated_diagnostics(
5556        &self,
5557        parser_diagnostics: &[ParserDiagnostic],
5558        token_errors: &[TokenSourceError],
5559    ) {
5560        // Parser diagnostics keep their event order: Java's console and
5561        // DiagnosticErrorListener print reports as prediction produces them,
5562        // so reportAttemptingFullContext precedes reportContextSensitivity
5563        // even though the latter's position is earlier. Buffered token-source
5564        // errors interleave by source position and win ties.
5565        let mut token_iter = token_errors.iter().peekable();
5566        for diagnostic in parser_diagnostics {
5567            while let Some(error) = token_iter.peek() {
5568                if (error.line, error.column) <= (diagnostic.line, diagnostic.column) {
5569                    self.dispatch_token_source_error(error);
5570                    token_iter.next();
5571                } else {
5572                    break;
5573                }
5574            }
5575            self.dispatch_parser_diagnostic(diagnostic);
5576        }
5577        for error in token_iter {
5578            self.dispatch_token_source_error(error);
5579        }
5580    }
5581
5582    /// Buffers ANTLR-style ambiguity diagnostics discovered by generated
5583    /// decision code.
5584    pub fn record_generated_ambiguity_diagnostic(
5585        &mut self,
5586        atn: &Atn,
5587        state_number: usize,
5588        start_index: usize,
5589        stop_index: usize,
5590        alts: &[usize],
5591    ) {
5592        if !self.report_diagnostic_errors || alts.len() < 2 {
5593            return;
5594        }
5595        let Some(decision) = atn
5596            .decision_to_state()
5597            .iter()
5598            .position(|candidate| candidate == state_number)
5599        else {
5600            return;
5601        };
5602        let Some(rule_index) = atn.state(state_number).and_then(AtnState::rule_index) else {
5603            return;
5604        };
5605        let rule_name = self
5606            .rule_names()
5607            .get(rule_index)
5608            .map_or_else(|| "<unknown>".to_owned(), Clone::clone);
5609        let input = display_input_text(&self.input.text(start_index, stop_index));
5610        let alts = alts
5611            .iter()
5612            .map(usize::to_string)
5613            .collect::<Vec<_>>()
5614            .join(", ");
5615        let key = (decision, start_index, format!("{alts}:{input}"));
5616        if !self.reported_prediction_diagnostics.insert(key) {
5617            return;
5618        }
5619        let start_diagnostic = diagnostic_for_token(
5620            self.token_at(start_index),
5621            format!("reportAttemptingFullContext d={decision} ({rule_name}), input='{input}'"),
5622        );
5623        let stop_diagnostic = diagnostic_for_token(
5624            self.token_at(stop_index),
5625            format!(
5626                "reportAmbiguity d={decision} ({rule_name}): ambigAlts={{{alts}}}, input='{input}'"
5627            ),
5628        );
5629        self.generated_parser_diagnostics.push(start_diagnostic);
5630        self.generated_parser_diagnostics.push(stop_diagnostic);
5631    }
5632
5633    /// Buffers ANTLR-style diagnostic-listener messages produced by generated
5634    /// parser calls to the adaptive simulator.
5635    pub fn record_generated_prediction_diagnostic(
5636        &mut self,
5637        atn: &Atn,
5638        state_number: usize,
5639        prediction: &ParserAtnPrediction,
5640    ) {
5641        let Some(diagnostic) = &prediction.diagnostic else {
5642            return;
5643        };
5644        if !self.report_diagnostic_errors || diagnostic.conflicting_alts.len() < 2 {
5645            return;
5646        }
5647        let Some(decision) = atn
5648            .decision_to_state()
5649            .iter()
5650            .position(|candidate| candidate == state_number)
5651        else {
5652            return;
5653        };
5654        let Some(rule_index) = atn.state(state_number).and_then(AtnState::rule_index) else {
5655            return;
5656        };
5657        let rule_name = self
5658            .rule_names()
5659            .get(rule_index)
5660            .map_or_else(|| "<unknown>".to_owned(), Clone::clone);
5661        let attempt_input = display_input_text(
5662            &self
5663                .input
5664                .text(diagnostic.start_index, diagnostic.sll_stop_index),
5665        );
5666        let result_input = display_input_text(
5667            &self
5668                .input
5669                .text(diagnostic.start_index, diagnostic.ll_stop_index),
5670        );
5671        let alts = diagnostic
5672            .conflicting_alts
5673            .iter()
5674            .map(usize::to_string)
5675            .collect::<Vec<_>>()
5676            .join(", ");
5677        let key = (
5678            decision,
5679            diagnostic.start_index,
5680            format!(
5681                "{:?}:{alts}:{attempt_input}:{result_input}",
5682                diagnostic.kind
5683            ),
5684        );
5685        if !self.reported_prediction_diagnostics.insert(key) {
5686            return;
5687        }
5688        let attempt_diagnostic = diagnostic_for_token(
5689            self.token_at(diagnostic.sll_stop_index),
5690            format!(
5691                "reportAttemptingFullContext d={decision} ({rule_name}), input='{attempt_input}'"
5692            ),
5693        );
5694        self.generated_parser_diagnostics.push(attempt_diagnostic);
5695        let message = match diagnostic.kind {
5696            ParserAtnPredictionDiagnosticKind::Ambiguity => {
5697                // Java's DiagnosticErrorListener is exactOnly by default:
5698                // non-exact ambiguities (default LL mode stopping at the
5699                // first resolvable conflict) report the attempt above but
5700                // suppress the ambiguity line itself.
5701                if !diagnostic.exact {
5702                    return;
5703                }
5704                format!(
5705                    "reportAmbiguity d={decision} ({rule_name}): ambigAlts={{{alts}}}, input='{result_input}'"
5706                )
5707            }
5708            ParserAtnPredictionDiagnosticKind::ContextSensitivity => {
5709                format!(
5710                    "reportContextSensitivity d={decision} ({rule_name}), input='{result_input}'"
5711                )
5712            }
5713        };
5714        let result_diagnostic =
5715            diagnostic_for_token(self.token_at(diagnostic.ll_stop_index), message);
5716        self.generated_parser_diagnostics.push(result_diagnostic);
5717    }
5718
5719    pub fn la(&self, offset: isize) -> i32 {
5720        self.input.la_token(offset)
5721    }
5722
5723    pub fn consume(&mut self) {
5724        IntStream::consume(&mut self.input);
5725    }
5726
5727    /// Sets a generated integer member value used by target-template tests.
5728    pub fn set_int_member(&mut self, member: usize, value: i64) {
5729        self.int_members.set_scalar(member, value);
5730    }
5731
5732    /// Reads a generated integer member value.
5733    pub fn int_member(&self, member: usize) -> Option<i64> {
5734        self.int_members.scalar(member)
5735    }
5736
5737    /// Pushes onto a generated stack-valued member slot (issue #206).
5738    pub fn push_stack_member(&mut self, member: usize, value: i64) {
5739        self.int_members.push_stack(member, value);
5740    }
5741
5742    /// Pops a generated stack-valued member slot, returning the removed value.
5743    /// `None` when the stack is empty.
5744    pub fn pop_stack_member(&mut self, member: usize) -> Option<i64> {
5745        self.int_members.pop_stack(member)
5746    }
5747
5748    /// Reads the top of a generated stack-valued member slot; `None` when
5749    /// empty or never pushed.
5750    #[must_use]
5751    pub fn stack_member_top(&self, member: usize) -> Option<i64> {
5752        self.int_members.stack_top(member)
5753    }
5754
5755    /// Depth of a generated stack-valued member slot.
5756    #[must_use]
5757    pub fn stack_member_len(&self, member: usize) -> usize {
5758        self.int_members.stack_len(member)
5759    }
5760
5761    /// Seeds grammar-declared initial member values (issue #206).
5762    ///
5763    /// Generated parsers call this at construction for a grammar whose
5764    /// `@members` declares an initializer (`private int level = 1;`). Without
5765    /// it the slot would start at 0, so a predicate reading it would reject
5766    /// input the source grammar accepts.
5767    pub fn set_initial_members(&mut self, initial: impl IntoIterator<Item = (usize, i64)>) {
5768        self.int_members = MemberEnv::with_initial_scalars(initial);
5769    }
5770
5771    /// Captures generated member state before speculative generated parser
5772    /// execution.
5773    ///
5774    /// The snapshot covers scalar *and* stack slots: restoring only scalars
5775    /// would leave a rolled-back path's pushes behind.
5776    #[must_use]
5777    pub fn int_members_checkpoint(&self) -> MemberEnv {
5778        self.int_members.clone()
5779    }
5780
5781    /// Restores generated member state after generated parser fallback.
5782    pub fn restore_int_members(&mut self, members: MemberEnv) {
5783        self.int_members = members;
5784    }
5785
5786    /// Adds `delta` to a generated integer member and returns the new value.
5787    pub fn add_int_member(&mut self, member: usize, delta: i64) -> i64 {
5788        self.int_members.add_scalar(member, delta)
5789    }
5790
5791    fn token_type_for_id(&self, id: TokenId) -> i32 {
5792        self.input.token_store().token_type(id).unwrap_or(TOKEN_EOF)
5793    }
5794
5795    fn terminal_tree(&mut self, id: TokenId) -> ParseTree {
5796        if self.build_parse_trees {
5797            self.tree.terminal(id)
5798        } else {
5799            NodeId::placeholder()
5800        }
5801    }
5802
5803    fn error_tree(&mut self, id: TokenId) -> ParseTree {
5804        if self.build_parse_trees {
5805            self.tree.error(id)
5806        } else {
5807            NodeId::placeholder()
5808        }
5809    }
5810
5811    const fn set_context_start(&self, context: &mut ParserRuleContext, id: TokenId) {
5812        context.set_start_id(id);
5813    }
5814
5815    const fn set_context_stop(&self, context: &mut ParserRuleContext, id: TokenId) {
5816        context.set_stop_id(id);
5817    }
5818
5819    fn insert_synthetic_token(
5820        &mut self,
5821        token_type: i32,
5822        text: String,
5823        line: usize,
5824        column: usize,
5825    ) -> Result<TokenId, AntlrError> {
5826        self.input
5827            .insert(
5828                TokenSpec::explicit(token_type, text)
5829                    .with_span(usize::MAX, usize::MAX)
5830                    .with_position(line, column),
5831            )
5832            .map_err(|error| AntlrError::Unsupported(error.to_string()))
5833    }
5834
5835    /// Matches and consumes the current token when it has the expected token
5836    /// type.
5837    ///
5838    /// On success the consumed token is wrapped as a terminal parse-tree node.
5839    /// On mismatch the error carries vocabulary display names so diagnostics are
5840    /// stable across literal and symbolic token naming.
5841    pub fn match_token(&mut self, token_type: i32) -> Result<ParseTree, AntlrError> {
5842        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
5843            line: 0,
5844            column: 0,
5845            message: "missing current token".to_owned(),
5846            offending: None,
5847        })?;
5848        let current_type = self.token_type_for_id(current);
5849        if current_type == token_type {
5850            self.reset_generated_recovery_state();
5851            self.consume();
5852            Ok(self.terminal_tree(current))
5853        } else {
5854            Err(AntlrError::MismatchedInput {
5855                expected: self.vocabulary().display_name(token_type),
5856                found: self.vocabulary().display_name(current_type),
5857            })
5858        }
5859    }
5860
5861    /// Matches a token from generated recursive-descent code, including ANTLR's
5862    /// single-token insertion recovery when the active rule context can legally
5863    /// continue at the current input symbol.
5864    pub fn match_token_recovering(
5865        &mut self,
5866        token_type: i32,
5867        follow_state: usize,
5868        atn: &Atn,
5869    ) -> Result<GeneratedMatch, AntlrError> {
5870        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
5871            line: 0,
5872            column: 0,
5873            message: "missing current token".to_owned(),
5874            offending: None,
5875        })?;
5876        let current_type = self.token_type_for_id(current);
5877        if current_type == token_type {
5878            self.generated_sync_expected = None;
5879            self.reset_generated_recovery_state();
5880            let consumed_eof = current_type == TOKEN_EOF;
5881            self.consume();
5882            return Ok(GeneratedMatch {
5883                children: GeneratedMatchChildren::One(self.terminal_tree(current)),
5884                consumed_eof,
5885            });
5886        }
5887        let mut expected_symbols = BTreeSet::new();
5888        expected_symbols.insert(token_type);
5889        self.recover_generated_match(
5890            current,
5891            GeneratedExpectedSymbols::Tree(&expected_symbols),
5892            follow_state,
5893            atn,
5894            |symbol| symbol == token_type,
5895        )
5896    }
5897
5898    pub fn match_set_recovering(
5899        &mut self,
5900        intervals: &[(i32, i32)],
5901        follow_state: usize,
5902        atn: &Atn,
5903    ) -> Result<GeneratedMatch, AntlrError> {
5904        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
5905            line: 0,
5906            column: 0,
5907            message: "missing current token".to_owned(),
5908            offending: None,
5909        })?;
5910        let current_type = self.token_type_for_id(current);
5911        if interval_set_contains(intervals, current_type) {
5912            self.generated_sync_expected = None;
5913            self.reset_generated_recovery_state();
5914            let consumed_eof = current_type == TOKEN_EOF;
5915            self.consume();
5916            return Ok(GeneratedMatch {
5917                children: GeneratedMatchChildren::One(self.terminal_tree(current)),
5918                consumed_eof,
5919            });
5920        }
5921        let expected_symbols = interval_symbols(intervals);
5922        self.recover_generated_match(
5923            current,
5924            GeneratedExpectedSymbols::Tree(&expected_symbols),
5925            follow_state,
5926            atn,
5927            |symbol| interval_set_contains(intervals, symbol),
5928        )
5929    }
5930
5931    pub fn match_token_set_recovering(
5932        &mut self,
5933        set: ParserIntervalSet<'_>,
5934        follow_state: usize,
5935        atn: &Atn,
5936    ) -> Result<GeneratedMatch, AntlrError> {
5937        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
5938            line: 0,
5939            column: 0,
5940            message: "missing current token".to_owned(),
5941            offending: None,
5942        })?;
5943        let current_type = self.token_type_for_id(current);
5944        if set.contains(current_type) {
5945            self.generated_sync_expected = None;
5946            self.reset_generated_recovery_state();
5947            let consumed_eof = current_type == TOKEN_EOF;
5948            self.consume();
5949            return Ok(GeneratedMatch {
5950                children: GeneratedMatchChildren::One(self.terminal_tree(current)),
5951                consumed_eof,
5952            });
5953        }
5954        self.recover_generated_match(
5955            current,
5956            GeneratedExpectedSymbols::TokenSet(set),
5957            follow_state,
5958            atn,
5959            |symbol| set.contains(symbol),
5960        )
5961    }
5962
5963    pub fn match_not_set_recovering(
5964        &mut self,
5965        intervals: &[(i32, i32)],
5966        min_vocabulary: i32,
5967        max_vocabulary: i32,
5968        follow_state: usize,
5969        atn: &Atn,
5970    ) -> Result<GeneratedMatch, AntlrError> {
5971        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
5972            line: 0,
5973            column: 0,
5974            message: "missing current token".to_owned(),
5975            offending: None,
5976        })?;
5977        let current_type = self.token_type_for_id(current);
5978        if (min_vocabulary..=max_vocabulary).contains(&current_type)
5979            && !interval_set_contains(intervals, current_type)
5980        {
5981            self.generated_sync_expected = None;
5982            self.reset_generated_recovery_state();
5983            let consumed_eof = current_type == TOKEN_EOF;
5984            self.consume();
5985            return Ok(GeneratedMatch {
5986                children: GeneratedMatchChildren::One(self.terminal_tree(current)),
5987                consumed_eof,
5988            });
5989        }
5990        let expected_symbols =
5991            interval_complement_symbols(intervals, min_vocabulary, max_vocabulary);
5992        self.recover_generated_match(
5993            current,
5994            GeneratedExpectedSymbols::Tree(&expected_symbols),
5995            follow_state,
5996            atn,
5997            |symbol| {
5998                (min_vocabulary..=max_vocabulary).contains(&symbol)
5999                    && !interval_set_contains(intervals, symbol)
6000            },
6001        )
6002    }
6003
6004    pub fn match_not_token_set_recovering(
6005        &mut self,
6006        set: ParserIntervalSet<'_>,
6007        min_vocabulary: i32,
6008        max_vocabulary: i32,
6009        follow_state: usize,
6010        atn: &Atn,
6011    ) -> Result<GeneratedMatch, AntlrError> {
6012        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
6013            line: 0,
6014            column: 0,
6015            message: "missing current token".to_owned(),
6016            offending: None,
6017        })?;
6018        let current_type = self.token_type_for_id(current);
6019        if (min_vocabulary..=max_vocabulary).contains(&current_type) && !set.contains(current_type)
6020        {
6021            self.generated_sync_expected = None;
6022            self.reset_generated_recovery_state();
6023            let consumed_eof = current_type == TOKEN_EOF;
6024            self.consume();
6025            return Ok(GeneratedMatch {
6026                children: GeneratedMatchChildren::One(self.terminal_tree(current)),
6027                consumed_eof,
6028            });
6029        }
6030        self.recover_generated_match(
6031            current,
6032            GeneratedExpectedSymbols::TokenSetComplement {
6033                set,
6034                min_vocabulary,
6035                max_vocabulary,
6036            },
6037            follow_state,
6038            atn,
6039            |symbol| (min_vocabulary..=max_vocabulary).contains(&symbol) && !set.contains(symbol),
6040        )
6041    }
6042
6043    fn recover_generated_match(
6044        &mut self,
6045        current: TokenId,
6046        expected_symbols: GeneratedExpectedSymbols<'_>,
6047        follow_state: usize,
6048        atn: &Atn,
6049        matches: impl Fn(i32) -> bool,
6050    ) -> Result<GeneratedMatch, AntlrError> {
6051        let expected_display = expected_symbols.display(self.vocabulary());
6052        let (current_type, current_line, current_column, current_display) = {
6053            let token = self
6054                .input
6055                .token_view(current)
6056                .expect("current token ID should be valid");
6057            (
6058                token.token_type(),
6059                token.line(),
6060                token.column(),
6061                token_input_display(&token),
6062            )
6063        };
6064        if self.bail_on_error {
6065            return Err(AntlrError::ParserError {
6066                line: current_line,
6067                column: current_column,
6068                message: format!("mismatched input {current_display} expecting {expected_display}"),
6069                offending: Some(current),
6070            });
6071        }
6072        if current_type != TOKEN_EOF
6073            && let Some(next) = self.input.lt_id(2)
6074            && matches(self.token_type_for_id(next))
6075        {
6076            let message =
6077                format!("extraneous input {current_display} expecting {expected_display}");
6078            self.push_generated_parser_diagnostic(ParserDiagnostic {
6079                line: current_line,
6080                column: current_column,
6081                message,
6082                offending: Some(current),
6083            });
6084            self.record_syntax_errors(1);
6085            self.generated_sync_expected = None;
6086            // Single-token deletion: skip `current`, then accept `next`. The
6087            // accepted token can be EOF only if it is a real EOF terminal.
6088            let consumed_eof = self.token_type_for_id(next) == TOKEN_EOF;
6089            self.consume();
6090            self.consume();
6091            self.reset_generated_recovery_state();
6092            return Ok(GeneratedMatch {
6093                children: GeneratedMatchChildren::Many(vec![
6094                    self.error_tree(current),
6095                    self.terminal_tree(next),
6096                ]),
6097                consumed_eof,
6098            });
6099        }
6100        let follow_symbols = self.generated_recovery_follow_symbols(atn, follow_state);
6101        // ANTLR's `singleTokenInsertion` inserts a missing token when the state
6102        // *after* the current element can consume the current symbol. At EOF that
6103        // only holds when the follow state EXPLICITLY expects EOF (e.g. an `EOF`
6104        // terminal follows in the rule, as in `r: . EOF;` or `r: ID EOF;`), not
6105        // when EOF merely leaks in from the empty enclosing context (as in
6106        // `start: ID+;` on empty input — antlr#6 `InvalidEmptyInput`, which must
6107        // stay a `mismatched input` error). `follow_symbols` mixes both sources,
6108        // so consult the follow state's OWN expected set for the explicit case.
6109        let follow_explicitly_expects_eof = current_type == TOKEN_EOF
6110            && self
6111                .cached_state_expected_symbols(atn, follow_state)
6112                .contains(&TOKEN_EOF);
6113        if follow_symbols.contains(&current_type)
6114            && (current_type != TOKEN_EOF
6115                || self.rule_context_stack.len() > 1
6116                || expected_symbols.is_empty()
6117                || follow_explicitly_expects_eof)
6118        {
6119            let message = format!("missing {expected_display} at {current_display}");
6120            self.push_generated_parser_diagnostic(ParserDiagnostic {
6121                line: current_line,
6122                column: current_column,
6123                message,
6124                offending: Some(current),
6125            });
6126            self.record_syntax_errors(1);
6127            self.generated_sync_expected = None;
6128            let token_type = expected_symbols.first().unwrap_or(TOKEN_EOF);
6129            let missing_display = expected_symbol_display(token_type, self.vocabulary());
6130            let token = self.insert_synthetic_token(
6131                token_type,
6132                format!("<missing {missing_display}>"),
6133                current_line,
6134                current_column,
6135            )?;
6136            // Single-token insertion synthesizes a missing token and consumes
6137            // nothing, so no EOF terminal is consumed even when the lookahead is
6138            // EOF. Reporting consumed_eof=false here is what keeps `finish_rule`
6139            // from recording EOF as the rule stop on this recovery path.
6140            return Ok(GeneratedMatch {
6141                children: GeneratedMatchChildren::One(self.error_tree(token)),
6142                consumed_eof: false,
6143            });
6144        }
6145        let mismatch_expected_display = self
6146            .generated_sync_expected
6147            .take()
6148            .map_or(expected_display, |symbols| {
6149                expected_symbols_display_iter(symbols.symbols(), self.vocabulary())
6150            });
6151        Err(AntlrError::ParserError {
6152            line: current_line,
6153            column: current_column,
6154            message: format!(
6155                "mismatched input {current_display} expecting {mismatch_expected_display}"
6156            ),
6157            offending: Some(current),
6158        })
6159    }
6160
6161    fn generated_recovery_follow_symbols(
6162        &mut self,
6163        atn: &Atn,
6164        follow_state: usize,
6165    ) -> BTreeSet<i32> {
6166        let mut follow = self
6167            .cached_state_expected_symbols(atn, follow_state)
6168            .as_ref()
6169            .clone();
6170        if self.cached_state_can_reach_rule_stop(atn, follow_state) {
6171            follow.extend(self.context_expected_symbols(atn));
6172        }
6173        follow
6174    }
6175
6176    pub fn match_eof(&mut self) -> Result<ParseTree, AntlrError> {
6177        self.match_token(TOKEN_EOF)
6178    }
6179
6180    pub fn match_set(&mut self, intervals: &[(i32, i32)]) -> Result<ParseTree, AntlrError> {
6181        self.match_interval_condition(intervals, |symbol| interval_set_contains(intervals, symbol))
6182    }
6183
6184    pub fn match_not_set(
6185        &mut self,
6186        intervals: &[(i32, i32)],
6187        min_vocabulary: i32,
6188        max_vocabulary: i32,
6189    ) -> Result<ParseTree, AntlrError> {
6190        self.match_interval_condition(intervals, |symbol| {
6191            (min_vocabulary..=max_vocabulary).contains(&symbol)
6192                && !interval_set_contains(intervals, symbol)
6193        })
6194    }
6195
6196    fn match_interval_condition(
6197        &mut self,
6198        intervals: &[(i32, i32)],
6199        matches: impl FnOnce(i32) -> bool,
6200    ) -> Result<ParseTree, AntlrError> {
6201        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
6202            line: 0,
6203            column: 0,
6204            message: "missing current token".to_owned(),
6205            offending: None,
6206        })?;
6207        let current_type = self.token_type_for_id(current);
6208        if matches(current_type) {
6209            self.reset_generated_recovery_state();
6210            self.consume();
6211            Ok(self.terminal_tree(current))
6212        } else {
6213            Err(AntlrError::MismatchedInput {
6214                expected: self.interval_display(intervals),
6215                found: self.vocabulary().display_name(current_type),
6216            })
6217        }
6218    }
6219
6220    fn interval_display(&self, intervals: &[(i32, i32)]) -> String {
6221        let values = intervals
6222            .iter()
6223            .map(|(start, stop)| {
6224                if start == stop {
6225                    self.vocabulary().display_name(*start)
6226                } else {
6227                    format!(
6228                        "{}..{}",
6229                        self.vocabulary().display_name(*start),
6230                        self.vocabulary().display_name(*stop)
6231                    )
6232                }
6233            })
6234            .collect::<Vec<_>>()
6235            .join(", ");
6236        format!("{{{values}}}")
6237    }
6238
6239    pub fn rule_node(&mut self, context: ParserRuleContext) -> ParseTree {
6240        if self.build_parse_trees {
6241            self.tree.finish_rule(context)
6242        } else {
6243            NodeId::placeholder()
6244        }
6245    }
6246
6247    /// Reports whether the generated rule dispatch should sample native stack
6248    /// capacity before descending into the next rule body.
6249    ///
6250    /// Generated recursive-descent methods otherwise map unbounded grammar
6251    /// nesting straight onto native call depth; sampling every
6252    /// [`GENERATED_RULE_STACK_CHECK_INTERVAL`] rule-context frames keeps the
6253    /// hot path free of per-call probes while guaranteeing a check runs before
6254    /// the red zone can be crossed.
6255    #[must_use]
6256    pub const fn generated_rule_stack_check_due(&self) -> bool {
6257        self.rule_context_stack
6258            .len()
6259            .is_multiple_of(GENERATED_RULE_STACK_CHECK_INTERVAL)
6260    }
6261
6262    /// Returns the positioned error to abort with when the configured
6263    /// rule-nesting depth cap would be exceeded by one more level, or `None`
6264    /// to keep parsing.
6265    ///
6266    /// Generated rule dispatch calls this before deepening — ahead of the
6267    /// rule-frame push at the dispatch boundary and ahead of each
6268    /// left-recursive expansion — letting callers parsing untrusted input
6269    /// bound CPU and tree memory ([`Parser::set_max_rule_depth`]). The
6270    /// inline fast path is one `Option` check when no cap is set (the
6271    /// default) and one addition plus compare when one is; only an actual
6272    /// violation leaves the inline path.
6273    ///
6274    /// The violation is sticky: rule-level recovery absorbs the returned
6275    /// error like any other rule failure and would otherwise keep spending
6276    /// the very resources the cap exists to bound, so every check after the
6277    /// first violation fails until [`Self::take_rule_depth_error`] drains it
6278    /// at the top-level entry.
6279    #[inline]
6280    pub fn rule_depth_cap_violation(&mut self) -> Option<AntlrError> {
6281        let max = self.max_rule_depth?;
6282        // Left-recursive operator iterations deepen the tree without pushing
6283        // a rule frame, so they count alongside the rule-context stack.
6284        if self.rule_depth_error.is_none()
6285            && self.rule_context_stack.len() + self.recursion_expansions < max
6286        {
6287            return None;
6288        }
6289        Some(self.rule_depth_cap_violation_cold(max))
6290    }
6291
6292    #[cold]
6293    fn rule_depth_cap_violation_cold(&mut self, max: usize) -> AntlrError {
6294        if let Some(error) = &self.rule_depth_error {
6295            return error.clone();
6296        }
6297        let current = self.input.lt(1);
6298        let (line, column) = current
6299            .as_ref()
6300            .map_or((0, 0), |token| (token.line(), token.column()));
6301        let error = AntlrError::ParserError {
6302            line,
6303            column,
6304            message: format!("rule nesting depth limit of {max} exceeded"),
6305            offending: current.as_ref().map(Token::token_id),
6306        };
6307        self.rule_depth_error = Some(error.clone());
6308        error
6309    }
6310
6311    /// Drains the sticky depth-cap violation recorded by
6312    /// [`Self::rule_depth_cap_violation`], if any.
6313    ///
6314    /// Generated top-level rule entries call this after recognition so a
6315    /// recovered parse that crossed the cap still fails, and so a reused
6316    /// parser starts its next parse clean.
6317    pub const fn take_rule_depth_error(&mut self) -> Option<AntlrError> {
6318        self.rule_depth_error.take()
6319    }
6320
6321    /// Reports whether a rule-nesting depth cap is configured.
6322    ///
6323    /// Generated dispatch consults this when selecting between the guarded
6324    /// recursive-descent body and the ATN-preferred interpreted fast path:
6325    /// only the generated body enforces the cap, so a configured bound
6326    /// overrides the performance preference.
6327    #[must_use]
6328    pub const fn has_rule_depth_cap(&self) -> bool {
6329        self.max_rule_depth.is_some()
6330    }
6331
6332    /// Registers a listener for committed rule enter/exit events during
6333    /// recognition (ANTLR's `addParseListener`). See [`ParseListener`] for
6334    /// the delivery contract.
6335    pub fn add_parse_listener<L>(&mut self, listener: L)
6336    where
6337        L: ParseListener + 'static,
6338    {
6339        self.parse_listeners
6340            .push(ParseListenerSlot(Box::new(listener)));
6341    }
6342
6343    /// Removes every registered parse listener and returns them, dropping any
6344    /// sticky abort a removed listener had requested.
6345    ///
6346    /// Returning the boxed listeners gives callers back the state they
6347    /// accumulated (depth counters, collected events) without threading
6348    /// shared handles through the listener.
6349    pub fn remove_parse_listeners(&mut self) -> Vec<Box<dyn ParseListener>> {
6350        self.parse_listener_abort = None;
6351        self.parse_listeners.drain(..).map(|slot| slot.0).collect()
6352    }
6353
6354    /// Reports whether any parse listener is registered.
6355    ///
6356    /// Generated dispatch consults this alongside [`Self::has_rule_depth_cap`]
6357    /// when choosing between the generated body (which fires events) and the
6358    /// ATN-preferred interpreted fast path (which does not).
6359    #[must_use]
6360    pub const fn has_parse_listeners(&self) -> bool {
6361        !self.parse_listeners.is_empty()
6362    }
6363
6364    /// Reports whether semantic hooks may override interpreted decisions.
6365    ///
6366    /// Generated parsers use this to keep adaptive performance routing from
6367    /// changing parse semantics after a decision DFA becomes warm.
6368    #[doc(hidden)]
6369    #[must_use]
6370    pub fn observes_parser_decisions(&self) -> bool {
6371        self.semantic_hooks.observes_parser_decisions()
6372    }
6373
6374    /// Fires `enter_every_rule` on registered parse listeners, returning the
6375    /// abort error if any listener requested one.
6376    ///
6377    /// Generated rule dispatch calls this after the depth-cap probe and
6378    /// before the rule body runs; the generated left-recursive loop calls it
6379    /// once per operator expansion, mirroring upstream ANTLR's simulated
6380    /// rule-entry event for `pushNewRecursionContext`. A listener abort is
6381    /// sticky exactly like a depth-cap violation: rule-level recovery absorbs
6382    /// the returned error, so the flag holds until the top-level entry drains
6383    /// it via [`Self::take_parse_listener_abort`] and fails the parse.
6384    pub fn parse_listener_enter_rule(&mut self, rule_index: usize) -> Option<AntlrError> {
6385        if self.parse_listeners.is_empty() {
6386            return None;
6387        }
6388        self.parse_listener_enter_rule_dispatch(rule_index)
6389    }
6390
6391    fn parse_listener_enter_rule_dispatch(&mut self, rule_index: usize) -> Option<AntlrError> {
6392        if let Some(error) = &self.parse_listener_abort {
6393            return Some(error.clone());
6394        }
6395        let event = EnterRuleEvent {
6396            rule_index,
6397            current: self.input.lt(1),
6398        };
6399        // Split borrows: the token view borrows the input while listeners
6400        // need `&mut`, so listeners are taken out for the dispatch. Listener
6401        // methods have no parser access and cannot observe the absence.
6402        let mut listeners = std::mem::take(&mut self.parse_listeners);
6403        let mut abort = None;
6404        for slot in &mut listeners {
6405            if let Err(error) = slot.0.enter_every_rule(&event) {
6406                abort = Some(error);
6407                break;
6408            }
6409        }
6410        self.parse_listeners = listeners;
6411        if let Some(error) = abort {
6412            self.parse_listener_abort = Some(error.clone());
6413            return Some(error);
6414        }
6415        None
6416    }
6417
6418    /// Fires `exit_every_rule` on registered parse listeners.
6419    ///
6420    /// Generated rule bodies call this on every exit path — success and
6421    /// recovery alike — keeping enter/exit pairs balanced, and the generated
6422    /// left-recursive loop calls it once per operator expansion when the rule
6423    /// finishes unrolling.
6424    pub fn parse_listener_exit_rule(&mut self, rule_index: usize) {
6425        if self.parse_listeners.is_empty() {
6426            return;
6427        }
6428        // Reverse registration order, matching upstream ANTLR
6429        // (`Parser.triggerExitRuleEvent` walks listeners back to front).
6430        for slot in self.parse_listeners.iter_mut().rev() {
6431            slot.0.exit_every_rule(rule_index);
6432        }
6433    }
6434
6435    /// Drains the sticky parse-listener abort recorded by
6436    /// [`Self::parse_listener_enter_rule`], if any.
6437    ///
6438    /// Generated top-level rule entries call this after recognition so an
6439    /// aborted parse fails even when recovery produced a tree, and so a
6440    /// reused parser starts its next parse clean.
6441    pub const fn take_parse_listener_abort(&mut self) -> Option<AntlrError> {
6442        self.parse_listener_abort.take()
6443    }
6444
6445    /// Drains every sticky parse abort — the depth-cap violation and the
6446    /// parse-listener abort — returning the depth error preferentially.
6447    ///
6448    /// Generated top-level rule entries call this on both exit paths: the
6449    /// recorded abort wins over errors derived from it (recovery may have
6450    /// absorbed the aborted rule and failed differently later), a recovered
6451    /// `Ok` tree still fails when an abort was recorded, and draining leaves
6452    /// the instance clean for the next entry-rule call.
6453    pub fn take_parse_abort(&mut self) -> Option<AntlrError> {
6454        if let Some(error) = self.rule_depth_error.take() {
6455            self.parse_listener_abort = None;
6456            return Some(error);
6457        }
6458        self.parse_listener_abort.take()
6459    }
6460
6461    /// Enters a generated parser rule and returns the context object the
6462    /// generated method should populate.
6463    pub fn enter_rule(&mut self, state: isize, rule_index: usize) -> ParserRuleContext {
6464        self.set_state(state);
6465        let invoking_state = self.pending_invoking_states.pop().unwrap_or(state);
6466        self.rule_context_stack.push(RuleContextFrame {
6467            rule_index,
6468            invoking_state,
6469        });
6470        self.advance_rule_context_version();
6471        let start_index = self.current_visible_index();
6472        let mut context = ParserRuleContext::new(rule_index, invoking_state);
6473        if let Some(token) = self.token_id_at(start_index) {
6474            self.set_context_start(&mut context, token);
6475        }
6476        context
6477    }
6478
6479    /// Records the ATN source state for the next generated rule invocation.
6480    ///
6481    /// ANTLR's full-context prediction reconstructs caller follow states from
6482    /// each active rule context's invoking state. Generated Rust rule methods are
6483    /// plain functions, so the caller supplies that ATN state just before making a
6484    /// rule call; `enter_rule` consumes it when the callee starts.
6485    pub fn push_invoking_state(&mut self, invoking_state: isize) -> usize {
6486        let marker = self.pending_invoking_states.len();
6487        self.pending_invoking_states.push(invoking_state);
6488        marker
6489    }
6490
6491    /// Discards an invoking-state marker if the callee did not consume it.
6492    pub fn discard_invoking_state(&mut self, marker: usize) {
6493        self.pending_invoking_states.truncate(marker);
6494    }
6495
6496    /// Exits the current generated parser rule.
6497    pub fn exit_rule(&mut self) {
6498        self.rule_context_stack.pop();
6499        self.advance_rule_context_version();
6500    }
6501
6502    /// Returns caller follow states for interning in a parser ATN simulator's
6503    /// prediction store. States are yielded outermost to innermost.
6504    pub fn prediction_context_return_states<'a>(
6505        &'a self,
6506        atn: &'a Atn,
6507    ) -> impl DoubleEndedIterator<Item = usize> + 'a {
6508        self.rule_context_stack.iter().skip(1).filter_map(|frame| {
6509            let Ok(state_number) = usize::try_from(frame.invoking_state) else {
6510                return None;
6511            };
6512            let Some(Transition::Rule { follow_state, .. }) = atn
6513                .state(state_number)
6514                .and_then(|state| state.transitions().first())
6515                .map(ParserTransition::data)
6516            else {
6517                return None;
6518            };
6519            Some(follow_state)
6520        })
6521    }
6522
6523    /// Returns a generation that changes whenever the active rule stack changes.
6524    ///
6525    /// A parser ATN simulator uses this to reuse an interned outer prediction
6526    /// context while generated predictions remain in the same rule context.
6527    pub const fn rule_context_version(&self) -> usize {
6528        self.rule_context_version
6529    }
6530
6531    const fn advance_rule_context_version(&mut self) {
6532        self.rule_context_version = self.rule_context_version.wrapping_add(1);
6533    }
6534
6535    /// Adds a generated parser child only when parse-tree construction is
6536    /// enabled. The match is recorded on the context either way (via `add_child`,
6537    /// or `note_matched_child` when trees are off) so generated recovery can tell
6538    /// whether the rule has matched anything yet without depending on `children`.
6539    pub fn add_parse_child(&mut self, context: &mut ParserRuleContext, child: ParseTree) {
6540        if self.build_parse_trees {
6541            self.tree.add_child(context, child);
6542        } else {
6543            context.note_matched_child();
6544        }
6545    }
6546
6547    fn release_tree_scratch_if_idle(&mut self) {
6548        if self.rule_context_stack.is_empty() {
6549            self.tree.release_scratch();
6550        }
6551    }
6552
6553    /// Finishes a generated parser rule and returns its parse-tree node.
6554    pub fn finish_rule(&mut self, mut context: ParserRuleContext, consumed_eof: bool) -> ParseTree {
6555        let stop_index = self.rule_stop_token_index(self.input.index(), consumed_eof);
6556        if let Some(token) = stop_index.and_then(|index| self.token_id_at(index)) {
6557            self.set_context_stop(&mut context, token);
6558        }
6559        let node = self.rule_node(context);
6560        self.exit_rule();
6561        self.release_tree_scratch_if_idle();
6562        node
6563    }
6564
6565    /// Recovers a generated rule catch block after a committed mismatch.
6566    ///
6567    /// ANTLR's generated parsers catch recognition errors inside each rule,
6568    /// report the original error, then consume unexpected tokens until the
6569    /// caller's recovery set can resume. Tokens consumed during recovery become
6570    /// error nodes in the current rule context.
6571    pub fn recover_generated_rule(
6572        &mut self,
6573        context: &mut ParserRuleContext,
6574        atn: &Atn,
6575        error: AntlrError,
6576    ) {
6577        let diagnostic = self.generated_rule_error_diagnostic(error);
6578        self.push_generated_parser_diagnostic(diagnostic);
6579        self.generated_sync_expected = None;
6580        let error_index = self.input.index();
6581        let error_state = self.data.state();
6582        // Match ANTLR's lastErrorIndex/lastErrorStates failsafe: a recovery
6583        // token can also be in the caller's follow set, leaving the cursor
6584        // unchanged and allowing generated outer decisions to revisit the same
6585        // failed state forever.
6586        if self.generated_recovery_error_index == Some(error_index)
6587            && self.generated_recovery_error_states.contains(&error_state)
6588            && self.la(1) != TOKEN_EOF
6589            && let Some(token) = self.input.lt_id(1)
6590        {
6591            self.consume();
6592            let child = self.error_tree(token);
6593            self.add_parse_child(context, child);
6594        }
6595        let recovery_index = self.input.index();
6596        if self.generated_recovery_error_index != Some(recovery_index) {
6597            self.generated_recovery_error_index = Some(recovery_index);
6598            self.generated_recovery_error_states.clear();
6599        }
6600        self.generated_recovery_error_states.insert(error_state);
6601        let recovery_symbols = self.context_expected_symbols(atn);
6602        loop {
6603            let symbol = self.la(1);
6604            if symbol == TOKEN_EOF || recovery_symbols.contains(&symbol) {
6605                break;
6606            }
6607            let Some(token) = self.input.lt_id(1) else {
6608                break;
6609            };
6610            self.consume();
6611            let child = self.error_tree(token);
6612            self.add_parse_child(context, child);
6613        }
6614        self.record_syntax_errors(1);
6615    }
6616
6617    fn reset_generated_recovery_state(&mut self) {
6618        if self.generated_recovery_error_index.is_some() {
6619            self.generated_recovery_error_index = None;
6620            self.generated_recovery_error_states.clear();
6621        }
6622    }
6623
6624    fn push_generated_parser_diagnostic(&mut self, diagnostic: ParserDiagnostic) {
6625        if self
6626            .generated_parser_diagnostics
6627            .iter()
6628            .any(|existing| existing == &diagnostic)
6629        {
6630            return;
6631        }
6632        self.generated_parser_diagnostics.push(diagnostic);
6633    }
6634
6635    fn generated_rule_error_diagnostic(&self, error: AntlrError) -> ParserDiagnostic {
6636        match error {
6637            // The anchor recorded where the error was built wins over the
6638            // current lookahead: prediction restores the cursor, so lt(1)
6639            // here can point at the decision start rather than the error.
6640            AntlrError::ParserError {
6641                line,
6642                column,
6643                message,
6644                offending,
6645            } => ParserDiagnostic {
6646                line,
6647                column,
6648                message,
6649                offending,
6650            },
6651            AntlrError::MismatchedInput { expected, found } => diagnostic_for_token(
6652                self.input.lt(1),
6653                format!("mismatched input {found} expecting {expected}"),
6654            ),
6655            AntlrError::NoViableAlternative { input } => diagnostic_for_token(
6656                self.input.lt(1),
6657                format!("no viable alternative at input {input}"),
6658            ),
6659            AntlrError::LexerError {
6660                line,
6661                column,
6662                message,
6663            } => ParserDiagnostic {
6664                line,
6665                column,
6666                message,
6667                offending: None,
6668            },
6669            AntlrError::Unsupported(message) => diagnostic_for_token(self.input.lt(1), message),
6670        }
6671    }
6672
6673    /// Finishes a generated left-recursive parser rule and returns its parse-tree node.
6674    pub fn finish_recursion_rule(
6675        &mut self,
6676        mut context: ParserRuleContext,
6677        consumed_eof: bool,
6678    ) -> ParseTree {
6679        let stop_index = self.rule_stop_token_index(self.input.index(), consumed_eof);
6680        if let Some(token) = stop_index.and_then(|index| self.token_id_at(index)) {
6681            self.set_context_stop(&mut context, token);
6682        }
6683        let node = self.rule_node(context);
6684        self.unroll_recursion_context();
6685        self.release_tree_scratch_if_idle();
6686        node
6687    }
6688
6689    /// Enters a generated left-recursive rule at `precedence`.
6690    pub fn enter_recursion_rule(
6691        &mut self,
6692        state: isize,
6693        rule_index: usize,
6694        precedence: i32,
6695    ) -> ParserRuleContext {
6696        self.precedence_stack.push(precedence);
6697        self.recursion_expansion_marks
6698            .push(self.recursion_expansions);
6699        self.enter_rule(state, rule_index)
6700    }
6701
6702    /// Replaces the current context while expanding a left-recursive rule.
6703    pub fn push_new_recursion_context(
6704        &mut self,
6705        state: isize,
6706        rule_index: usize,
6707    ) -> ParserRuleContext {
6708        self.set_state(state);
6709        // Counts toward the depth cap: upstream treats this as rule entry
6710        // (`Parser.pushNewRecursionContext` fires `triggerEnterRuleEvent`).
6711        self.recursion_expansions += 1;
6712        ParserRuleContext::new(rule_index, state)
6713    }
6714
6715    /// Wraps the previous left-recursive context before parsing the next
6716    /// recursive operator alternative.
6717    pub fn push_new_recursion_context_with_previous(
6718        &mut self,
6719        state: isize,
6720        rule_index: usize,
6721        current: &mut ParserRuleContext,
6722    ) {
6723        self.set_state(state);
6724        // Counts toward the depth cap: each operator iteration deepens the
6725        // parse tree one level without pushing a rule frame, and upstream
6726        // fires a rule-entry listener event for it. The parse-listener enter
6727        // event for this expansion fires from the generated loop's probe
6728        // just before this call, where a listener abort can propagate.
6729        self.recursion_expansions += 1;
6730        if let Some(stop) = self
6731            .rule_stop_token_index(self.input.index(), false)
6732            .and_then(|index| self.token_id_at(index))
6733        {
6734            self.set_context_stop(current, stop);
6735        }
6736        let invoking_state = current.invoking_state();
6737        let start = current.start_id();
6738        let mut replacement = ParserRuleContext::new(rule_index, invoking_state);
6739        if start.is_some() {
6740            replacement.set_start_from_context(current);
6741        }
6742        let previous = std::mem::replace(current, replacement);
6743        if self.build_parse_trees {
6744            let previous = self.rule_node(previous);
6745            self.tree.add_child(current, previous);
6746        }
6747    }
6748
6749    /// Leaves a generated left-recursive rule.
6750    pub fn unroll_recursion_context(&mut self) {
6751        if self.precedence_stack.len() > 1 {
6752            self.precedence_stack.pop();
6753        }
6754        // Parse-listener exits for expansions fire inside the generated
6755        // operator loop (top of each pass, upstream's `recRuleSetPrevCtx`),
6756        // and the dispatch wrapper's exit covers the final live context —
6757        // upstream's `unrollRecursionContexts` walks exactly one link, so no
6758        // batched exits happen here. Only the depth-cap accounting rewinds.
6759        if let Some(mark) = self.recursion_expansion_marks.pop() {
6760            self.recursion_expansions = mark;
6761        }
6762        self.exit_rule();
6763    }
6764
6765    /// Predicts a generated left-recursive loop from one-token lookahead.
6766    ///
6767    /// `Some(true)` enters the operator alternative, `Some(false)` exits, and
6768    /// `None` means caller overlap, a dangerous multi-token prefix, or an
6769    /// unresolved semantic predicate requires full `StarLoopEntry` adaptive
6770    /// prediction (which includes the exit alt and precedence filtering).
6771    ///
6772    /// Single-token operators and multi-token prefixes that do not shadow a
6773    /// lower-precedence single-token operator keep the one-token enter fast path.
6774    ///
6775    /// Multi-token prefixes that **do** shadow a lower-precedence single-token
6776    /// operator must not force enter; the adaptive decision may need to select
6777    /// the loop exit instead.
6778    pub fn left_recursive_loop_enter_prediction(
6779        &mut self,
6780        atn: &Atn,
6781        state_number: usize,
6782        precedence: i32,
6783    ) -> Option<bool> {
6784        let symbol = self.la(1);
6785        if symbol == TOKEN_EOF {
6786            return Some(false);
6787        }
6788        let operator_lookahead =
6789            Self::cached_left_recursive_operator_lookahead(atn, state_number, precedence);
6790        let can_single = operator_lookahead.single_token.contains(symbol);
6791        let can_multi = operator_lookahead.multi_token_prefix.contains(symbol);
6792        let can_predicate = operator_lookahead.predicate_dependent.contains(symbol);
6793        if !can_single && !can_multi && !can_predicate {
6794            return Some(false);
6795        }
6796        if can_predicate && !can_single {
6797            return None;
6798        }
6799        // Multi-token-only at this precedence, but the same symbol is a
6800        // single-token operator at precedence 0: defer so exit can win when the
6801        // multi-token sequence does not actually match (e.g. `>` vs `>>`).
6802        if !can_single && can_multi && precedence > 0 {
6803            let baseline = Self::cached_left_recursive_operator_lookahead(atn, state_number, 0);
6804            if baseline.single_token.contains(symbol) {
6805                return None;
6806            }
6807        }
6808        let atn_key = SharedAtnCacheKey::for_atn(atn);
6809        let cached_overlap = self
6810            .left_recursive_caller_overlap_cache
6811            .iter()
6812            .flatten()
6813            .find(|entry| {
6814                entry.atn_key == atn_key
6815                    && entry.state_number == state_number
6816                    && entry.symbol == symbol
6817                    && entry.context_version == self.rule_context_version
6818            })
6819            .map(|entry| entry.overlaps);
6820        let caller_overlaps = cached_overlap.unwrap_or_else(|| {
6821            let overlaps = caller_context_can_match_symbol_before_state(
6822                atn,
6823                self.prediction_context_return_states(atn),
6824                state_number,
6825                symbol,
6826            );
6827            if let Some(slot) = self
6828                .left_recursive_caller_overlap_cache
6829                .iter_mut()
6830                .find(|slot| slot.is_none())
6831            {
6832                *slot = Some(LeftRecursiveCallerOverlap {
6833                    atn_key,
6834                    state_number,
6835                    symbol,
6836                    context_version: self.rule_context_version,
6837                    overlaps,
6838                });
6839            }
6840            overlaps
6841        });
6842        if caller_overlaps {
6843            return None;
6844        }
6845        Some(true)
6846    }
6847
6848    fn cached_left_recursive_operator_lookahead(
6849        atn: &Atn,
6850        state_number: usize,
6851        precedence: i32,
6852    ) -> Rc<LeftRecursiveOperatorLookahead> {
6853        with_shared_atn_caches(atn, |cache| {
6854            let key = (state_number, precedence);
6855            if let Some(cached) = cache.left_recursive_operator_lookahead.get(&key) {
6856                return Rc::clone(cached);
6857            }
6858            let lookahead = Rc::new(left_recursive_operator_lookahead(
6859                atn,
6860                state_number,
6861                precedence,
6862            ));
6863            cache
6864                .left_recursive_operator_lookahead
6865                .insert(key, Rc::clone(&lookahead));
6866            lookahead
6867        })
6868    }
6869
6870    /// Checks whether a generated left-recursive loop can unambiguously enter
6871    /// its operator alternative from one-token lookahead.
6872    pub fn left_recursive_loop_enter_matches(
6873        &mut self,
6874        atn: &Atn,
6875        state_number: usize,
6876        precedence: i32,
6877    ) -> bool {
6878        self.left_recursive_loop_enter_prediction(atn, state_number, precedence) == Some(true)
6879    }
6880
6881    /// Implements generated `precpred(_ctx, k)` checks.
6882    pub fn precpred(&self, precedence: i32) -> bool {
6883        precedence >= self.precedence_stack.last().copied().unwrap_or_default()
6884    }
6885
6886    /// Evaluates a generated parser semantic predicate at the current input
6887    /// position.
6888    pub fn parser_semantic_predicate_matches(
6889        &mut self,
6890        predicates: &[(usize, usize, ParserPredicate)],
6891        rule_index: usize,
6892        pred_index: usize,
6893    ) -> bool {
6894        self.parser_semantic_predicate_matches_inner(predicates, rule_index, pred_index, None)
6895    }
6896
6897    /// Evaluates a generated parser semantic predicate with the current integer
6898    /// rule argument exposed as `$_p`/`$i` metadata where applicable.
6899    pub fn parser_semantic_predicate_matches_with_local(
6900        &mut self,
6901        predicates: &[(usize, usize, ParserPredicate)],
6902        rule_index: usize,
6903        pred_index: usize,
6904        local_int_arg: i32,
6905    ) -> bool {
6906        self.parser_semantic_predicate_matches_inner(
6907            predicates,
6908            rule_index,
6909            pred_index,
6910            Some((rule_index, i64::from(local_int_arg))),
6911        )
6912    }
6913
6914    fn parser_semantic_predicate_matches_inner(
6915        &mut self,
6916        predicates: &[(usize, usize, ParserPredicate)],
6917        rule_index: usize,
6918        pred_index: usize,
6919        local_int_arg: Option<(usize, i64)>,
6920    ) -> bool {
6921        let index = self.input.index();
6922        let member_values = self.int_members.clone();
6923        self.parser_predicate_matches(PredicateEval {
6924            index,
6925            rule_index,
6926            pred_index,
6927            predicates,
6928            semantics: None,
6929            context: None,
6930            local_int_arg,
6931            member_values: &member_values,
6932        })
6933    }
6934
6935    /// Evaluates a generated parser semantic predicate with access to the
6936    /// current generated rule context.
6937    pub fn parser_semantic_predicate_matches_with_context_and_local(
6938        &mut self,
6939        predicates: &[(usize, usize, ParserPredicate)],
6940        rule_index: usize,
6941        pred_index: usize,
6942        context: &ParserRuleContext,
6943        local_int_arg: i32,
6944    ) -> bool {
6945        let index = self.input.index();
6946        let member_values = self.int_members.clone();
6947        self.parser_predicate_matches(PredicateEval {
6948            index,
6949            rule_index,
6950            pred_index,
6951            predicates,
6952            semantics: None,
6953            context: Some(context),
6954            local_int_arg: Some((rule_index, i64::from(local_int_arg))),
6955            member_values: &member_values,
6956        })
6957    }
6958
6959    /// Evaluates a generated `SemIR` parser predicate with access to the current
6960    /// generated rule context.
6961    pub fn parser_semantic_ir_predicate_matches_with_context_and_local(
6962        &mut self,
6963        semantics: &ParserSemantics,
6964        rule_index: usize,
6965        pred_index: usize,
6966        context: &ParserRuleContext,
6967        local_int_arg: i32,
6968    ) -> bool {
6969        let index = self.input.index();
6970        let member_values = self.int_members.clone();
6971        self.parser_predicate_matches(PredicateEval {
6972            index,
6973            rule_index,
6974            pred_index,
6975            predicates: &[],
6976            semantics: Some(semantics),
6977            context: Some(context),
6978            local_int_arg: Some((rule_index, i64::from(local_int_arg))),
6979            member_values: &member_values,
6980        })
6981    }
6982
6983    /// Returns a generated fail-option message for a parser semantic
6984    /// predicate coordinate.
6985    pub fn parser_semantic_predicate_failure_message(
6986        &self,
6987        rule_index: usize,
6988        pred_index: usize,
6989        predicates: &[(usize, usize, ParserPredicate)],
6990    ) -> Option<&'static str> {
6991        self.parser_predicate_failure_message(rule_index, pred_index, predicates)
6992    }
6993
6994    /// Matches any non-EOF token.
6995    pub fn match_wildcard(&mut self) -> Result<ParseTree, AntlrError> {
6996        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
6997            line: 0,
6998            column: 0,
6999            message: "missing current token".to_owned(),
7000            offending: None,
7001        })?;
7002        if self.token_type_for_id(current) == TOKEN_EOF {
7003            return Err(AntlrError::MismatchedInput {
7004                expected: "wildcard".to_owned(),
7005                found: self.vocabulary().display_name(TOKEN_EOF),
7006            });
7007        }
7008        self.reset_generated_recovery_state();
7009        self.consume();
7010        Ok(self.terminal_tree(current))
7011    }
7012
7013    /// Generated parser synchronization hook. The current interpreter owns
7014    /// recovery; direct generated methods can call this as a no-op until the
7015    /// generated recovery strategy is expanded.
7016    #[allow(clippy::unnecessary_wraps)]
7017    pub fn sync(&mut self, state: isize) -> Result<(), AntlrError> {
7018        self.set_state(state);
7019        Ok(())
7020    }
7021
7022    /// Synchronizes a generated parser decision against the ATN lookahead set.
7023    ///
7024    /// ANTLR generated parsers call the error strategy before optional and loop
7025    /// decisions. When the current token cannot start any alternative, follow a
7026    /// nullable exit, or be deleted before a later synchronization token, the
7027    /// generated Rust method reports that decision-level mismatch instead of
7028    /// descending into a child rule that cannot start at the current token.
7029    pub fn sync_decision(
7030        &mut self,
7031        atn: &Atn,
7032        state_number: usize,
7033        _current_context_empty: bool,
7034        loop_back: bool,
7035    ) -> Result<Vec<ParseTree>, AntlrError> {
7036        self.set_state(isize::try_from(state_number).unwrap_or(isize::MAX));
7037        self.generated_sync_expected = None;
7038        let Some(state) = atn.state(state_number) else {
7039            return Ok(Vec::new());
7040        };
7041        let Some(rule_index) = state.rule_index() else {
7042            return Ok(Vec::new());
7043        };
7044        let Some(rule_stop) = atn.rule_to_stop_state().get(rule_index) else {
7045            return Ok(Vec::new());
7046        };
7047        let entry = self.cached_decision_lookahead(atn, state, rule_stop);
7048        let symbol = self.la(1);
7049        let mut has_expected_symbols = false;
7050        let mut nullable = false;
7051        // Whether EOF is an EXPLICIT expected token of this decision (a real `EOF`
7052        // reference in the grammar, e.g. `A* EOF`), as opposed to merely the
7053        // implicit rule-follow that a nullable exit inherits (e.g. a start rule's
7054        // end). Only an explicit EOF makes a token-before-EOF genuinely extraneous
7055        // and worth deleting; an implicit-follow EOF means the loop should simply
7056        // exit and leave the token for the (absent) caller — matching ANTLR, which
7057        // exits the loop via prediction rather than consuming up to a synthetic EOF.
7058        let mut explicit_eof_expected = false;
7059        for transition in &entry.transitions {
7060            if transition.symbols.contains(symbol) {
7061                return Ok(Vec::new());
7062            }
7063            has_expected_symbols |= !transition.symbols.is_empty();
7064            nullable |= transition.nullable;
7065            explicit_eof_expected |= transition.symbols.contains(TOKEN_EOF);
7066        }
7067        // Java's DefaultErrorStrategy.sync returns as soon as nextTokens
7068        // contains EPSILON. It remembers the decision/context expected set for
7069        // a later mismatch, but must not attempt single-token deletion or
7070        // loop-back recovery first: a nullable decision leaves the current
7071        // token to its caller even when that token is not in the context-free
7072        // FOLLOW set.
7073        if nullable {
7074            // Valid exits only need a membership probe. Materialize the full
7075            // expected set below solely when a later caller mismatch may need
7076            // the combined decision/context diagnostic.
7077            if self.context_expected_contains(atn, symbol) {
7078                return Ok(Vec::new());
7079            }
7080            let mut expected = self.context_expected_token_set(atn);
7081            for transition in &entry.transitions {
7082                expected.extend_from(&transition.symbols);
7083            }
7084            self.generated_sync_expected = Some(expected);
7085            return Ok(Vec::new());
7086        }
7087        if !has_expected_symbols {
7088            return Ok(Vec::new());
7089        }
7090        let mut expected = TokenBitSet::default();
7091        for transition in &entry.transitions {
7092            expected.extend_from(&transition.symbols);
7093        }
7094        // ANTLR's `DefaultErrorStrategy.sync` recovers differently by decision kind:
7095        // a loop-BACK sync (STAR_LOOP_BACK / PLUS_LOOP_BACK — reached only after at
7096        // least one iteration) does `consumeUntil` the follow set — multi-token
7097        // deletion, one error per skipped token across iterations; a loop ENTRY
7098        // (STAR_LOOP_ENTRY) and a plain optional/block entry (BLOCK_START /
7099        // *-block / +-block starts) do `singleTokenDeletion` — delete the one
7100        // unexpected token only when LA(2) is expected, otherwise report a mismatch
7101        // and leave recovery to the rule.
7102        //
7103        // The generated loop always presents the loop-ENTRY state to this method on
7104        // every pass, so `state.kind()` cannot distinguish entry from back; the caller
7105        // passes `loop_back` (false on a `*` loop's first sync / on a block, true once
7106        // an iteration has been taken, and true on a `+` loop's first sync since its
7107        // mandatory first element is iteration 1). Treating a loop entry as a
7108        // loop-back would over-consume (e.g. `s: A* EOF;` on `c c` would delete both
7109        // `c`s, which ANTLR rejects with `mismatched input`).
7110        let loop_sync = loop_back;
7111        if symbol != TOKEN_EOF {
7112            let mut cursor = self.input.index();
7113            let mut skipped = Vec::new();
7114            loop {
7115                let current = self.token_type_at(cursor);
7116                if current == TOKEN_EOF {
7117                    break;
7118                }
7119                skipped.push(cursor);
7120                let next = self.consume_index(cursor, current);
7121                if next == cursor {
7122                    break;
7123                }
7124                let next_symbol = self.token_type_at(next);
7125                // Stop (and delete the skipped tokens as error nodes) when the next
7126                // token is a real expected continuation. EOF counts only when it is
7127                // an EXPLICIT grammar token (`A* EOF`): then the deleted tokens are
7128                // genuinely extraneous and the generated EOF match consumes the real
7129                // EOF afterwards. An implicit-follow EOF (a nullable exit's inherited
7130                // rule-follow) does NOT count — the loop must exit and leave the
7131                // token, as ANTLR does, instead of deleting up to a synthetic EOF.
7132                let next_is_expected_stop = if next_symbol == TOKEN_EOF {
7133                    explicit_eof_expected
7134                } else {
7135                    expected.contains(next_symbol)
7136                };
7137                if next_is_expected_stop {
7138                    let current_token = self.input.lt(1);
7139                    let expected_symbols = expected.to_btree_set();
7140                    let message = format!(
7141                        "extraneous input {} expecting {}",
7142                        current_token
7143                            .as_ref()
7144                            .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
7145                        self.expected_symbols_display(&expected_symbols)
7146                    );
7147                    self.push_generated_parser_diagnostic(diagnostic_for_token(
7148                        current_token,
7149                        message,
7150                    ));
7151                    self.record_syntax_errors(1);
7152                    let mut children = Vec::with_capacity(skipped.len());
7153                    for index in skipped {
7154                        if let Some(token) = self.token_id_at(index) {
7155                            self.consume();
7156                            children.push(self.error_tree(token));
7157                        }
7158                    }
7159                    if !loop_sync {
7160                        self.reset_generated_recovery_state();
7161                    }
7162                    return Ok(children);
7163                }
7164                // A non-loop block entry deletes at most one token (single-token
7165                // deletion): if LA(2) is not expected, stop scanning so the mismatch
7166                // is reported at the first token instead of skipping ahead.
7167                if !loop_sync {
7168                    break;
7169                }
7170                cursor = next;
7171            }
7172        }
7173        let current = self.input.lt(1);
7174        let expected_symbols = expected.to_btree_set();
7175        Err(AntlrError::ParserError {
7176            line: current.as_ref().map(Token::line).unwrap_or_default(),
7177            column: current.as_ref().map(Token::column).unwrap_or_default(),
7178            message: format!(
7179                "mismatched input {} expecting {}",
7180                current
7181                    .as_ref()
7182                    .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
7183                self.expected_symbols_display(&expected_symbols)
7184            ),
7185            offending: current.as_ref().map(Token::token_id),
7186        })
7187    }
7188
7189    /// Returns a generated-parser prediction when one token of lookahead
7190    /// uniquely selects an alternative for `state_number`.
7191    ///
7192    /// This mirrors the interpreter's LL(1) commit point and lets generated
7193    /// recursive-descent methods avoid invoking the adaptive simulator for
7194    /// simple optional/block/loop decisions.
7195    pub fn ll1_decision_prediction(
7196        &mut self,
7197        atn: &Atn,
7198        state_number: usize,
7199    ) -> Option<ParserAtnPrediction> {
7200        let state = atn.state(state_number)?;
7201        if state.precedence_rule_decision() {
7202            return None;
7203        }
7204        let rule_stop = state
7205            .rule_index()
7206            .and_then(|rule_index| atn.rule_to_stop_state().get(rule_index))?;
7207        let symbol = self.la(1);
7208        let entry = self.cached_decision_lookahead(atn, state, rule_stop);
7209        ll1_greedy_alt(&entry, symbol, state.non_greedy()).map(|alt| ParserAtnPrediction {
7210            alt: alt + 1,
7211            requires_full_context: false,
7212            has_semantic_context: false,
7213            diagnostic: None,
7214        })
7215    }
7216
7217    fn context_expected_symbols(&mut self, atn: &Atn) -> BTreeSet<i32> {
7218        let mut expected = BTreeSet::new();
7219        for index in (1..self.rule_context_stack.len()).rev() {
7220            let invoking_state = self.rule_context_stack[index].invoking_state;
7221            let Ok(state_number) = usize::try_from(invoking_state) else {
7222                continue;
7223            };
7224            let Some(Transition::Rule { follow_state, .. }) = atn
7225                .state(state_number)
7226                .and_then(|state| state.transitions().first())
7227                .map(ParserTransition::data)
7228            else {
7229                continue;
7230            };
7231            let return_state = follow_state;
7232            expected.extend(self.cached_state_expected_symbols(atn, return_state).iter());
7233            if !self.cached_state_can_reach_rule_stop(atn, return_state) {
7234                return expected;
7235            }
7236        }
7237        expected.insert(TOKEN_EOF);
7238        expected
7239    }
7240
7241    fn context_expected_token_set(&mut self, atn: &Atn) -> TokenBitSet {
7242        let mut expected = TokenBitSet::default();
7243        for index in (1..self.rule_context_stack.len()).rev() {
7244            let invoking_state = self.rule_context_stack[index].invoking_state;
7245            let Ok(state_number) = usize::try_from(invoking_state) else {
7246                continue;
7247            };
7248            let Some(Transition::Rule { follow_state, .. }) = atn
7249                .state(state_number)
7250                .and_then(|state| state.transitions().first())
7251                .map(ParserTransition::data)
7252            else {
7253                continue;
7254            };
7255            expected.extend_from(&self.cached_state_expected_token_set(atn, follow_state));
7256            if !self.cached_state_can_reach_rule_stop(atn, follow_state) {
7257                return expected;
7258            }
7259        }
7260        expected.insert(TOKEN_EOF);
7261        expected
7262    }
7263
7264    /// Reports whether `symbol` is in `context_expected_token_set(atn)`
7265    /// without materializing the union.
7266    ///
7267    /// The walk follows the same rule-stack return chain as adaptive
7268    /// prediction. Valid nullable exits normally match the innermost frame,
7269    /// keeping their synchronization path to one cached membership probe.
7270    fn context_expected_contains(&mut self, atn: &Atn, symbol: i32) -> bool {
7271        for index in (1..self.rule_context_stack.len()).rev() {
7272            let invoking_state = self.rule_context_stack[index].invoking_state;
7273            let Ok(state_number) = usize::try_from(invoking_state) else {
7274                continue;
7275            };
7276            let Some(Transition::Rule { follow_state, .. }) = atn
7277                .state(state_number)
7278                .and_then(|state| state.transitions().first())
7279                .map(ParserTransition::data)
7280            else {
7281                continue;
7282            };
7283            if self
7284                .cached_state_expected_token_set(atn, follow_state)
7285                .contains(symbol)
7286            {
7287                return true;
7288            }
7289            if !self.cached_state_can_reach_rule_stop(atn, follow_state) {
7290                return false;
7291            }
7292        }
7293        symbol == TOKEN_EOF
7294    }
7295
7296    /// Builds a generated no-viable-alternative parser error.
7297    pub fn no_viable_alternative_error(&self, start_index: usize) -> AntlrError {
7298        let error_index = self.input.index();
7299        self.no_viable_alternative_error_at(start_index, error_index)
7300    }
7301
7302    /// Builds a generated no-viable-alternative parser error at the simulator's
7303    /// failing lookahead index. `adaptive_predict` restores the input cursor
7304    /// before returning, so generated parsers have to pass the recorded index
7305    /// explicitly to preserve ANTLR's LL(k) diagnostic span.
7306    pub fn no_viable_alternative_error_at(
7307        &self,
7308        start_index: usize,
7309        error_index: usize,
7310    ) -> AntlrError {
7311        let diagnostic = self.no_viable_alternative(start_index, error_index);
7312        AntlrError::ParserError {
7313            line: diagnostic.line,
7314            column: diagnostic.column,
7315            message: diagnostic.message,
7316            offending: diagnostic.offending,
7317        }
7318    }
7319
7320    /// Builds a generated failed-predicate parser error.
7321    pub fn failed_predicate_error(&self, message: impl Into<String>) -> AntlrError {
7322        let current = self.input.lt(1);
7323        AntlrError::ParserError {
7324            line: current.as_ref().map(Token::line).unwrap_or_default(),
7325            column: current.as_ref().map(Token::column).unwrap_or_default(),
7326            message: format!("rule failed predicate: {}", message.into()),
7327            offending: current.as_ref().map(Token::token_id),
7328        }
7329    }
7330
7331    /// Builds a generated parser error for a semantic predicate with ANTLR's
7332    /// `<fail='...'>` option.
7333    pub fn failed_predicate_option_error(
7334        &self,
7335        rule_index: usize,
7336        message: impl Into<String>,
7337    ) -> AntlrError {
7338        let current = self.input.lt(1);
7339        let rule_name = self
7340            .rule_names()
7341            .get(rule_index)
7342            .map_or_else(|| rule_index.to_string(), Clone::clone);
7343        AntlrError::ParserError {
7344            line: current.as_ref().map(Token::line).unwrap_or_default(),
7345            column: current.as_ref().map(Token::column).unwrap_or_default(),
7346            message: format!("rule {rule_name} {}", message.into()),
7347            offending: current.as_ref().map(Token::token_id),
7348        }
7349    }
7350
7351    /// Builds a generated parser-action event at the current input position.
7352    pub fn parser_action_at_current(
7353        &mut self,
7354        source_state: usize,
7355        rule_index: usize,
7356        start_index: usize,
7357        consumed_eof: bool,
7358    ) -> ParserAction {
7359        let stop_index = self.rule_stop_token_index(self.input.index(), consumed_eof);
7360        ParserAction::new(source_state, rule_index, start_index, stop_index)
7361    }
7362
7363    /// Builds an indexed generated parser-action event at the current input position.
7364    pub fn parser_action_at_current_indexed(
7365        &mut self,
7366        source_state: usize,
7367        rule_index: usize,
7368        action_index: usize,
7369        start_index: usize,
7370        consumed_eof: bool,
7371    ) -> ParserAction {
7372        let stop_index = self.rule_stop_token_index(self.input.index(), consumed_eof);
7373        ParserAction::new_indexed(
7374            source_state,
7375            rule_index,
7376            action_index,
7377            start_index,
7378            stop_index,
7379        )
7380    }
7381
7382    /// Offers a committed parser action event to the user semantic hook.
7383    ///
7384    /// Generated parsers call this for action source states that were present
7385    /// in the ATN but not translated into a built-in Rust action template.
7386    pub fn parser_action_hook(&mut self, action: ParserAction, tree: ParseTree) -> bool {
7387        self.parser_action_hook_inner(action, None, Some(tree), None, true)
7388    }
7389
7390    /// Offers an action to semantic hooks at its committed grammar position.
7391    ///
7392    /// The current rule context contains children completed before the action;
7393    /// the full rule tree is not available until the rule returns.
7394    pub fn parser_action_hook_with_context(
7395        &mut self,
7396        action: ParserAction,
7397        context: &ParserRuleContext,
7398    ) -> bool {
7399        self.parser_action_hook_inner(action, Some(context), None, None, true)
7400    }
7401
7402    /// Offers an action with the current generated rule's integer argument.
7403    ///
7404    /// Generated parameterized rules use the same integer carrier as generated
7405    /// predicate evaluation. The context exposes it through
7406    /// [`ParserSemCtx::local_int_arg`].
7407    pub fn parser_action_hook_with_context_and_local(
7408        &mut self,
7409        action: ParserAction,
7410        context: &ParserRuleContext,
7411        local_int_arg: i32,
7412    ) -> bool {
7413        self.parser_action_hook_inner(
7414            action,
7415            Some(context),
7416            None,
7417            Some((action.rule_index(), i64::from(local_int_arg))),
7418            true,
7419        )
7420    }
7421
7422    /// Offers a rule-init action at rule entry while preserving legacy replay.
7423    ///
7424    /// A declined init is returned to the generated caller, so it is not an
7425    /// unhandled action yet and must not trip the fail-loud policy here.
7426    fn parser_rule_init_hook_with_context(
7427        &mut self,
7428        action: ParserAction,
7429        context: &ParserRuleContext,
7430        local_int_arg: Option<(usize, i64)>,
7431    ) -> bool {
7432        debug_assert!(action.is_rule_init());
7433        self.parser_action_hook_inner(action, Some(context), None, local_int_arg, false)
7434    }
7435
7436    fn parser_action_hook_inner(
7437        &mut self,
7438        action: ParserAction,
7439        context: Option<&ParserRuleContext>,
7440        tree: Option<ParseTree>,
7441        local_int_arg: Option<(usize, i64)>,
7442        record_unhandled: bool,
7443    ) -> bool {
7444        let rule_index = action.rule_index();
7445        let rule_name = self.rule_names().get(rule_index).cloned();
7446        let input = &mut self.input;
7447        let semantic_hooks = &mut self.semantic_hooks;
7448        let member_values = &self.int_members;
7449        let mut ctx = ParserSemCtx {
7450            input,
7451            tree_storage: &self.tree,
7452            rule_index,
7453            coordinate_index: action.action_index().unwrap_or(usize::MAX),
7454            rule_name,
7455            context,
7456            tree,
7457            local_int_arg,
7458            member_values,
7459            action: Some(action),
7460        };
7461        let handled = semantic_hooks.action(&mut ctx, action);
7462        // This action reached the hook because it had no translated arm. If no
7463        // hook handled it either (`SemanticHooks::action` returns `false`), the
7464        // committed action is silently dropped — record it so the parse entry
7465        // can fail loud under the fail-loud boundary, mirroring unknown
7466        // predicates. `assume-*` policies opt out of the fail-loud recording.
7467        if record_unhandled
7468            && !handled
7469            && matches!(self.unknown_predicate_policy, UnknownSemanticPolicy::Error)
7470        {
7471            let coordinate = (rule_index, action.source_state());
7472            if !self.unhandled_action_hits.contains(&coordinate) {
7473                self.unhandled_action_hits.push(coordinate);
7474            }
7475        }
7476        handled
7477    }
7478
7479    /// Attempts to execute a whole generated rule by committing simulator
7480    /// decisions directly. Unsupported constructs or decisions that need
7481    /// full-context / predicate evaluation restore the input cursor and fall
7482    /// back to [`Self::parse_atn_rule`].
7483    pub fn parse_atn_rule_adaptive_or_fallback<'atn>(
7484        &mut self,
7485        atn: &'atn Atn,
7486        simulator: &mut ParserAtnSimulator<'atn>,
7487        rule_index: usize,
7488    ) -> Result<ParseTree, AntlrError> {
7489        let start_index = self.current_visible_index();
7490        self.clear_prediction_diagnostics();
7491        self.reset_per_parse_caches();
7492        self.reset_recognition_arena();
7493        let tree_checkpoint = self.tree.checkpoint();
7494        let mut decision_by_state = vec![None; atn.states().len()];
7495        for (decision, state_number) in atn.decision_to_state().iter().enumerate() {
7496            if let Some(slot) = decision_by_state.get_mut(state_number) {
7497                *slot = Some(decision);
7498            }
7499        }
7500
7501        let result = DirectAdaptiveParser {
7502            parser: self,
7503            atn,
7504            simulator,
7505            decision_by_state,
7506            steps: 0,
7507        }
7508        .parse_rule(rule_index, -1, 0);
7509
7510        match result {
7511            Ok(tree) => {
7512                self.report_token_source_errors();
7513                self.release_tree_scratch_if_idle();
7514                Ok(tree)
7515            }
7516            Err(DirectAdaptiveParseControl::Fallback(reason)) => {
7517                let _ = reason;
7518                self.tree.rollback(tree_checkpoint);
7519                self.input.seek(start_index);
7520                self.parse_atn_rule(atn, rule_index)
7521            }
7522        }
7523    }
7524
7525    /// Parses a generated rule by interpreting the parser ATN from the rule's
7526    /// start state to its stop state.
7527    ///
7528    /// The recognizer backtracks across alternatives and loop exits using token
7529    /// stream indices instead of committing to input consumption immediately.
7530    /// Once a viable ATN path is found, the parser commits the accepted token
7531    /// interval and returns a rule node whose children mirror every grammar
7532    /// rule invocation reached on that path, matching ANTLR's parse-tree
7533    /// shape.
7534    pub fn parse_atn_rule(
7535        &mut self,
7536        atn: &Atn,
7537        rule_index: usize,
7538    ) -> Result<ParseTree, AntlrError> {
7539        self.parse_atn_rule_with_precedence(atn, rule_index, 0)
7540    }
7541
7542    /// Parses a generated rule by interpreting the parser ATN with an initial
7543    /// left-recursive precedence threshold.
7544    pub fn parse_atn_rule_with_precedence(
7545        &mut self,
7546        atn: &Atn,
7547        rule_index: usize,
7548        precedence: i32,
7549    ) -> Result<ParseTree, AntlrError> {
7550        self.parse_atn_rule_with_precedence_inner(
7551            atn,
7552            rule_index,
7553            precedence,
7554            None,
7555            AltNumberTracking::default(),
7556        )
7557    }
7558
7559    fn parse_atn_rule_with_precedence_inner(
7560        &mut self,
7561        atn: &Atn,
7562        rule_index: usize,
7563        precedence: i32,
7564        predicate_context: Option<FastPredicateContext<'_>>,
7565        alt_tracking: AltNumberTracking,
7566    ) -> Result<ParseTree, AntlrError> {
7567        let report_unrecovered_error = self.is_top_level_entry();
7568        let start_state = atn.rule_to_start_state().get(rule_index).ok_or_else(|| {
7569            AntlrError::Unsupported(format!("rule {rule_index} has no start state"))
7570        })?;
7571        let stop_state = atn
7572            .rule_to_stop_state()
7573            .get(rule_index)
7574            .filter(|state| *state != usize::MAX)
7575            .ok_or_else(|| {
7576                AntlrError::Unsupported(format!("rule {rule_index} has no stop state"))
7577            })?;
7578
7579        let start_index = self.current_visible_index();
7580        self.clear_prediction_diagnostics();
7581        self.reset_per_parse_caches();
7582        self.reset_recognition_arena();
7583        let caller_follow_state = self.pending_invoking_follow_state(atn);
7584        self.fast_recovery_enabled = false;
7585        self.fast_token_nodes_enabled = false;
7586        self.fast_track_alt_numbers = alt_tracking.any();
7587        let top_request = FastRecognizeTopRequest {
7588            start_state,
7589            stop_state,
7590            start_index,
7591            precedence,
7592            caller_follow_state,
7593        };
7594        let first_pass = self.fast_recognize_top(atn, top_request, predicate_context);
7595        self.fast_token_nodes_enabled = self.build_parse_trees;
7596        let needs_tree_retry = matches!(
7597            &first_pass,
7598            Ok((outcome, _, _))
7599                if self.build_parse_trees
7600                    && self
7601                        .recognition_arena
7602                        .sequence_has_left_recursive_boundary(outcome.nodes)
7603        );
7604        let needs_retry = match &first_pass {
7605            // The FIRST-set prefilter trims speculative rule calls that can't
7606            // match the current lookahead — useful for perf on grammars with
7607            // many epsilon-reachable rules, but the trim also bypasses
7608            // single-token insertion / deletion recovery that ANTLR's
7609            // reference parser runs at the child rule's first consuming
7610            // transition. Retry without the prefilter whenever the first pass
7611            // either produced no outcome at all or produced a recovered
7612            // outcome (diagnostics non-empty), since the second pass might
7613            // surface a child-level recovery with cleaner diagnostics or
7614            // closer parity to ANTLR's tree shape. Left-recursive tree
7615            // boundaries also need the token-node pass; otherwise the fold has
7616            // no concrete left operand to wrap into ANTLR's recursive context.
7617            Err(_) => true,
7618            Ok((outcome, _, _)) => !outcome.diagnostics.is_empty() || needs_tree_retry,
7619        };
7620        let (outcome, _expected, alt_number) = if needs_retry {
7621            self.fast_first_set_prefilter = false;
7622            self.fast_recovery_enabled = false;
7623            let clean_retry = self.fast_recognize_top(atn, top_request, predicate_context);
7624            let clean_selected = if needs_tree_retry {
7625                match clean_retry {
7626                    ok @ Ok(_) => ok,
7627                    Err(_) => first_pass,
7628                }
7629            } else {
7630                select_better_top_outcome(first_pass, clean_retry, &self.recognition_arena)
7631            };
7632            let selected = if clean_selected.is_err()
7633                || matches!(&clean_selected, Ok((outcome, _, _)) if !outcome.diagnostics.is_empty())
7634            {
7635                self.fast_recovery_enabled = true;
7636                let recovery_retry = self.fast_recognize_top(atn, top_request, predicate_context);
7637                select_better_top_outcome(clean_selected, recovery_retry, &self.recognition_arena)
7638            } else {
7639                clean_selected
7640            };
7641            self.fast_first_set_prefilter = true;
7642            self.fast_recovery_enabled = true;
7643            selected.map_err(|expected| {
7644                if predicate_context.is_some()
7645                    && let Some(error) = self.unknown_semantic_error()
7646                {
7647                    self.report_token_source_errors();
7648                    return error;
7649                }
7650                let error = self.recognition_error(rule_index, start_index, &expected);
7651                self.record_syntax_errors(1);
7652                self.report_token_source_errors();
7653                if report_unrecovered_error {
7654                    self.report_unrecovered_parser_error(&error);
7655                }
7656                error
7657            })?
7658        } else {
7659            first_pass.expect("first_pass is Ok in the no-retry branch")
7660        };
7661        if predicate_context.is_some()
7662            && let Some(error) = self.unknown_semantic_error()
7663        {
7664            self.report_token_source_errors();
7665            return Err(error);
7666        }
7667        self.record_syntax_errors(self.recognition_arena.diagnostics_len(outcome.diagnostics));
7668        self.dispatch_parser_diagnostics(&self.prediction_diagnostics);
7669        self.dispatch_parser_diagnostics(self.recognition_arena.diagnostics(outcome.diagnostics));
7670        self.report_token_source_errors();
7671        let mut context = ParserRuleContext::with_child_capacity(
7672            rule_index,
7673            self.state(),
7674            if self.build_parse_trees {
7675                self.recognition_arena.sequence_len(outcome.nodes)
7676            } else {
7677                0
7678            },
7679        );
7680        if alt_tracking.public {
7681            context.set_alt_number(alt_number.max(1));
7682        }
7683        if alt_tracking.context {
7684            context.set_context_alt_number(alt_number);
7685        }
7686        if let Some(token) = self.token_id_at(start_index) {
7687            self.set_context_start(&mut context, token);
7688        }
7689        let stop_index = self.rule_stop_token_index(outcome.index, outcome.consumed_eof);
7690        if let Some(token) = stop_index.and_then(|token_index| self.token_id_at(token_index)) {
7691            self.set_context_stop(&mut context, token);
7692        }
7693        let live_root = if self.build_parse_trees {
7694            self.recognition_arena
7695                .fold_left_recursive_boundaries(outcome.nodes)
7696        } else {
7697            outcome.nodes
7698        };
7699        if self.build_parse_trees {
7700            if self
7701                .recognition_arena
7702                .sequence_has_explicit_token(live_root)
7703            {
7704                let mut cursor = live_root;
7705                while let Some(link) = self.recognition_arena.link(cursor) {
7706                    let child = self.arena_recognized_node_tree(
7707                        link.head,
7708                        alt_tracking.public,
7709                        alt_tracking.context,
7710                    )?;
7711                    self.tree.add_child(&mut context, child);
7712                    cursor = link.tail;
7713                }
7714            } else {
7715                self.add_arena_implicit_token_children(
7716                    &mut context,
7717                    start_index,
7718                    stop_index,
7719                    live_root,
7720                    alt_tracking,
7721                )?;
7722            }
7723        }
7724        self.finish_recognition_arena(live_root, outcome.diagnostics);
7725        self.input.seek(outcome.index);
7726
7727        let tree = self.rule_node(context);
7728        self.release_tree_scratch_if_idle();
7729        Ok(tree)
7730    }
7731
7732    fn pending_invoking_follow_state(&self, atn: &Atn) -> Option<usize> {
7733        let invoking_state = self.pending_invoking_states.last().copied()?;
7734        let state_number = usize::try_from(invoking_state).ok()?;
7735        match atn.state(state_number)?.transitions().first()?.data() {
7736            Transition::Rule { follow_state, .. } => Some(follow_state),
7737            _ => None,
7738        }
7739    }
7740
7741    #[cfg(test)]
7742    fn caller_follow_token_info(&mut self, index: usize) -> (i32, bool, bool) {
7743        caller_follow_token_info_for_stream(&mut self.input, index)
7744    }
7745
7746    /// Runs the fast recognizer once from the rule's start state and returns
7747    /// the best outcome or the per-attempt expected-token accumulator. The
7748    /// caller flips `fast_first_set_prefilter` between calls when a retry is
7749    /// needed, so the FIRST-set cache is left intact across both passes.
7750    fn fast_recognize_top(
7751        &mut self,
7752        atn: &Atn,
7753        request: FastRecognizeTopRequest,
7754        predicate_context: Option<FastPredicateContext<'_>>,
7755    ) -> Result<(FastRecognizeOutcome, ExpectedTokens, usize), ExpectedTokens> {
7756        let FastRecognizeTopRequest {
7757            start_state,
7758            stop_state,
7759            start_index,
7760            precedence,
7761            caller_follow_state,
7762        } = request;
7763        // `input.size()` is intentionally only the currently buffered token
7764        // count here. Do not restore an up-front fill just to size this map:
7765        // a small floor avoids tiny-input churn, and larger inputs reserve from
7766        // the buffered token count without forcing startup tokenization. The
7767        // 8x multiplier matches the empirical
7768        // memo-insert / token ratio on heavy grammars (C# averages ~6× and
7769        // Kotlin ~12× memo entries per token), so the table avoids one
7770        // rehash on the typical hot path.
7771        let memo_capacity = fast_recognize_memo_capacity(self.input.size());
7772        let mut recognize_scratch = std::mem::take(&mut self.fast_recognize_scratch);
7773        recognize_scratch.prepare(memo_capacity);
7774        let mut expected = ExpectedTokens::default();
7775        let empty_recovery = self.empty_recovery_symbols();
7776        let outcomes = self.recognize_state_fast(
7777            atn,
7778            FastRecognizeRequest {
7779                state_number: start_state,
7780                stop_state,
7781                index: start_index,
7782                rule_start_index: start_index,
7783                decision_start_index: None,
7784                precedence,
7785                depth: 0,
7786                recovery_symbols: empty_recovery,
7787                recovery_state: None,
7788            },
7789            FastRecognizeScratch {
7790                predicate_context,
7791                visiting: &mut recognize_scratch.visiting,
7792                memo: &mut recognize_scratch.memo,
7793                expected: &mut expected,
7794                native_depth: 0,
7795            },
7796        );
7797        recognize_scratch.release_oversized_memo();
7798        self.fast_recognize_scratch = recognize_scratch;
7799        #[cfg(feature = "perf-counters")]
7800        if std::env::var("ANTLR_PERF_DUMP").is_ok() {
7801            perf_counters::dump();
7802            perf_counters::reset();
7803        }
7804        let caller_follow =
7805            caller_follow_state.map(|state| self.cached_state_expected_token_set(atn, state));
7806        let selected = {
7807            let arena = &self.recognition_arena;
7808            let input = &mut self.input;
7809            select_best_fast_outcome(
7810                outcomes.into_iter(),
7811                self.prediction_mode,
7812                caller_follow.as_deref(),
7813                |index| caller_follow_token_info_for_stream(input, index),
7814                arena,
7815            )
7816        };
7817        match selected {
7818            Some(mut outcome) => {
7819                let alt_number = if self.build_parse_trees || self.fast_track_alt_numbers {
7820                    self.materialize_fast_outcome_nodes(&mut outcome)
7821                } else {
7822                    0
7823                };
7824                Ok((outcome, expected, alt_number))
7825            }
7826            None => Err(expected),
7827        }
7828    }
7829
7830    /// Converts one speculative arena record into the flat public CST.
7831    fn arena_recognized_node_tree(
7832        &mut self,
7833        node_id: RecognizedNodeId,
7834        track_alt_numbers: bool,
7835        track_context_alt_numbers: bool,
7836    ) -> Result<ParseTree, AntlrError> {
7837        let node = self.recognition_arena.node(node_id);
7838        match node {
7839            ArenaRecognizedNode::Token { token } => Ok(self.terminal_tree(token)),
7840            ArenaRecognizedNode::ErrorToken { token } => Ok(self.error_tree(token)),
7841            ArenaRecognizedNode::MissingToken { extra } => {
7842                let (token_type, at_index, text) = match self.recognition_arena.extra(extra) {
7843                    RecognitionExtra::MissingToken {
7844                        token_type,
7845                        at_index,
7846                        text,
7847                    } => (*token_type, *at_index as usize, text.clone()),
7848                    RecognitionExtra::ReturnValues(_) | RecognitionExtra::Diagnostic(_) => {
7849                        unreachable!("missing-token node must reference missing-token extra")
7850                    }
7851                };
7852                let (line, column) = self
7853                    .token_at(at_index)
7854                    .map_or((0, 0), |token| (token.line(), token.column()));
7855                let token = self.insert_synthetic_token(token_type, text, line, column)?;
7856                Ok(self.error_tree(token))
7857            }
7858            ArenaRecognizedNode::Rule {
7859                rule_index,
7860                invoking_state,
7861                alt_number,
7862                start_index,
7863                stop_index,
7864                return_values,
7865                children,
7866            } => {
7867                let mut context = ParserRuleContext::with_child_capacity(
7868                    rule_index as usize,
7869                    invoking_state as isize,
7870                    self.recognition_arena.sequence_len(children),
7871                );
7872                if track_alt_numbers {
7873                    context.set_alt_number((alt_number as usize).max(1));
7874                }
7875                if track_context_alt_numbers {
7876                    context.set_context_alt_number(alt_number as usize);
7877                }
7878                if let Some(extra) = return_values {
7879                    let RecognitionExtra::ReturnValues(values) =
7880                        self.recognition_arena.extra(extra)
7881                    else {
7882                        unreachable!("rule node must reference return-values extra");
7883                    };
7884                    for (name, value) in values {
7885                        context.set_int_return(name.clone(), *value);
7886                    }
7887                }
7888                if let Some(token) = self.token_id_at(start_index as usize) {
7889                    self.set_context_start(&mut context, token);
7890                }
7891                if let Some(token) = stop_index.and_then(|index| self.token_id_at(index as usize)) {
7892                    self.set_context_stop(&mut context, token);
7893                }
7894                let mut cursor = self
7895                    .recognition_arena
7896                    .fold_left_recursive_boundaries(children);
7897                while let Some(link) = self.recognition_arena.link(cursor) {
7898                    let child = self.arena_recognized_node_tree(
7899                        link.head,
7900                        track_alt_numbers,
7901                        track_context_alt_numbers,
7902                    )?;
7903                    self.tree.add_child(&mut context, child);
7904                    cursor = link.tail;
7905                }
7906                Ok(self.rule_node(context))
7907            }
7908            ArenaRecognizedNode::LeftRecursiveBoundary { rule_index, .. } => {
7909                Err(AntlrError::Unsupported(format!(
7910                    "unfolded left-recursive boundary for rule {rule_index}"
7911                )))
7912            }
7913        }
7914    }
7915
7916    fn arena_recognized_node_tree_with_implicit_tokens(
7917        &mut self,
7918        node_id: RecognizedNodeId,
7919        alt_tracking: AltNumberTracking,
7920    ) -> Result<ParseTree, AntlrError> {
7921        let node = self.recognition_arena.node(node_id);
7922        match node {
7923            ArenaRecognizedNode::Rule {
7924                rule_index,
7925                invoking_state,
7926                alt_number,
7927                start_index,
7928                stop_index,
7929                children,
7930                ..
7931            } => {
7932                let mut context = ParserRuleContext::with_child_capacity(
7933                    rule_index as usize,
7934                    invoking_state as isize,
7935                    self.recognition_arena.sequence_len(children),
7936                );
7937                if alt_tracking.public {
7938                    context.set_alt_number((alt_number as usize).max(1));
7939                }
7940                if alt_tracking.context {
7941                    context.set_context_alt_number(alt_number as usize);
7942                }
7943                if let Some(token) = self.token_id_at(start_index as usize) {
7944                    self.set_context_start(&mut context, token);
7945                }
7946                if let Some(token) = stop_index.and_then(|index| self.token_id_at(index as usize)) {
7947                    self.set_context_stop(&mut context, token);
7948                }
7949                let children = self
7950                    .recognition_arena
7951                    .fold_left_recursive_boundaries(children);
7952                self.add_arena_implicit_token_children(
7953                    &mut context,
7954                    start_index as usize,
7955                    stop_index.map(|index| index as usize),
7956                    children,
7957                    alt_tracking,
7958                )?;
7959                Ok(self.rule_node(context))
7960            }
7961            _ => {
7962                self.arena_recognized_node_tree(node_id, alt_tracking.public, alt_tracking.context)
7963            }
7964        }
7965    }
7966
7967    fn add_arena_implicit_token_children(
7968        &mut self,
7969        context: &mut ParserRuleContext,
7970        start_index: usize,
7971        stop_index: Option<usize>,
7972        mut children: NodeSeqId,
7973        alt_tracking: AltNumberTracking,
7974    ) -> Result<(), AntlrError> {
7975        let mut cursor = Some(start_index);
7976        while let Some(link) = self.recognition_arena.link(children) {
7977            if let Some((child_start, child_stop)) = self.recognition_arena.node_span(link.head) {
7978                self.add_visible_terminals_before(context, &mut cursor, child_start)?;
7979                let child =
7980                    self.arena_recognized_node_tree_with_implicit_tokens(link.head, alt_tracking)?;
7981                self.tree.add_child(context, child);
7982                if let Some(child_stop) = child_stop {
7983                    let next = self.next_visible_after_token(child_stop);
7984                    cursor = match (cursor, next) {
7985                        (None, _) | (_, None) => None,
7986                        (Some(current), Some(next)) => Some(current.max(next)),
7987                    };
7988                }
7989            } else {
7990                let child =
7991                    self.arena_recognized_node_tree_with_implicit_tokens(link.head, alt_tracking)?;
7992                self.tree.add_child(context, child);
7993            }
7994            children = link.tail;
7995        }
7996        if let Some(stop) = stop_index {
7997            self.add_visible_terminals_through(context, cursor, stop)?;
7998        }
7999        Ok(())
8000    }
8001
8002    fn add_visible_terminals_before(
8003        &mut self,
8004        context: &mut ParserRuleContext,
8005        cursor: &mut Option<usize>,
8006        before: usize,
8007    ) -> Result<(), AntlrError> {
8008        let Some(stop) = before.checked_sub(1) else {
8009            return Ok(());
8010        };
8011        let next = self.add_visible_terminals_through(context, *cursor, stop)?;
8012        *cursor = next;
8013        Ok(())
8014    }
8015
8016    fn add_visible_terminals_through(
8017        &mut self,
8018        context: &mut ParserRuleContext,
8019        mut cursor: Option<usize>,
8020        stop: usize,
8021    ) -> Result<Option<usize>, AntlrError> {
8022        while let Some(index) = cursor {
8023            if index > stop {
8024                return Ok(Some(index));
8025            }
8026            let token = self
8027                .input
8028                .get_id(index)
8029                .ok_or_else(|| AntlrError::ParserError {
8030                    line: 0,
8031                    column: 0,
8032                    message: format!("missing token at index {index}"),
8033                    offending: None,
8034                })?;
8035            let is_eof = self.token_type_for_id(token) == TOKEN_EOF;
8036            let child = self.terminal_tree(token);
8037            self.tree.add_child(context, child);
8038            if is_eof {
8039                return Ok(None);
8040            }
8041            cursor = self.next_visible_after_token(index);
8042        }
8043        Ok(None)
8044    }
8045
8046    fn next_visible_after_token(&mut self, index: usize) -> Option<usize> {
8047        let next = self.input.next_visible_after(index);
8048        (next != index).then_some(next)
8049    }
8050
8051    /// Parses a generated rule and returns semantic actions reached on the
8052    /// selected ATN path.
8053    ///
8054    /// This slower path preserves action ordering and token intervals for
8055    /// generated code that replays target-specific action templates after the
8056    /// recognizer has chosen one viable parse path.
8057    pub fn parse_atn_rule_with_actions(
8058        &mut self,
8059        atn: &Atn,
8060        rule_index: usize,
8061    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
8062        self.parse_atn_rule_with_action_options(atn, rule_index, &[], false)
8063    }
8064
8065    /// Parses a generated rule and emits ATN actions plus selected rule-init
8066    /// actions reached on the chosen path.
8067    ///
8068    /// Generated parsers use this when a grammar contains rule-level `@init`
8069    /// templates that must run for nested rule invocations. The runtime keeps
8070    /// the action list path-sensitive, so init templates are replayed only for
8071    /// rules that were actually entered by the selected parse.
8072    pub fn parse_atn_rule_with_action_inits(
8073        &mut self,
8074        atn: &Atn,
8075        rule_index: usize,
8076        init_action_rules: &[usize],
8077    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
8078        self.parse_atn_rule_with_action_options(atn, rule_index, init_action_rules, false)
8079    }
8080
8081    /// Parses a generated rule with optional semantic-action replay features.
8082    ///
8083    /// `track_alt_numbers` is used by grammars that opt into ANTLR's
8084    /// alt-numbered context behavior. It keeps ordinary parse-tree rendering
8085    /// unchanged for grammars that do not request that target template.
8086    pub fn parse_atn_rule_with_action_options(
8087        &mut self,
8088        atn: &Atn,
8089        rule_index: usize,
8090        init_action_rules: &[usize],
8091        track_alt_numbers: bool,
8092    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
8093        self.parse_atn_rule_with_runtime_options(
8094            atn,
8095            rule_index,
8096            ParserRuntimeOptions {
8097                init_action_rules,
8098                track_alt_numbers,
8099                ..ParserRuntimeOptions::default()
8100            },
8101        )
8102    }
8103
8104    /// Parses a generated rule with action replay and parser predicate support.
8105    ///
8106    /// `predicates` maps serialized `(rule_index, pred_index)` coordinates to
8107    /// target-template predicate semantics emitted by the generator. Missing
8108    /// entries are treated as true so unsupported predicate-free grammars keep
8109    /// the previous unconditional transition behavior.
8110    pub fn parse_atn_rule_with_runtime_options(
8111        &mut self,
8112        atn: &Atn,
8113        rule_index: usize,
8114        options: ParserRuntimeOptions<'_>,
8115    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
8116        self.parse_atn_rule_with_runtime_options_and_precedence(atn, rule_index, 0, options)
8117    }
8118
8119    fn parse_atn_rule_committed_with_runtime_options(
8120        &mut self,
8121        atn: &Atn,
8122        rule_index: usize,
8123        precedence: i32,
8124        options: ParserRuntimeOptions<'_>,
8125    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
8126        let top_level_entry = self.is_top_level_entry();
8127        self.unknown_predicate_policy = options.unknown_predicate_policy;
8128        let prior_unknown_predicate_hits = std::mem::take(&mut self.unknown_predicate_hits);
8129        let prior_unhandled_action_hits = std::mem::take(&mut self.unhandled_action_hits);
8130        self.clear_prediction_diagnostics();
8131        self.reset_per_parse_caches();
8132        self.reset_recognition_arena();
8133
8134        let mut decision_by_state = vec![None; atn.states().len()];
8135        for (decision, state_number) in atn.decision_to_state().iter().enumerate() {
8136            if let Some(slot) = decision_by_state.get_mut(state_number) {
8137                *slot = Some(decision);
8138            }
8139        }
8140        let mut action_index_by_state = FxHashMap::default();
8141        for &(state, index) in options.action_indices {
8142            action_index_by_state.entry(state).or_insert(index);
8143        }
8144        let mut simulator = ParserAtnSimulator::new(atn);
8145        simulator.set_track_prediction_rule_calls(!options.rule_args.is_empty());
8146        let (result, deferred_actions) = {
8147            let mut committed = CommittedAtnParser {
8148                parser: self,
8149                atn,
8150                simulator,
8151                options,
8152                decision_by_state,
8153                action_index_by_state,
8154                deferred_actions: Vec::new(),
8155            };
8156            let result = committed.parse_rule(rule_index, precedence, None, None);
8157            (result, committed.deferred_actions)
8158        };
8159
8160        if top_level_entry {
8161            self.report_generated_parser_diagnostics();
8162        }
8163        let semantic_error = self.unknown_semantic_error();
8164        self.restore_prior_unknown_predicate_hits(prior_unknown_predicate_hits);
8165        self.restore_prior_unhandled_action_hits(prior_unhandled_action_hits);
8166        if top_level_entry && let Some(error) = self.take_parse_abort() {
8167            self.reset_unknown_semantic_hits();
8168            return Err(error);
8169        }
8170        if let Some(error) = semantic_error {
8171            if top_level_entry {
8172                self.reset_unknown_semantic_hits();
8173            }
8174            return Err(error);
8175        }
8176        let result = result.map(|outcome| (outcome.tree, deferred_actions));
8177        if top_level_entry && let Err(error) = &result {
8178            self.report_unrecovered_parser_error(error);
8179        }
8180        result
8181    }
8182
8183    /// Parses a generated rule with action replay, parser predicate support,
8184    /// and an initial left-recursive precedence threshold.
8185    pub fn parse_atn_rule_with_runtime_options_and_precedence(
8186        &mut self,
8187        atn: &Atn,
8188        rule_index: usize,
8189        precedence: i32,
8190        options: ParserRuntimeOptions<'_>,
8191    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
8192        if !options.action_indices.is_empty() {
8193            return self.parse_atn_rule_committed_with_runtime_options(
8194                atn, rule_index, precedence, options,
8195            );
8196        }
8197        let report_unrecovered_error = self.is_top_level_entry();
8198        let ParserRuntimeOptions {
8199            init_action_rules,
8200            track_alt_numbers,
8201            track_context_alt_numbers,
8202            predicates,
8203            semantics,
8204            rule_args,
8205            member_actions,
8206            return_actions,
8207            unknown_predicate_policy,
8208            ..
8209        } = options;
8210        let capture_alt_numbers = track_alt_numbers || track_context_alt_numbers;
8211        if init_action_rules.is_empty()
8212            && !capture_alt_numbers
8213            && predicates.is_empty()
8214            && semantics.is_none()
8215            && rule_args.is_empty()
8216            && member_actions.is_empty()
8217            && return_actions.is_empty()
8218            && unknown_predicate_policy == UnknownSemanticPolicy::AssumeTrue
8219            && !atn_has_observable_action_transitions(atn)
8220            && !self.semantic_hooks.observes_parser_decisions()
8221            && (!self.semantic_hooks.observes_parser_predicates()
8222                || !atn_has_predicate_transitions(atn))
8223        {
8224            return self
8225                .parse_atn_rule_with_precedence(atn, rule_index, precedence)
8226                .map(|tree| (tree, Vec::new()));
8227        }
8228        if !self.semantic_hooks.observes_parser_decisions()
8229            && can_use_fast_predicate_recognizer(atn, &options)
8230        {
8231            self.unknown_predicate_policy = unknown_predicate_policy;
8232            let prior_unknown_predicate_hits = std::mem::take(&mut self.unknown_predicate_hits);
8233            let member_values = self.int_members.clone();
8234            let result = self
8235                .parse_atn_rule_with_precedence_inner(
8236                    atn,
8237                    rule_index,
8238                    precedence,
8239                    Some(FastPredicateContext {
8240                        predicates,
8241                        semantics,
8242                        member_values: &member_values,
8243                    }),
8244                    AltNumberTracking {
8245                        public: track_alt_numbers,
8246                        context: track_context_alt_numbers,
8247                    },
8248                )
8249                .map(|tree| (tree, Vec::new()));
8250            if self.unknown_predicate_hits.is_empty() && self.unhandled_action_hits.is_empty() {
8251                self.restore_prior_unknown_predicate_hits(prior_unknown_predicate_hits);
8252            }
8253            return result;
8254        }
8255        self.unknown_predicate_policy = unknown_predicate_policy;
8256        // A generated parent may have already recorded unknown-predicate
8257        // coordinates before descending into this (interpreted) child. Clearing
8258        // unconditionally would drop them before the parent's public entry
8259        // surfaces them, so stash and restore around this call: recognition sees
8260        // only the hits it records itself (so the fail-loud check below reflects
8261        // this rule), and the parent's prior hits are merged back afterward.
8262        let prior_unknown_predicate_hits = std::mem::take(&mut self.unknown_predicate_hits);
8263        let start_state = atn.rule_to_start_state().get(rule_index).ok_or_else(|| {
8264            AntlrError::Unsupported(format!("rule {rule_index} has no start state"))
8265        })?;
8266        let stop_state = atn
8267            .rule_to_stop_state()
8268            .get(rule_index)
8269            .filter(|state| *state != usize::MAX)
8270            .ok_or_else(|| {
8271                AntlrError::Unsupported(format!("rule {rule_index} has no stop state"))
8272            })?;
8273
8274        let start_index = self.current_visible_index();
8275        self.clear_prediction_diagnostics();
8276        self.reset_per_parse_caches();
8277        self.reset_recognition_arena();
8278        let init_action_rules = init_action_rules.iter().copied().collect::<BTreeSet<_>>();
8279        let invoking_state = self.pending_invoking_states.pop();
8280        let local_int_arg = invoking_state
8281            .and_then(|state| usize::try_from(state).ok())
8282            .and_then(|state| rule_local_int_arg(rule_args, state, rule_index, None));
8283        let mut visiting = BTreeSet::new();
8284        let mut memo = BTreeMap::new();
8285        let mut expected = ExpectedTokens::default();
8286        let member_values = self.int_members.clone();
8287        let return_values = BTreeMap::new();
8288        let outcomes = self.recognize_state(
8289            atn,
8290            RecognizeRequest {
8291                state_number: start_state,
8292                stop_state,
8293                index: start_index,
8294                rule_start_index: start_index,
8295                decision_start_index: None,
8296                init_action_rules: &init_action_rules,
8297                predicates,
8298                semantics,
8299                rule_args,
8300                member_actions,
8301                return_actions,
8302                local_int_arg,
8303                member_values,
8304                return_values,
8305                rule_alt_number: 0,
8306                track_alt_numbers: capture_alt_numbers,
8307                consumed_eof: false,
8308                committed_decision: false,
8309                precedence,
8310                depth: 0,
8311                recovery_symbols: BTreeSet::new(),
8312                recovery_state: None,
8313            },
8314            &mut visiting,
8315            &mut memo,
8316            &mut expected,
8317        );
8318        if let Some(error) = self.unknown_semantic_error() {
8319            self.report_token_source_errors();
8320            // Keep the recorded coordinates: when this interpreted rule is a
8321            // child of a generated parent, the parent's catch block recovers an
8322            // ordinary `AntlrError` into a partial subtree, so the fail-loud
8323            // coordinate must survive on the parser for the top-level entry's
8324            // `take_unknown_semantic_error` to surface it. Cross-parse staleness
8325            // is handled by clearing at the top-level generated entry instead.
8326            return Err(error);
8327        }
8328        // Recognition recorded no unresolved coordinate of its own; merge the
8329        // parent's prior hits back so its public entry can still surface them.
8330        self.restore_prior_unknown_predicate_hits(prior_unknown_predicate_hits);
8331        let Some(outcome) = select_best_outcome(
8332            outcomes.into_iter(),
8333            self.prediction_mode,
8334            &self.recognition_arena,
8335        ) else {
8336            let error = self.recognition_error(rule_index, start_index, &expected);
8337            self.record_syntax_errors(1);
8338            self.report_token_source_errors();
8339            if report_unrecovered_error {
8340                self.report_unrecovered_parser_error(&error);
8341            }
8342            return Err(error);
8343        };
8344
8345        self.record_syntax_errors(self.recognition_arena.diagnostics_len(outcome.diagnostics));
8346        self.dispatch_parser_diagnostics(&self.prediction_diagnostics);
8347        self.dispatch_parser_diagnostics(self.recognition_arena.diagnostics(outcome.diagnostics));
8348        self.report_token_source_errors();
8349        let mut actions = outcome.actions;
8350        if init_action_rules.contains(&rule_index) {
8351            actions.insert(
8352                0,
8353                ParserAction::new_rule_init(rule_index, start_index, Some(start_state)),
8354            );
8355        }
8356        let mut context =
8357            ParserRuleContext::new(rule_index, invoking_state.unwrap_or_else(|| self.state()));
8358        if track_alt_numbers {
8359            context.set_alt_number(outcome.alt_number.max(1));
8360        }
8361        if track_context_alt_numbers {
8362            context.set_context_alt_number(outcome.alt_number);
8363        }
8364        for (name, value) in outcome.return_values {
8365            context.set_int_return(name, value);
8366        }
8367        if let Some(token) = self.token_id_at(start_index) {
8368            self.set_context_start(&mut context, token);
8369        }
8370        if let Some(token) = self.rule_stop_token_id(outcome.index, outcome.consumed_eof) {
8371            self.set_context_stop(&mut context, token);
8372        }
8373        let live_root = if self.build_parse_trees {
8374            self.recognition_arena
8375                .fold_left_recursive_boundaries(outcome.nodes)
8376        } else {
8377            outcome.nodes
8378        };
8379        if self.build_parse_trees {
8380            let mut nodes = live_root;
8381            while let Some(link) = self.recognition_arena.link(nodes) {
8382                let child = self.arena_recognized_node_tree(
8383                    link.head,
8384                    track_alt_numbers,
8385                    track_context_alt_numbers,
8386                )?;
8387                self.tree.add_child(&mut context, child);
8388                nodes = link.tail;
8389            }
8390        }
8391        self.finish_recognition_arena(live_root, outcome.diagnostics);
8392        self.input.seek(outcome.index);
8393
8394        let tree = self.rule_node(context);
8395        self.release_tree_scratch_if_idle();
8396        Ok((tree, actions))
8397    }
8398
8399    /// Temporary parser entry used by generated parser methods while the parser
8400    /// ATN simulator is being implemented.
8401    ///
8402    /// This keeps generated parser crates buildable and gives us a stable method
8403    /// surface for every grammar rule. It intentionally accepts all remaining
8404    /// tokens into one rule context; it is not the final parser semantics.
8405    pub fn parse_interpreted_rule(&mut self, rule_index: usize) -> Result<ParseTree, AntlrError> {
8406        let mut context = ParserRuleContext::new(rule_index, self.state());
8407        while self.la(1) != TOKEN_EOF {
8408            let token_type = self.la(1);
8409            let child = self.match_token(token_type)?;
8410            if self.build_parse_trees {
8411                self.tree.add_child(&mut context, child);
8412            }
8413        }
8414        if self.build_parse_trees {
8415            let child = self.match_eof()?;
8416            self.tree.add_child(&mut context, child);
8417        }
8418        let tree = self.rule_node(context);
8419        self.release_tree_scratch_if_idle();
8420        Ok(tree)
8421    }
8422
8423    /// Builds the parser error reported when no ATN path can reach the active
8424    /// rule stop state.
8425    fn recognition_error(
8426        &mut self,
8427        rule_index: usize,
8428        start_index: usize,
8429        expected: &ExpectedTokens,
8430    ) -> AntlrError {
8431        let (index, message) = self.expected_error_message(rule_index, start_index, expected);
8432        self.input.seek(index);
8433        let current = self.input.lt(1);
8434        let line = current.as_ref().map(Token::line).unwrap_or_default();
8435        let column = current.as_ref().map(Token::column).unwrap_or_default();
8436        AntlrError::ParserError {
8437            line,
8438            column,
8439            message,
8440            offending: current.as_ref().map(Token::token_id),
8441        }
8442    }
8443
8444    /// Builds the token index and ANTLR-compatible message for a failed rule.
8445    fn expected_error_message(
8446        &mut self,
8447        rule_index: usize,
8448        start_index: usize,
8449        expected: &ExpectedTokens,
8450    ) -> (usize, String) {
8451        let index = expected
8452            .index
8453            .or_else(|| expected.no_viable.map(|no_viable| no_viable.error_index))
8454            .unwrap_or_else(|| self.input.index());
8455        self.input.seek(index);
8456        let current = self.input.lt(1);
8457        let message = if expected
8458            .no_viable
8459            .as_ref()
8460            .is_some_and(|no_viable| no_viable.error_index == index)
8461        {
8462            let start = expected
8463                .no_viable
8464                .as_ref()
8465                .map_or(start_index, |no_viable| no_viable.start_index);
8466            let text = display_input_text(&self.input.text(start, index));
8467            format!("no viable alternative at input '{text}'")
8468        } else if expected.symbols.is_empty() {
8469            if expected.index.is_some() {
8470                let found = current
8471                    .as_ref()
8472                    .map_or_else(|| "'<EOF>'".to_owned(), token_input_display);
8473                if current
8474                    .as_ref()
8475                    .is_some_and(|token| token.token_type() == TOKEN_EOF)
8476                {
8477                    format!(
8478                        "missing {} at {found}",
8479                        self.expected_symbols_display(&expected.symbols)
8480                    )
8481                } else {
8482                    format!("mismatched input {found}")
8483                }
8484            } else {
8485                format!("no viable alternative while parsing rule {rule_index}")
8486            }
8487        } else {
8488            format!(
8489                "mismatched input {} expecting {}",
8490                current
8491                    .as_ref()
8492                    .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
8493                self.expected_symbols_display(&expected.symbols)
8494            )
8495        };
8496        (index, message)
8497    }
8498
8499    /// Converts a failed child rule into a recovered outcome so the parent can
8500    /// continue after reporting the child diagnostic.
8501    fn child_rule_failure_recovery(
8502        &mut self,
8503        rule_index: usize,
8504        start_index: usize,
8505        sync_symbols: &BTreeSet<i32>,
8506        member_values: MemberEnv,
8507        expected: &ExpectedTokens,
8508    ) -> Option<RecognizeOutcome> {
8509        let (error_index, message) = self.expected_error_message(rule_index, start_index, expected);
8510        let diagnostic = diagnostic_for_token(self.token_at(error_index), message);
8511        let mut next_index = error_index;
8512        loop {
8513            let symbol = self.token_type_at(next_index);
8514            if sync_symbols.contains(&symbol) {
8515                if next_index == error_index {
8516                    return None;
8517                }
8518                break;
8519            }
8520            if symbol == TOKEN_EOF {
8521                break;
8522            }
8523            let after = self.consume_index(next_index, symbol);
8524            if after == next_index {
8525                break;
8526            }
8527            next_index = after;
8528        }
8529        let mut nodes = NodeSeqId::EMPTY;
8530        let error = self.arena_token_node(error_index, true);
8531        self.arena_prepend(&mut nodes, error);
8532        let diagnostics = self
8533            .recognition_arena
8534            .prepend_diagnostic(DiagnosticSeqId::EMPTY, diagnostic);
8535        Some(RecognizeOutcome {
8536            index: next_index,
8537            consumed_eof: false,
8538            alt_number: 0,
8539            member_values,
8540            return_values: BTreeMap::new(),
8541            diagnostics,
8542            decisions: Vec::new(),
8543            actions: Vec::new(),
8544            nodes,
8545        })
8546    }
8547
8548    /// Adapts the optional recovery result to the normal outcome list used by
8549    /// rule-call transitions.
8550    fn child_rule_failure_recovery_outcomes(
8551        &mut self,
8552        request: ChildRuleFailureRecovery<'_>,
8553    ) -> Vec<RecognizeOutcome> {
8554        let sync_symbols =
8555            state_sync_symbols(request.atn, request.follow_state, request.stop_state);
8556        self.child_rule_failure_recovery(
8557            request.rule_index,
8558            request.start_index,
8559            &sync_symbols,
8560            request.member_values,
8561            request.expected,
8562        )
8563        .into_iter()
8564        .collect()
8565    }
8566
8567    /// Formats expected token types using ANTLR's single-token or set syntax.
8568    fn expected_symbols_display(&self, symbols: &BTreeSet<i32>) -> String {
8569        expected_symbols_display(symbols, self.vocabulary())
8570    }
8571
8572    /// Returns the single-token deletion repair if the token after `index`
8573    /// satisfies the failed consuming transition.
8574    fn single_token_deletion(
8575        &mut self,
8576        transition: ParserTransition<'_>,
8577        index: usize,
8578        max_token_type: i32,
8579        expected_symbols: &BTreeSet<i32>,
8580    ) -> Option<(ParserDiagnostic, usize, i32)> {
8581        let current_symbol = self.token_type_at(index);
8582        if current_symbol == TOKEN_EOF {
8583            return None;
8584        }
8585        let next_index = self.consume_index(index, current_symbol);
8586        if next_index == index {
8587            return None;
8588        }
8589        let next_symbol = self.token_type_at(next_index);
8590        if !transition.matches(next_symbol, 1, max_token_type) {
8591            return None;
8592        }
8593        let transition_expected = transition_expected_symbols(transition, max_token_type);
8594        let expected_display = self.expected_symbols_display(if expected_symbols.is_empty() {
8595            &transition_expected
8596        } else {
8597            expected_symbols
8598        });
8599        let current = self.token_at(index);
8600        let message = format!(
8601            "extraneous input {} expecting {expected_display}",
8602            current
8603                .as_ref()
8604                .map_or_else(|| "'<EOF>'".to_owned(), token_input_display)
8605        );
8606        Some((
8607            diagnostic_for_token(current, message),
8608            next_index,
8609            next_symbol,
8610        ))
8611    }
8612
8613    /// Returns the repair used when deleting the current token lets a recovery
8614    /// state continue with the following token.
8615    fn current_token_deletion(
8616        &mut self,
8617        index: usize,
8618        expected_symbols: &BTreeSet<i32>,
8619    ) -> Option<(ParserDiagnostic, usize, Vec<usize>)> {
8620        if expected_symbols.is_empty() {
8621            return None;
8622        }
8623        let current_symbol = self.token_type_at(index);
8624        if current_symbol == TOKEN_EOF {
8625            return None;
8626        }
8627        let current = self.token_at(index);
8628        let message = format!(
8629            "extraneous input {} expecting {}",
8630            current
8631                .as_ref()
8632                .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
8633            self.expected_symbols_display(expected_symbols)
8634        );
8635        let diagnostic = diagnostic_for_token(current, message);
8636        let mut skipped = Vec::new();
8637        let mut cursor = index;
8638        loop {
8639            let symbol = self.token_type_at(cursor);
8640            if symbol == TOKEN_EOF {
8641                return None;
8642            }
8643            skipped.push(cursor);
8644            let next_index = self.consume_index(cursor, symbol);
8645            if next_index == cursor {
8646                return None;
8647            }
8648            let next_symbol = self.token_type_at(next_index);
8649            if expected_symbols.contains(&next_symbol) {
8650                return Some((diagnostic, next_index, skipped));
8651            }
8652            cursor = next_index;
8653        }
8654    }
8655
8656    /// Returns the single-token insertion repair for a failed consuming
8657    /// transition. The caller validates the repair by continuing from the
8658    /// transition target at the same input index.
8659    fn single_token_insertion(
8660        &mut self,
8661        transition: ParserTransition<'_>,
8662        index: usize,
8663        max_token_type: i32,
8664        expected_symbols: &BTreeSet<i32>,
8665        follow_symbols: &BTreeSet<i32>,
8666    ) -> Option<(ParserDiagnostic, i32, String)> {
8667        let current_symbol = self.token_type_at(index);
8668        if !follow_symbols.contains(&current_symbol) {
8669            return None;
8670        }
8671        let transition_expected = transition_expected_symbols(transition, max_token_type);
8672        let token_type = transition_expected.iter().next().copied()?;
8673        let expected_display = self.expected_symbols_display(if expected_symbols.is_empty() {
8674            &transition_expected
8675        } else {
8676            expected_symbols
8677        });
8678        let mut token_symbols = BTreeSet::new();
8679        token_symbols.insert(token_type);
8680        let missing_token_display = self.expected_symbols_display(&token_symbols);
8681        let current = self.token_at(index);
8682        let message = format!(
8683            "missing {expected_display} at {}",
8684            current
8685                .as_ref()
8686                .map_or_else(|| "'<EOF>'".to_owned(), token_input_display)
8687        );
8688        let text = format!("<missing {missing_token_display}>");
8689        Some((
8690            diagnostic_for_token(current.as_ref(), message),
8691            token_type,
8692            text,
8693        ))
8694    }
8695
8696    /// Explores ANTLR's single-token deletion recovery for the fast recognizer:
8697    /// skip the unexpected current token when the following token satisfies the
8698    /// transition that failed.
8699    fn fast_single_token_deletion_recovery(
8700        &mut self,
8701        recovery: FastRecoveryRequest<'_, '_>,
8702        predicate_context: Option<FastPredicateContext<'_>>,
8703    ) -> Vec<FastRecognizeOutcome> {
8704        let FastRecoveryRequest {
8705            atn,
8706            transition,
8707            expected_symbols,
8708            target,
8709            request,
8710            visiting,
8711            memo,
8712            expected,
8713        } = recovery;
8714        let FastRecognizeRequest {
8715            stop_state,
8716            index,
8717            rule_start_index,
8718            decision_start_index,
8719            precedence,
8720            depth,
8721            ..
8722        } = request;
8723        let Some((diagnostic, next_index, next_symbol)) =
8724            self.single_token_deletion(transition, index, atn.max_token_type(), &expected_symbols)
8725        else {
8726            return Vec::new();
8727        };
8728        let after_next = self.consume_index(next_index, next_symbol);
8729        let empty_recovery = self.empty_recovery_symbols();
8730        self.recognize_state_fast(
8731            atn,
8732            FastRecognizeRequest {
8733                state_number: target,
8734                stop_state,
8735                index: after_next,
8736                rule_start_index,
8737                decision_start_index,
8738                precedence,
8739                depth: depth + 1,
8740                recovery_symbols: empty_recovery,
8741                recovery_state: None,
8742            },
8743            FastRecognizeScratch {
8744                predicate_context,
8745                visiting,
8746                memo,
8747                expected,
8748                native_depth: 0,
8749            },
8750        )
8751        .into_iter()
8752        .map(|mut outcome| {
8753            outcome.consumed_eof |= next_symbol == TOKEN_EOF;
8754            outcome.diagnostics = self
8755                .recognition_arena
8756                .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
8757            if self.fast_token_nodes_enabled {
8758                let token = self.arena_token_node(next_index, false);
8759                self.defer_fast_outcome_node(&mut outcome, token);
8760                let error = self.arena_token_node(index, true);
8761                self.defer_fast_outcome_node(&mut outcome, error);
8762            }
8763            outcome
8764        })
8765        .collect()
8766    }
8767
8768    /// Explores ANTLR's single-token insertion recovery for the fast recognizer:
8769    /// pretend the expected transition token was present and continue without
8770    /// consuming the current token.
8771    fn fast_single_token_insertion_recovery(
8772        &mut self,
8773        recovery: FastRecoveryRequest<'_, '_>,
8774        predicate_context: Option<FastPredicateContext<'_>>,
8775    ) -> Vec<FastRecognizeOutcome> {
8776        let FastRecoveryRequest {
8777            atn,
8778            transition,
8779            expected_symbols,
8780            target,
8781            request,
8782            visiting,
8783            memo,
8784            expected,
8785        } = recovery;
8786        let FastRecognizeRequest {
8787            stop_state,
8788            index,
8789            rule_start_index,
8790            decision_start_index,
8791            precedence,
8792            depth,
8793            ..
8794        } = request;
8795        let follow_symbols = self.cached_state_expected_symbols(atn, transition.target());
8796        let Some((diagnostic, token_type, text)) = self.single_token_insertion(
8797            transition,
8798            index,
8799            atn.max_token_type(),
8800            &expected_symbols,
8801            &follow_symbols,
8802        ) else {
8803            return Vec::new();
8804        };
8805        let empty_recovery = self.empty_recovery_symbols();
8806        self.recognize_state_fast(
8807            atn,
8808            FastRecognizeRequest {
8809                state_number: target,
8810                stop_state,
8811                index,
8812                rule_start_index,
8813                decision_start_index,
8814                precedence,
8815                depth: depth + 1,
8816                recovery_symbols: empty_recovery,
8817                recovery_state: None,
8818            },
8819            FastRecognizeScratch {
8820                predicate_context,
8821                visiting,
8822                memo,
8823                expected,
8824                native_depth: 0,
8825            },
8826        )
8827        .into_iter()
8828        .map(|mut outcome| {
8829            outcome.diagnostics = self
8830                .recognition_arena
8831                .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
8832            let missing = self.arena_missing_token_node(token_type, index, text.clone());
8833            self.defer_fast_outcome_node(&mut outcome, missing);
8834            outcome
8835        })
8836        .collect()
8837    }
8838
8839    /// Retries the current fast-recognition state after deleting one
8840    /// unexpected token that precedes a valid loop or block continuation.
8841    fn fast_current_token_deletion_recovery(
8842        &mut self,
8843        recovery: FastCurrentTokenDeletionRequest<'_, '_>,
8844        predicate_context: Option<FastPredicateContext<'_>>,
8845    ) -> Vec<FastRecognizeOutcome> {
8846        let FastCurrentTokenDeletionRequest {
8847            atn,
8848            expected_symbols,
8849            mut request,
8850            visiting,
8851            memo,
8852            expected,
8853        } = recovery;
8854        if request.index == request.rule_start_index {
8855            return Vec::new();
8856        }
8857        let Some((diagnostic, next_index, skipped)) =
8858            self.current_token_deletion(request.index, &expected_symbols)
8859        else {
8860            return Vec::new();
8861        };
8862        request.state_number = request.recovery_state.unwrap_or(request.state_number);
8863        request.index = next_index;
8864        request.depth += 1;
8865        request.recovery_state = None;
8866        self.recognize_state_fast(
8867            atn,
8868            request,
8869            FastRecognizeScratch {
8870                predicate_context,
8871                visiting,
8872                memo,
8873                expected,
8874                native_depth: 0,
8875            },
8876        )
8877        .into_iter()
8878        .map(|mut outcome| {
8879            outcome.diagnostics = self
8880                .recognition_arena
8881                .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
8882            for index in skipped.iter().rev() {
8883                let error = self.arena_token_node(*index, true);
8884                self.defer_fast_outcome_node(&mut outcome, error);
8885            }
8886            outcome
8887        })
8888        .collect()
8889    }
8890
8891    /// Converts a failed child rule into a recovered fast-recognizer outcome so
8892    /// the parent can keep its child rule context and continue at a sync token.
8893    fn fast_child_rule_failure_recovery(
8894        &mut self,
8895        rule_index: usize,
8896        start_index: usize,
8897        sync_symbols: &BTreeSet<i32>,
8898        expected: &ExpectedTokens,
8899    ) -> Option<FastRecognizeOutcome> {
8900        let (error_index, message) = self.expected_error_message(rule_index, start_index, expected);
8901        let diagnostic = diagnostic_for_token(self.token_at(error_index), message);
8902        let mut next_index = error_index;
8903        loop {
8904            let symbol = self.token_type_at(next_index);
8905            if sync_symbols.contains(&symbol) {
8906                if next_index == error_index {
8907                    return None;
8908                }
8909                break;
8910            }
8911            if symbol == TOKEN_EOF {
8912                break;
8913            }
8914            let after = self.consume_index(next_index, symbol);
8915            if after == next_index {
8916                break;
8917            }
8918            next_index = after;
8919        }
8920        let diagnostics = self
8921            .recognition_arena
8922            .prepend_diagnostic(DiagnosticSeqId::EMPTY, diagnostic);
8923        let mut nodes = NodeSeqId::EMPTY;
8924        if self.fast_token_nodes_enabled {
8925            let error = self.arena_token_node(error_index, true);
8926            self.arena_prepend(&mut nodes, error);
8927        }
8928        Some(FastRecognizeOutcome {
8929            index: next_index,
8930            consumed_eof: false,
8931            diagnostics,
8932            deferred_nodes: FastDeferredNodeId::EMPTY,
8933            nodes,
8934        })
8935    }
8936
8937    /// Adapts the optional child-rule recovery result to the fast-recognizer
8938    /// outcome list used by rule-call transitions.
8939    fn fast_child_rule_failure_recovery_outcomes(
8940        &mut self,
8941        request: FastChildRuleFailureRecoveryRequest<'_>,
8942    ) -> Vec<FastRecognizeOutcome> {
8943        let FastChildRuleFailureRecoveryRequest {
8944            atn,
8945            rule_index,
8946            start_index,
8947            follow_state,
8948            stop_state,
8949            expected,
8950        } = request;
8951        let sync_symbols = state_sync_symbols(atn, follow_state, stop_state);
8952        self.fast_child_rule_failure_recovery(rule_index, start_index, &sync_symbols, expected)
8953            .into_iter()
8954            .collect()
8955    }
8956
8957    fn defer_fast_outcome_node(
8958        &mut self,
8959        outcome: &mut FastRecognizeOutcome,
8960        node: RecognizedNodeId,
8961    ) {
8962        if outcome.deferred_nodes.is_empty() {
8963            self.arena_prepend(&mut outcome.nodes, node);
8964            return;
8965        }
8966        let fragment = self.recognition_arena.prepend(NodeSeqId::EMPTY, node);
8967        let fragment = self.recognition_arena.deferred_fragment(fragment);
8968        outcome.deferred_nodes = self
8969            .recognition_arena
8970            .concat_deferred_nodes(fragment, outcome.deferred_nodes);
8971    }
8972
8973    fn defer_fast_outcome_alternative(
8974        &mut self,
8975        outcome: &mut FastRecognizeOutcome,
8976        alt_number: usize,
8977    ) {
8978        let alternative = self.recognition_arena.deferred_alternative(alt_number);
8979        outcome.deferred_nodes = self
8980            .recognition_arena
8981            .concat_deferred_nodes(alternative, outcome.deferred_nodes);
8982    }
8983
8984    fn defer_fast_outcome_boundary(
8985        &mut self,
8986        outcome: &mut FastRecognizeOutcome,
8987        rule_index: usize,
8988    ) {
8989        let boundary = self
8990            .recognition_arena
8991            .deferred_left_recursive_boundary(rule_index);
8992        outcome.deferred_nodes = self
8993            .recognition_arena
8994            .concat_deferred_nodes(boundary, outcome.deferred_nodes);
8995    }
8996
8997    fn materialize_fast_deferred_nodes(
8998        &mut self,
8999        root: FastDeferredNodeId,
9000        initial_suffix: NodeSeqId,
9001    ) -> (NodeSeqId, usize) {
9002        if root.is_empty() {
9003            return (initial_suffix, 0);
9004        }
9005
9006        enum Frame {
9007            Visit(FastDeferredNodeId),
9008            ContinuePrefix(FastDeferredNodeId),
9009            FinishRule {
9010                rule: FastDeferredRule,
9011                parent_suffix: NodeSeqId,
9012                parent_alt_number: u32,
9013                parent_pending_boundary: Option<RecognizedNodeId>,
9014            },
9015        }
9016
9017        let mut result = initial_suffix;
9018        // The rope is visited suffix-first while nodes are prepended. Later
9019        // alternatives arrive first, so earlier markers overwrite them; a
9020        // boundary redirects those earlier markers to the wrapped context.
9021        let mut alt_number = 0;
9022        let mut pending_boundary = None;
9023        let mut pending = Vec::with_capacity(16);
9024        pending.push(Frame::Visit(root));
9025        let mut fragment_nodes = Vec::new();
9026        while let Some(frame) = pending.pop() {
9027            match frame {
9028                Frame::Visit(deferred) => {
9029                    if deferred.is_empty() {
9030                        continue;
9031                    }
9032
9033                    match self.recognition_arena.deferred_node(deferred) {
9034                        FastDeferredNode::Fragment(sequence) => {
9035                            fragment_nodes.clear();
9036                            fragment_nodes.extend(self.recognition_arena.iter(sequence));
9037                            while let Some(node) = fragment_nodes.pop() {
9038                                self.arena_prepend(&mut result, node);
9039                            }
9040                        }
9041                        FastDeferredNode::Rule(rule) => {
9042                            let rule = self.recognition_arena.deferred_rule(rule);
9043                            let parent_suffix = result;
9044                            let parent_alt_number = alt_number;
9045                            let parent_pending_boundary = pending_boundary;
9046                            result = rule.children;
9047                            alt_number = 0;
9048                            pending_boundary = None;
9049                            pending.push(Frame::FinishRule {
9050                                rule,
9051                                parent_suffix,
9052                                parent_alt_number,
9053                                parent_pending_boundary,
9054                            });
9055                            pending.push(Frame::Visit(rule.deferred_children));
9056                        }
9057                        FastDeferredNode::Alternative(selected) => {
9058                            if let Some(boundary) = pending_boundary {
9059                                self.recognition_arena
9060                                    .set_boundary_alt_number(boundary, selected);
9061                            } else {
9062                                alt_number = selected;
9063                            }
9064                        }
9065                        FastDeferredNode::LeftRecursiveBoundary { rule_index } => {
9066                            let boundary = self.arena_boundary_node(rule_index as usize, 0);
9067                            self.arena_prepend(&mut result, boundary);
9068                            pending_boundary = Some(boundary);
9069                        }
9070                        FastDeferredNode::Concat {
9071                            prefix,
9072                            suffix: deferred_suffix,
9073                        } => {
9074                            pending.push(Frame::ContinuePrefix(prefix));
9075                            pending.push(Frame::Visit(deferred_suffix));
9076                        }
9077                    }
9078                }
9079                Frame::ContinuePrefix(prefix) => pending.push(Frame::Visit(prefix)),
9080                Frame::FinishRule {
9081                    rule,
9082                    parent_suffix,
9083                    parent_alt_number,
9084                    parent_pending_boundary,
9085                } => {
9086                    let node = self.recognition_arena.push_node(ArenaRecognizedNode::Rule {
9087                        rule_index: rule.rule_index,
9088                        invoking_state: rule.invoking_state,
9089                        alt_number,
9090                        start_index: rule.start_index,
9091                        stop_index: rule.stop_index,
9092                        return_values: None,
9093                        children: result,
9094                    });
9095                    result = parent_suffix;
9096                    self.arena_prepend(&mut result, node);
9097                    alt_number = parent_alt_number;
9098                    pending_boundary = parent_pending_boundary;
9099                }
9100            }
9101        }
9102        (result, alt_number as usize)
9103    }
9104
9105    fn materialize_fast_outcome_nodes(&mut self, outcome: &mut FastRecognizeOutcome) -> usize {
9106        let deferred_nodes = std::mem::take(&mut outcome.deferred_nodes);
9107        let (nodes, alt_number) =
9108            self.materialize_fast_deferred_nodes(deferred_nodes, outcome.nodes);
9109        outcome.nodes = nodes;
9110        alt_number
9111    }
9112
9113    /// Walks one ordinary `*`/`+` repetition at a time so input length grows
9114    /// heap work instead of the native call stack.
9115    fn recognize_repetition_fast(
9116        &mut self,
9117        atn: &Atn,
9118        request: &FastRecognizeRequest,
9119        shape: FastRepetitionShape,
9120        scratch: FastRecognizeScratch<'_, '_>,
9121    ) -> Vec<FastRecognizeOutcome> {
9122        let FastRecognizeScratch {
9123            predicate_context,
9124            visiting,
9125            memo,
9126            expected,
9127            native_depth,
9128        } = scratch;
9129        let lookahead = if self.fast_first_set_prefilter {
9130            atn.state(request.state_number).and_then(|state| {
9131                state
9132                    .rule_index()
9133                    .and_then(|rule_index| atn.rule_to_stop_state().get(rule_index))
9134                    .map(|rule_stop| self.cached_decision_lookahead(atn, state, rule_stop))
9135            })
9136        } else {
9137            None
9138        };
9139        let (enter_alt_number, exit_alt_number) = if self.fast_track_alt_numbers {
9140            let state = atn
9141                .state(request.state_number)
9142                .expect("repetition request state must exist");
9143            (
9144                next_alt_number(state, 2, shape.enter_transition_index, 0, true),
9145                next_alt_number(state, 2, shape.exit_transition_index, 0, true),
9146            )
9147        } else {
9148            (0, 0)
9149        };
9150        let mut work = Vec::with_capacity(2);
9151        push_fast_repetition_work(
9152            &mut work,
9153            shape,
9154            FastRepetitionPath {
9155                index: request.index,
9156                deferred_nodes: FastDeferredNodeId::EMPTY,
9157                diagnostics: DiagnosticSeqId::EMPTY,
9158                consumed_eof: false,
9159            },
9160            lookahead.as_deref(),
9161            self.token_type_at(request.index),
9162        );
9163        let mut coordinates = FastRepetitionCoordinates::new(request.index);
9164        let mut outcomes = Vec::new();
9165        while let Some(item) = work.pop() {
9166            match item {
9167                FastRepetitionWork::Enter(path) => {
9168                    if !coordinates.insert_entered(path) {
9169                        continue;
9170                    }
9171                    let path_nodes = if enter_alt_number == 0 {
9172                        path.deferred_nodes
9173                    } else {
9174                        let alternative = self
9175                            .recognition_arena
9176                            .deferred_alternative(enter_alt_number);
9177                        self.recognition_arena
9178                            .concat_deferred_nodes(path.deferred_nodes, alternative)
9179                    };
9180                    let body_outcomes = self.recognize_state_fast(
9181                        atn,
9182                        FastRecognizeRequest {
9183                            state_number: shape.enter_target,
9184                            stop_state: shape.body_stop_state,
9185                            index: path.index,
9186                            rule_start_index: request.rule_start_index,
9187                            decision_start_index: request.decision_start_index,
9188                            precedence: request.precedence,
9189                            depth: request.depth.saturating_add(1),
9190                            recovery_symbols: Rc::clone(&request.recovery_symbols),
9191                            recovery_state: request.recovery_state,
9192                        },
9193                        FastRecognizeScratch {
9194                            predicate_context,
9195                            visiting: &mut *visiting,
9196                            memo: &mut *memo,
9197                            expected: &mut *expected,
9198                            native_depth: native_depth + 1,
9199                        },
9200                    );
9201                    for body in body_outcomes.into_iter().rev() {
9202                        // ANTLR rejects nullable repetition bodies. Keep the
9203                        // interpreter bounded for malformed or recovered ATNs
9204                        // by mirroring the existing same-coordinate cycle cut.
9205                        if body.index <= path.index {
9206                            continue;
9207                        }
9208                        let body_fragment = self.recognition_arena.deferred_fragment(body.nodes);
9209                        let body_nodes = self
9210                            .recognition_arena
9211                            .concat_deferred_nodes(body.deferred_nodes, body_fragment);
9212                        let deferred_nodes = self
9213                            .recognition_arena
9214                            .concat_deferred_nodes(path_nodes, body_nodes);
9215                        let next_path = FastRepetitionPath {
9216                            index: body.index,
9217                            deferred_nodes,
9218                            diagnostics: self
9219                                .recognition_arena
9220                                .concat_diagnostics(path.diagnostics, body.diagnostics),
9221                            consumed_eof: path.consumed_eof || body.consumed_eof,
9222                        };
9223                        let symbol = self.token_type_at(next_path.index);
9224                        push_fast_repetition_work(
9225                            &mut work,
9226                            shape,
9227                            next_path,
9228                            lookahead.as_deref(),
9229                            symbol,
9230                        );
9231                    }
9232                }
9233                FastRepetitionWork::Exit(path) => {
9234                    if !coordinates.insert_exited(path) {
9235                        continue;
9236                    }
9237                    let path_nodes = if exit_alt_number == 0 {
9238                        path.deferred_nodes
9239                    } else {
9240                        let alternative =
9241                            self.recognition_arena.deferred_alternative(exit_alt_number);
9242                        self.recognition_arena
9243                            .concat_deferred_nodes(path.deferred_nodes, alternative)
9244                    };
9245                    let suffixes = self.recognize_state_fast(
9246                        atn,
9247                        FastRecognizeRequest {
9248                            state_number: shape.exit_target,
9249                            stop_state: request.stop_state,
9250                            index: path.index,
9251                            rule_start_index: request.rule_start_index,
9252                            decision_start_index: request.decision_start_index,
9253                            precedence: request.precedence,
9254                            depth: request.depth.saturating_add(1),
9255                            recovery_symbols: Rc::clone(&request.recovery_symbols),
9256                            recovery_state: request.recovery_state,
9257                        },
9258                        FastRecognizeScratch {
9259                            predicate_context,
9260                            visiting: &mut *visiting,
9261                            memo: &mut *memo,
9262                            expected: &mut *expected,
9263                            native_depth: native_depth + 1,
9264                        },
9265                    );
9266                    for mut outcome in suffixes {
9267                        outcome.deferred_nodes = self
9268                            .recognition_arena
9269                            .concat_deferred_nodes(path_nodes, outcome.deferred_nodes);
9270                        outcome.diagnostics = self
9271                            .recognition_arena
9272                            .concat_diagnostics(path.diagnostics, outcome.diagnostics);
9273                        outcome.consumed_eof |= path.consumed_eof;
9274                        outcomes.push(outcome);
9275                    }
9276                }
9277            }
9278        }
9279        dedupe_clean_fast_outcomes(&mut outcomes, &mut self.fast_outcome_dedup);
9280        outcomes
9281    }
9282
9283    /// Attempts to reach `stop_state` from `state_number` without committing
9284    /// token consumption to the parser's public stream position.
9285    fn recognize_state_fast(
9286        &mut self,
9287        atn: &Atn,
9288        request: FastRecognizeRequest,
9289        scratch: FastRecognizeScratch<'_, '_>,
9290    ) -> Vec<FastRecognizeOutcome> {
9291        if scratch.native_depth != 0 && scratch.native_depth < FAST_RECOGNIZE_STACK_CHECK_INTERVAL {
9292            return self.recognize_state_fast_inner(atn, request, scratch);
9293        }
9294        self.recognize_state_fast_checked(atn, request, scratch)
9295    }
9296
9297    #[inline(never)]
9298    fn recognize_state_fast_checked(
9299        &mut self,
9300        atn: &Atn,
9301        request: FastRecognizeRequest,
9302        mut scratch: FastRecognizeScratch<'_, '_>,
9303    ) -> Vec<FastRecognizeOutcome> {
9304        scratch.native_depth = 1;
9305        stacker::maybe_grow(FAST_RECOGNIZE_RED_ZONE, FAST_RECOGNIZE_STACK_SIZE, || {
9306            self.recognize_state_fast_inner(atn, request, scratch)
9307        })
9308    }
9309
9310    #[allow(clippy::too_many_lines)]
9311    fn recognize_state_fast_inner(
9312        &mut self,
9313        atn: &Atn,
9314        request: FastRecognizeRequest,
9315        scratch: FastRecognizeScratch<'_, '_>,
9316    ) -> Vec<FastRecognizeOutcome> {
9317        #[cfg(feature = "perf-counters")]
9318        perf_counters::inc(&perf_counters::RFS_CALLS, 1);
9319        let FastRecognizeScratch {
9320            predicate_context,
9321            visiting,
9322            memo,
9323            expected,
9324            native_depth,
9325        } = scratch;
9326        let FastRecognizeRequest {
9327            mut state_number,
9328            stop_state,
9329            mut index,
9330            rule_start_index,
9331            decision_start_index,
9332            precedence,
9333            mut depth,
9334            recovery_symbols,
9335            recovery_state,
9336        } = request;
9337        let max_token_type = atn.max_token_type();
9338        // Walk straight-line epsilon chains in a loop instead of recursing
9339        // into `recognize_state_fast` for each intermediate state. ATN
9340        // serialization places long sequences of `BasicBlock` epsilon
9341        // transitions between decisions: turning that chain into a loop
9342        // collapses many recursive calls (and their memo lookups, vec
9343        // allocations, and visit-set churn) into a single function frame.
9344        // The loop exits as soon as we hit the original state's logic
9345        // (multi-alt, decision, rule call, unmatched atom/range/set, gated
9346        // precedence) so existing fanout, recovery, and memoization still
9347        // apply unchanged.
9348        //
9349        // The inline case also handles single-atom-match states on the
9350        // happy-pass path: when the lone consuming transition matches the
9351        // current lookahead, advance the index and continue without paying
9352        // for a full `recognize_state_fast` recursion. We track tokens we
9353        // consumed inline in `inline_consumed_tokens` so they can be
9354        // prepended onto the eventual outcome list once we hit a state
9355        // whose handling falls outside this fast loop.
9356        let mut inline_consumed_tokens: Vec<usize> = Vec::new();
9357        let mut inline_consumed_eof = false;
9358        loop {
9359            if depth > RECOGNITION_DEPTH_LIMIT {
9360                return Vec::new();
9361            }
9362            if state_number == stop_state {
9363                let mut nodes = NodeSeqId::EMPTY;
9364                if self.fast_token_nodes_enabled {
9365                    for token_index in inline_consumed_tokens.iter().rev() {
9366                        let token = self.arena_token_node(*token_index, false);
9367                        self.arena_prepend(&mut nodes, token);
9368                    }
9369                }
9370                return vec![FastRecognizeOutcome {
9371                    index,
9372                    consumed_eof: inline_consumed_eof,
9373                    diagnostics: DiagnosticSeqId::EMPTY,
9374                    deferred_nodes: FastDeferredNodeId::EMPTY,
9375                    nodes,
9376                }];
9377            }
9378            let Some(state) = atn.state(state_number) else {
9379                return Vec::new();
9380            };
9381            let transitions = state.transitions();
9382            if transitions.len() == 1 && !state.precedence_rule_decision() {
9383                let transition = transitions
9384                    .first()
9385                    .expect("single transition checked above");
9386                let transition_kind = transition.kind();
9387                let target = transition.target();
9388                match transition_kind {
9389                    ParserTransitionKind::Epsilon | ParserTransitionKind::Action
9390                        if left_recursive_boundary(atn, state, target).is_none() =>
9391                    {
9392                        #[cfg(feature = "perf-counters")]
9393                        perf_counters::inc(&perf_counters::EPSILON_TRANSITIONS, 1);
9394                        state_number = target;
9395                        depth += 1;
9396                        continue;
9397                    }
9398                    ParserTransitionKind::Predicate
9399                        if left_recursive_boundary(atn, state, target).is_none() =>
9400                    {
9401                        #[cfg(feature = "perf-counters")]
9402                        perf_counters::inc(&perf_counters::EPSILON_TRANSITIONS, 1);
9403                        if !self.fast_parser_predicate_matches(predicate_context, transition, index)
9404                        {
9405                            record_predicate_no_viable(expected, decision_start_index, index);
9406                            return Vec::new();
9407                        }
9408                        state_number = target;
9409                        depth += 1;
9410                        continue;
9411                    }
9412                    ParserTransitionKind::Precedence
9413                        if packed_i32(transition.arg0()) >= precedence
9414                            && left_recursive_boundary(atn, state, target).is_none() =>
9415                    {
9416                        #[cfg(feature = "perf-counters")]
9417                        perf_counters::inc(&perf_counters::EPSILON_TRANSITIONS, 1);
9418                        state_number = target;
9419                        depth += 1;
9420                        continue;
9421                    }
9422                    // Single-atom / range / set / wildcard / not-set states
9423                    // are common (~17K of ~125K calls on C#) and almost
9424                    // always succeed in pass 1: no fanout, no recovery, no
9425                    // diagnostics. Inline the token match and continue
9426                    // walking instead of recursing — the recursive path
9427                    // would just allocate a Vec, build one outcome, prepend
9428                    // a Token node, and return. Skip pass 2 (recovery
9429                    // enabled): there the failure branch matters and the
9430                    // existing recursive code records expected symbols.
9431                    ParserTransitionKind::Atom
9432                    | ParserTransitionKind::Range
9433                    | ParserTransitionKind::Set
9434                    | ParserTransitionKind::NotSet
9435                    | ParserTransitionKind::Wildcard
9436                        if !self.fast_recovery_enabled =>
9437                    {
9438                        let symbol = self.token_type_at(index);
9439                        if transition.matches_kind(transition_kind, symbol, 1, max_token_type) {
9440                            #[cfg(feature = "perf-counters")]
9441                            perf_counters::inc(&perf_counters::ATOM_RANGE_TRANSITIONS, 1);
9442                            if self.fast_token_nodes_enabled {
9443                                inline_consumed_tokens.push(index);
9444                            }
9445                            inline_consumed_eof |= symbol == TOKEN_EOF;
9446                            index = self.consume_index(index, symbol);
9447                            state_number = target;
9448                            depth += 1;
9449                            continue;
9450                        }
9451                        // Fall through to break and let the regular
9452                        // body handle the no-match case (returns empty).
9453                    }
9454                    _ => {}
9455                }
9456            }
9457            break;
9458        }
9459        // If we collected token nodes inline but bail to the recursive
9460        // body (decision state, rule call, etc.), the outcomes returned
9461        // below will need those token nodes prepended.
9462        let inline_pending = !inline_consumed_tokens.is_empty() || inline_consumed_eof;
9463        let Some(state) = atn.state(state_number) else {
9464            return Vec::new();
9465        };
9466        let transitions = state.transitions();
9467        let transition_count = transitions.len();
9468        if !self.fast_recovery_enabled
9469            && let Some(shape) = fast_repetition_shape(atn, state)
9470        {
9471            let mut outcomes = self.recognize_repetition_fast(
9472                atn,
9473                &FastRecognizeRequest {
9474                    state_number,
9475                    stop_state,
9476                    index,
9477                    rule_start_index,
9478                    decision_start_index,
9479                    precedence,
9480                    depth,
9481                    recovery_symbols: Rc::clone(&recovery_symbols),
9482                    recovery_state,
9483                },
9484                shape,
9485                FastRecognizeScratch {
9486                    predicate_context,
9487                    visiting: &mut *visiting,
9488                    memo: &mut *memo,
9489                    expected: &mut *expected,
9490                    native_depth: native_depth + 1,
9491                },
9492            );
9493            if inline_pending {
9494                for outcome in &mut outcomes {
9495                    outcome.consumed_eof |= inline_consumed_eof;
9496                    if self.fast_token_nodes_enabled {
9497                        for token_index in inline_consumed_tokens.iter().rev() {
9498                            let token = self.arena_token_node(*token_index, false);
9499                            self.defer_fast_outcome_node(outcome, token);
9500                        }
9501                    }
9502                }
9503            }
9504            return outcomes;
9505        }
9506        // In pass 1 (`fast_recovery_enabled == false`) the recovery-related
9507        // fields and the rule/decision boundary indices are pure plumbing —
9508        // they only affect the recovery branch and the no-viable diagnostic
9509        // recording, neither of which fires when recovery is off. Zeroing
9510        // them in the memo key collapses calls that visit the same
9511        // `(state, index)` from different rule-call sites onto one cache
9512        // entry, which is the dominant cost on large grammars (e.g. C#) where
9513        // many rules eventually delegate into the same `expression` /
9514        // `primary_expression` / `type` branches.
9515        let key = if self.fast_recovery_enabled {
9516            FastRecognizeKey {
9517                state_number,
9518                stop_state,
9519                index,
9520                rule_start_index,
9521                decision_start_index,
9522                precedence,
9523                recovery_symbols_id: Rc::as_ptr(&recovery_symbols) as usize,
9524                recovery_state,
9525            }
9526        } else {
9527            FastRecognizeKey {
9528                state_number,
9529                stop_state,
9530                index,
9531                rule_start_index: 0,
9532                decision_start_index: None,
9533                precedence,
9534                recovery_symbols_id: 0,
9535                recovery_state: None,
9536            }
9537        };
9538        // Once the clean-pass probe has established that coordinates do not
9539        // repeat, stop paying for the full memo table. Recovery always keeps
9540        // memoization because cached failures carry diagnostics, while
9541        // repeat-heavy clean parses promote before reaching sparse mode.
9542        let memo_lookup_enabled = self.fast_recovery_enabled
9543            || (transition_count > 1 && self.clean_memo_enabled_for_key(&key));
9544        if memo_lookup_enabled {
9545            if let Some(outcomes) = memo.get(&key) {
9546                #[cfg(feature = "perf-counters")]
9547                {
9548                    perf_counters::inc(&perf_counters::RFS_MEMO_HITS, 1);
9549                    perf_counters::inc(&perf_counters::OUTCOMES_CLONED, outcomes.len() as u64);
9550                }
9551                // Materialize a fresh `Vec` from the cached slice; the caller
9552                // mutates per-outcome state (eof flags, prepended nodes) so we
9553                // can't hand them the shared backing.
9554                if !inline_consumed_tokens.is_empty() || inline_consumed_eof {
9555                    let inline_eof = inline_consumed_eof;
9556                    let inline_tokens = &inline_consumed_tokens;
9557                    return outcomes
9558                        .iter()
9559                        .copied()
9560                        .map(|mut outcome| {
9561                            if inline_eof {
9562                                outcome.consumed_eof = true;
9563                            }
9564                            if self.fast_token_nodes_enabled {
9565                                for token_index in inline_tokens.iter().rev() {
9566                                    let token = self.arena_token_node(*token_index, false);
9567                                    self.defer_fast_outcome_node(&mut outcome, token);
9568                                }
9569                            }
9570                            outcome
9571                        })
9572                        .collect();
9573                }
9574                return outcomes.to_vec();
9575            }
9576            #[cfg(feature = "perf-counters")]
9577            perf_counters::inc(&perf_counters::RFS_MEMO_MISSES, 1);
9578        }
9579
9580        // Cycle detection: clean recognition keeps the narrow static cycle
9581        // guard used on hot paths. Recovery needs the broader epsilon-state
9582        // guard because an otherwise non-nullable loop body can recover as an
9583        // empty child at EOF and re-enter the loop at the same token.
9584        let needs_cycle_guard = if self.fast_recovery_enabled {
9585            transitions.iter().any(ParserTransition::is_epsilon)
9586        } else {
9587            transition_count > 1 && self.state_can_reenter_without_consuming(atn, state_number)
9588        };
9589        #[cfg(feature = "perf-counters")]
9590        if needs_cycle_guard {
9591            perf_counters::inc(&perf_counters::MULTI_TRANS_BODY, 1);
9592        } else {
9593            perf_counters::inc(&perf_counters::SINGLE_TRANS_BODY, 1);
9594            match state
9595                .transitions()
9596                .first()
9597                .expect("single-transition path requires one transition")
9598                .data()
9599            {
9600                Transition::Rule { .. } => {
9601                    perf_counters::inc(&perf_counters::SINGLE_TRANS_RULE, 1);
9602                }
9603                Transition::Atom { .. }
9604                | Transition::Range { .. }
9605                | Transition::Set { .. }
9606                | Transition::NotSet { .. }
9607                | Transition::Wildcard { .. } => {
9608                    perf_counters::inc(&perf_counters::SINGLE_TRANS_ATOM, 1);
9609                }
9610                _ => {
9611                    perf_counters::inc(&perf_counters::SINGLE_TRANS_OTHER, 1);
9612                }
9613            }
9614        }
9615        let has_inserted_cycle_guard = if needs_cycle_guard {
9616            if !visiting.insert(key.clone()) {
9617                #[cfg(feature = "perf-counters")]
9618                perf_counters::inc(&perf_counters::RFS_VISITING_CYCLE, 1);
9619                return Vec::new();
9620            }
9621            true
9622        } else {
9623            false
9624        };
9625        let next_decision_start_index = if starts_prediction_decision(state, transition_count) {
9626            Some(index)
9627        } else {
9628            decision_start_index
9629        };
9630        let (epsilon_recovery_symbols, epsilon_recovery_state) = if self.fast_recovery_enabled {
9631            fast_next_recovery_context(self, atn, state, &recovery_symbols, recovery_state)
9632        } else {
9633            (Rc::clone(&recovery_symbols), recovery_state)
9634        };
9635
9636        // Lookahead-based pruning. At a multi-alternative state we cache the
9637        // look-1 set of every outgoing transition; on visit we keep only the
9638        // transitions whose look-1 can accept the current lookahead (or that
9639        // can be reached without consuming and so could legitimately match a
9640        // shorter input). This is the main speedup vs. blind speculative
9641        // recursion: it lets each visit fan out only to the alternatives that
9642        // could possibly contribute a clean parse, mirroring the SLL phase of
9643        // ANTLR's adaptive prediction.
9644        //
9645        // Pruning is skipped at:
9646        //   * rule-start states (a child rule call may need every internal
9647        //     transition to surface single-token recovery diagnostics that
9648        //     ANTLR's reference parser emits at the rule's first consuming
9649        //     transition; the FIRST-set retry path turns the prefilter off
9650        //     entirely so let's keep this lightweight too),
9651        //   * left-recursive precedence loops (the precedence transition's
9652        //     gating is dynamic),
9653        //   * states with too few alternatives to benefit.
9654        let lookahead_filter = if transition_count > 1
9655            && self.fast_first_set_prefilter
9656            && !state.precedence_rule_decision()
9657            && (!self.fast_recovery_enabled || state.kind() != AtnStateKind::RuleStart)
9658        {
9659            state
9660                .rule_index()
9661                .and_then(|rule_index| atn.rule_to_stop_state().get(rule_index))
9662                .map(|rule_stop| {
9663                    let symbol = self.token_type_at(index);
9664                    let entry = self.cached_decision_lookahead(atn, state, rule_stop);
9665                    (symbol, entry)
9666                })
9667        } else {
9668            None
9669        };
9670        // LL(1) fast path: when the FIRST sets for the decision are disjoint
9671        // and none is nullable, the lookahead deterministically selects one
9672        // alternative. The recursive recognizer can then commit to that single
9673        // alt without iterating every transition through `should_skip_via_lookahead`
9674        // — saving (transition_count - 1) filter probes per visit.
9675        //
9676        // Result is cached per `(state, lookahead_token)` on the parser
9677        // instance, so subsequent visits skip the FIRST-set scan entirely.
9678        let ll1_only_alt: Option<usize> = if transition_count > 1
9679            && let Some((symbol, entry)) = lookahead_filter.as_ref()
9680        {
9681            let key = (state.state_number(), *symbol);
9682            if let Some(&cached) = self.ll1_decision_cache.get(&key) {
9683                cached
9684            } else {
9685                let result = ll1_unique_alt(entry, *symbol);
9686                self.ll1_decision_cache.insert(key, result);
9687                result
9688            }
9689        } else {
9690            None
9691        };
9692        let lookahead_filter = lookahead_filter.as_ref();
9693        // Pre-size only when we expect at least one outcome to land — most
9694        // single-transition fall-throughs (the loop above didn't catch
9695        // because they're atom/rule/predicate) push at most one entry, so
9696        // reserving one slot avoids a reallocation while keeping the
9697        // unused-slot waste at one element.
9698        let mut outcomes: Vec<FastRecognizeOutcome> = Vec::with_capacity(transition_count.min(2));
9699        for (transition_index, transition) in transitions.iter().enumerate() {
9700            if let Some(alt) = ll1_only_alt {
9701                // LL(1) determinism: skip every alt except the chosen one.
9702                if alt != transition_index {
9703                    continue;
9704                }
9705            }
9706            let transition_kind = transition.kind();
9707            if ll1_only_alt.is_none()
9708                && should_skip_via_lookahead(
9709                    transition_kind,
9710                    transition_index,
9711                    lookahead_filter,
9712                    index,
9713                    self.fast_recovery_enabled,
9714                    expected,
9715                )
9716            {
9717                continue;
9718            }
9719            let target = transition.target();
9720            let outcomes_before_transition = outcomes.len();
9721            let left_recursive_boundary = match transition_kind {
9722                ParserTransitionKind::Epsilon
9723                | ParserTransitionKind::Action
9724                | ParserTransitionKind::Predicate
9725                | ParserTransitionKind::Precedence => left_recursive_boundary(atn, state, target),
9726                ParserTransitionKind::Atom
9727                | ParserTransitionKind::Range
9728                | ParserTransitionKind::Set
9729                | ParserTransitionKind::NotSet
9730                | ParserTransitionKind::Wildcard
9731                | ParserTransitionKind::Rule => None,
9732            };
9733            match transition_kind {
9734                ParserTransitionKind::Epsilon | ParserTransitionKind::Action => {
9735                    #[cfg(feature = "perf-counters")]
9736                    perf_counters::inc(&perf_counters::EPSILON_TRANSITIONS, 1);
9737                    outcomes.extend(self.recognize_state_fast(
9738                        atn,
9739                        FastRecognizeRequest {
9740                            state_number: target,
9741                            stop_state,
9742                            index,
9743                            rule_start_index,
9744                            decision_start_index: next_decision_start_index,
9745                            precedence,
9746                            depth: depth + 1,
9747                            recovery_symbols: Rc::clone(&epsilon_recovery_symbols),
9748                            recovery_state: epsilon_recovery_state,
9749                        },
9750                        FastRecognizeScratch {
9751                            predicate_context,
9752                            visiting,
9753                            memo,
9754                            expected,
9755                            native_depth: native_depth + 1,
9756                        },
9757                    ));
9758                }
9759                ParserTransitionKind::Predicate => {
9760                    #[cfg(feature = "perf-counters")]
9761                    perf_counters::inc(&perf_counters::EPSILON_TRANSITIONS, 1);
9762                    if self.fast_parser_predicate_matches(predicate_context, transition, index) {
9763                        outcomes.extend(self.recognize_state_fast(
9764                            atn,
9765                            FastRecognizeRequest {
9766                                state_number: target,
9767                                stop_state,
9768                                index,
9769                                rule_start_index,
9770                                decision_start_index: next_decision_start_index,
9771                                precedence,
9772                                depth: depth + 1,
9773                                recovery_symbols: Rc::clone(&epsilon_recovery_symbols),
9774                                recovery_state: epsilon_recovery_state,
9775                            },
9776                            FastRecognizeScratch {
9777                                predicate_context,
9778                                visiting,
9779                                memo,
9780                                expected,
9781                                native_depth: native_depth + 1,
9782                            },
9783                        ));
9784                    } else {
9785                        record_predicate_no_viable(expected, next_decision_start_index, index);
9786                    }
9787                }
9788                ParserTransitionKind::Precedence => {
9789                    let transition_precedence = packed_i32(transition.arg0());
9790                    if transition_precedence >= precedence {
9791                        outcomes.extend(self.recognize_state_fast(
9792                            atn,
9793                            FastRecognizeRequest {
9794                                state_number: target,
9795                                stop_state,
9796                                index,
9797                                rule_start_index,
9798                                decision_start_index: next_decision_start_index,
9799                                precedence,
9800                                depth: depth + 1,
9801                                recovery_symbols: Rc::clone(&epsilon_recovery_symbols),
9802                                recovery_state: epsilon_recovery_state,
9803                            },
9804                            FastRecognizeScratch {
9805                                predicate_context,
9806                                visiting,
9807                                memo,
9808                                expected,
9809                                native_depth: native_depth + 1,
9810                            },
9811                        ));
9812                    }
9813                }
9814                ParserTransitionKind::Rule => {
9815                    let rule_index = transition.arg0() as usize;
9816                    let follow_state = transition.arg1() as usize;
9817                    let rule_precedence = packed_i32(transition.arg2());
9818                    #[cfg(feature = "perf-counters")]
9819                    perf_counters::inc(&perf_counters::RULE_TRANSITIONS, 1);
9820                    let Some(child_stop) = atn.rule_to_stop_state().get(rule_index) else {
9821                        continue;
9822                    };
9823                    // Lookahead-based pruning. The recognizer would otherwise
9824                    // explore every speculative rule call, producing exponential
9825                    // work on grammars with many epsilon-reachable rules. When
9826                    // the rule is non-nullable and its FIRST set excludes the
9827                    // current lookahead, recursion can't find a clean path
9828                    // *through this rule*. Skipping is only safe if some sibling
9829                    // transition can still consume the lookahead — otherwise the
9830                    // rule call is the sole continuation and must run so the
9831                    // single-token insertion / deletion recovery inside the
9832                    // called rule can fire (mirroring ANTLR's reference behavior
9833                    // of conjuring a missing token at child-rule entry).
9834                    let symbol = self.token_type_at(index);
9835                    if self.fast_first_set_prefilter {
9836                        // Probe the shared cross-parse cache first; build
9837                        // the entry on miss and intern it there. The
9838                        // computation is purely a function of the ATN, so
9839                        // the cached entry is reused across parses (and
9840                        // freshly-instantiated parser values that share
9841                        // the same `&'static Atn`).
9842                        //
9843                        // `rule_first_set` returns the computed entry
9844                        // directly — it intentionally skips inserting into
9845                        // the cache when the FIRST-set walk hit a cycle, so
9846                        // we cannot assume the entry is in the cache after
9847                        // computing it.
9848                        let first = self.cached_rule_first_set(atn, target, child_stop);
9849                        if should_skip_rule_via_first_set(
9850                            &first,
9851                            symbol,
9852                            self.fast_recovery_enabled,
9853                            index,
9854                            expected,
9855                        ) {
9856                            continue;
9857                        }
9858                    }
9859                    let expected_before_child =
9860                        self.fast_recovery_enabled.then(|| expected.clone());
9861                    let mut children = self.recognize_state_fast(
9862                        atn,
9863                        FastRecognizeRequest {
9864                            state_number: target,
9865                            stop_state: child_stop,
9866                            index,
9867                            rule_start_index: index,
9868                            decision_start_index: None,
9869                            precedence: rule_precedence,
9870                            depth: depth + 1,
9871                            recovery_symbols: Rc::clone(&epsilon_recovery_symbols),
9872                            recovery_state: epsilon_recovery_state,
9873                        },
9874                        FastRecognizeScratch {
9875                            predicate_context,
9876                            visiting,
9877                            memo,
9878                            expected,
9879                            native_depth: native_depth + 1,
9880                        },
9881                    );
9882                    if children.is_empty() && self.fast_recovery_enabled {
9883                        children = self.fast_child_rule_failure_recovery_outcomes(
9884                            FastChildRuleFailureRecoveryRequest {
9885                                atn,
9886                                rule_index,
9887                                start_index: index,
9888                                follow_state,
9889                                stop_state,
9890                                expected,
9891                            },
9892                        );
9893                    }
9894                    if let Some(expected_before_child) = expected_before_child {
9895                        if children
9896                            .iter()
9897                            .any(|child| child.diagnostics.is_empty() && child.index > index)
9898                        {
9899                            *expected = expected_before_child;
9900                        }
9901                    }
9902                    for child in children {
9903                        let child_index = child.index;
9904                        let child_consumed_eof = child.consumed_eof;
9905                        let child_diagnostics = child.diagnostics;
9906                        let empty_recovery = self.empty_recovery_symbols();
9907                        let follow_outcomes = self.recognize_state_fast(
9908                            atn,
9909                            FastRecognizeRequest {
9910                                state_number: follow_state,
9911                                stop_state,
9912                                index: child_index,
9913                                rule_start_index,
9914                                decision_start_index: next_decision_start_index,
9915                                precedence,
9916                                depth: depth + 1,
9917                                recovery_symbols: empty_recovery,
9918                                recovery_state: None,
9919                            },
9920                            FastRecognizeScratch {
9921                                predicate_context,
9922                                visiting,
9923                                memo,
9924                                expected,
9925                                native_depth: native_depth + 1,
9926                            },
9927                        );
9928                        if follow_outcomes.is_empty() {
9929                            continue;
9930                        }
9931                        let child_stop_index =
9932                            self.rule_stop_token_index(child_index, child_consumed_eof);
9933                        let child_node = self.build_parse_trees.then(|| {
9934                            self.recognition_arena.deferred_rule_node(FastDeferredRule {
9935                                rule_index: u32::try_from(rule_index)
9936                                    .expect("rule index fits in u32"),
9937                                invoking_state: i32::try_from(invoking_state_number(state_number))
9938                                    .expect("invoking state fits in i32"),
9939                                start_index: u32::try_from(index)
9940                                    .expect("rule start index fits in u32"),
9941                                stop_index: child_stop_index.map(|stop_index| {
9942                                    u32::try_from(stop_index).expect("rule stop index fits in u32")
9943                                }),
9944                                deferred_children: child.deferred_nodes,
9945                                children: child.nodes,
9946                            })
9947                        });
9948                        let child_diags_empty = child_diagnostics.is_empty();
9949                        outcomes.extend(follow_outcomes.into_iter().map(|mut outcome| {
9950                            outcome.consumed_eof |= child_consumed_eof;
9951                            // Skip the prepend dance when there's nothing to
9952                            // merge from the child — common case in pass 1.
9953                            if !child_diags_empty {
9954                                outcome.diagnostics = self
9955                                    .recognition_arena
9956                                    .concat_diagnostics(child_diagnostics, outcome.diagnostics);
9957                            }
9958                            if let Some(child_node) = child_node {
9959                                outcome.deferred_nodes = self
9960                                    .recognition_arena
9961                                    .concat_deferred_nodes(child_node, outcome.deferred_nodes);
9962                            }
9963                            outcome
9964                        }));
9965                    }
9966                }
9967                ParserTransitionKind::Atom
9968                | ParserTransitionKind::Range
9969                | ParserTransitionKind::Set
9970                | ParserTransitionKind::NotSet
9971                | ParserTransitionKind::Wildcard => {
9972                    #[cfg(feature = "perf-counters")]
9973                    perf_counters::inc(&perf_counters::ATOM_RANGE_TRANSITIONS, 1);
9974                    let symbol = self.token_type_at(index);
9975                    if transition.matches_kind(transition_kind, symbol, 1, max_token_type) {
9976                        let next_index = self.consume_index(index, symbol);
9977                        let empty_recovery = self.empty_recovery_symbols();
9978                        outcomes.extend(
9979                            self.recognize_state_fast(
9980                                atn,
9981                                FastRecognizeRequest {
9982                                    state_number: target,
9983                                    stop_state,
9984                                    index: next_index,
9985                                    rule_start_index,
9986                                    decision_start_index: next_decision_start_index,
9987                                    precedence,
9988                                    depth: depth + 1,
9989                                    recovery_symbols: empty_recovery,
9990                                    recovery_state: None,
9991                                },
9992                                FastRecognizeScratch {
9993                                    predicate_context,
9994                                    visiting,
9995                                    memo,
9996                                    expected,
9997                                    native_depth: native_depth + 1,
9998                                },
9999                            )
10000                            .into_iter()
10001                            .map(|mut outcome| {
10002                                outcome.consumed_eof |= symbol == TOKEN_EOF;
10003                                if self.fast_token_nodes_enabled {
10004                                    let token = self.arena_token_node(index, false);
10005                                    self.defer_fast_outcome_node(&mut outcome, token);
10006                                }
10007                                outcome
10008                            }),
10009                        );
10010                    } else {
10011                        if !self.fast_recovery_enabled {
10012                            // In pass 1 there is no recovery to attempt; the
10013                            // recovery branch below would never run, and the
10014                            // `expected_symbols` computation is just there
10015                            // to gate that branch. Skipping it eliminates
10016                            // ~1× `state_expected_symbols` lookup per failed
10017                            // atom transition (≈82K on mono-statement.cs)
10018                            // for zero observable behavior change.
10019                            continue;
10020                        }
10021                        let expected_symbols = fast_recovery_expected_symbols(
10022                            self,
10023                            atn,
10024                            state.state_number(),
10025                            &recovery_symbols,
10026                        );
10027                        if expected_symbols.contains(&symbol) {
10028                            continue;
10029                        }
10030                        {
10031                            expected.record_transition(index, transition, max_token_type);
10032                            record_no_viable_if_ambiguous(
10033                                expected,
10034                                next_decision_start_index,
10035                                index,
10036                            );
10037                            outcomes.extend(self.fast_single_token_deletion_recovery(
10038                                FastRecoveryRequest {
10039                                    atn,
10040                                    transition,
10041                                    expected_symbols: Rc::clone(&expected_symbols),
10042                                    target,
10043                                    request: FastRecognizeRequest {
10044                                        state_number,
10045                                        stop_state,
10046                                        index,
10047                                        rule_start_index,
10048                                        decision_start_index,
10049                                        precedence,
10050                                        depth,
10051                                        recovery_symbols: Rc::clone(&recovery_symbols),
10052                                        recovery_state,
10053                                    },
10054                                    visiting,
10055                                    memo,
10056                                    expected,
10057                                },
10058                                predicate_context,
10059                            ));
10060                            if !state_is_left_recursive_rule(atn, state) {
10061                                outcomes.extend(self.fast_single_token_insertion_recovery(
10062                                    FastRecoveryRequest {
10063                                        atn,
10064                                        transition,
10065                                        expected_symbols: Rc::clone(&expected_symbols),
10066                                        target,
10067                                        request: FastRecognizeRequest {
10068                                            state_number,
10069                                            stop_state,
10070                                            index,
10071                                            rule_start_index,
10072                                            decision_start_index,
10073                                            precedence,
10074                                            depth,
10075                                            recovery_symbols: Rc::clone(&recovery_symbols),
10076                                            recovery_state,
10077                                        },
10078                                        visiting,
10079                                        memo,
10080                                        expected,
10081                                    },
10082                                    predicate_context,
10083                                ));
10084                            }
10085                            outcomes.extend(self.fast_current_token_deletion_recovery(
10086                                FastCurrentTokenDeletionRequest {
10087                                    atn,
10088                                    expected_symbols,
10089                                    request: FastRecognizeRequest {
10090                                        state_number,
10091                                        stop_state,
10092                                        index,
10093                                        rule_start_index,
10094                                        decision_start_index,
10095                                        precedence,
10096                                        depth,
10097                                        recovery_symbols: Rc::clone(&recovery_symbols),
10098                                        recovery_state,
10099                                    },
10100                                    visiting,
10101                                    memo,
10102                                    expected,
10103                                },
10104                                predicate_context,
10105                            ));
10106                        }
10107                    }
10108                }
10109            }
10110            let alt_number = next_alt_number(
10111                state,
10112                transition_count,
10113                transition_index,
10114                0,
10115                self.fast_track_alt_numbers,
10116            );
10117            if alt_number != 0 || left_recursive_boundary.is_some() {
10118                for outcome in &mut outcomes[outcomes_before_transition..] {
10119                    if alt_number != 0 {
10120                        self.defer_fast_outcome_alternative(outcome, alt_number);
10121                    }
10122                    if let Some(rule_index) = left_recursive_boundary {
10123                        self.defer_fast_outcome_boundary(outcome, rule_index);
10124                    }
10125                }
10126            }
10127        }
10128
10129        if has_inserted_cycle_guard {
10130            visiting.remove(&key);
10131        }
10132        if matches!(
10133            self.prediction_mode,
10134            PredictionMode::Ll | PredictionMode::LlExactAmbigDetection
10135        ) && self.fast_recovery_enabled
10136        {
10137            // Without recovery enabled every outcome already has empty
10138            // diagnostics, so the discard pass is a no-op — skipping it
10139            // saves an iter+retain on each of the ~1M visits.
10140            discard_recovered_fast_outcomes_if_clean_path_exists(&mut outcomes);
10141        }
10142        if self.fast_recovery_enabled {
10143            dedupe_fast_outcomes(&mut outcomes, &self.recognition_arena);
10144        } else {
10145            dedupe_clean_fast_outcomes(&mut outcomes, &mut self.fast_outcome_dedup);
10146        }
10147        // Skip memoization for single-transition states whose outcome is
10148        // unambiguous: they only get re-entered if the caller revisits the
10149        // exact same call site, which is rare since the loop above already
10150        // collapsed straight-line epsilon walks. Multi-alternative states
10151        // are where backtracking actually revisits the same coordinate, so
10152        // we still memoize there. With recovery on we keep the existing
10153        // memoization unconditionally because the recovery branch may
10154        // record diagnostics that the cache must surface to repeated
10155        // failed visits.
10156        let should_memoize = self.fast_recovery_enabled
10157            || (transition_count > 1 && self.clean_memo_mode != CleanMemoMode::Sparse);
10158        // Apply inline pending state to each outcome before returning.
10159        // Tokens consumed inline by the loop-collapse don't appear in the
10160        // recursive recognizer's output, so we need to prepend them here.
10161        let mut apply_inline_pending = |mut outcome: FastRecognizeOutcome| -> FastRecognizeOutcome {
10162            if inline_consumed_eof {
10163                outcome.consumed_eof = true;
10164            }
10165            if !inline_consumed_tokens.is_empty() {
10166                for token_index in inline_consumed_tokens.iter().rev() {
10167                    let token = self.arena_token_node(*token_index, false);
10168                    self.defer_fast_outcome_node(&mut outcome, token);
10169                }
10170            }
10171            outcome
10172        };
10173        if should_memoize {
10174            #[cfg(feature = "perf-counters")]
10175            {
10176                perf_counters::inc(&perf_counters::MEMO_INSERTED, 1);
10177                perf_counters::inc(&perf_counters::OUTCOMES_PUSHED, outcomes.len() as u64);
10178                match outcomes.len() {
10179                    0 => perf_counters::inc(&perf_counters::OUTCOMES_RETURN_0, 1),
10180                    1 => perf_counters::inc(&perf_counters::OUTCOMES_RETURN_1, 1),
10181                    _ => perf_counters::inc(&perf_counters::OUTCOMES_RETURN_N, 1),
10182                }
10183            }
10184            // The memo is keyed by the loop-exit `(state_number, index)` so
10185            // the inline-consumed tokens belong to *this* call's output, not
10186            // the cached result. Memoize the bare outcomes (without the
10187            // inline-pending data), then prepend the inline data on return.
10188            let stored: Rc<[FastRecognizeOutcome]> = Rc::from(outcomes);
10189            memo.insert(key, Rc::clone(&stored));
10190            if inline_pending {
10191                return stored
10192                    .iter()
10193                    .copied()
10194                    .map(&mut apply_inline_pending)
10195                    .collect();
10196            }
10197            return stored.to_vec();
10198        }
10199        #[cfg(feature = "perf-counters")]
10200        match outcomes.len() {
10201            0 => perf_counters::inc(&perf_counters::OUTCOMES_RETURN_0, 1),
10202            1 => perf_counters::inc(&perf_counters::OUTCOMES_RETURN_1, 1),
10203            _ => perf_counters::inc(&perf_counters::OUTCOMES_RETURN_N, 1),
10204        }
10205        if inline_pending {
10206            return outcomes.into_iter().map(apply_inline_pending).collect();
10207        }
10208        outcomes
10209    }
10210
10211    /// Explores single-token deletion recovery while preserving the matched
10212    /// token and skipped error token in the selected parse tree path.
10213    fn single_token_deletion_recovery(
10214        &mut self,
10215        recovery: RecoveryRequest<'_, '_>,
10216    ) -> Vec<RecognizeOutcome> {
10217        let RecoveryRequest {
10218            atn,
10219            transition,
10220            expected_symbols,
10221            target,
10222            request,
10223            visiting,
10224            memo,
10225            expected,
10226        } = recovery;
10227        let RecognizeRequest {
10228            stop_state,
10229            index,
10230            rule_start_index,
10231            decision_start_index,
10232            init_action_rules,
10233            predicates,
10234            semantics,
10235            rule_args,
10236            member_actions,
10237            return_actions,
10238            local_int_arg,
10239            member_values,
10240            return_values,
10241            rule_alt_number,
10242            track_alt_numbers,
10243            consumed_eof,
10244            precedence,
10245            depth,
10246            ..
10247        } = request;
10248        let Some((diagnostic, next_index, next_symbol)) =
10249            self.single_token_deletion(transition, index, atn.max_token_type(), &expected_symbols)
10250        else {
10251            return Vec::new();
10252        };
10253        let after_next = self.consume_index(next_index, next_symbol);
10254        self.recognize_state(
10255            atn,
10256            RecognizeRequest {
10257                state_number: target,
10258                stop_state,
10259                index: after_next,
10260                rule_start_index,
10261                decision_start_index,
10262                init_action_rules,
10263                predicates,
10264                semantics,
10265                rule_args,
10266                member_actions,
10267                return_actions,
10268                local_int_arg,
10269                member_values,
10270                return_values,
10271                rule_alt_number,
10272                track_alt_numbers,
10273                consumed_eof: consumed_eof || next_symbol == TOKEN_EOF,
10274                committed_decision: false,
10275                precedence,
10276                depth: depth + 1,
10277                recovery_symbols: BTreeSet::new(),
10278                recovery_state: None,
10279            },
10280            visiting,
10281            memo,
10282            expected,
10283        )
10284        .into_iter()
10285        .map(|mut outcome| {
10286            outcome.consumed_eof |= next_symbol == TOKEN_EOF;
10287            outcome.diagnostics = self
10288                .recognition_arena
10289                .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
10290            let token = self.arena_token_node(next_index, false);
10291            self.arena_prepend(&mut outcome.nodes, token);
10292            let error = self.arena_token_node(index, true);
10293            self.arena_prepend(&mut outcome.nodes, error);
10294            outcome
10295        })
10296        .collect()
10297    }
10298
10299    /// Retries the current recognition state after deleting one unexpected
10300    /// token, preserving the deleted token as an error node in the parse tree.
10301    fn current_token_deletion_recovery(
10302        &mut self,
10303        recovery: CurrentTokenDeletionRequest<'_, '_>,
10304    ) -> Vec<RecognizeOutcome> {
10305        let CurrentTokenDeletionRequest {
10306            atn,
10307            expected_symbols,
10308            mut request,
10309            visiting,
10310            memo,
10311            expected,
10312        } = recovery;
10313        let error_index = request.index;
10314        if error_index == request.rule_start_index {
10315            return Vec::new();
10316        }
10317        let Some((diagnostic, next_index, skipped)) =
10318            self.current_token_deletion(error_index, &expected_symbols)
10319        else {
10320            return Vec::new();
10321        };
10322        request.state_number = request.recovery_state.unwrap_or(request.state_number);
10323        request.index = next_index;
10324        request.committed_decision = false;
10325        request.depth += 1;
10326        request.recovery_state = None;
10327        self.recognize_state(atn, request, visiting, memo, expected)
10328            .into_iter()
10329            .map(|mut outcome| {
10330                outcome.diagnostics = self
10331                    .recognition_arena
10332                    .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
10333                for index in skipped.iter().rev() {
10334                    let error = self.arena_token_node(*index, true);
10335                    self.arena_prepend(&mut outcome.nodes, error);
10336                }
10337                outcome
10338            })
10339            .collect()
10340    }
10341
10342    /// Falls back after deletion/insertion repairs cannot continue from a
10343    /// failed consuming transition.
10344    fn consuming_failure_fallback(
10345        &mut self,
10346        fallback: ConsumingFailureFallback<'_>,
10347        visiting: &mut BTreeSet<RecognizeKey>,
10348        memo: &mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
10349        expected: &mut ExpectedTokens,
10350    ) -> Vec<RecognizeOutcome> {
10351        if fallback.expected_symbols.is_empty() {
10352            return Vec::new();
10353        }
10354        if fallback.symbol == TOKEN_EOF {
10355            return self.eof_consuming_failure_fallback(fallback, expected);
10356        }
10357        self.non_eof_consuming_failure_fallback(fallback, visiting, memo, expected)
10358    }
10359
10360    /// Keeps unexpected non-EOF input visible as an error node when no repair
10361    /// path can otherwise reach the transition target.
10362    fn non_eof_consuming_failure_fallback(
10363        &mut self,
10364        fallback: ConsumingFailureFallback<'_>,
10365        visiting: &mut BTreeSet<RecognizeKey>,
10366        memo: &mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
10367        expected: &mut ExpectedTokens,
10368    ) -> Vec<RecognizeOutcome> {
10369        let ConsumingFailureFallback {
10370            atn,
10371            target,
10372            request,
10373            symbol,
10374            expected_symbols,
10375            decision_start_index,
10376            decision,
10377        } = fallback;
10378        let error_index = request.index;
10379        let diagnostic =
10380            self.recovery_failure_diagnostic(error_index, decision_start_index, &expected_symbols);
10381        let next_index = self.consume_index(error_index, symbol);
10382        self.recognize_state(
10383            atn,
10384            RecognizeRequest {
10385                state_number: target,
10386                stop_state: request.stop_state,
10387                index: next_index,
10388                rule_start_index: request.rule_start_index,
10389                decision_start_index,
10390                init_action_rules: request.init_action_rules,
10391                predicates: request.predicates,
10392                semantics: request.semantics,
10393                rule_args: request.rule_args,
10394                member_actions: request.member_actions,
10395                return_actions: request.return_actions,
10396                local_int_arg: request.local_int_arg,
10397                member_values: request.member_values,
10398                return_values: request.return_values,
10399                rule_alt_number: request.rule_alt_number,
10400                track_alt_numbers: request.track_alt_numbers,
10401                consumed_eof: request.consumed_eof,
10402                committed_decision: false,
10403                precedence: request.precedence,
10404                depth: request.depth + 1,
10405                recovery_symbols: BTreeSet::new(),
10406                recovery_state: None,
10407            },
10408            visiting,
10409            memo,
10410            expected,
10411        )
10412        .into_iter()
10413        .map(|mut outcome| {
10414            prepend_decision(&mut outcome, decision);
10415            outcome.diagnostics = self
10416                .recognition_arena
10417                .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
10418            let error = self.arena_token_node(error_index, true);
10419            self.arena_prepend(&mut outcome.nodes, error);
10420            outcome
10421        })
10422        .collect()
10423    }
10424
10425    /// Stops the current rule at EOF after a nested failure, matching ANTLR's
10426    /// behavior of unwinding instead of inserting caller tokens at EOF.
10427    fn eof_consuming_failure_fallback(
10428        &mut self,
10429        fallback: ConsumingFailureFallback<'_>,
10430        expected: &ExpectedTokens,
10431    ) -> Vec<RecognizeOutcome> {
10432        let request = fallback.request;
10433        if request.index == request.rule_start_index {
10434            return Vec::new();
10435        }
10436        let diagnostic =
10437            self.eof_rule_recovery_diagnostic(request.index, &fallback.expected_symbols, expected);
10438        let diagnostics = self
10439            .recognition_arena
10440            .prepend_diagnostic(DiagnosticSeqId::EMPTY, diagnostic);
10441        vec![RecognizeOutcome {
10442            index: request.index,
10443            consumed_eof: request.consumed_eof,
10444            alt_number: request.rule_alt_number,
10445            member_values: request.member_values,
10446            return_values: request.return_values,
10447            diagnostics,
10448            decisions: Vec::new(),
10449            actions: Vec::new(),
10450            nodes: NodeSeqId::EMPTY,
10451        }]
10452    }
10453
10454    /// Explores single-token insertion recovery while adding a conjured
10455    /// missing-token error node to the selected parse tree path.
10456    fn single_token_insertion_recovery(
10457        &mut self,
10458        recovery: RecoveryRequest<'_, '_>,
10459    ) -> Vec<RecognizeOutcome> {
10460        let RecoveryRequest {
10461            atn,
10462            transition,
10463            expected_symbols,
10464            target,
10465            request,
10466            visiting,
10467            memo,
10468            expected,
10469        } = recovery;
10470        let RecognizeRequest {
10471            stop_state,
10472            index,
10473            rule_start_index,
10474            decision_start_index,
10475            init_action_rules,
10476            predicates,
10477            semantics,
10478            rule_args,
10479            member_actions,
10480            return_actions,
10481            local_int_arg,
10482            member_values,
10483            return_values,
10484            rule_alt_number,
10485            track_alt_numbers,
10486            consumed_eof,
10487            precedence,
10488            depth,
10489            ..
10490        } = request;
10491        let follow_symbols = state_expected_symbols(atn, transition.target());
10492        let Some((diagnostic, token_type, text)) = self.single_token_insertion(
10493            transition,
10494            index,
10495            atn.max_token_type(),
10496            &expected_symbols,
10497            &follow_symbols,
10498        ) else {
10499            return Vec::new();
10500        };
10501        self.recognize_state(
10502            atn,
10503            RecognizeRequest {
10504                state_number: target,
10505                stop_state,
10506                index,
10507                rule_start_index,
10508                decision_start_index,
10509                init_action_rules,
10510                predicates,
10511                semantics,
10512                rule_args,
10513                member_actions,
10514                return_actions,
10515                local_int_arg,
10516                member_values,
10517                return_values,
10518                rule_alt_number,
10519                track_alt_numbers,
10520                consumed_eof,
10521                committed_decision: false,
10522                precedence,
10523                depth: depth + 1,
10524                recovery_symbols: BTreeSet::new(),
10525                recovery_state: None,
10526            },
10527            visiting,
10528            memo,
10529            expected,
10530        )
10531        .into_iter()
10532        .map(|mut outcome| {
10533            outcome.diagnostics = self
10534                .recognition_arena
10535                .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
10536            let missing = self.arena_missing_token_node(token_type, index, text.clone());
10537            self.arena_prepend(&mut outcome.nodes, missing);
10538            outcome
10539        })
10540        .collect()
10541    }
10542
10543    /// Attempts to reach `stop_state` and carries semantic actions for the
10544    /// selected parser path.
10545    #[allow(clippy::too_many_lines)]
10546    fn recognize_state(
10547        &mut self,
10548        atn: &Atn,
10549        request: RecognizeRequest<'_>,
10550        visiting: &mut BTreeSet<RecognizeKey>,
10551        memo: &mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
10552        expected: &mut ExpectedTokens,
10553    ) -> Vec<RecognizeOutcome> {
10554        let request_template = request.clone();
10555        let RecognizeRequest {
10556            state_number,
10557            stop_state,
10558            index,
10559            rule_start_index,
10560            decision_start_index,
10561            init_action_rules,
10562            predicates,
10563            semantics,
10564            rule_args,
10565            member_actions,
10566            return_actions,
10567            local_int_arg,
10568            member_values,
10569            return_values,
10570            rule_alt_number,
10571            track_alt_numbers,
10572            consumed_eof,
10573            committed_decision,
10574            precedence,
10575            depth,
10576            recovery_symbols,
10577            recovery_state,
10578        } = request;
10579        if depth > RECOGNITION_DEPTH_LIMIT {
10580            return Vec::new();
10581        }
10582        if state_number == stop_state {
10583            return stop_outcome(
10584                index,
10585                consumed_eof,
10586                rule_alt_number,
10587                member_values,
10588                return_values,
10589            );
10590        }
10591        let key = RecognizeKey {
10592            state_number,
10593            stop_state,
10594            index,
10595            rule_start_index,
10596            decision_start_index,
10597            local_int_arg,
10598            member_values: member_values.clone(),
10599            return_values: return_values.clone(),
10600            rule_alt_number,
10601            track_alt_numbers,
10602            consumed_eof,
10603            committed_decision,
10604            precedence,
10605            recovery_symbols: recovery_symbols.clone(),
10606            recovery_state,
10607        };
10608        if let Some(outcomes) = memo.get(&key) {
10609            return outcomes.clone();
10610        }
10611
10612        let visit_key = key.clone();
10613        if !visiting.insert(visit_key.clone()) {
10614            return Vec::new();
10615        }
10616
10617        let Some(state) = atn.state(state_number) else {
10618            visiting.remove(&visit_key);
10619            return Vec::new();
10620        };
10621        let decision_override_generation = self.decision_override_generation;
10622        let transitions = state.transitions();
10623        let transition_count = transitions.len();
10624        let overridden_transition = if transition_count > 1
10625            && self.semantic_hooks.observes_parser_decisions()
10626        {
10627            atn.decision_to_state()
10628                .iter()
10629                .position(|candidate| candidate == state_number)
10630                .and_then(|decision| {
10631                    self.semantic_hooks
10632                        .parser_decision_override(decision, index, transition_count)
10633                })
10634                .and_then(|alternative| alternative.checked_sub(1))
10635                .filter(|alternative| *alternative < transition_count)
10636        } else {
10637            None
10638        };
10639        if overridden_transition.is_some() {
10640            self.decision_override_generation = self.decision_override_generation.wrapping_add(1);
10641        }
10642        let next_decision_start_index = if starts_prediction_decision(state, transition_count) {
10643            Some(index)
10644        } else {
10645            decision_start_index
10646        };
10647        let (epsilon_recovery_symbols, epsilon_recovery_state) =
10648            next_recovery_context(atn, state, &recovery_symbols, recovery_state);
10649        let mut outcomes = Vec::new();
10650        for (transition_index, transition) in transitions.iter().enumerate() {
10651            if overridden_transition.is_some_and(|forced| forced != transition_index) {
10652                continue;
10653            }
10654            let transition_committed =
10655                committed_decision || overridden_transition == Some(transition_index);
10656            let mut transition_request = request_template.clone();
10657            transition_request.committed_decision = transition_committed;
10658            let decision =
10659                transition_decision(atn, state, transition_count, transition_index, predicates);
10660            let next_alt_number = next_alt_number(
10661                state,
10662                transition_count,
10663                transition_index,
10664                rule_alt_number,
10665                track_alt_numbers,
10666            );
10667            let transition_data = transition.data();
10668            match &transition_data {
10669                Transition::Epsilon { target } | Transition::Action { target, .. } => {
10670                    let (action_rule_index, action_index) = match &transition_data {
10671                        Transition::Action {
10672                            rule_index,
10673                            action_index,
10674                            ..
10675                        } => (Some(*rule_index), *action_index),
10676                        _ => (None, None),
10677                    };
10678                    outcomes.extend(self.recognize_epsilon_or_action_step(
10679                        atn,
10680                        &transition_request,
10681                        EpsilonActionStep {
10682                            source_state: state_number,
10683                            target: *target,
10684                            action_rule_index,
10685                            action_index,
10686                            left_recursive_boundary: left_recursive_boundary(atn, state, *target),
10687                            decision,
10688                            decision_start_index: next_decision_start_index,
10689                            alt_number: next_alt_number,
10690                            recovery_symbols: epsilon_recovery_symbols.clone(),
10691                            recovery_state: epsilon_recovery_state,
10692                        },
10693                        RecognizeScratch {
10694                            visiting,
10695                            memo,
10696                            expected,
10697                        },
10698                    ));
10699                }
10700                Transition::Predicate {
10701                    target,
10702                    rule_index,
10703                    pred_index,
10704                    ..
10705                } => {
10706                    let predicate = PredicateEval {
10707                        index,
10708                        rule_index: *rule_index,
10709                        pred_index: *pred_index,
10710                        predicates,
10711                        semantics,
10712                        context: None,
10713                        local_int_arg,
10714                        member_values: &member_values,
10715                    };
10716                    if self.parser_predicate_matches(predicate) {
10717                        let left_recursive_boundary = left_recursive_boundary(atn, state, *target);
10718                        outcomes.extend(
10719                            self.recognize_state(
10720                                atn,
10721                                RecognizeRequest {
10722                                    state_number: *target,
10723                                    stop_state,
10724                                    index,
10725                                    rule_start_index,
10726                                    decision_start_index: next_decision_start_index,
10727                                    init_action_rules,
10728                                    predicates,
10729                                    semantics,
10730                                    rule_args,
10731                                    member_actions,
10732                                    return_actions,
10733                                    local_int_arg,
10734                                    member_values: member_values.clone(),
10735                                    return_values: return_values.clone(),
10736                                    rule_alt_number: next_alt_number,
10737                                    track_alt_numbers,
10738                                    consumed_eof,
10739                                    committed_decision: transition_committed,
10740                                    precedence,
10741                                    depth: depth + 1,
10742                                    recovery_symbols: epsilon_recovery_symbols.clone(),
10743                                    recovery_state: epsilon_recovery_state,
10744                                },
10745                                visiting,
10746                                memo,
10747                                expected,
10748                            )
10749                            .into_iter()
10750                            .map(|mut outcome| {
10751                                prepend_decision(&mut outcome, decision);
10752                                if let Some(rule_index) = left_recursive_boundary {
10753                                    let boundary =
10754                                        self.arena_boundary_node(rule_index, next_alt_number);
10755                                    self.arena_prepend(&mut outcome.nodes, boundary);
10756                                }
10757                                outcome
10758                            }),
10759                        );
10760                    } else if let Some(message) = semantics
10761                        .and_then(|semantics| {
10762                            self.parser_semantic_ir_predicate_failure_message(
10763                                *rule_index,
10764                                *pred_index,
10765                                semantics,
10766                            )
10767                        })
10768                        .or_else(|| {
10769                            self.parser_predicate_failure_message(
10770                                *rule_index,
10771                                *pred_index,
10772                                predicates,
10773                            )
10774                        })
10775                    {
10776                        outcomes.push(self.predicate_failure_recovery(PredicateFailureRecovery {
10777                            rule_index: *rule_index,
10778                            index,
10779                            message,
10780                            member_values: member_values.clone(),
10781                            return_values: return_values.clone(),
10782                            rule_alt_number,
10783                        }));
10784                    } else {
10785                        record_predicate_no_viable(expected, next_decision_start_index, index);
10786                    }
10787                }
10788                Transition::Precedence {
10789                    target,
10790                    precedence: transition_precedence,
10791                } => {
10792                    if *transition_precedence >= precedence {
10793                        outcomes.extend(
10794                            self.recognize_state(
10795                                atn,
10796                                RecognizeRequest {
10797                                    state_number: *target,
10798                                    stop_state,
10799                                    index,
10800                                    rule_start_index,
10801                                    decision_start_index: next_decision_start_index,
10802                                    init_action_rules,
10803                                    predicates,
10804                                    semantics,
10805                                    rule_args,
10806                                    member_actions,
10807                                    return_actions,
10808                                    local_int_arg,
10809                                    member_values: member_values.clone(),
10810                                    return_values: return_values.clone(),
10811                                    rule_alt_number: next_alt_number,
10812                                    track_alt_numbers,
10813                                    consumed_eof,
10814                                    committed_decision: transition_committed,
10815                                    precedence,
10816                                    depth: depth + 1,
10817                                    recovery_symbols: epsilon_recovery_symbols.clone(),
10818                                    recovery_state: epsilon_recovery_state,
10819                                },
10820                                visiting,
10821                                memo,
10822                                expected,
10823                            )
10824                            .into_iter()
10825                            .map(|mut outcome| {
10826                                prepend_decision(&mut outcome, decision);
10827                                outcome
10828                            }),
10829                        );
10830                    }
10831                }
10832                Transition::Rule {
10833                    target,
10834                    rule_index,
10835                    follow_state,
10836                    precedence: rule_precedence,
10837                    ..
10838                } => {
10839                    let Some(child_stop) = atn.rule_to_stop_state().get(*rule_index) else {
10840                        continue;
10841                    };
10842                    let child_local_int_arg =
10843                        rule_local_int_arg(rule_args, state_number, *rule_index, local_int_arg);
10844                    let expected_before_child = expected.clone();
10845                    let children = self.recognize_state(
10846                        atn,
10847                        RecognizeRequest {
10848                            state_number: *target,
10849                            stop_state: child_stop,
10850                            index,
10851                            rule_start_index: index,
10852                            decision_start_index: None,
10853                            init_action_rules,
10854                            predicates,
10855                            semantics,
10856                            rule_args,
10857                            member_actions,
10858                            return_actions,
10859                            local_int_arg: child_local_int_arg,
10860                            member_values: member_values.clone(),
10861                            return_values: BTreeMap::new(),
10862                            rule_alt_number: 0,
10863                            track_alt_numbers,
10864                            consumed_eof: false,
10865                            committed_decision: transition_committed,
10866                            precedence: *rule_precedence,
10867                            depth: depth + 1,
10868                            recovery_symbols: epsilon_recovery_symbols.clone(),
10869                            recovery_state: epsilon_recovery_state,
10870                        },
10871                        visiting,
10872                        memo,
10873                        expected,
10874                    );
10875                    let children = if children.is_empty() {
10876                        self.child_rule_failure_recovery_outcomes(ChildRuleFailureRecovery {
10877                            atn,
10878                            rule_index: *rule_index,
10879                            start_index: index,
10880                            follow_state: *follow_state,
10881                            stop_state,
10882                            member_values: member_values.clone(),
10883                            expected,
10884                        })
10885                    } else {
10886                        children
10887                    };
10888                    let preserve_child_expected =
10889                        self.child_expected_reaches_clean_eof(&children, expected);
10890                    restore_expected(
10891                        &children,
10892                        index,
10893                        expected,
10894                        expected_before_child,
10895                        preserve_child_expected,
10896                    );
10897                    for child in children {
10898                        let child_stop_index =
10899                            self.rule_stop_token_index(child.index, child.consumed_eof);
10900                        let child_nodes = self
10901                            .recognition_arena
10902                            .fold_left_recursive_boundaries(child.nodes);
10903                        let child_node = self.arena_rule_node(ArenaRuleSpec {
10904                            rule_index: *rule_index,
10905                            invoking_state: invoking_state_number(state_number),
10906                            alt_number: child.alt_number,
10907                            start_index: index,
10908                            stop_index: child_stop_index,
10909                            return_values: child.return_values.clone(),
10910                            children: child_nodes,
10911                        });
10912                        outcomes.extend(
10913                            self.recognize_state(
10914                                atn,
10915                                RecognizeRequest {
10916                                    state_number: *follow_state,
10917                                    stop_state,
10918                                    index: child.index,
10919                                    rule_start_index,
10920                                    decision_start_index: next_decision_start_index,
10921                                    init_action_rules,
10922                                    predicates,
10923                                    semantics,
10924                                    rule_args,
10925                                    member_actions,
10926                                    return_actions,
10927                                    local_int_arg,
10928                                    member_values: child.member_values.clone(),
10929                                    return_values: return_values.clone(),
10930                                    rule_alt_number,
10931                                    track_alt_numbers,
10932                                    consumed_eof: consumed_eof || child.consumed_eof,
10933                                    committed_decision: transition_committed
10934                                        && child.index == index,
10935                                    precedence,
10936                                    depth: depth + 1,
10937                                    recovery_symbols: BTreeSet::new(),
10938                                    recovery_state: None,
10939                                },
10940                                visiting,
10941                                memo,
10942                                expected,
10943                            )
10944                            .into_iter()
10945                            .map(|mut outcome| {
10946                                outcome.consumed_eof |= child.consumed_eof;
10947                                outcome.diagnostics = self
10948                                    .recognition_arena
10949                                    .concat_diagnostics(child.diagnostics, outcome.diagnostics);
10950                                let mut decisions = child.decisions.clone();
10951                                decisions.append(&mut outcome.decisions);
10952                                outcome.decisions = decisions;
10953                                prepend_decision(&mut outcome, decision);
10954                                let mut actions = child.actions.clone();
10955                                if init_action_rules.contains(rule_index) {
10956                                    actions.insert(
10957                                        0,
10958                                        ParserAction::new_rule_init(
10959                                            *rule_index,
10960                                            index,
10961                                            Some(*follow_state),
10962                                        ),
10963                                    );
10964                                }
10965                                actions.append(&mut outcome.actions);
10966                                outcome.actions = actions;
10967                                self.arena_prepend(&mut outcome.nodes, child_node);
10968                                outcome
10969                            }),
10970                        );
10971                    }
10972                }
10973                Transition::Atom { target, .. }
10974                | Transition::Range { target, .. }
10975                | Transition::Set { target, .. }
10976                | Transition::NotSet { target, .. }
10977                | Transition::Wildcard { target, .. } => {
10978                    let symbol = self.token_type_at(index);
10979                    if transition_data.matches(symbol, 1, atn.max_token_type()) {
10980                        let next_index = self.consume_index(index, symbol);
10981                        outcomes.extend(
10982                            self.recognize_state(
10983                                atn,
10984                                RecognizeRequest {
10985                                    state_number: *target,
10986                                    stop_state,
10987                                    index: next_index,
10988                                    rule_start_index,
10989                                    decision_start_index: next_decision_start_index,
10990                                    init_action_rules,
10991                                    predicates,
10992                                    semantics,
10993                                    rule_args,
10994                                    member_actions,
10995                                    return_actions,
10996                                    local_int_arg,
10997                                    member_values: member_values.clone(),
10998                                    return_values: return_values.clone(),
10999                                    rule_alt_number: next_alt_number,
11000                                    track_alt_numbers,
11001                                    consumed_eof: consumed_eof || symbol == TOKEN_EOF,
11002                                    committed_decision: false,
11003                                    precedence,
11004                                    depth: depth + 1,
11005                                    recovery_symbols: BTreeSet::new(),
11006                                    recovery_state: None,
11007                                },
11008                                visiting,
11009                                memo,
11010                                expected,
11011                            )
11012                            .into_iter()
11013                            .map(|mut outcome| {
11014                                prepend_decision(&mut outcome, decision);
11015                                outcome.consumed_eof |= symbol == TOKEN_EOF;
11016                                let token = self.arena_token_node(index, false);
11017                                self.arena_prepend(&mut outcome.nodes, token);
11018                                outcome
11019                            }),
11020                        );
11021                    } else {
11022                        let expected_symbols =
11023                            recovery_expected_symbols(atn, state.state_number(), &recovery_symbols);
11024                        if expected_symbols.contains(&symbol) && !transition_committed {
11025                            continue;
11026                        }
11027                        expected.record_transition(index, transition, atn.max_token_type());
11028                        record_no_viable_if_ambiguous(expected, next_decision_start_index, index);
11029                        let before_recovery = outcomes.len();
11030                        let recovery_request = transition_request.clone();
11031                        if transition_committed {
11032                            outcomes.extend(self.consuming_failure_fallback(
11033                                ConsumingFailureFallback {
11034                                    atn,
11035                                    target: *target,
11036                                    request: recovery_request,
11037                                    symbol,
11038                                    expected_symbols,
11039                                    decision_start_index: next_decision_start_index,
11040                                    decision,
11041                                },
11042                                visiting,
11043                                memo,
11044                                expected,
11045                            ));
11046                            break;
11047                        }
11048                        outcomes.extend(
11049                            self.single_token_deletion_recovery(RecoveryRequest {
11050                                atn,
11051                                transition,
11052                                expected_symbols: expected_symbols.clone(),
11053                                target: *target,
11054                                request: recovery_request.clone(),
11055                                visiting,
11056                                memo,
11057                                expected,
11058                            })
11059                            .into_iter()
11060                            .map(|mut outcome| {
11061                                prepend_decision(&mut outcome, decision);
11062                                outcome
11063                            }),
11064                        );
11065                        if !state_is_left_recursive_rule(atn, state) {
11066                            outcomes.extend(
11067                                self.single_token_insertion_recovery(RecoveryRequest {
11068                                    atn,
11069                                    transition,
11070                                    expected_symbols: expected_symbols.clone(),
11071                                    target: *target,
11072                                    request: recovery_request.clone(),
11073                                    visiting,
11074                                    memo,
11075                                    expected,
11076                                })
11077                                .into_iter()
11078                                .map(|mut outcome| {
11079                                    prepend_decision(&mut outcome, decision);
11080                                    outcome
11081                                }),
11082                            );
11083                        }
11084                        outcomes.extend(self.current_token_deletion_recovery(
11085                            CurrentTokenDeletionRequest {
11086                                atn,
11087                                expected_symbols: expected_symbols.clone(),
11088                                request: recovery_request.clone(),
11089                                visiting,
11090                                memo,
11091                                expected,
11092                            },
11093                        ));
11094                        if outcomes.len() == before_recovery {
11095                            outcomes.extend(self.consuming_failure_fallback(
11096                                ConsumingFailureFallback {
11097                                    atn,
11098                                    target: *target,
11099                                    request: recovery_request,
11100                                    symbol,
11101                                    expected_symbols,
11102                                    decision_start_index: next_decision_start_index,
11103                                    decision,
11104                                },
11105                                visiting,
11106                                memo,
11107                                expected,
11108                            ));
11109                        }
11110                    }
11111                }
11112            }
11113            if self.decision_override_generation != decision_override_generation {
11114                break;
11115            }
11116        }
11117
11118        visiting.remove(&visit_key);
11119        self.record_prediction_diagnostics(atn, state, index, &outcomes);
11120        if matches!(
11121            self.prediction_mode,
11122            PredictionMode::Ll | PredictionMode::LlExactAmbigDetection
11123        ) {
11124            discard_recovered_outcomes_if_clean_path_exists(&mut outcomes, &self.recognition_arena);
11125        }
11126        dedupe_outcomes(&mut outcomes, &self.recognition_arena);
11127        memo.insert(key, outcomes.clone());
11128        outcomes
11129    }
11130
11131    /// Follows an epsilon or semantic-action transition while preserving the
11132    /// path-local side effects that may later become generated action output.
11133    fn recognize_epsilon_or_action_step(
11134        &mut self,
11135        atn: &Atn,
11136        request: &RecognizeRequest<'_>,
11137        step: EpsilonActionStep,
11138        scratch: RecognizeScratch<'_>,
11139    ) -> Vec<RecognizeOutcome> {
11140        let RecognizeScratch {
11141            visiting,
11142            memo,
11143            expected,
11144        } = scratch;
11145        let action = step.action_rule_index.map(|rule_index| {
11146            let stop_index = self.rule_stop_token_index(request.index, request.consumed_eof);
11147            step.action_index.map_or_else(
11148                || {
11149                    ParserAction::new(
11150                        step.source_state,
11151                        rule_index,
11152                        request.rule_start_index,
11153                        stop_index,
11154                    )
11155                },
11156                |action_index| {
11157                    ParserAction::new_indexed(
11158                        step.source_state,
11159                        rule_index,
11160                        action_index,
11161                        request.rule_start_index,
11162                        stop_index,
11163                    )
11164                },
11165            )
11166        });
11167        let next_member_values = if action.is_some() {
11168            member_values_after_action(
11169                step.source_state,
11170                request.member_actions,
11171                request.semantics,
11172                &request.member_values,
11173            )
11174        } else {
11175            request.member_values.clone()
11176        };
11177        let next_return_values = action.map_or_else(
11178            || request.return_values.clone(),
11179            |action| {
11180                return_values_after_action(
11181                    step.source_state,
11182                    action.rule_index(),
11183                    request.return_actions,
11184                    request.semantics,
11185                    &request.return_values,
11186                )
11187            },
11188        );
11189
11190        self.recognize_state(
11191            atn,
11192            RecognizeRequest {
11193                state_number: step.target,
11194                stop_state: request.stop_state,
11195                index: request.index,
11196                rule_start_index: request.rule_start_index,
11197                decision_start_index: step.decision_start_index,
11198                init_action_rules: request.init_action_rules,
11199                predicates: request.predicates,
11200                semantics: request.semantics,
11201                rule_args: request.rule_args,
11202                member_actions: request.member_actions,
11203                return_actions: request.return_actions,
11204                local_int_arg: request.local_int_arg,
11205                member_values: next_member_values,
11206                return_values: next_return_values,
11207                rule_alt_number: if step.left_recursive_boundary.is_some() {
11208                    0
11209                } else {
11210                    step.alt_number
11211                },
11212                track_alt_numbers: request.track_alt_numbers,
11213                consumed_eof: request.consumed_eof,
11214                committed_decision: request.committed_decision,
11215                precedence: request.precedence,
11216                depth: request.depth + 1,
11217                recovery_symbols: step.recovery_symbols,
11218                recovery_state: step.recovery_state,
11219            },
11220            visiting,
11221            memo,
11222            expected,
11223        )
11224        .into_iter()
11225        .map(|mut outcome| {
11226            prepend_decision(&mut outcome, step.decision);
11227            if let Some(rule_index) = step.left_recursive_boundary {
11228                let boundary = self.arena_boundary_node(rule_index, step.alt_number);
11229                self.arena_prepend(&mut outcome.nodes, boundary);
11230            }
11231            if let Some(action) = action {
11232                outcome.actions.insert(0, action);
11233            }
11234            outcome
11235        })
11236        .collect()
11237    }
11238
11239    /// Reads the token type at an absolute token-stream index without moving
11240    /// the parser's stream cursor. The fast recognizer probes lookahead at
11241    /// every state visit, so avoiding the seek round-trip is a measurable
11242    /// hot-path win on long inputs.
11243    fn token_type_at(&mut self, index: usize) -> i32 {
11244        if index >= FAST_RECOGNIZER_DEFERRED_FILL_AT && !self.input.is_filled() {
11245            self.input.fill();
11246        }
11247        self.input.token_type_at_index(index)
11248    }
11249
11250    /// Returns the cached `state_expected_symbols` set for an ATN state.
11251    ///
11252    /// The fast recognizer consults this set on every state visit through
11253    /// `next_recovery_context`; the underlying DFS is a pure function of the
11254    /// ATN, so caching the `Rc` lets clones reduce to a reference bump.
11255    ///
11256    /// Caching is layered through `intern_recovery_symbols` so two ATN states
11257    /// with the same expected-symbol set share one `Rc`. That invariant is
11258    /// what lets `FastRecognizeKey` hash on `recovery_symbols` by pointer
11259    /// without violating the `Hash`/`Eq` contract — `recovery_symbols` is
11260    /// always interned before it ends up in a key.
11261    fn cached_state_expected_symbols(
11262        &mut self,
11263        atn: &Atn,
11264        state_number: usize,
11265    ) -> Rc<BTreeSet<i32>> {
11266        if let Some(cached) = self.state_expected_cache.get(&state_number) {
11267            return Rc::clone(cached);
11268        }
11269        let symbols = state_expected_symbols(atn, state_number);
11270        let entry = self.intern_recovery_symbols(symbols);
11271        self.state_expected_cache
11272            .insert(state_number, Rc::clone(&entry));
11273        entry
11274    }
11275
11276    fn cached_state_expected_token_set(
11277        &mut self,
11278        atn: &Atn,
11279        state_number: usize,
11280    ) -> Rc<TokenBitSet> {
11281        if let Some(cached) = self.state_expected_token_cache.get(&state_number) {
11282            return Rc::clone(cached);
11283        }
11284        // Purely a function of the ATN, so back the per-parser cache with the
11285        // thread-shared one — fresh parser instances (one per parse in
11286        // generated usage) start warm instead of rewalking the ATN.
11287        let symbols = with_shared_atn_caches(atn, |cache| {
11288            if let Some(cached) = cache.state_expected_tokens.get(&state_number) {
11289                return Rc::clone(cached);
11290            }
11291            let symbols = Rc::new(state_expected_token_set(atn, state_number));
11292            cache
11293                .state_expected_tokens
11294                .insert(state_number, Rc::clone(&symbols));
11295            symbols
11296        });
11297        self.state_expected_token_cache
11298            .insert(state_number, Rc::clone(&symbols));
11299        symbols
11300    }
11301
11302    fn cached_state_can_reach_rule_stop(&mut self, atn: &Atn, state_number: usize) -> bool {
11303        if self.rule_stop_reach_cache.len() <= state_number {
11304            self.rule_stop_reach_cache
11305                .resize_with(atn.states().len().max(state_number + 1), || None);
11306        }
11307        if let Some(reaches) = self.rule_stop_reach_cache[state_number] {
11308            return reaches;
11309        }
11310        let reaches = with_shared_atn_caches(atn, |cache| {
11311            *cache
11312                .rule_stop_reach
11313                .entry(state_number)
11314                .or_insert_with(|| state_can_reach_rule_stop(atn, state_number))
11315        });
11316        self.rule_stop_reach_cache[state_number] = Some(reaches);
11317        reaches
11318    }
11319
11320    /// Returns the parser's empty `recovery_symbols` singleton so callers can
11321    /// share an `Rc` instead of allocating new `BTreeSet`s for the common case.
11322    fn empty_recovery_symbols(&self) -> Rc<BTreeSet<i32>> {
11323        Rc::clone(&self.empty_recovery_symbols)
11324    }
11325
11326    /// Returns the interned `Rc` form of a `recovery_symbols` set so the fast
11327    /// recognizer can hash and compare keys by pointer.
11328    ///
11329    /// Every `Rc<BTreeSet<i32>>` that flows into a `FastRecognizeKey` must
11330    /// come from this method or the empty singleton; otherwise two
11331    /// content-equal `Rc`s could end up with different `Rc::as_ptr` values,
11332    /// and the pointer-keyed hash on `FastRecognizeKey` would split equivalent
11333    /// recognition coordinates.
11334    fn intern_recovery_symbols(&mut self, set: BTreeSet<i32>) -> Rc<BTreeSet<i32>> {
11335        if set.is_empty() {
11336            return Rc::clone(&self.empty_recovery_symbols);
11337        }
11338        let candidate = Rc::new(set);
11339        match self.recovery_symbols_intern.get(&candidate) {
11340            Some(existing) => Rc::clone(existing),
11341            None => {
11342                self.recovery_symbols_intern
11343                    .insert(Rc::clone(&candidate), Rc::clone(&candidate));
11344                candidate
11345            }
11346        }
11347    }
11348
11349    /// Returns the cached look-1 entry for a decision state, computing it on
11350    /// first use. Multi-alternative states are visited many times during
11351    /// recognition; sharing the entry through `Rc` keeps the prefilter to one
11352    /// hash lookup per visit.
11353    fn cached_decision_lookahead(
11354        &mut self,
11355        atn: &Atn,
11356        state: AtnState<'_>,
11357        rule_stop_state: usize,
11358    ) -> Rc<DecisionLookahead> {
11359        // Hit the parser-instance cache first. Decision lookahead is purely
11360        // a function of the ATN/state, so on a warm cache we skip the
11361        // thread-local + RefCell + HashMap-entry dance through
11362        // SHARED_ATN_CACHES — which on multi-trans-heavy grammars (C# does
11363        // ~58K multi-trans visits per parse) shows up as RefCell borrow and
11364        // hashmap-entry overhead in profiles.
11365        if let Some(cached) = self.decision_lookahead_cache.get(&state.state_number()) {
11366            return Rc::clone(cached);
11367        }
11368        let entry = with_shared_atn_caches(atn, |cache| {
11369            if let Some(cached) = cache.decision_lookahead.get(&state.state_number()) {
11370                return Rc::clone(cached);
11371            }
11372            let mut entry = DecisionLookahead {
11373                transitions: Vec::with_capacity(state.transitions().len()),
11374            };
11375            for transition in &state.transitions() {
11376                entry.transitions.push(transition_first_set(
11377                    atn,
11378                    transition,
11379                    rule_stop_state,
11380                    &mut cache.first_set,
11381                ));
11382            }
11383            let entry = Rc::new(entry);
11384            cache
11385                .decision_lookahead
11386                .insert(state.state_number(), Rc::clone(&entry));
11387            entry
11388        });
11389        self.decision_lookahead_cache
11390            .insert(state.state_number(), Rc::clone(&entry));
11391        entry
11392    }
11393
11394    fn cached_rule_first_set(
11395        &mut self,
11396        atn: &Atn,
11397        target: usize,
11398        child_stop: usize,
11399    ) -> Rc<FirstSet> {
11400        if self.rule_first_set_cache.len() <= target {
11401            self.rule_first_set_cache
11402                .resize_with(atn.states().len().max(target + 1), || None);
11403        }
11404        if let Some(cached) = self
11405            .rule_first_set_cache
11406            .get(target)
11407            .and_then(Option::as_ref)
11408        {
11409            return Rc::clone(cached);
11410        }
11411        let first = with_shared_first_set_cache(atn, |cache| {
11412            rule_first_set(atn, target, child_stop, cache)
11413        });
11414        self.rule_first_set_cache[target] = Some(Rc::clone(&first));
11415        first
11416    }
11417
11418    fn state_can_reenter_without_consuming(&mut self, atn: &Atn, state_number: usize) -> bool {
11419        let atn_key = SharedAtnCacheKey::for_atn(atn);
11420        if self.empty_cycle_cache_atn != Some(atn_key) {
11421            self.empty_cycle_cache.clear();
11422            self.empty_cycle_cache_atn = Some(atn_key);
11423        }
11424        if self.empty_cycle_cache.len() <= state_number {
11425            self.empty_cycle_cache
11426                .resize_with(atn.state_count().max(state_number + 1), || None);
11427        }
11428        if let Some(cached) = self.empty_cycle_cache[state_number] {
11429            return cached;
11430        }
11431        let mut visited = FxHashSet::with_capacity_and_hasher(64, FxBuildHasher::default());
11432        let result = self.empty_path_reaches_state(atn, state_number, state_number, &mut visited);
11433        self.empty_cycle_cache[state_number] = Some(result);
11434        result
11435    }
11436
11437    fn empty_path_reaches_state(
11438        &mut self,
11439        atn: &Atn,
11440        state_number: usize,
11441        target_state: usize,
11442        visited: &mut FxHashSet<usize>,
11443    ) -> bool {
11444        enum Work {
11445            Visit(usize),
11446            RuleFollow {
11447                target: usize,
11448                rule_index: usize,
11449                follow_state: usize,
11450            },
11451        }
11452
11453        let mut work = vec![Work::Visit(state_number)];
11454        while let Some(item) = work.pop() {
11455            match item {
11456                Work::Visit(state_number) => {
11457                    if !visited.insert(state_number) {
11458                        continue;
11459                    }
11460                    let Some(state) = atn.state(state_number) else {
11461                        continue;
11462                    };
11463                    let transitions = state.transitions();
11464                    for transition_index in (0..transitions.len()).rev() {
11465                        let transition = transitions
11466                            .get(transition_index)
11467                            .expect("in-bounds parser transition");
11468                        let kind = transition.kind();
11469                        let target = transition.target();
11470                        match kind {
11471                            ParserTransitionKind::Atom
11472                            | ParserTransitionKind::Range
11473                            | ParserTransitionKind::Set
11474                            | ParserTransitionKind::NotSet
11475                            | ParserTransitionKind::Wildcard => {}
11476                            ParserTransitionKind::Rule => {
11477                                if target == target_state {
11478                                    return true;
11479                                }
11480                                work.push(Work::RuleFollow {
11481                                    target,
11482                                    rule_index: transition.arg0() as usize,
11483                                    follow_state: transition.arg1() as usize,
11484                                });
11485                                work.push(Work::Visit(target));
11486                            }
11487                            ParserTransitionKind::Epsilon
11488                            | ParserTransitionKind::Predicate
11489                            | ParserTransitionKind::Action
11490                            | ParserTransitionKind::Precedence => {
11491                                if target == target_state {
11492                                    return true;
11493                                }
11494                                work.push(Work::Visit(target));
11495                            }
11496                        }
11497                    }
11498                }
11499                Work::RuleFollow {
11500                    target,
11501                    rule_index,
11502                    follow_state,
11503                } => {
11504                    let Some(child_stop) = atn.rule_to_stop_state().get(rule_index) else {
11505                        continue;
11506                    };
11507                    if self.cached_rule_first_set(atn, target, child_stop).nullable {
11508                        if follow_state == target_state {
11509                            return true;
11510                        }
11511                        work.push(Work::Visit(follow_state));
11512                    }
11513                }
11514            }
11515        }
11516        false
11517    }
11518
11519    /// Decides whether the clean recognizer should use its full outcome memo
11520    /// table for this coordinate.
11521    fn clean_memo_enabled_for_key(&mut self, key: &FastRecognizeKey) -> bool {
11522        match self.clean_memo_mode {
11523            CleanMemoMode::Promote => true,
11524            CleanMemoMode::Probe => self.observe_clean_memo_probe(key),
11525            CleanMemoMode::Sparse => {
11526                self.clean_memo_sparse_samples += 1;
11527                if self.clean_memo_sparse_samples < CLEAN_MEMO_REPROBE_INTERVAL {
11528                    return false;
11529                }
11530                self.clean_memo_sparse_samples = 0;
11531                self.clean_memo_mode = CleanMemoMode::Probe;
11532                self.clean_memo_probe_samples = 0;
11533                self.clean_memo_probe_repeats = 0;
11534                self.clean_memo_probe_seen.clear();
11535                self.observe_clean_memo_probe(key)
11536            }
11537        }
11538    }
11539
11540    fn observe_clean_memo_probe(&mut self, key: &FastRecognizeKey) -> bool {
11541        self.clean_memo_probe_samples += 1;
11542        if !self.clean_memo_probe_seen.insert(key.clone()) {
11543            self.clean_memo_probe_repeats += 1;
11544        }
11545        if self.clean_memo_probe_repeats >= CLEAN_MEMO_REPEAT_LIMIT {
11546            self.clean_memo_mode = CleanMemoMode::Promote;
11547            self.clean_memo_probe_seen.clear();
11548            return true;
11549        }
11550        if self.clean_memo_probe_samples >= CLEAN_MEMO_PROBE_LIMIT {
11551            self.clean_memo_mode = CleanMemoMode::Sparse;
11552            self.clean_memo_sparse_samples = 0;
11553            self.clean_memo_probe_seen.clear();
11554            return false;
11555        }
11556        true
11557    }
11558
11559    /// Borrows the visible token at an absolute token-stream index.
11560    fn token_at(&self, index: usize) -> Option<TokenView<'_>> {
11561        self.input.get(index)
11562    }
11563
11564    /// Returns the compact token ID at an absolute token-stream index.
11565    fn token_id_at(&self, index: usize) -> Option<TokenId> {
11566        self.input.get_id(index)
11567    }
11568
11569    fn arena_token_node(&mut self, index: usize, error: bool) -> RecognizedNodeId {
11570        let token = self
11571            .token_id_at(index)
11572            .expect("recognized token index must exist in the token store");
11573        let node = if error {
11574            ArenaRecognizedNode::ErrorToken { token }
11575        } else {
11576            ArenaRecognizedNode::Token { token }
11577        };
11578        self.recognition_arena.push_node(node)
11579    }
11580
11581    fn arena_missing_token_node(
11582        &mut self,
11583        token_type: i32,
11584        at_index: usize,
11585        text: String,
11586    ) -> RecognizedNodeId {
11587        let extra = self
11588            .recognition_arena
11589            .push_extra(RecognitionExtra::MissingToken {
11590                token_type,
11591                at_index: u32::try_from(at_index).expect("missing-token stream index fits in u32"),
11592                text,
11593            });
11594        self.recognition_arena
11595            .push_node(ArenaRecognizedNode::MissingToken { extra })
11596    }
11597
11598    fn arena_rule_node(&mut self, spec: ArenaRuleSpec) -> RecognizedNodeId {
11599        let ArenaRuleSpec {
11600            rule_index,
11601            invoking_state,
11602            alt_number,
11603            start_index,
11604            stop_index,
11605            return_values,
11606            children,
11607        } = spec;
11608        let return_values = (!return_values.is_empty()).then(|| {
11609            self.recognition_arena
11610                .push_extra(RecognitionExtra::ReturnValues(return_values))
11611        });
11612        self.recognition_arena.push_node(ArenaRecognizedNode::Rule {
11613            rule_index: u32::try_from(rule_index).expect("rule index fits in u32"),
11614            invoking_state: i32::try_from(invoking_state).expect("invoking state fits in i32"),
11615            alt_number: u32::try_from(alt_number).expect("alternative number fits in u32"),
11616            start_index: u32::try_from(start_index).expect("rule start index fits in u32"),
11617            stop_index: stop_index
11618                .map(|index| u32::try_from(index).expect("rule stop index fits in u32")),
11619            return_values,
11620            children,
11621        })
11622    }
11623
11624    fn arena_boundary_node(&mut self, rule_index: usize, alt_number: usize) -> RecognizedNodeId {
11625        self.recognition_arena
11626            .push_node(ArenaRecognizedNode::LeftRecursiveBoundary {
11627                rule_index: u32::try_from(rule_index).expect("rule index fits in u32"),
11628                alt_number: u32::try_from(alt_number).expect("alternative number fits in u32"),
11629            })
11630    }
11631
11632    fn arena_prepend(&mut self, sequence: &mut NodeSeqId, node: RecognizedNodeId) {
11633        *sequence = self.recognition_arena.prepend(*sequence, node);
11634    }
11635
11636    // The perf-counters branch reads the process environment, so this cannot
11637    // become const even when Clippy analyzes the branch-free configuration.
11638    #[allow(clippy::missing_const_for_fn)]
11639    fn finish_recognition_arena(&mut self, root: NodeSeqId, diagnostics: DiagnosticSeqId) {
11640        self.last_recognition_arena_root = root;
11641        self.last_recognition_arena_diagnostics = diagnostics;
11642        #[cfg(feature = "perf-counters")]
11643        if std::env::var("ANTLR_PERF_DUMP").is_ok() {
11644            let stats = self.recognition_arena_stats();
11645            #[allow(clippy::print_stderr)]
11646            {
11647                eprintln!("perf recognition_nodes_total={}", stats.total_nodes);
11648                eprintln!("perf recognition_nodes_live={}", stats.live_nodes);
11649                eprintln!("perf recognition_nodes_dead={}", stats.dead_nodes);
11650                eprintln!("perf recognition_nodes_capacity={}", stats.node_capacity);
11651                eprintln!("perf recognition_links_total={}", stats.total_links);
11652                eprintln!("perf recognition_links_live={}", stats.live_links);
11653                eprintln!("perf recognition_links_dead={}", stats.dead_links);
11654                eprintln!("perf recognition_links_capacity={}", stats.link_capacity);
11655                eprintln!("perf recognition_extras_total={}", stats.total_extras);
11656                eprintln!("perf recognition_extras_live={}", stats.live_extras);
11657                eprintln!("perf recognition_extras_dead={}", stats.dead_extras);
11658                eprintln!("perf recognition_extras_capacity={}", stats.extra_capacity);
11659            }
11660        }
11661    }
11662
11663    fn reset_recognition_arena(&mut self) {
11664        self.recognition_arena.reset();
11665        self.last_recognition_arena_root = NodeSeqId::EMPTY;
11666        self.last_recognition_arena_diagnostics = DiagnosticSeqId::EMPTY;
11667    }
11668
11669    /// Normalizes the current token-stream cursor to the next parser-visible
11670    /// token before capturing a rule start boundary.
11671    fn current_visible_index(&mut self) -> usize {
11672        let index = self.input.index();
11673        self.input.seek(index);
11674        self.input.index()
11675    }
11676
11677    /// Reports whether a child rule reached EOF cleanly while also recording
11678    /// an EOF expectation from a longer path inside that child.
11679    fn child_expected_reaches_clean_eof(
11680        &mut self,
11681        children: &[RecognizeOutcome],
11682        expected: &ExpectedTokens,
11683    ) -> bool {
11684        let Some(index) = expected.index else {
11685            return false;
11686        };
11687        self.token_type_at(index) == TOKEN_EOF
11688            && children
11689                .iter()
11690                .any(|child| child.diagnostics.is_empty() && child.index == index)
11691    }
11692
11693    /// Finds the previous token visible to the parser before `index`.
11694    ///
11695    /// The token stream cursor skips hidden-channel tokens, so subtracting one
11696    /// from a visible-token index can point at whitespace. Parser intervals use
11697    /// this helper to stop at the previous visible token while preserving hidden
11698    /// text inside the rendered interval.
11699    fn previous_token_index(&self, index: usize) -> Option<usize> {
11700        self.input.previous_visible_token_index(index)
11701    }
11702
11703    /// Returns the token-stream index used as a rule stop boundary.
11704    ///
11705    /// EOF transitions keep the cursor on EOF, so a rule that consumed EOF must
11706    /// stop at `index` rather than at the previous visible token.
11707    fn rule_stop_token_index(&mut self, index: usize, consumed_eof: bool) -> Option<usize> {
11708        if consumed_eof && self.token_type_at(index) == TOKEN_EOF {
11709            Some(index)
11710        } else {
11711            self.previous_token_index(index)
11712        }
11713    }
11714
11715    /// Stop-token index for a rule's `@after` action, matching the boundary that
11716    /// `finish_rule` records on the rule context.
11717    ///
11718    /// A rule that matched EOF leaves the cursor parked on the EOF token
11719    /// (`CommonTokenStream::consume` does not advance past EOF), so the stop is
11720    /// the current index rather than the previous visible token. Without this,
11721    /// `$stop`/`$text` in an `@after` action on a rule like `r: a* EOF;` would
11722    /// report the token before EOF (or `None` for empty input), diverging from
11723    /// the rule context that `finish_rule` builds.
11724    ///
11725    /// NOTE: this infers `consumed_eof` from the cursor, which is wrong when a
11726    /// rule ends right before EOF without matching it (the cursor is parked on
11727    /// EOF, but the rule did not consume it). Prefer
11728    /// [`Self::after_action_stop_index_for_tree`], which reuses the stop token the
11729    /// rule context already recorded with the real flag. Kept for callers without
11730    /// the rule tree in hand.
11731    #[must_use]
11732    pub fn after_action_stop_index(&mut self, current_index: usize) -> Option<usize> {
11733        let consumed_eof = self.token_type_at(current_index) == TOKEN_EOF;
11734        self.rule_stop_token_index(current_index, consumed_eof)
11735    }
11736
11737    /// Stop-token index for a rule's `@after` action, taken from the stop token
11738    /// the rule context already recorded.
11739    ///
11740    /// `finish_rule` computes the rule stop with the real `consumed_eof` flag, so
11741    /// reading it back keeps `$stop`/`$text` in an `@after` action aligned with
11742    /// the rule context — even when the rule ends immediately before EOF without
11743    /// matching it (cursor parked on EOF, but `consumed_eof` is false). Falls back
11744    /// to the cursor-based inference only when the tree carries no rule stop.
11745    #[must_use]
11746    pub fn after_action_stop_index_for_tree(
11747        &mut self,
11748        tree: ParseTree,
11749        current_index: usize,
11750    ) -> Option<usize> {
11751        if let Some(stop) = self
11752            .node(tree)
11753            .as_rule()
11754            .and_then(crate::tree::RuleNodeView::stop_id)
11755        {
11756            return Some(stop.index());
11757        }
11758        self.after_action_stop_index(current_index)
11759    }
11760
11761    /// Start-token index for a rule's `@after` action, taken from the start token
11762    /// the rule context already recorded.
11763    ///
11764    /// `enter_rule` sets the rule context start to the first visible token (it
11765    /// skips leading hidden-channel tokens), so reading it back keeps `$start` /
11766    /// `$text` in an `@after` action aligned with the rule context — even when the
11767    /// rule begins after a hidden prefix (e.g. leading whitespace) that the raw
11768    /// pre-rule cursor still points at. Falls back to `fallback_index` only when
11769    /// the tree carries no rule start.
11770    #[must_use]
11771    pub fn after_action_start_index_for_tree(
11772        &self,
11773        tree: ParseTree,
11774        fallback_index: usize,
11775    ) -> usize {
11776        if let Some(start) = self
11777            .node(tree)
11778            .as_rule()
11779            .and_then(crate::tree::RuleNodeView::start_id)
11780        {
11781            return start.index();
11782        }
11783        fallback_index
11784    }
11785
11786    /// Returns the rule stop token for a selected parse path.
11787    ///
11788    /// EOF transitions do not advance the token-stream cursor, so an EOF match
11789    /// must use the current token rather than the previous visible token.
11790    fn rule_stop_token_id(&mut self, index: usize, consumed_eof: bool) -> Option<TokenId> {
11791        self.rule_stop_token_index(index, consumed_eof)
11792            .and_then(|token_index| self.token_id_at(token_index))
11793    }
11794
11795    /// Recovers from a semantic predicate with an ANTLR `<fail='...'>` option.
11796    ///
11797    /// Generated Java reports the failed-predicate message at the current
11798    /// lookahead, then consumes until rule recovery can resume. The metadata
11799    /// runtime models the same visible tree shape by keeping skipped tokens as
11800    /// error nodes and returning from the active rule at EOF.
11801    fn predicate_failure_recovery(
11802        &mut self,
11803        request: PredicateFailureRecovery<'_>,
11804    ) -> RecognizeOutcome {
11805        let PredicateFailureRecovery {
11806            rule_index,
11807            index,
11808            message,
11809            member_values,
11810            return_values,
11811            rule_alt_number,
11812        } = request;
11813        let rule_name = self
11814            .rule_names()
11815            .get(rule_index)
11816            .map_or_else(|| rule_index.to_string(), Clone::clone);
11817        let diagnostic = diagnostic_for_token(
11818            self.token_at(index).as_ref(),
11819            format!("rule {rule_name} {message}"),
11820        );
11821        let mut reversed_nodes = NodeSeqId::EMPTY;
11822        let mut next_index = index;
11823        loop {
11824            let symbol = self.token_type_at(next_index);
11825            if symbol == TOKEN_EOF {
11826                break;
11827            }
11828            let error = self.arena_token_node(next_index, true);
11829            self.arena_prepend(&mut reversed_nodes, error);
11830            let after = self.consume_index(next_index, symbol);
11831            if after == next_index {
11832                break;
11833            }
11834            next_index = after;
11835        }
11836        let nodes = self.recognition_arena.reverse_sequence(reversed_nodes);
11837        let diagnostics = self
11838            .recognition_arena
11839            .prepend_diagnostic(DiagnosticSeqId::EMPTY, diagnostic);
11840        RecognizeOutcome {
11841            index: next_index,
11842            consumed_eof: false,
11843            alt_number: rule_alt_number,
11844            member_values,
11845            return_values,
11846            diagnostics,
11847            decisions: Vec::new(),
11848            actions: Vec::new(),
11849            nodes,
11850        }
11851    }
11852
11853    /// Evaluates a user hook for a predicate coordinate that has no generated
11854    /// runtime table entry.
11855    fn parser_semantic_hook_result(
11856        &mut self,
11857        request: ParserSemanticHookRequest<'_>,
11858    ) -> Option<bool> {
11859        let ParserSemanticHookRequest {
11860            index,
11861            rule_index,
11862            pred_index,
11863            context,
11864            local_int_arg,
11865            member_values,
11866        } = request;
11867        let rule_name = self.rule_names().get(rule_index).cloned();
11868        self.input.seek(index);
11869        let input = &mut self.input;
11870        let semantic_hooks = &mut self.semantic_hooks;
11871        let mut ctx = ParserSemCtx {
11872            input,
11873            tree_storage: &self.tree,
11874            rule_index,
11875            coordinate_index: pred_index,
11876            rule_name,
11877            context,
11878            tree: None,
11879            local_int_arg,
11880            member_values,
11881            action: None,
11882        };
11883        semantic_hooks.sempred(&mut ctx, rule_index, pred_index)
11884    }
11885
11886    /// Re-inserts unknown-predicate coordinates recorded before a nested
11887    /// interpreted recognition, preserving order and skipping any the nested
11888    /// call already recorded, so a generated parent's fail-loud coordinates
11889    /// survive descending into an interpreted child.
11890    fn restore_prior_unknown_predicate_hits(&mut self, prior: Vec<(usize, usize)>) {
11891        if prior.is_empty() {
11892            return;
11893        }
11894        let mut merged = prior;
11895        for coordinate in std::mem::take(&mut self.unknown_predicate_hits) {
11896            if !merged.contains(&coordinate) {
11897                merged.push(coordinate);
11898            }
11899        }
11900        self.unknown_predicate_hits = merged;
11901    }
11902
11903    /// Re-inserts unhandled action coordinates recorded before a nested
11904    /// committed parse so only that child parse's misses affect its result.
11905    fn restore_prior_unhandled_action_hits(&mut self, prior: Vec<(usize, usize)>) {
11906        if prior.is_empty() {
11907            return;
11908        }
11909        let mut merged = prior;
11910        for coordinate in std::mem::take(&mut self.unhandled_action_hits) {
11911            if !merged.contains(&coordinate) {
11912                merged.push(coordinate);
11913            }
11914        }
11915        self.unhandled_action_hits = merged;
11916    }
11917
11918    /// Applies the active [`UnknownSemanticPolicy`] to a predicate coordinate
11919    /// that has no entry in the generated predicate table.
11920    ///
11921    /// Under [`UnknownSemanticPolicy::Error`] the coordinate is recorded and
11922    /// the guarded path is abandoned; the parse entry surfaces the recorded
11923    /// coordinates as [`AntlrError::Unsupported`] once recognition finishes,
11924    /// because a parse that consulted an unknown predicate is unreliable no
11925    /// matter which paths were ultimately selected.
11926    fn unknown_predicate_result(&mut self, rule_index: usize, pred_index: usize) -> bool {
11927        apply_unknown_predicate_policy(
11928            self.unknown_predicate_policy,
11929            rule_index,
11930            pred_index,
11931            &mut self.unknown_predicate_hits,
11932        )
11933    }
11934
11935    /// Builds the fail-loud error for unknown predicate coordinates recorded
11936    /// by the current parse, if any.
11937    fn unknown_semantic_error(&self) -> Option<AntlrError> {
11938        use std::fmt::Write as _;
11939        if self.unknown_predicate_hits.is_empty() && self.unhandled_action_hits.is_empty() {
11940            return None;
11941        }
11942        let mut message = String::new();
11943        for (rule_index, pred_index) in &self.unknown_predicate_hits {
11944            if !message.is_empty() {
11945                message.push_str("; ");
11946            }
11947            let _ = match self.rule_names().get(*rule_index) {
11948                Some(rule_name) => write!(
11949                    message,
11950                    "unsupported semantic predicate: rule={rule_name}({rule_index}) pred_index={pred_index}"
11951                ),
11952                None => write!(
11953                    message,
11954                    "unsupported semantic predicate: rule_index={rule_index} pred_index={pred_index}"
11955                ),
11956            };
11957        }
11958        for (rule_index, source_state) in &self.unhandled_action_hits {
11959            if !message.is_empty() {
11960                message.push_str("; ");
11961            }
11962            let _ = match self.rule_names().get(*rule_index) {
11963                Some(rule_name) => write!(
11964                    message,
11965                    "unhandled semantic action: rule={rule_name}({rule_index}) state={source_state}"
11966                ),
11967                None => write!(
11968                    message,
11969                    "unhandled semantic action: rule_index={rule_index} state={source_state}"
11970                ),
11971            };
11972        }
11973        Some(AntlrError::Unsupported(message))
11974    }
11975
11976    /// Evaluates one lowered predicate expression at the requested input
11977    /// position.
11978    ///
11979    /// This sits in the prediction hot loop, so the context borrows the
11980    /// speculative member state read-only and the rule name by reference —
11981    /// no per-evaluation allocation. Only the hook escape path materializes
11982    /// owned copies, and only when a hook is actually consulted.
11983    fn parser_semir_predicate_matches(
11984        &mut self,
11985        semantics: &ParserSemantics,
11986        predicate: &ParserSemanticPredicate,
11987        request: ParserSemanticHookRequest<'_>,
11988    ) -> bool {
11989        self.input.seek(request.index);
11990        let rule_name = self
11991            .data
11992            .rule_names()
11993            .get(request.rule_index)
11994            .map(String::as_str);
11995        let unknown_predicate_policy = self.unknown_predicate_policy;
11996        let mut ctx = ParserSemIrCtx {
11997            input: &mut self.input,
11998            tree_storage: &self.tree,
11999            semantic_hooks: &mut self.semantic_hooks,
12000            rule_index: request.rule_index,
12001            coordinate_index: request.pred_index,
12002            rule_name,
12003            context: request.context,
12004            local_int_arg: request.local_int_arg,
12005            member_values: request.member_values,
12006            invoked_predicates: &mut self.invoked_predicates,
12007            unknown_predicate_policy,
12008            unknown_predicate_hits: &mut self.unknown_predicate_hits,
12009        };
12010        semir::eval_pred(&semantics.ir, predicate.expr, &mut ctx)
12011    }
12012
12013    fn fast_parser_predicate_matches(
12014        &mut self,
12015        context: Option<FastPredicateContext<'_>>,
12016        transition: ParserTransition<'_>,
12017        index: usize,
12018    ) -> bool {
12019        let Some(context) = context else {
12020            return true;
12021        };
12022        let rule_index = transition.arg0() as usize;
12023        let pred_index = transition.arg1() as usize;
12024        let key = (index, rule_index, pred_index);
12025        if let Some(result) = self.fast_predicate_cache.get(&key) {
12026            return *result;
12027        }
12028        let result = self.parser_predicate_matches(PredicateEval {
12029            index,
12030            rule_index,
12031            pred_index,
12032            predicates: context.predicates,
12033            semantics: context.semantics,
12034            context: None,
12035            local_int_arg: None,
12036            member_values: context.member_values,
12037        });
12038        self.fast_predicate_cache.insert(key, result);
12039        result
12040    }
12041
12042    fn parser_predicate_matches(&mut self, eval: PredicateEval<'_>) -> bool {
12043        let PredicateEval {
12044            index,
12045            rule_index,
12046            pred_index,
12047            predicates,
12048            semantics,
12049            context,
12050            local_int_arg,
12051            member_values,
12052        } = eval;
12053        if let Some((semantics, predicate)) = semantics.and_then(|semantics| {
12054            semantics
12055                .predicates
12056                .iter()
12057                .find(|predicate| {
12058                    predicate.rule_index == rule_index && predicate.pred_index == pred_index
12059                })
12060                .map(|predicate| (semantics, predicate))
12061        }) {
12062            return self.parser_semir_predicate_matches(
12063                semantics,
12064                predicate,
12065                ParserSemanticHookRequest {
12066                    index,
12067                    rule_index,
12068                    pred_index,
12069                    context,
12070                    local_int_arg,
12071                    member_values,
12072                },
12073            );
12074        }
12075        let Some((_, _, predicate)) = predicates
12076            .iter()
12077            .find(|(rule, pred, _)| *rule == rule_index && *pred == pred_index)
12078        else {
12079            if let Some(result) = self.parser_semantic_hook_result(ParserSemanticHookRequest {
12080                index,
12081                rule_index,
12082                pred_index,
12083                context,
12084                local_int_arg,
12085                member_values,
12086            }) {
12087                return result;
12088            }
12089            return self.unknown_predicate_result(rule_index, pred_index);
12090        };
12091        self.input.seek(index);
12092        match predicate {
12093            ParserPredicate::True => true,
12094            ParserPredicate::False => false,
12095            ParserPredicate::FalseWithMessage { .. } => false,
12096            ParserPredicate::Invoke { value } => {
12097                let key = (rule_index, pred_index);
12098                if !self.invoked_predicates.contains(&key) {
12099                    self.invoked_predicates.push(key);
12100                    use std::io::Write as _;
12101                    let mut stdout = std::io::stdout().lock();
12102                    let _ = writeln!(stdout, "eval={value}");
12103                }
12104                *value
12105            }
12106            ParserPredicate::LookaheadTextEquals { offset, text } => self
12107                .input
12108                .lt(*offset)
12109                .is_some_and(|token| Token::text(&token) == Some(*text)),
12110            ParserPredicate::LookaheadNotEquals { offset, token_type } => {
12111                self.la(*offset) != *token_type
12112            }
12113            ParserPredicate::TokenPairAdjacent => {
12114                let Some(first) = self.input.lt_id(-2).map(TokenId::index) else {
12115                    return false;
12116                };
12117                let Some(second) = self.input.lt_id(-1).map(TokenId::index) else {
12118                    return false;
12119                };
12120                first + 1 == second
12121            }
12122            ParserPredicate::ContextChildRuleTextNotEquals { rule_index, text } => context
12123                .and_then(|context| {
12124                    context
12125                        .child_rules(&self.tree, self.input.token_store(), *rule_index)
12126                        .next()
12127                        .map(crate::tree::RuleNodeView::text)
12128                })
12129                .is_none_or(|actual| actual != *text),
12130            ParserPredicate::LocalIntEquals { value } => {
12131                local_int_arg.is_none_or(|(_, actual)| actual == *value)
12132            }
12133            ParserPredicate::LocalIntLessOrEqual { value } => {
12134                local_int_arg.is_none_or(|(_, actual)| actual <= *value)
12135            }
12136            ParserPredicate::MemberModuloEquals {
12137                member,
12138                modulus,
12139                value,
12140                equals,
12141            } => {
12142                if *modulus == 0 {
12143                    return false;
12144                }
12145                let actual = member_values.scalar(*member).unwrap_or_default() % *modulus;
12146                (actual == *value) == *equals
12147            }
12148            ParserPredicate::MemberEquals {
12149                member,
12150                value,
12151                equals,
12152            } => {
12153                let actual = member_values.scalar(*member).unwrap_or_default();
12154                (actual == *value) == *equals
12155            }
12156        }
12157    }
12158
12159    /// Returns a generated fail-option message for a predicate coordinate.
12160    fn parser_predicate_failure_message(
12161        &self,
12162        rule_index: usize,
12163        pred_index: usize,
12164        predicates: &[(usize, usize, ParserPredicate)],
12165    ) -> Option<&'static str> {
12166        predicates
12167            .iter()
12168            .find_map(|(rule, pred, predicate)| match predicate {
12169                ParserPredicate::FalseWithMessage { message }
12170                    if *rule == rule_index && *pred == pred_index =>
12171                {
12172                    Some(*message)
12173                }
12174                _ => None,
12175            })
12176    }
12177
12178    /// Returns a generated fail-option message for a `SemIR` predicate
12179    /// coordinate.
12180    pub fn parser_semantic_ir_predicate_failure_message(
12181        &self,
12182        rule_index: usize,
12183        pred_index: usize,
12184        semantics: &ParserSemantics,
12185    ) -> Option<&'static str> {
12186        semantics
12187            .predicates
12188            .iter()
12189            .find(|predicate| {
12190                predicate.rule_index == rule_index && predicate.pred_index == pred_index
12191            })
12192            .and_then(|predicate| predicate.failure_message)
12193    }
12194
12195    /// Returns the token-stream index after consuming `symbol` at `index`.
12196    ///
12197    /// EOF is not advanced by ANTLR token streams, so EOF transitions keep the
12198    /// index stable and rely on `consumed_eof` to record that EOF was matched.
12199    /// The parser's stream cursor is left untouched: speculative recognition
12200    /// reads ahead by absolute index, so paying for `seek` on every visited
12201    /// state would dominate the hot path. Real consumption is committed by
12202    /// `parse_atn_rule` via `seek` once a viable outcome is selected.
12203    fn consume_index(&mut self, index: usize, symbol: i32) -> usize {
12204        if symbol == TOKEN_EOF {
12205            return index;
12206        }
12207        self.input.next_visible_after(index)
12208    }
12209
12210    /// Builds ANTLR's no-viable-alternative diagnostic for an ambiguous
12211    /// decision that failed after consuming a shared prefix.
12212    fn no_viable_alternative(&self, start_index: usize, error_index: usize) -> ParserDiagnostic {
12213        let text = display_input_text(&self.input.text(start_index, error_index));
12214        diagnostic_for_token(
12215            self.token_at(error_index).as_ref(),
12216            format!("no viable alternative at input '{text}'"),
12217        )
12218    }
12219
12220    /// Selects the diagnostic for a failed consuming transition after all
12221    /// recovery repairs have been ruled out.
12222    fn recovery_failure_diagnostic(
12223        &self,
12224        index: usize,
12225        decision_start_index: Option<usize>,
12226        expected_symbols: &BTreeSet<i32>,
12227    ) -> ParserDiagnostic {
12228        if expected_symbols.len() > 1 {
12229            if let Some(decision_start) = no_viable_decision_start(decision_start_index, index) {
12230                return self.no_viable_alternative(decision_start, index);
12231            }
12232        }
12233        diagnostic_for_token(
12234            self.token_at(index).as_ref(),
12235            format!(
12236                "mismatched input {} expecting {}",
12237                self.token_at(index)
12238                    .as_ref()
12239                    .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
12240                self.expected_symbols_display(expected_symbols)
12241            ),
12242        )
12243    }
12244
12245    /// Builds the EOF diagnostic used when ANTLR unwinds a failed nested rule
12246    /// instead of inserting missing tokens in the caller.
12247    fn eof_rule_recovery_diagnostic(
12248        &self,
12249        index: usize,
12250        expected_symbols: &BTreeSet<i32>,
12251        expected: &ExpectedTokens,
12252    ) -> ParserDiagnostic {
12253        let symbols = if expected.index == Some(index) && !expected.symbols.is_empty() {
12254            &expected.symbols
12255        } else {
12256            expected_symbols
12257        };
12258        diagnostic_for_token(
12259            self.token_at(index).as_ref(),
12260            format!(
12261                "mismatched input {} expecting {}",
12262                self.token_at(index)
12263                    .as_ref()
12264                    .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
12265                self.expected_symbols_display(symbols)
12266            ),
12267        )
12268    }
12269
12270    /// Returns token text for a buffered token interval used by generated
12271    /// `$text` actions.
12272    ///
12273    /// ANTLR treats EOF as a range boundary rather than printable input text,
12274    /// even when an action interval explicitly stops at the EOF token.
12275    pub fn text_interval(&self, start: usize, stop: Option<usize>) -> String {
12276        let Some(stop) = stop else {
12277            return String::new();
12278        };
12279        let stop = if self
12280            .token_at(stop)
12281            .is_some_and(|token| token.token_type() == TOKEN_EOF)
12282        {
12283            let Some(previous) = self.previous_token_index(stop) else {
12284                return String::new();
12285            };
12286            previous
12287        } else {
12288            stop
12289        };
12290        self.input.text(start, stop)
12291    }
12292
12293    /// Resets per-parse prediction diagnostics while keeping the parser-level
12294    /// reporting flag configured by generated harness code.
12295    fn clear_prediction_diagnostics(&mut self) {
12296        self.prediction_diagnostics.clear();
12297        self.reported_prediction_diagnostics.clear();
12298    }
12299
12300    /// Drops every per-parse cache that depends on ATN identity or pins
12301    /// recovery-symbol allocations.
12302    ///
12303    /// `BaseParser::parse_atn_rule` takes `&Atn` on each invocation, so the
12304    /// same parser instance can legally be driven against different grammars
12305    /// in sequence. The four caches reset here are keyed by raw ATN
12306    /// coordinates (state numbers, rule indexes) and would silently hand back
12307    /// entries from a previous ATN if reused — pruning lookahead against the
12308    /// wrong transitions or pinning recovery `Rc<BTreeSet<i32>>` allocations
12309    /// for the rest of the process. Clearing them on every parse entry keeps
12310    /// the perf wins (caches still amortize within one parse) without making
12311    /// long-lived parsers leak memory or surface stale ATN data:
12312    ///
12313    /// * `rule_first_set_cache` and `decision_lookahead_cache` are pure
12314    ///   functions of the ATN's state graph.
12315    /// * `state_expected_cache`, `state_expected_token_cache`,
12316    ///   `rule_stop_reach_cache`, and
12317    ///   `recovery_symbols_intern` together form
12318    ///   the identity invariant that lets `FastRecognizeKey` hash
12319    ///   `recovery_symbols` by pointer; they have to be cleared in lockstep
12320    ///   so a stale interned `Rc` cannot outlive its map entry.
12321    /// * `empty_cycle_cache` is grammar-static and carries its own ATN key, so
12322    ///   it is retained here and invalidated lazily when the ATN changes.
12323    fn reset_per_parse_caches(&mut self) {
12324        self.rule_first_set_cache.clear();
12325        self.decision_lookahead_cache.clear();
12326        self.ll1_decision_cache.clear();
12327        self.fast_predicate_cache.clear();
12328        self.rule_stop_reach_cache.clear();
12329        self.clean_memo_mode = CleanMemoMode::Probe;
12330        self.clean_memo_probe_seen.clear();
12331        self.clean_memo_probe_samples = 0;
12332        self.clean_memo_probe_repeats = 0;
12333        self.clean_memo_sparse_samples = 0;
12334        self.recovery_symbols_intern.clear();
12335        self.state_expected_cache.clear();
12336        self.state_expected_token_cache.clear();
12337    }
12338
12339    /// Buffers ANTLR-style diagnostic-listener messages for decision states
12340    /// where multiple clean alternatives survive full-context recognition.
12341    fn record_prediction_diagnostics(
12342        &mut self,
12343        atn: &Atn,
12344        state: AtnState<'_>,
12345        start_index: usize,
12346        outcomes: &[RecognizeOutcome],
12347    ) {
12348        if !self.report_diagnostic_errors || state.transitions().len() < 2 {
12349            return;
12350        }
12351        let Some(decision) = atn
12352            .decision_to_state()
12353            .iter()
12354            .position(|state_number| state_number == state.state_number())
12355        else {
12356            return;
12357        };
12358        let Some(rule_index) = state.rule_index() else {
12359            return;
12360        };
12361        let mut alts_by_end = BTreeMap::<usize, BTreeSet<usize>>::new();
12362        for outcome in outcomes
12363            .iter()
12364            .filter(|outcome| outcome.diagnostics.is_empty())
12365        {
12366            let Some(alt) = outcome.decisions.first() else {
12367                continue;
12368            };
12369            alts_by_end
12370                .entry(outcome.index)
12371                .or_default()
12372                .insert(alt + 1);
12373        }
12374        let Some((&end_index, ambig_alts)) = alts_by_end
12375            .iter()
12376            .filter(|(_, alts)| alts.len() > 1)
12377            .max_by_key(|(end, _)| *end)
12378        else {
12379            return;
12380        };
12381        let rule_name = self
12382            .rule_names()
12383            .get(rule_index)
12384            .map_or_else(|| "<unknown>".to_owned(), Clone::clone);
12385        let stop_index = self.previous_token_index(end_index).unwrap_or(start_index);
12386        let input = display_input_text(&self.input.text(start_index, stop_index));
12387        let alts = ambig_alts
12388            .iter()
12389            .map(usize::to_string)
12390            .collect::<Vec<_>>()
12391            .join(", ");
12392        let key = (decision, start_index, format!("{alts}:{input}"));
12393        if !self.reported_prediction_diagnostics.insert(key) {
12394            return;
12395        }
12396        let start_diagnostic = diagnostic_for_token(
12397            self.token_at(start_index),
12398            format!("reportAttemptingFullContext d={decision} ({rule_name}), input='{input}'"),
12399        );
12400        let stop_diagnostic = diagnostic_for_token(
12401            self.token_at(stop_index),
12402            format!(
12403                "reportAmbiguity d={decision} ({rule_name}): ambigAlts={{{alts}}}, input='{input}'"
12404            ),
12405        );
12406        self.prediction_diagnostics.push(start_diagnostic);
12407        self.prediction_diagnostics.push(stop_diagnostic);
12408    }
12409
12410    /// Formats the tokens expected from an ATN state using ANTLR display names.
12411    pub fn expected_tokens_at_state(&self, atn: &Atn, state_number: usize) -> String {
12412        expected_symbols_display(
12413            &state_expected_symbols(atn, state_number),
12414            self.vocabulary(),
12415        )
12416    }
12417
12418    /// Expected-token set at the parser's current ATN state — ANTLR's
12419    /// `getExpectedTokens()`. Generated recognizers expose this as
12420    /// `self.expected_tokens()` for embedded test actions
12421    /// (`self.expected_tokens().to_token_string(self.vocabulary())`).
12422    pub fn expected_tokens_current(&self, atn: &Atn) -> ExpectedTokenSet {
12423        let state = usize::try_from(self.data().state()).unwrap_or(0);
12424        ExpectedTokenSet {
12425            symbols: state_expected_symbols(atn, state),
12426        }
12427    }
12428
12429    /// Enables the bail error strategy: the first syntax error aborts the
12430    /// parse instead of recovering.
12431    pub const fn set_bail_on_error(&mut self, bail: bool) {
12432        self.bail_on_error = bail;
12433    }
12434
12435    /// Whether the bail error strategy is active.
12436    #[must_use]
12437    pub const fn bail_on_error(&self) -> bool {
12438        self.bail_on_error
12439    }
12440
12441    /// Names of the rules on the live invocation stack, current rule first —
12442    /// ANTLR's `getRuleInvocationStack()`.
12443    pub fn rule_invocation_stack(&self) -> Vec<String> {
12444        self.rule_context_stack
12445            .iter()
12446            .rev()
12447            .map(|frame| {
12448                self.data()
12449                    .rule_names()
12450                    .get(frame.rule_index)
12451                    .cloned()
12452                    .unwrap_or_else(|| format!("<{}>", frame.rule_index))
12453            })
12454            .collect()
12455    }
12456
12457    /// Invoking-state chain for the active rule context, current rule first.
12458    ///
12459    /// The root frame is excluded, matching Java's `RuleContext.toString()`.
12460    pub fn active_invocation_states(&self) -> Vec<isize> {
12461        self.rule_context_stack
12462            .iter()
12463            .skip(1)
12464            .rev()
12465            .map(|frame| frame.invoking_state)
12466            .collect()
12467    }
12468
12469    /// Formats a buffered token in ANTLR's diagnostic token display form.
12470    pub fn token_display_at(&self, index: usize) -> Option<String> {
12471        self.token_at(index).map(|token| format!("{token}"))
12472    }
12473}
12474
12475impl<'atn, S, H> DirectAdaptiveParser<'atn, '_, S, H>
12476where
12477    S: TokenSource,
12478    H: SemanticHooks,
12479{
12480    fn parse_rule(
12481        &mut self,
12482        rule_index: usize,
12483        invoking_state: isize,
12484        precedence: i32,
12485    ) -> DirectAdaptiveParseResult<ParseTree> {
12486        let start_state = self.atn.rule_to_start_state().get(rule_index).ok_or(
12487            DirectAdaptiveParseControl::Fallback(DirectAdaptiveFallback::MissingAtn),
12488        )?;
12489        let stop_state = self
12490            .atn
12491            .rule_to_stop_state()
12492            .get(rule_index)
12493            .filter(|state| *state != usize::MAX)
12494            .ok_or(DirectAdaptiveParseControl::Fallback(
12495                DirectAdaptiveFallback::MissingAtn,
12496            ))?;
12497        let start_index = self.parser.current_visible_index();
12498        let mut context = ParserRuleContext::new(rule_index, invoking_state);
12499        if let Some(token) = self.parser.token_id_at(start_index) {
12500            self.parser.set_context_start(&mut context, token);
12501        }
12502        let mut state_number = start_state;
12503        let mut consumed_eof = false;
12504        while state_number != stop_state {
12505            self.step()?;
12506            let (transition, boundary) = self.next_transition(state_number, precedence)?;
12507            if boundary.is_some() {
12508                return Err(DirectAdaptiveParseControl::Fallback(
12509                    DirectAdaptiveFallback::LeftRecursiveBoundary,
12510                ));
12511            }
12512            match transition.data() {
12513                Transition::Epsilon { target } => {
12514                    state_number = target;
12515                }
12516                Transition::Precedence {
12517                    target,
12518                    precedence: transition_precedence,
12519                } => {
12520                    if transition_precedence < precedence {
12521                        return Err(DirectAdaptiveParseControl::Fallback(
12522                            DirectAdaptiveFallback::Precedence,
12523                        ));
12524                    }
12525                    state_number = target;
12526                }
12527                Transition::Rule {
12528                    rule_index,
12529                    follow_state,
12530                    precedence: rule_precedence,
12531                    ..
12532                } => {
12533                    let child = self.parse_rule(
12534                        rule_index,
12535                        invoking_state_number(state_number),
12536                        rule_precedence,
12537                    )?;
12538                    if self.parser.build_parse_trees {
12539                        self.parser.tree.add_child(&mut context, child);
12540                    }
12541                    state_number = follow_state;
12542                }
12543                Transition::Atom { .. }
12544                | Transition::Range { .. }
12545                | Transition::Set { .. }
12546                | Transition::NotSet { .. }
12547                | Transition::Wildcard { .. } => {
12548                    let (matched_eof, child) = self.consume_transition(transition)?;
12549                    consumed_eof |= matched_eof;
12550                    if let Some(child) = child {
12551                        self.parser.tree.add_child(&mut context, child);
12552                    }
12553                    state_number = transition.target();
12554                }
12555                Transition::Predicate { .. } => {
12556                    return Err(DirectAdaptiveParseControl::Fallback(
12557                        DirectAdaptiveFallback::Predicate,
12558                    ));
12559                }
12560                Transition::Action { .. } => {
12561                    return Err(DirectAdaptiveParseControl::Fallback(
12562                        DirectAdaptiveFallback::Action,
12563                    ));
12564                }
12565            }
12566        }
12567
12568        let stop_index = self
12569            .parser
12570            .rule_stop_token_index(self.parser.input.index(), consumed_eof);
12571        if let Some(token) = stop_index.and_then(|index| self.parser.token_id_at(index)) {
12572            self.parser.set_context_stop(&mut context, token);
12573        }
12574        Ok(self.parser.rule_node(context))
12575    }
12576
12577    const fn step(&mut self) -> DirectAdaptiveParseResult<()> {
12578        self.steps += 1;
12579        if self.steps > ADAPTIVE_DIRECT_STEP_LIMIT {
12580            return Err(DirectAdaptiveParseControl::Fallback(
12581                DirectAdaptiveFallback::StepLimit,
12582            ));
12583        }
12584        Ok(())
12585    }
12586
12587    fn next_transition(
12588        &mut self,
12589        state_number: usize,
12590        precedence: i32,
12591    ) -> DirectAdaptiveParseResult<(ParserTransition<'atn>, Option<usize>)> {
12592        let state = self
12593            .atn
12594            .state(state_number)
12595            .ok_or(DirectAdaptiveParseControl::Fallback(
12596                DirectAdaptiveFallback::MissingAtn,
12597            ))?;
12598        if state.is_rule_stop() {
12599            return Err(DirectAdaptiveParseControl::Fallback(
12600                DirectAdaptiveFallback::RuleStop,
12601            ));
12602        }
12603        let transition_index =
12604            self.transition_index(state_number, state.transitions().len(), precedence)?;
12605        let transition = state.transitions().get(transition_index).ok_or(
12606            DirectAdaptiveParseControl::Fallback(DirectAdaptiveFallback::NoTransition),
12607        )?;
12608        let boundary = match &transition.data() {
12609            Transition::Epsilon { target } | Transition::Precedence { target, .. } => {
12610                left_recursive_boundary(self.atn, state, *target)
12611            }
12612            _ => None,
12613        };
12614        Ok((transition, boundary))
12615    }
12616
12617    fn transition_index(
12618        &mut self,
12619        state_number: usize,
12620        transition_count: usize,
12621        precedence: i32,
12622    ) -> DirectAdaptiveParseResult<usize> {
12623        match transition_count {
12624            0 => Err(DirectAdaptiveParseControl::Fallback(
12625                DirectAdaptiveFallback::NoTransition,
12626            )),
12627            1 => Ok(0),
12628            _ => {
12629                if let Some(alt) = self.ll1_transition_index(state_number, transition_count)? {
12630                    return Ok(alt);
12631                }
12632                let decision = self
12633                    .decision_by_state
12634                    .get(state_number)
12635                    .and_then(|decision| *decision)
12636                    .ok_or(DirectAdaptiveParseControl::Fallback(
12637                        DirectAdaptiveFallback::UnknownDecision,
12638                    ))?;
12639                let prediction = self
12640                    .simulator
12641                    .adaptive_predict_stream_info_with_precedence(
12642                        decision,
12643                        direct_precedence(precedence),
12644                        &mut self.parser.input,
12645                    )
12646                    .map_err(|_| {
12647                        DirectAdaptiveParseControl::Fallback(DirectAdaptiveFallback::Prediction)
12648                    })?;
12649                if prediction.has_semantic_context {
12650                    return Err(DirectAdaptiveParseControl::Fallback(
12651                        DirectAdaptiveFallback::SemanticContext,
12652                    ));
12653                }
12654                prediction
12655                    .alt
12656                    .checked_sub(1)
12657                    .filter(|index| *index < transition_count)
12658                    .ok_or(DirectAdaptiveParseControl::Fallback(
12659                        DirectAdaptiveFallback::InvalidAlt,
12660                    ))
12661            }
12662        }
12663    }
12664
12665    fn ll1_transition_index(
12666        &mut self,
12667        state_number: usize,
12668        transition_count: usize,
12669    ) -> DirectAdaptiveParseResult<Option<usize>> {
12670        let state = self
12671            .atn
12672            .state(state_number)
12673            .ok_or(DirectAdaptiveParseControl::Fallback(
12674                DirectAdaptiveFallback::MissingAtn,
12675            ))?;
12676        if state.precedence_rule_decision() {
12677            return Ok(None);
12678        }
12679        let Some(rule_stop) = state
12680            .rule_index()
12681            .and_then(|rule_index| self.atn.rule_to_stop_state().get(rule_index))
12682        else {
12683            return Ok(None);
12684        };
12685        let symbol = self.parser.input.la_token(1);
12686        let entry = self
12687            .parser
12688            .cached_decision_lookahead(self.atn, state, rule_stop);
12689        Ok(
12690            ll1_greedy_alt(&entry, symbol, state.non_greedy())
12691                .filter(|alt| *alt < transition_count),
12692        )
12693    }
12694
12695    fn consume_transition(
12696        &mut self,
12697        transition: ParserTransition<'_>,
12698    ) -> DirectAdaptiveParseResult<(bool, Option<ParseTree>)> {
12699        let symbol = self.parser.input.la_token(1);
12700        if !transition.matches(symbol, 1, self.atn.max_token_type()) {
12701            return Err(DirectAdaptiveParseControl::Fallback(
12702                DirectAdaptiveFallback::TokenMismatch,
12703            ));
12704        }
12705        let token = self
12706            .parser
12707            .input
12708            .lt_id(1)
12709            .ok_or(DirectAdaptiveParseControl::Fallback(
12710                DirectAdaptiveFallback::TokenMismatch,
12711            ))?;
12712        let matched_eof = symbol == TOKEN_EOF;
12713        if !matched_eof {
12714            self.parser.consume();
12715        }
12716        let child = self
12717            .parser
12718            .build_parse_trees
12719            .then(|| self.parser.terminal_tree(token));
12720        Ok((matched_eof, child))
12721    }
12722}
12723
12724impl<S, H> CommittedAtnParser<'_, '_, '_, S, H>
12725where
12726    S: TokenSource,
12727    H: SemanticHooks,
12728{
12729    fn parse_rule(
12730        &mut self,
12731        rule_index: usize,
12732        precedence: i32,
12733        inherited_local_int_arg: Option<(usize, i64)>,
12734        init_expected_state: Option<usize>,
12735    ) -> Result<CommittedRuleOutcome, AntlrError> {
12736        let start_state = self
12737            .atn
12738            .rule_to_start_state()
12739            .get(rule_index)
12740            .ok_or_else(|| {
12741                AntlrError::Unsupported(format!("rule {rule_index} has no start state"))
12742            })?;
12743        let stop_state = self
12744            .atn
12745            .rule_to_stop_state()
12746            .get(rule_index)
12747            .filter(|state| *state != usize::MAX)
12748            .ok_or_else(|| {
12749                AntlrError::Unsupported(format!("rule {rule_index} has no stop state"))
12750            })?;
12751        let left_recursive = self
12752            .atn
12753            .state(start_state)
12754            .is_some_and(AtnState::left_recursive_rule);
12755        if let Some(error) = self.parser.rule_depth_cap_violation() {
12756            return Err(error);
12757        }
12758        if let Some(error) = self.parser.parse_listener_enter_rule(rule_index) {
12759            return Err(error);
12760        }
12761        let mut context = if left_recursive {
12762            self.parser.enter_recursion_rule(
12763                invoking_state_number(start_state),
12764                rule_index,
12765                precedence,
12766            )
12767        } else {
12768            self.parser
12769                .enter_rule(invoking_state_number(start_state), rule_index)
12770        };
12771        let rule_start_index = self.parser.current_visible_index();
12772        let local_int_arg =
12773            usize::try_from(context.invoking_state())
12774                .ok()
12775                .and_then(|source_state| {
12776                    rule_local_int_arg(
12777                        self.options.rule_args,
12778                        source_state,
12779                        rule_index,
12780                        inherited_local_int_arg,
12781                    )
12782                });
12783        if self.options.init_action_rules.contains(&rule_index) {
12784            let action = ParserAction::new_rule_init(
12785                rule_index,
12786                rule_start_index,
12787                init_expected_state.or(Some(start_state)),
12788            );
12789            if !self
12790                .parser
12791                .parser_rule_init_hook_with_context(action, &context, local_int_arg)
12792            {
12793                self.deferred_actions.push(action);
12794            }
12795        }
12796        let mut consumed_eof = false;
12797        let result = self.walk_rule(
12798            rule_index,
12799            start_state,
12800            stop_state,
12801            precedence,
12802            rule_start_index,
12803            local_int_arg,
12804            left_recursive,
12805            &mut context,
12806            &mut consumed_eof,
12807        );
12808
12809        let result = match result {
12810            Ok(()) => Ok(if left_recursive {
12811                self.parser.finish_recursion_rule(context, consumed_eof)
12812            } else {
12813                self.parser.finish_rule(context, consumed_eof)
12814            }),
12815            Err(error) if self.parser.bail_on_error() => {
12816                if left_recursive {
12817                    self.parser.unroll_recursion_context();
12818                } else {
12819                    self.parser.exit_rule();
12820                }
12821                Err(error)
12822            }
12823            Err(error) => {
12824                self.parser
12825                    .recover_generated_rule(&mut context, self.atn, error);
12826                Ok(if left_recursive {
12827                    self.parser.finish_recursion_rule(context, consumed_eof)
12828                } else {
12829                    self.parser.finish_rule(context, consumed_eof)
12830                })
12831            }
12832        };
12833        self.parser.parse_listener_exit_rule(rule_index);
12834        result.map(|tree| CommittedRuleOutcome { tree, consumed_eof })
12835    }
12836
12837    #[allow(clippy::too_many_arguments)]
12838    fn walk_rule(
12839        &mut self,
12840        rule_index: usize,
12841        mut state_number: usize,
12842        stop_state: usize,
12843        precedence: i32,
12844        rule_start_index: usize,
12845        local_int_arg: Option<(usize, i64)>,
12846        left_recursive: bool,
12847        context: &mut ParserRuleContext,
12848        consumed_eof: &mut bool,
12849    ) -> Result<(), AntlrError> {
12850        let mut entered_loops = BTreeSet::new();
12851        let mut visited_coordinates = FxHashSet::default();
12852        let mut guarded_input_index = self.parser.input.index();
12853        while state_number != stop_state {
12854            let input_index = self.parser.input.index();
12855            if input_index != guarded_input_index {
12856                visited_coordinates.clear();
12857                guarded_input_index = input_index;
12858            }
12859            if !visited_coordinates.insert((state_number, input_index)) {
12860                return Err(AntlrError::Unsupported(format!(
12861                    "committed parser encountered a non-consuming ATN cycle at state \
12862                         {state_number}"
12863                )));
12864            }
12865            let state = self.atn.state(state_number).ok_or_else(|| {
12866                AntlrError::Unsupported(format!("missing parser ATN state {state_number}"))
12867            })?;
12868            if state.is_rule_stop() {
12869                return Err(AntlrError::Unsupported(format!(
12870                    "rule {rule_index} reached unexpected stop state {state_number}"
12871                )));
12872            }
12873            let transition_index = {
12874                let mut decision_context = CommittedDecisionContext {
12875                    precedence,
12876                    local_int_arg,
12877                    context,
12878                    entered_loops: &mut entered_loops,
12879                };
12880                self.transition_index(state, &mut decision_context)?
12881            };
12882            let transition = state.transitions().get(transition_index).ok_or_else(|| {
12883                AntlrError::Unsupported(format!(
12884                    "missing transition {transition_index} from parser ATN state {state_number}"
12885                ))
12886            })?;
12887
12888            let next_alt = next_alt_number(
12889                state,
12890                state.transitions().len(),
12891                transition_index,
12892                context.alt_number(),
12893                self.options.track_alt_numbers,
12894            );
12895            if self.options.track_alt_numbers && context.alt_number() == 0 && next_alt != 0 {
12896                context.set_alt_number(next_alt);
12897            }
12898            let next_context_alt = next_alt_number(
12899                state,
12900                state.transitions().len(),
12901                transition_index,
12902                context.context_alt_number(),
12903                self.options.track_context_alt_numbers,
12904            );
12905            if self.options.track_context_alt_numbers
12906                && context.context_alt_number() == 0
12907                && next_context_alt != 0
12908            {
12909                context.set_context_alt_number(next_context_alt);
12910            }
12911
12912            if left_recursive
12913                && left_recursive_boundary(self.atn, state, transition.target()).is_some()
12914            {
12915                if let Some(error) = self.parser.rule_depth_cap_violation() {
12916                    return Err(error);
12917                }
12918                self.parser.parse_listener_exit_rule(rule_index);
12919                self.parser.push_new_recursion_context_with_previous(
12920                    invoking_state_number(
12921                        self.atn
12922                            .rule_to_start_state()
12923                            .get(rule_index)
12924                            .unwrap_or(state_number),
12925                    ),
12926                    rule_index,
12927                    context,
12928                );
12929                if let Some(error) = self.parser.parse_listener_enter_rule(rule_index) {
12930                    return Err(error);
12931                }
12932            }
12933            state_number = self.apply_transition(
12934                state_number,
12935                transition,
12936                precedence,
12937                rule_start_index,
12938                local_int_arg,
12939                context,
12940                consumed_eof,
12941            )?;
12942        }
12943        Ok(())
12944    }
12945
12946    fn transition_index(
12947        &mut self,
12948        state: AtnState<'_>,
12949        decision_context: &mut CommittedDecisionContext<'_>,
12950    ) -> Result<usize, AntlrError> {
12951        let transition_count = state.transitions().len();
12952        if transition_count == 1 {
12953            return Ok(0);
12954        }
12955        let Some(decision) = self
12956            .decision_by_state
12957            .get(state.state_number())
12958            .copied()
12959            .flatten()
12960        else {
12961            return Err(AntlrError::Unsupported(format!(
12962                "parser ATN state {} has {transition_count} transitions but is not a decision",
12963                state.state_number()
12964            )));
12965        };
12966
12967        let decision_start = self.parser.input.index();
12968        let overridden_transition = if self.parser.semantic_hooks.observes_parser_decisions() {
12969            self.parser
12970                .semantic_hooks
12971                .parser_decision_override(decision, decision_start, transition_count)
12972                .and_then(|alternative| alternative.checked_sub(1))
12973                .filter(|alternative| *alternative < transition_count)
12974        } else {
12975            None
12976        };
12977        if let Some(selected) = overridden_transition {
12978            self.update_loop_selection(state, selected, decision_context);
12979            return Ok(selected);
12980        }
12981
12982        if !state.precedence_rule_decision() {
12983            let loop_back = match state.kind() {
12984                AtnStateKind::PlusLoopBack | AtnStateKind::StarLoopBack => true,
12985                AtnStateKind::StarLoopEntry => decision_context
12986                    .entered_loops
12987                    .contains(&state.state_number()),
12988                _ => false,
12989            };
12990            let children = self.parser.sync_decision(
12991                self.atn,
12992                state.state_number(),
12993                !decision_context.context.has_matched_child(),
12994                loop_back,
12995            )?;
12996            for child in children {
12997                self.parser.add_parse_child(decision_context.context, child);
12998            }
12999        }
13000
13001        let prediction_precedence = if state.precedence_rule_decision() {
13002            usize::try_from(decision_context.precedence.max(0)).unwrap_or_default()
13003        } else {
13004            0
13005        };
13006        let prediction_context = {
13007            let return_states = self
13008                .parser
13009                .prediction_context_return_states(self.atn)
13010                .collect::<Vec<_>>();
13011            self.simulator
13012                .intern_prediction_context(self.parser.rule_context_version(), return_states)
13013        };
13014        self.simulator.set_exact_ambig_detection(
13015            self.parser.prediction_mode() == PredictionMode::LlExactAmbigDetection,
13016        );
13017        let prediction_mode = self.parser.prediction_mode();
13018        let prediction = match self.simulator.adaptive_predict_stream_info_sll_probe(
13019            decision,
13020            prediction_precedence,
13021            &mut self.parser.input,
13022        ) {
13023            Ok(prediction)
13024                if prediction.requires_full_context && prediction_mode != PredictionMode::Sll =>
13025            {
13026                self.simulator.adaptive_predict_stream_info_with_context(
13027                    decision,
13028                    prediction_precedence,
13029                    &mut self.parser.input,
13030                    prediction_context,
13031                )
13032            }
13033            prediction => prediction,
13034        };
13035        let mut prediction = match prediction {
13036            Ok(prediction) => prediction,
13037            Err(ParserAtnSimulatorError::NoViableAlt { index, .. })
13038                if state.precedence_rule_decision() =>
13039            {
13040                let enter_alt = state.transitions().iter().position(|transition| {
13041                    self.atn
13042                        .state(transition.target())
13043                        .is_some_and(|target| target.kind() != AtnStateKind::LoopEnd)
13044                });
13045                let exit_alt = state.transitions().iter().position(|transition| {
13046                    self.atn
13047                        .state(transition.target())
13048                        .is_some_and(|target| target.kind() == AtnStateKind::LoopEnd)
13049                });
13050                let selected = if self.parser.left_recursive_loop_enter_matches(
13051                    self.atn,
13052                    state.state_number(),
13053                    decision_context.precedence,
13054                ) {
13055                    enter_alt
13056                } else {
13057                    exit_alt
13058                };
13059                let Some(selected) = selected else {
13060                    return Err(self
13061                        .parser
13062                        .no_viable_alternative_error_at(decision_start, index));
13063                };
13064                ParserAtnPrediction {
13065                    alt: selected + 1,
13066                    requires_full_context: true,
13067                    has_semantic_context: true,
13068                    diagnostic: None,
13069                }
13070            }
13071            Err(ParserAtnSimulatorError::NoViableAlt { index, .. }) => {
13072                return Err(self
13073                    .parser
13074                    .no_viable_alternative_error_at(decision_start, index));
13075            }
13076            Err(ParserAtnSimulatorError::PredictionRequiresMoreLookahead) => {
13077                return Err(self.parser.no_viable_alternative_error(decision_start));
13078            }
13079            Err(error) => {
13080                return Err(AntlrError::Unsupported(format!(
13081                    "committed parser prediction failed at decision {decision}: {error:?}"
13082                )));
13083            }
13084        };
13085        let mut selected = prediction
13086            .alt
13087            .checked_sub(1)
13088            .filter(|index| *index < transition_count)
13089            .ok_or_else(|| self.parser.no_viable_alternative_error(decision_start))?;
13090
13091        let semantic_candidates = self.simulator.prediction_semantic_candidates();
13092        if !semantic_candidates.is_empty() {
13093            let predicted_alt = prediction.alt;
13094            let mut semantic_results = BTreeMap::new();
13095            let selected_alt = selected + 1;
13096            let selected_matches = self.semantic_alternative_matches(
13097                selected_alt,
13098                decision_context,
13099                &semantic_candidates,
13100            );
13101            semantic_results.insert(selected_alt, selected_matches);
13102            if !selected_matches {
13103                let alternatives = semantic_candidates
13104                    .iter()
13105                    .map(|candidate| candidate.alt)
13106                    .filter(|alternative| *alternative != 0 && *alternative <= transition_count)
13107                    .collect::<BTreeSet<_>>();
13108                selected = alternatives
13109                    .into_iter()
13110                    .find(|alternative| {
13111                        let matches = self.semantic_alternative_matches(
13112                            *alternative,
13113                            decision_context,
13114                            &semantic_candidates,
13115                        );
13116                        semantic_results.insert(*alternative, matches);
13117                        matches
13118                    })
13119                    .and_then(|alternative| alternative.checked_sub(1))
13120                    .ok_or_else(|| self.parser.no_viable_alternative_error(decision_start))?;
13121            }
13122            if self.parser.report_diagnostic_errors
13123                && let Some(diagnostic) = prediction.diagnostic.as_ref()
13124            {
13125                for alternative in diagnostic.conflicting_alts.clone() {
13126                    if semantic_results.contains_key(&alternative)
13127                        || !semantic_candidates
13128                            .iter()
13129                            .any(|candidate| candidate.alt == alternative)
13130                    {
13131                        continue;
13132                    }
13133                    let matches = self.semantic_alternative_matches(
13134                        alternative,
13135                        decision_context,
13136                        &semantic_candidates,
13137                    );
13138                    semantic_results.insert(alternative, matches);
13139                }
13140            }
13141            Self::filter_prediction_diagnostic(
13142                &mut prediction,
13143                predicted_alt,
13144                selected + 1,
13145                &semantic_results,
13146            );
13147        }
13148        self.parser.record_generated_prediction_diagnostic(
13149            self.atn,
13150            state.state_number(),
13151            &prediction,
13152        );
13153
13154        self.update_loop_selection(state, selected, decision_context);
13155        Ok(selected)
13156    }
13157
13158    fn semantic_alternative_matches(
13159        &mut self,
13160        alternative: usize,
13161        decision_context: &CommittedDecisionContext<'_>,
13162        candidates: &[ParserSemanticCandidate],
13163    ) -> bool {
13164        candidates
13165            .iter()
13166            .filter(|candidate| candidate.alt == alternative)
13167            .any(|candidate| {
13168                self.semantic_context_matches(&candidate.context, decision_context, candidate)
13169            })
13170    }
13171
13172    fn filter_prediction_diagnostic(
13173        prediction: &mut ParserAtnPrediction,
13174        predicted_alt: usize,
13175        selected_alt: usize,
13176        semantic_results: &BTreeMap<usize, bool>,
13177    ) {
13178        prediction.alt = selected_alt;
13179        if selected_alt != predicted_alt {
13180            prediction.diagnostic = None;
13181            return;
13182        }
13183        if let Some(diagnostic) = prediction.diagnostic.as_mut() {
13184            diagnostic
13185                .conflicting_alts
13186                .retain(|alternative| semantic_results.get(alternative).copied().unwrap_or(true));
13187            if diagnostic.conflicting_alts.len() < 2 {
13188                prediction.diagnostic = None;
13189            }
13190        }
13191    }
13192
13193    fn semantic_context_matches(
13194        &mut self,
13195        semantic_context: &SemanticContext,
13196        decision_context: &CommittedDecisionContext<'_>,
13197        candidate: &ParserSemanticCandidate,
13198    ) -> bool {
13199        match semantic_context {
13200            SemanticContext::None => true,
13201            SemanticContext::Predicate {
13202                rule_index,
13203                pred_index,
13204                ..
13205            } => {
13206                let mut matched_provenance = false;
13207                for predicate_call in candidate
13208                    .predicate_calls
13209                    .iter()
13210                    .filter(|call| call.rule_index == *rule_index && call.pred_index == *pred_index)
13211                {
13212                    matched_provenance = true;
13213                    let mut local_int_arg = decision_context.local_int_arg;
13214                    for rule_call in &predicate_call.rule_calls {
13215                        local_int_arg = rule_local_int_arg(
13216                            self.options.rule_args,
13217                            rule_call.source_state,
13218                            rule_call.rule_index,
13219                            local_int_arg,
13220                        );
13221                    }
13222                    if !self.semantic_predicate_matches(
13223                        *rule_index,
13224                        *pred_index,
13225                        decision_context,
13226                        local_int_arg,
13227                    ) {
13228                        return false;
13229                    }
13230                }
13231                if matched_provenance {
13232                    true
13233                } else {
13234                    self.semantic_predicate_matches(
13235                        *rule_index,
13236                        *pred_index,
13237                        decision_context,
13238                        decision_context.local_int_arg,
13239                    )
13240                }
13241            }
13242            SemanticContext::Precedence { precedence } => {
13243                *precedence >= decision_context.precedence
13244            }
13245            SemanticContext::And(children) => {
13246                for child in children {
13247                    if !self.semantic_context_matches(child, decision_context, candidate) {
13248                        return false;
13249                    }
13250                }
13251                true
13252            }
13253            SemanticContext::Or(children) => {
13254                for child in children {
13255                    if self.semantic_context_matches(child, decision_context, candidate) {
13256                        return true;
13257                    }
13258                }
13259                false
13260            }
13261        }
13262    }
13263
13264    fn semantic_predicate_matches(
13265        &mut self,
13266        rule_index: usize,
13267        pred_index: usize,
13268        decision_context: &CommittedDecisionContext<'_>,
13269        local_int_arg: Option<(usize, i64)>,
13270    ) -> bool {
13271        let member_values = self.parser.int_members.clone();
13272        self.parser.parser_predicate_matches(PredicateEval {
13273            index: self.parser.input.index(),
13274            rule_index,
13275            pred_index,
13276            predicates: self.options.predicates,
13277            semantics: self.options.semantics,
13278            context: Some(&*decision_context.context),
13279            local_int_arg,
13280            member_values: &member_values,
13281        })
13282    }
13283
13284    fn update_loop_selection(
13285        &self,
13286        state: AtnState<'_>,
13287        selected: usize,
13288        decision_context: &mut CommittedDecisionContext<'_>,
13289    ) {
13290        if state.kind() == AtnStateKind::StarLoopEntry {
13291            let enters = self
13292                .atn
13293                .state(
13294                    state
13295                        .transitions()
13296                        .get(selected)
13297                        .expect("selected transition is in bounds")
13298                        .target(),
13299                )
13300                .is_some_and(|target| target.kind() != AtnStateKind::LoopEnd);
13301            if enters {
13302                decision_context.entered_loops.insert(state.state_number());
13303            } else {
13304                decision_context.entered_loops.remove(&state.state_number());
13305            }
13306        }
13307    }
13308
13309    #[allow(clippy::too_many_arguments)]
13310    fn apply_transition(
13311        &mut self,
13312        source_state: usize,
13313        transition: ParserTransition<'_>,
13314        precedence: i32,
13315        rule_start_index: usize,
13316        local_int_arg: Option<(usize, i64)>,
13317        context: &mut ParserRuleContext,
13318        consumed_eof: &mut bool,
13319    ) -> Result<usize, AntlrError> {
13320        self.parser.set_state(invoking_state_number(source_state));
13321        match transition.data() {
13322            Transition::Epsilon { target } => Ok(target),
13323            Transition::Atom { target, label } => {
13324                let matched = self
13325                    .parser
13326                    .match_token_recovering(label, target, self.atn)?;
13327                *consumed_eof |= matched.consumed_eof();
13328                for child in matched.into_child_iter() {
13329                    self.parser.add_parse_child(context, child);
13330                }
13331                Ok(target)
13332            }
13333            Transition::Range {
13334                target,
13335                start,
13336                stop,
13337            } => {
13338                let matched =
13339                    self.parser
13340                        .match_set_recovering(&[(start, stop)], target, self.atn)?;
13341                *consumed_eof |= matched.consumed_eof();
13342                for child in matched.into_child_iter() {
13343                    self.parser.add_parse_child(context, child);
13344                }
13345                Ok(target)
13346            }
13347            Transition::Set { target, set } => {
13348                let matched = self
13349                    .parser
13350                    .match_token_set_recovering(set, target, self.atn)?;
13351                *consumed_eof |= matched.consumed_eof();
13352                for child in matched.into_child_iter() {
13353                    self.parser.add_parse_child(context, child);
13354                }
13355                Ok(target)
13356            }
13357            Transition::NotSet { target, set } => {
13358                let matched = self.parser.match_not_token_set_recovering(
13359                    set,
13360                    1,
13361                    self.atn.max_token_type(),
13362                    target,
13363                    self.atn,
13364                )?;
13365                *consumed_eof |= matched.consumed_eof();
13366                for child in matched.into_child_iter() {
13367                    self.parser.add_parse_child(context, child);
13368                }
13369                Ok(target)
13370            }
13371            Transition::Wildcard { target } => {
13372                let matched = self.parser.match_not_set_recovering(
13373                    &[],
13374                    1,
13375                    self.atn.max_token_type(),
13376                    target,
13377                    self.atn,
13378                )?;
13379                *consumed_eof |= matched.consumed_eof();
13380                for child in matched.into_child_iter() {
13381                    self.parser.add_parse_child(context, child);
13382                }
13383                Ok(target)
13384            }
13385            Transition::Rule {
13386                rule_index,
13387                follow_state,
13388                precedence: rule_precedence,
13389                ..
13390            } => {
13391                let marker = self
13392                    .parser
13393                    .push_invoking_state(invoking_state_number(source_state));
13394                let child = if self.parser.generated_rule_stack_check_due() {
13395                    grow_generated_rule_stack(|| {
13396                        self.parse_rule(
13397                            rule_index,
13398                            rule_precedence,
13399                            local_int_arg,
13400                            Some(follow_state),
13401                        )
13402                    })
13403                } else {
13404                    self.parse_rule(
13405                        rule_index,
13406                        rule_precedence,
13407                        local_int_arg,
13408                        Some(follow_state),
13409                    )
13410                };
13411                self.parser.discard_invoking_state(marker);
13412                let child = child?;
13413                *consumed_eof |= child.consumed_eof;
13414                self.parser.add_parse_child(context, child.tree);
13415                Ok(follow_state)
13416            }
13417            Transition::Predicate {
13418                target,
13419                rule_index,
13420                pred_index,
13421                ..
13422            } => {
13423                let member_values = self.parser.int_members.clone();
13424                if self.parser.parser_predicate_matches(PredicateEval {
13425                    index: self.parser.input.index(),
13426                    rule_index,
13427                    pred_index,
13428                    predicates: self.options.predicates,
13429                    semantics: self.options.semantics,
13430                    context: Some(context),
13431                    local_int_arg,
13432                    member_values: &member_values,
13433                }) {
13434                    return Ok(target);
13435                }
13436                if let Some(message) = self
13437                    .options
13438                    .semantics
13439                    .and_then(|semantics| {
13440                        self.parser.parser_semantic_ir_predicate_failure_message(
13441                            rule_index, pred_index, semantics,
13442                        )
13443                    })
13444                    .or_else(|| {
13445                        self.parser.parser_predicate_failure_message(
13446                            rule_index,
13447                            pred_index,
13448                            self.options.predicates,
13449                        )
13450                    })
13451                {
13452                    return Err(self
13453                        .parser
13454                        .failed_predicate_option_error(rule_index, message));
13455                }
13456                Err(self.parser.failed_predicate_error("semantic predicate"))
13457            }
13458            Transition::Action {
13459                target, rule_index, ..
13460            } => {
13461                self.apply_translated_actions(source_state, rule_index, context);
13462                if let Some(action_index) = self.action_index(source_state) {
13463                    let action = self.parser.parser_action_at_current_indexed(
13464                        source_state,
13465                        rule_index,
13466                        action_index,
13467                        rule_start_index,
13468                        *consumed_eof,
13469                    );
13470                    let _ = self.parser.parser_action_hook_inner(
13471                        action,
13472                        Some(context),
13473                        None,
13474                        local_int_arg,
13475                        true,
13476                    );
13477                }
13478                Ok(target)
13479            }
13480            Transition::Precedence {
13481                target,
13482                precedence: transition_precedence,
13483            } => {
13484                if transition_precedence >= precedence {
13485                    Ok(target)
13486                } else {
13487                    Err(self
13488                        .parser
13489                        .failed_predicate_error(format!("precpred(_ctx, {transition_precedence})")))
13490                }
13491            }
13492        }
13493    }
13494
13495    fn apply_translated_actions(
13496        &mut self,
13497        source_state: usize,
13498        rule_index: usize,
13499        context: &mut ParserRuleContext,
13500    ) {
13501        apply_member_actions(
13502            source_state,
13503            self.options.member_actions,
13504            self.options.semantics,
13505            &mut self.parser.int_members,
13506        );
13507        let return_values = return_values_after_action(
13508            source_state,
13509            rule_index,
13510            self.options.return_actions,
13511            self.options.semantics,
13512            &BTreeMap::new(),
13513        );
13514        for (name, value) in return_values {
13515            context.set_int_return(name, value);
13516        }
13517    }
13518
13519    fn action_index(&self, source_state: usize) -> Option<usize> {
13520        self.action_index_by_state.get(&source_state).copied()
13521    }
13522}
13523
13524/// Detects the loop edge where ANTLR would call `pushNewRecursionContext` for a
13525/// transformed left-recursive rule.
13526fn left_recursive_boundary(atn: &Atn, state: AtnState<'_>, target: usize) -> Option<usize> {
13527    if !state.precedence_rule_decision() {
13528        return None;
13529    }
13530    let target_state = atn.state(target)?;
13531    if target_state.kind() == AtnStateKind::LoopEnd {
13532        return None;
13533    }
13534    state.rule_index()
13535}
13536
13537/// Selects the first outer alternative observed for a rule path.
13538///
13539/// ANTLR's alt-numbered tree contexts store the rule alternative chosen at the
13540/// outer decision. The metadata recognizer only needs this when a generated
13541/// grammar opts into that target template; otherwise the value remains `0` and
13542/// parse-tree rendering is unchanged.
13543fn next_alt_number(
13544    state: AtnState<'_>,
13545    transition_count: usize,
13546    transition_index: usize,
13547    current_alt_number: usize,
13548    track_alt_numbers: bool,
13549) -> usize {
13550    if !track_alt_numbers || current_alt_number != 0 || transition_count <= 1 {
13551        return current_alt_number;
13552    }
13553    if matches!(
13554        state.kind(),
13555        AtnStateKind::Basic
13556            | AtnStateKind::BlockStart
13557            | AtnStateKind::PlusBlockStart
13558            | AtnStateKind::StarBlockStart
13559            | AtnStateKind::StarLoopEntry
13560    ) && !state.precedence_rule_decision()
13561    {
13562        return transition_index + 1;
13563    }
13564    current_alt_number
13565}
13566
13567/// Converts an ATN state number into the signed invoking-state slot used by
13568/// ANTLR parse-tree contexts, saturating only for impossible platform widths.
13569fn invoking_state_number(state_number: usize) -> isize {
13570    isize::try_from(state_number).unwrap_or(isize::MAX)
13571}
13572
13573const fn packed_i32(value: u32) -> i32 {
13574    i32::from_le_bytes(value.to_le_bytes())
13575}
13576
13577fn direct_precedence(precedence: i32) -> usize {
13578    usize::try_from(precedence.max(0)).unwrap_or_default()
13579}
13580
13581fn token_input_display(token: &impl Token) -> String {
13582    format!("'{}'", token.text().unwrap_or("<EOF>"))
13583}
13584
13585fn display_input_text(text: &str) -> String {
13586    let mut out = String::new();
13587    for ch in text.chars() {
13588        match ch {
13589            '\n' => out.push_str("\\n"),
13590            '\r' => out.push_str("\\r"),
13591            '\t' => out.push_str("\\t"),
13592            other => out.push(other),
13593        }
13594    }
13595    out
13596}
13597
13598fn diagnostic_for_token<T: Token>(token: Option<T>, message: String) -> ParserDiagnostic {
13599    let (line, column, offending) = token.map_or((0, 0, None), |token| {
13600        (token.line(), token.column(), Some(token.token_id()))
13601    });
13602    ParserDiagnostic {
13603        line,
13604        column,
13605        message,
13606        offending,
13607    }
13608}
13609
13610fn expected_symbols_display(symbols: &BTreeSet<i32>, vocabulary: &Vocabulary) -> String {
13611    expected_symbols_display_iter(symbols.iter().copied(), vocabulary)
13612}
13613
13614fn expected_symbols_display_iter(
13615    symbols: impl IntoIterator<Item = i32>,
13616    vocabulary: &Vocabulary,
13617) -> String {
13618    let items = symbols
13619        .into_iter()
13620        .map(|symbol| expected_symbol_display(symbol, vocabulary))
13621        .collect::<Vec<_>>();
13622    if let [single] = items.as_slice() {
13623        return single.clone();
13624    }
13625    format!("{{{}}}", items.join(", "))
13626}
13627
13628fn expected_symbol_display(symbol: i32, vocabulary: &Vocabulary) -> String {
13629    if symbol == TOKEN_EOF {
13630        return "<EOF>".to_owned();
13631    }
13632    vocabulary.display_name(symbol)
13633}
13634
13635fn caller_follow_token_info_for_stream<S: TokenSource>(
13636    input: &mut CommonTokenStream<S>,
13637    index: usize,
13638) -> (i32, bool, bool) {
13639    // Generated callers own statement separators; leave them available when
13640    // an interpreted child rule can either stop before or consume one.
13641    if index >= FAST_RECOGNIZER_DEFERRED_FILL_AT && !input.is_filled() {
13642        input.fill();
13643    }
13644    let token_type = input.token_type_at_index(index);
13645    let visible_channel = input.channel();
13646    let token = input.get(index);
13647    let is_boundary = token
13648        .as_ref()
13649        .and_then(Token::text)
13650        .is_some_and(is_caller_follow_boundary_text);
13651    let is_boundary_gap = token.as_ref().is_some_and(|token| {
13652        token.channel() != visible_channel
13653            || is_caller_follow_boundary_gap_text(token.text_or_empty())
13654    });
13655    (token_type, is_boundary, is_boundary_gap)
13656}
13657
13658fn is_caller_follow_boundary_text(text: &str) -> bool {
13659    text.chars().any(|ch| ch == ';' || ch == '\n')
13660        && text.chars().all(|ch| ch.is_whitespace() || ch == ';')
13661}
13662
13663fn is_caller_follow_boundary_gap_text(text: &str) -> bool {
13664    text.chars().all(|ch| ch.is_whitespace() || ch == ';')
13665}
13666
13667/// Returns whether `state` belongs to an ANTLR-transformed left-recursive rule.
13668/// Inline insertion in those precedence loops can synthesize a missing operand
13669/// before an operator and then block the legitimate loop-exit path.
13670fn state_is_left_recursive_rule(atn: &Atn, state: AtnState<'_>) -> bool {
13671    let Some(rule_index) = state.rule_index() else {
13672        return false;
13673    };
13674    atn.rule_to_start_state()
13675        .get(rule_index)
13676        .and_then(|state_number| atn.state(state_number))
13677        .is_some_and(AtnState::left_recursive_rule)
13678}
13679
13680/// Picks the better of two `parse_atn_rule` passes (with and without the
13681/// FIRST-set prefilter). A clean outcome (no diagnostics) always wins over a
13682/// recovered one; among recovered outcomes the second pass is preferred
13683/// because the no-prefilter walk reaches ANTLR-style recovery inside child
13684/// rules. If both passes failed, the second pass's expected-token snapshot
13685/// is returned so the caller renders the same diagnostic ANTLR would.
13686fn select_better_top_outcome(
13687    first: Result<(FastRecognizeOutcome, ExpectedTokens, usize), ExpectedTokens>,
13688    second: Result<(FastRecognizeOutcome, ExpectedTokens, usize), ExpectedTokens>,
13689    arena: &RecognitionArena,
13690) -> Result<(FastRecognizeOutcome, ExpectedTokens, usize), ExpectedTokens> {
13691    match (first, second) {
13692        (Ok(first), Ok(second)) => {
13693            if arena.diagnostics(first.0.diagnostics).next().is_none() {
13694                Ok(first)
13695            } else {
13696                Ok(second)
13697            }
13698        }
13699        (Ok(first), Err(_)) => Ok(first),
13700        (Err(_), Ok(second)) => Ok(second),
13701        (Err(_), Err(second_expected)) => Err(second_expected),
13702    }
13703}
13704
13705/// Chooses the outermost parse result that consumed the most input.
13706///
13707/// The recognizer intentionally keeps shorter endpoints available while walking
13708/// nested rule transitions so callers can satisfy following tokens such as
13709/// `expr 'and' expr`. Only the public rule entry commits to one endpoint.
13710fn select_best_fast_outcome(
13711    outcomes: impl Iterator<Item = FastRecognizeOutcome>,
13712    prediction_mode: PredictionMode,
13713    caller_follow: Option<&TokenBitSet>,
13714    mut token_info_at: impl FnMut(usize) -> (i32, bool, bool),
13715    arena: &RecognitionArena,
13716) -> Option<FastRecognizeOutcome> {
13717    let mut best = None;
13718    let mut best_caller_follow = None;
13719    for outcome in outcomes {
13720        if matches!(
13721            prediction_mode,
13722            PredictionMode::Ll | PredictionMode::LlExactAmbigDetection
13723        ) && outcome.diagnostics.is_empty()
13724            && let Some(follow) = caller_follow
13725        {
13726            let (token_type, is_boundary, _) = token_info_at(outcome.index);
13727            if is_boundary && follow.contains(token_type) {
13728                let replace =
13729                    best_caller_follow
13730                        .as_ref()
13731                        .is_none_or(|existing: &FastRecognizeOutcome| {
13732                            (outcome.index, outcome.consumed_eof)
13733                                < (existing.index, existing.consumed_eof)
13734                        });
13735                if replace {
13736                    best_caller_follow = Some(outcome);
13737                }
13738            }
13739        }
13740        let Some(existing) = best else {
13741            best = Some(outcome);
13742            continue;
13743        };
13744        let outcome_position = (outcome.index, outcome.consumed_eof);
13745        let best_position = (existing.index, existing.consumed_eof);
13746        let better = match prediction_mode {
13747            PredictionMode::Ll | PredictionMode::LlExactAmbigDetection => outcome_is_better(
13748                outcome_position,
13749                outcome.diagnostics,
13750                best_position,
13751                existing.diagnostics,
13752                arena,
13753            ),
13754            PredictionMode::Sll => outcome.index > existing.index,
13755        };
13756        best = Some(if better { outcome } else { existing });
13757    }
13758    let should_use_caller_follow =
13759        best_caller_follow
13760            .as_ref()
13761            .zip(best.as_ref())
13762            .is_some_and(|(candidate, selected)| {
13763                if !selected.diagnostics.is_empty() {
13764                    return true;
13765                }
13766                candidate.index < selected.index
13767                    && (candidate.index..selected.index).all(|index| token_info_at(index).2)
13768            });
13769    if should_use_caller_follow {
13770        best_caller_follow
13771    } else {
13772        best
13773    }
13774}
13775
13776fn select_best_outcome(
13777    outcomes: impl Iterator<Item = RecognizeOutcome>,
13778    prediction_mode: PredictionMode,
13779    arena: &RecognitionArena,
13780) -> Option<RecognizeOutcome> {
13781    let outcomes = outcomes.collect::<Vec<_>>();
13782    let prefer_first_tie = outcomes
13783        .iter()
13784        .any(|outcome| arena.sequence_needs_stable_tie(outcome.nodes));
13785    outcomes.into_iter().reduce(|best, outcome| {
13786        let outcome_position = (outcome.index, outcome.consumed_eof);
13787        let best_position = (best.index, best.consumed_eof);
13788        let better = match prediction_mode {
13789            PredictionMode::Ll | PredictionMode::LlExactAmbigDetection => {
13790                outcome_is_better(
13791                    outcome_position,
13792                    outcome.diagnostics,
13793                    best_position,
13794                    best.diagnostics,
13795                    arena,
13796                ) || (outcome_position == best_position
13797                    && arena.diagnostics_len(outcome.diagnostics)
13798                        == arena.diagnostics_len(best.diagnostics)
13799                    && arena.diagnostics_recovery_rank(outcome.diagnostics)
13800                        == arena.diagnostics_recovery_rank(best.diagnostics)
13801                    && (outcome.decisions < best.decisions
13802                        || (!prefer_first_tie
13803                            && outcome.decisions == best.decisions
13804                            && outcome.actions > best.actions)))
13805            }
13806            PredictionMode::Sll => {
13807                outcome_position > best_position
13808                    || (outcome_position == best_position
13809                        && !prefer_first_tie
13810                        && (outcome.decisions < best.decisions
13811                            || (outcome.decisions == best.decisions
13812                                && outcome_is_better(
13813                                    outcome_position,
13814                                    outcome.diagnostics,
13815                                    best_position,
13816                                    best.diagnostics,
13817                                    arena,
13818                                ))))
13819            }
13820        };
13821        if better {
13822            return outcome;
13823        }
13824        best
13825    })
13826}
13827
13828/// Records the serialized transition order at parser decision states.
13829///
13830/// When two clean paths consume the same input, ANTLR's adaptive prediction
13831/// chooses by alternative order. Keeping this compact trace lets the metadata
13832/// recognizer distinguish greedy and non-greedy optional blocks without a full
13833/// prediction simulator.
13834fn transition_decision(
13835    atn: &Atn,
13836    state: AtnState<'_>,
13837    transition_count: usize,
13838    transition_index: usize,
13839    predicates: &[(usize, usize, ParserPredicate)],
13840) -> Option<usize> {
13841    if transition_count <= 1 || decision_reaches_unsupported_predicate(atn, state, predicates) {
13842        return None;
13843    }
13844    Some(transition_index)
13845}
13846
13847/// Reports whether a state should reset the active no-viable decision start.
13848///
13849/// Loop entry/back states are continuations of the surrounding adaptive
13850/// prediction; resetting at those states would turn LL-star failures back into
13851/// ordinary mismatches.
13852fn starts_prediction_decision(state: AtnState<'_>, transition_count: usize) -> bool {
13853    transition_count > 1
13854        && !matches!(
13855            state.kind(),
13856            AtnStateKind::PlusLoopBack | AtnStateKind::StarLoopBack | AtnStateKind::StarLoopEntry
13857        )
13858}
13859
13860/// Marks a farthest expected-token set as no-viable when multiple alternatives
13861/// failed after the active decision had already consumed input.
13862fn record_no_viable_if_ambiguous(
13863    expected: &mut ExpectedTokens,
13864    decision_start_index: Option<usize>,
13865    index: usize,
13866) {
13867    if expected.index == Some(index) && expected.symbols.len() > 1 {
13868        if let Some(decision_start) = no_viable_decision_start(decision_start_index, index) {
13869            expected.record_no_viable(decision_start, index);
13870        }
13871    }
13872}
13873
13874/// Records a no-viable decision caused by a failed semantic predicate before
13875/// any consuming transition can contribute an expected-token set.
13876const fn record_predicate_no_viable(
13877    expected: &mut ExpectedTokens,
13878    decision_start_index: Option<usize>,
13879    index: usize,
13880) {
13881    if let Some(decision_start) = decision_start_index {
13882        expected.record_no_viable(decision_start, index);
13883    }
13884}
13885
13886/// Returns the active decision start only when the error is past that start.
13887const fn no_viable_decision_start(
13888    decision_start_index: Option<usize>,
13889    index: usize,
13890) -> Option<usize> {
13891    match decision_start_index {
13892        Some(start) if index > start => Some(start),
13893        _ => None,
13894    }
13895}
13896
13897/// Restores expected-token bookkeeping when a child rule found a clean
13898/// consuming path; failures in longer child alternatives should not pollute the
13899/// caller's final expectation set.
13900fn restore_expected(
13901    children: &[RecognizeOutcome],
13902    child_start_index: usize,
13903    expected: &mut ExpectedTokens,
13904    snapshot: ExpectedTokens,
13905    preserve_child_expected: bool,
13906) {
13907    if preserve_child_expected {
13908        return;
13909    }
13910    if children
13911        .iter()
13912        .any(|child| child.diagnostics.is_empty() && child.index > child_start_index)
13913    {
13914        *expected = snapshot;
13915    }
13916}
13917
13918/// Reports whether a decision can reach a predicate the generator did not
13919/// translate. Static alternative order is unsafe for those context predicates.
13920fn decision_reaches_unsupported_predicate(
13921    atn: &Atn,
13922    state: AtnState<'_>,
13923    predicates: &[(usize, usize, ParserPredicate)],
13924) -> bool {
13925    state.transitions().iter().any(|transition| {
13926        transition_reaches_unsupported_predicate(atn, transition, predicates, &mut BTreeSet::new())
13927    })
13928}
13929
13930/// Walks epsilon-like edges from one transition to find unsupported predicates.
13931fn transition_reaches_unsupported_predicate(
13932    atn: &Atn,
13933    transition: ParserTransition<'_>,
13934    predicates: &[(usize, usize, ParserPredicate)],
13935    visited: &mut BTreeSet<usize>,
13936) -> bool {
13937    match &transition.data() {
13938        Transition::Predicate {
13939            rule_index,
13940            pred_index,
13941            ..
13942        } => !predicates
13943            .iter()
13944            .any(|(rule, pred, _)| rule == rule_index && pred == pred_index),
13945        Transition::Epsilon { target }
13946        | Transition::Action { target, .. }
13947        | Transition::Rule { target, .. } => {
13948            state_reaches_unsupported_predicate(atn, *target, predicates, visited)
13949        }
13950        Transition::Precedence { .. }
13951        | Transition::Atom { .. }
13952        | Transition::Range { .. }
13953        | Transition::Set { .. }
13954        | Transition::NotSet { .. }
13955        | Transition::Wildcard { .. } => false,
13956    }
13957}
13958
13959/// Finds an unsupported predicate reachable before a consuming transition.
13960fn state_reaches_unsupported_predicate(
13961    atn: &Atn,
13962    state_number: usize,
13963    predicates: &[(usize, usize, ParserPredicate)],
13964    visited: &mut BTreeSet<usize>,
13965) -> bool {
13966    if !visited.insert(state_number) {
13967        return false;
13968    }
13969    let Some(state) = atn.state(state_number) else {
13970        return false;
13971    };
13972    state.transitions().iter().any(|transition| {
13973        transition_reaches_unsupported_predicate(atn, transition, predicates, visited)
13974    })
13975}
13976
13977/// Adds a decision step to the front of an already-recognized suffix path.
13978fn prepend_decision(outcome: &mut RecognizeOutcome, decision: Option<usize>) {
13979    if let Some(decision) = decision {
13980        outcome.decisions.insert(0, decision);
13981    }
13982}
13983
13984fn outcome_is_better(
13985    outcome_position: (usize, bool),
13986    outcome_diagnostics: DiagnosticSeqId,
13987    best_position: (usize, bool),
13988    best_diagnostics: DiagnosticSeqId,
13989    arena: &RecognitionArena,
13990) -> bool {
13991    let outcome_len = arena.diagnostics_len(outcome_diagnostics);
13992    let best_len = arena.diagnostics_len(best_diagnostics);
13993    outcome_position > best_position
13994        || (outcome_position == best_position
13995            && (outcome_len < best_len
13996                || (outcome_len == best_len
13997                    && arena.diagnostics_recovery_rank(outcome_diagnostics)
13998                        < arena.diagnostics_recovery_rank(best_diagnostics))))
13999}
14000
14001fn discard_recovered_fast_outcomes_if_clean_path_exists(outcomes: &mut Vec<FastRecognizeOutcome>) {
14002    if outcomes
14003        .iter()
14004        .any(|outcome| outcome.diagnostics.is_empty())
14005    {
14006        outcomes.retain(|outcome| outcome.diagnostics.is_empty());
14007    }
14008}
14009
14010fn discard_recovered_outcomes_if_clean_path_exists(
14011    outcomes: &mut Vec<RecognizeOutcome>,
14012    arena: &RecognitionArena,
14013) {
14014    if outcomes
14015        .iter()
14016        .any(|outcome| outcome_has_rule_failure_diagnostic(outcome, arena))
14017    {
14018        return;
14019    }
14020    if outcomes
14021        .iter()
14022        .any(|outcome| outcome.diagnostics.is_empty())
14023    {
14024        outcomes.retain(|outcome| outcome.diagnostics.is_empty());
14025    }
14026}
14027
14028/// Reports whether a recovered outcome came from an explicit predicate
14029/// fail-option and therefore should compete with shorter clean loop exits.
14030fn outcome_has_rule_failure_diagnostic(
14031    outcome: &RecognizeOutcome,
14032    arena: &RecognitionArena,
14033) -> bool {
14034    arena
14035        .diagnostics(outcome.diagnostics)
14036        .any(|diagnostic| diagnostic.message.starts_with("rule "))
14037}
14038
14039/// Removes equivalent endpoints before memoizing a state result while
14040/// preserving ATN transition-discovery order.
14041///
14042/// Outcomes are compared on observable recognition state — the input index,
14043/// EOF consumption, and diagnostics — without descending into the parse-tree
14044/// fragment carried by `nodes`. Two paths reaching the same point with
14045/// different node trees would otherwise prevent memoization from collapsing
14046/// equivalent suffixes and explode the speculative-path cache.
14047///
14048/// The first occurrence per recognition key wins, which matches ANTLR's
14049/// greedy alternative selection: serialized ATNs put greedy `*`/`+` loop-back
14050/// transitions before loop-exit, so the first-discovered outcome carries the
14051/// greedy parse-tree fragment.
14052fn dedupe_fast_outcomes(outcomes: &mut Vec<FastRecognizeOutcome>, arena: &RecognitionArena) {
14053    if outcomes.len() < 2 {
14054        return;
14055    }
14056    let mut seen = FxHashSet::with_capacity_and_hasher(outcomes.len(), FxBuildHasher::default());
14057    outcomes.retain(|outcome| {
14058        seen.insert((
14059            outcome.index,
14060            outcome.consumed_eof,
14061            arena.diagnostics_len(outcome.diagnostics),
14062            arena.diagnostics_recovery_rank(outcome.diagnostics),
14063        ))
14064    });
14065}
14066
14067const FAST_OUTCOME_INLINE_KEYS: usize = 8;
14068const FAST_OUTCOME_BITS_PER_WORD: usize = 64;
14069const MAX_FAST_OUTCOME_DENSE_BYTES: usize = 64 * 1024;
14070const MAX_RETAINED_FAST_OUTCOME_SPARSE_KEYS: usize = 65_536;
14071
14072#[derive(Clone, Copy, Debug, Eq, PartialEq)]
14073enum FastOutcomeDedupStrategy {
14074    Inline,
14075    Dense,
14076    Sparse,
14077}
14078
14079impl FastOutcomeDedupScratch {
14080    fn prepare_dense(&mut self, word_count: usize) {
14081        while let Some(word_index) = self.touched_dense_words.pop() {
14082            self.dense_words[usize::try_from(word_index).expect("u32 fits in usize")] = 0;
14083        }
14084        if self.dense_words.len() < word_count {
14085            self.dense_words.resize(word_count, 0);
14086        }
14087    }
14088}
14089
14090fn clean_fast_outcome_dense_layout(outcomes: &[FastRecognizeOutcome]) -> Option<(usize, usize)> {
14091    let first_index = outcomes.first()?.index;
14092    let (min_index, max_index) = outcomes[1..].iter().fold(
14093        (first_index, first_index),
14094        |(min_index, max_index), outcome| {
14095            (min_index.min(outcome.index), max_index.max(outcome.index))
14096        },
14097    );
14098    let index_span = max_index.checked_sub(min_index)?.checked_add(1)?;
14099    let bit_count = index_span.checked_mul(2)?;
14100    let word_count =
14101        bit_count.checked_add(FAST_OUTCOME_BITS_PER_WORD - 1)? / FAST_OUTCOME_BITS_PER_WORD;
14102    let dense_bytes = word_count.checked_mul(size_of::<u64>())?;
14103    let sparse_key_bytes = outcomes.len().checked_mul(size_of::<(usize, bool)>())?;
14104    (dense_bytes <= MAX_FAST_OUTCOME_DENSE_BYTES && dense_bytes <= sparse_key_bytes)
14105        .then_some((min_index, word_count))
14106}
14107
14108#[cfg(feature = "perf-counters")]
14109fn record_clean_fast_outcome_dedup(
14110    strategy: FastOutcomeDedupStrategy,
14111    input_len: usize,
14112    output_len: usize,
14113    dense_words: usize,
14114) {
14115    let counter = match strategy {
14116        FastOutcomeDedupStrategy::Inline => &perf_counters::OUTCOME_DEDUPE_INLINE,
14117        FastOutcomeDedupStrategy::Dense => &perf_counters::OUTCOME_DEDUPE_DENSE,
14118        FastOutcomeDedupStrategy::Sparse => &perf_counters::OUTCOME_DEDUPE_SPARSE,
14119    };
14120    perf_counters::inc(
14121        &perf_counters::OUTCOME_DEDUPE_INPUTS,
14122        u64::try_from(input_len).unwrap_or(u64::MAX),
14123    );
14124    perf_counters::inc(
14125        &perf_counters::OUTCOME_DEDUPE_REMOVED,
14126        u64::try_from(input_len - output_len).unwrap_or(u64::MAX),
14127    );
14128    perf_counters::inc(counter, 1);
14129    perf_counters::inc(
14130        &perf_counters::OUTCOME_DEDUPE_DENSE_WORDS,
14131        u64::try_from(dense_words).unwrap_or(u64::MAX),
14132    );
14133}
14134
14135/// Removes duplicate clean endpoints while preserving transition-discovery
14136/// order. Tiny lists stay on the stack; larger compact ranges use a direct
14137/// bitmap, and only wide sparse ranges pay for hashing.
14138fn dedupe_clean_fast_outcomes(
14139    outcomes: &mut Vec<FastRecognizeOutcome>,
14140    scratch: &mut FastOutcomeDedupScratch,
14141) -> FastOutcomeDedupStrategy {
14142    #[cfg(feature = "perf-counters")]
14143    let input_len = outcomes.len();
14144    if outcomes.len() <= FAST_OUTCOME_INLINE_KEYS {
14145        let mut inline_keys = [(0, false); FAST_OUTCOME_INLINE_KEYS];
14146        let mut inline_len = 0_usize;
14147        outcomes.retain(|outcome| {
14148            let key = (outcome.index, outcome.consumed_eof);
14149            if inline_keys[..inline_len].contains(&key) {
14150                return false;
14151            }
14152            inline_keys[inline_len] = key;
14153            inline_len += 1;
14154            true
14155        });
14156        #[cfg(feature = "perf-counters")]
14157        record_clean_fast_outcome_dedup(
14158            FastOutcomeDedupStrategy::Inline,
14159            input_len,
14160            outcomes.len(),
14161            0,
14162        );
14163        return FastOutcomeDedupStrategy::Inline;
14164    }
14165
14166    if let Some((base_index, word_count)) = clean_fast_outcome_dense_layout(outcomes) {
14167        scratch.prepare_dense(word_count);
14168        outcomes.retain(|outcome| {
14169            let bit_index = (outcome.index - base_index) * 2 + usize::from(outcome.consumed_eof);
14170            let word_index = bit_index / FAST_OUTCOME_BITS_PER_WORD;
14171            let bit = 1_u64 << (bit_index % FAST_OUTCOME_BITS_PER_WORD);
14172            let word = &mut scratch.dense_words[word_index];
14173            if *word & bit != 0 {
14174                return false;
14175            }
14176            if *word == 0 {
14177                scratch
14178                    .touched_dense_words
14179                    .push(u32::try_from(word_index).expect("dense outcome bitmap is capped"));
14180            }
14181            *word |= bit;
14182            true
14183        });
14184        #[cfg(feature = "perf-counters")]
14185        record_clean_fast_outcome_dedup(
14186            FastOutcomeDedupStrategy::Dense,
14187            input_len,
14188            outcomes.len(),
14189            word_count,
14190        );
14191        return FastOutcomeDedupStrategy::Dense;
14192    }
14193
14194    scratch.sparse_keys.clear();
14195    scratch.sparse_keys.reserve(outcomes.len());
14196    outcomes.retain(|outcome| {
14197        scratch
14198            .sparse_keys
14199            .insert((outcome.index, outcome.consumed_eof))
14200    });
14201    #[cfg(feature = "perf-counters")]
14202    record_clean_fast_outcome_dedup(
14203        FastOutcomeDedupStrategy::Sparse,
14204        input_len,
14205        outcomes.len(),
14206        0,
14207    );
14208    if scratch.sparse_keys.capacity() > MAX_RETAINED_FAST_OUTCOME_SPARSE_KEYS {
14209        scratch.sparse_keys = FxHashSet::default();
14210    }
14211    FastOutcomeDedupStrategy::Sparse
14212}
14213
14214/// Sorts and removes equivalent endpoints, including action traces and the
14215/// arena-backed node sequence's structural contents.
14216fn dedupe_outcomes(outcomes: &mut Vec<RecognizeOutcome>, arena: &RecognitionArena) {
14217    outcomes.sort_unstable_by(|left, right| compare_recognize_outcomes(left, right, arena));
14218    outcomes
14219        .dedup_by(|left, right| compare_recognize_outcomes(left, right, arena) == Ordering::Equal);
14220}
14221
14222fn compare_recognize_outcomes(
14223    left: &RecognizeOutcome,
14224    right: &RecognizeOutcome,
14225    arena: &RecognitionArena,
14226) -> Ordering {
14227    left.index
14228        .cmp(&right.index)
14229        .then_with(|| left.consumed_eof.cmp(&right.consumed_eof))
14230        .then_with(|| left.alt_number.cmp(&right.alt_number))
14231        .then_with(|| left.member_values.cmp(&right.member_values))
14232        .then_with(|| left.return_values.cmp(&right.return_values))
14233        .then_with(|| arena.compare_diagnostics(left.diagnostics, right.diagnostics))
14234        .then_with(|| left.decisions.cmp(&right.decisions))
14235        .then_with(|| left.actions.cmp(&right.actions))
14236        .then_with(|| arena.compare_sequences(left.nodes, right.nodes))
14237}
14238
14239impl<S, H> Recognizer for BaseParser<S, H>
14240where
14241    S: TokenSource,
14242    H: SemanticHooks,
14243{
14244    fn data(&self) -> &RecognizerData {
14245        &self.data
14246    }
14247
14248    fn data_mut(&mut self) -> &mut RecognizerData {
14249        &mut self.data
14250    }
14251}
14252
14253impl<S, H> Parser for BaseParser<S, H>
14254where
14255    S: TokenSource,
14256    H: SemanticHooks,
14257{
14258    fn build_parse_trees(&self) -> bool {
14259        self.build_parse_trees
14260    }
14261
14262    fn set_build_parse_trees(&mut self, build: bool) {
14263        self.build_parse_trees = build;
14264    }
14265
14266    fn number_of_syntax_errors(&self) -> usize {
14267        Self::number_of_syntax_errors(self)
14268    }
14269
14270    fn report_diagnostic_errors(&self) -> bool {
14271        self.report_diagnostic_errors
14272    }
14273
14274    fn set_report_diagnostic_errors(&mut self, report: bool) {
14275        self.report_diagnostic_errors = report;
14276    }
14277
14278    fn prediction_mode(&self) -> PredictionMode {
14279        self.prediction_mode
14280    }
14281
14282    fn set_prediction_mode(&mut self, mode: PredictionMode) {
14283        self.prediction_mode = mode;
14284    }
14285
14286    fn max_rule_depth(&self) -> Option<usize> {
14287        self.max_rule_depth
14288    }
14289
14290    fn set_max_rule_depth(&mut self, depth: Option<usize>) {
14291        self.max_rule_depth = depth;
14292    }
14293
14294    fn add_parse_listener(&mut self, listener: Box<dyn ParseListener>) {
14295        self.parse_listeners.push(ParseListenerSlot(listener));
14296    }
14297
14298    fn remove_parse_listeners(&mut self) -> Vec<Box<dyn ParseListener>> {
14299        Self::remove_parse_listeners(self)
14300    }
14301}
14302
14303#[cfg(test)]
14304#[allow(clippy::disallowed_methods)] // `insta` assertion macros unwrap internal I/O.
14305mod tests {
14306    use super::*;
14307    use crate::atn::parser::{
14308        ParserAtnPredictionDiagnostic, ParserAtnPredictionDiagnosticKind, ParserAtnSimulator,
14309    };
14310    use crate::atn::serialized::{AtnDeserializer, SerializedAtn};
14311    use crate::token::{HIDDEN_CHANNEL, Token, TokenId, TokenSink, TokenSpec, TokenStoreError};
14312    use crate::token_stream::CommonTokenStream;
14313    use crate::tree::{NodeKind, ParseTreeStats};
14314    use crate::vocabulary::Vocabulary;
14315    use std::cell::RefCell;
14316    use std::mem::size_of;
14317    use std::rc::Rc;
14318    use std::sync::{Arc, Mutex};
14319
14320    #[test]
14321    fn fx_hasher_write_matches_typed_methods_for_full_words() {
14322        // PR #5 review (Greptile P2): future key types whose `Hash` impl funnels
14323        // bytes through `Hasher::write` (e.g. `String`, `[u8; 8]`, slice-typed
14324        // fields) must hash the same as the typed methods, otherwise an
14325        // `FxHashMap` keyed on such a type silently disagrees with itself
14326        // depending on which entry point the caller used. Verify the
14327        // little-endian word equivalence this PR established.
14328        let value: u64 = 0x0102_0304_0506_0708;
14329        let mut typed = FxHasher::default();
14330        typed.write_u64(value);
14331        let mut bytewise = FxHasher::default();
14332        bytewise.write(&value.to_le_bytes());
14333        assert_eq!(typed.finish(), bytewise.finish());
14334    }
14335
14336    #[derive(Clone, Debug)]
14337    struct TestToken {
14338        spec: TokenSpec,
14339        id: TokenId,
14340        source_name: String,
14341    }
14342
14343    impl TestToken {
14344        fn new(token_type: i32) -> Self {
14345            Self {
14346                spec: TokenSpec::explicit(token_type, ""),
14347                id: TokenId::try_from(0).expect("zero token ID"),
14348                source_name: String::new(),
14349            }
14350        }
14351
14352        fn eof(source_name: &str, index: usize, line: usize, column: usize) -> Self {
14353            Self {
14354                spec: TokenSpec::eof(index, index, line, column),
14355                id: TokenId::try_from(0).expect("zero token ID"),
14356                source_name: source_name.to_owned(),
14357            }
14358        }
14359
14360        fn with_text(mut self, text: impl Into<String>) -> Self {
14361            self.spec.text = Some(text.into());
14362            self
14363        }
14364
14365        const fn with_channel(mut self, channel: i32) -> Self {
14366            self.spec.channel = channel;
14367            self
14368        }
14369
14370        fn with_span(mut self, start: usize, stop: usize) -> Self {
14371            self.spec = self.spec.with_span(start, stop);
14372            self
14373        }
14374
14375        fn with_byte_span(mut self, start: usize, stop: usize) -> Self {
14376            self.spec = self.spec.with_byte_span(start, stop);
14377            self
14378        }
14379
14380        const fn with_position(mut self, line: usize, column: usize) -> Self {
14381            self.spec.line = line;
14382            self.spec.column = column;
14383            self
14384        }
14385
14386        fn set_token_index(&mut self, index: isize) {
14387            self.id = TokenId::try_from(index.max(0).cast_unsigned()).expect("test token index");
14388        }
14389    }
14390
14391    impl Token for TestToken {
14392        fn token_id(&self) -> TokenId {
14393            self.id
14394        }
14395
14396        fn token_type(&self) -> i32 {
14397            self.spec.token_type
14398        }
14399
14400        fn channel(&self) -> i32 {
14401            self.spec.channel
14402        }
14403
14404        fn start(&self) -> usize {
14405            self.spec.start
14406        }
14407
14408        fn stop(&self) -> usize {
14409            self.spec.stop
14410        }
14411
14412        fn line(&self) -> usize {
14413            self.spec.line
14414        }
14415
14416        fn column(&self) -> usize {
14417            self.spec.column
14418        }
14419
14420        fn text(&self) -> Option<&str> {
14421            self.spec.text.as_deref()
14422        }
14423
14424        fn source_name(&self) -> &str {
14425            &self.source_name
14426        }
14427
14428        fn start_byte(&self) -> Option<usize> {
14429            (self.spec.start_byte != usize::MAX).then_some(self.spec.start_byte)
14430        }
14431
14432        fn stop_byte(&self) -> Option<usize> {
14433            (self.spec.stop_byte != usize::MAX).then_some(self.spec.stop_byte)
14434        }
14435    }
14436
14437    #[derive(Debug)]
14438    struct Source {
14439        tokens: Vec<TestToken>,
14440        index: usize,
14441    }
14442
14443    impl TokenSource for Source {
14444        fn next_token(&mut self, sink: &mut TokenSink<'_>) -> Result<TokenId, TokenStoreError> {
14445            let token = self
14446                .tokens
14447                .get(self.index)
14448                .cloned()
14449                .unwrap_or_else(|| TestToken::eof("parser-test", self.index, 1, self.index));
14450            self.index += 1;
14451            sink.push(token.spec)
14452        }
14453
14454        fn line(&self) -> usize {
14455            1
14456        }
14457
14458        fn column(&self) -> usize {
14459            self.index
14460        }
14461
14462        fn source_name(&self) -> &'static str {
14463            "parser-test"
14464        }
14465    }
14466
14467    #[derive(Clone, Debug, Eq, PartialEq)]
14468    struct RecordedDiagnostic {
14469        grammar_file_name: String,
14470        offending_text: Option<String>,
14471        line: usize,
14472        column: usize,
14473        span: Option<std::ops::Range<usize>>,
14474        message: String,
14475        error: Option<AntlrError>,
14476    }
14477
14478    #[derive(Clone, Debug)]
14479    struct RecordingErrorListener {
14480        diagnostics: Arc<Mutex<Vec<RecordedDiagnostic>>>,
14481    }
14482
14483    impl<R> crate::ErrorListener<R> for RecordingErrorListener
14484    where
14485        R: Recognizer + ?Sized,
14486    {
14487        fn syntax_error(&mut self, recognizer: &R, event: &SyntaxErrorEvent<'_>) {
14488            self.diagnostics
14489                .lock()
14490                .expect("recorded diagnostics lock")
14491                .push(RecordedDiagnostic {
14492                    grammar_file_name: recognizer.grammar_file_name().to_owned(),
14493                    offending_text: event
14494                        .offending
14495                        .and_then(|token| token.text().map(str::to_owned)),
14496                    line: event.line,
14497                    column: event.column,
14498                    span: event.span.clone(),
14499                    message: event.message.to_owned(),
14500                    error: event.error.cloned(),
14501                });
14502        }
14503    }
14504
14505    #[derive(Debug)]
14506    struct ReportingSource {
14507        source: Source,
14508        diagnostics: Rc<RefCell<Vec<TokenSourceError>>>,
14509    }
14510
14511    impl TokenSource for ReportingSource {
14512        fn next_token(&mut self, sink: &mut TokenSink<'_>) -> Result<TokenId, TokenStoreError> {
14513            self.source.next_token(sink)
14514        }
14515
14516        fn line(&self) -> usize {
14517            self.source.line()
14518        }
14519
14520        fn column(&self) -> usize {
14521            self.source.column()
14522        }
14523
14524        fn source_name(&self) -> &str {
14525            self.source.source_name()
14526        }
14527
14528        fn report_error(&self, error: &TokenSourceError) -> bool {
14529            self.diagnostics.borrow_mut().push(error.clone());
14530            true
14531        }
14532    }
14533
14534    fn mini_parser_data() -> RecognizerData {
14535        RecognizerData::new(
14536            "Mini.g4",
14537            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
14538        )
14539        .with_rule_names(["s"])
14540    }
14541
14542    fn mini_parser(tokens: Vec<TestToken>) -> BaseParser<Source> {
14543        let data = mini_parser_data();
14544        BaseParser::new(CommonTokenStream::new(Source { tokens, index: 0 }), data)
14545    }
14546
14547    fn mini_parser_with_hooks<H>(tokens: Vec<TestToken>, hooks: H) -> BaseParser<Source, H>
14548    where
14549        H: SemanticHooks,
14550    {
14551        BaseParser::with_semantic_hooks(
14552            CommonTokenStream::new(Source { tokens, index: 0 }),
14553            mini_parser_data(),
14554            hooks,
14555        )
14556    }
14557
14558    #[test]
14559    fn parser_dispatches_recovery_diagnostics_through_registered_listeners() {
14560        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 0, 1, 0)]);
14561        parser.remove_error_listeners();
14562        let diagnostics = Arc::new(Mutex::new(Vec::new()));
14563        parser.add_error_listener(RecordingErrorListener {
14564            diagnostics: Arc::clone(&diagnostics),
14565        });
14566        let parser_diagnostics = [ParserDiagnostic {
14567            line: 1,
14568            column: 2,
14569            message: "missing 'x' at 'y'".to_owned(),
14570            offending: None,
14571        }];
14572        let token_errors = [
14573            TokenSourceError::new(1, 1, "token recognition error at: '@'").with_span(1..2),
14574            TokenSourceError::new(1, 3, "token recognition error at: '#'").with_span(3..4),
14575        ];
14576
14577        parser.dispatch_generated_diagnostics(&parser_diagnostics, &token_errors);
14578
14579        // The interleaved token/parser diagnostic stream (ordering, columns, messages) is one
14580        // reviewable snapshot instead of three hand-written RecordedDiagnostic literals.
14581        insta::assert_debug_snapshot!(
14582            "parser_dispatches_recovery_diagnostics_through_registered_listeners",
14583            *diagnostics.lock().expect("recorded diagnostics lock")
14584        );
14585
14586        parser.remove_error_listeners();
14587        parser.dispatch_generated_diagnostics(&parser_diagnostics, &token_errors);
14588        assert_eq!(
14589            diagnostics.lock().expect("recorded diagnostics lock").len(),
14590            3
14591        );
14592    }
14593
14594    #[test]
14595    fn recovery_diagnostics_expose_the_offending_token_to_listeners() {
14596        let mut parser = mini_parser(vec![
14597            TestToken::new(7)
14598                .with_text("oops")
14599                .with_span(0, 3)
14600                .with_byte_span(0, 4)
14601                .with_position(1, 2),
14602            TestToken::eof("parser-test", 4, 1, 6),
14603        ]);
14604        parser.remove_error_listeners();
14605        let diagnostics = Arc::new(Mutex::new(Vec::new()));
14606        parser.add_error_listener(RecordingErrorListener {
14607            diagnostics: Arc::clone(&diagnostics),
14608        });
14609        let offending = parser.input.lt_id(1);
14610        assert!(offending.is_some(), "current token should be buffered");
14611        let parser_diagnostics = [ParserDiagnostic {
14612            line: 1,
14613            column: 2,
14614            message: "extraneous input 'oops'".to_owned(),
14615            offending,
14616        }];
14617
14618        parser.dispatch_generated_diagnostics(&parser_diagnostics, &[]);
14619
14620        // Listeners receive a resolvable view of the offending token — the
14621        // ANTLR offendingSymbol contract downstream span-building error
14622        // reporters (miette-style byte-offset underlines) rely on.
14623        let recorded = diagnostics
14624            .lock()
14625            .expect("recorded diagnostics lock")
14626            .clone();
14627        insta::assert_debug_snapshot!(
14628            "recovery_diagnostics_expose_the_offending_token_to_listeners",
14629            recorded
14630        );
14631    }
14632
14633    #[test]
14634    fn recovery_diagnostics_preserve_unknown_custom_token_span() {
14635        let mut parser = mini_parser(vec![
14636            TestToken::new(7)
14637                .with_text("oops")
14638                .with_span(0, 3)
14639                .with_position(1, 2),
14640            TestToken::eof("parser-test", 4, 1, 6),
14641        ]);
14642        parser.remove_error_listeners();
14643        let diagnostics = Arc::new(Mutex::new(Vec::new()));
14644        parser.add_error_listener(RecordingErrorListener {
14645            diagnostics: Arc::clone(&diagnostics),
14646        });
14647        let offending = parser.input.lt_id(1);
14648        assert!(offending.is_some(), "current token should be buffered");
14649
14650        parser.dispatch_parser_diagnostic(&ParserDiagnostic {
14651            line: 1,
14652            column: 2,
14653            message: "extraneous input 'oops'".to_owned(),
14654            offending,
14655        });
14656
14657        let span = {
14658            let diagnostics = diagnostics.lock().expect("recorded diagnostics lock");
14659            assert_eq!(diagnostics.len(), 1);
14660            diagnostics[0].span.clone()
14661        };
14662        assert_eq!(span, None);
14663    }
14664
14665    #[test]
14666    fn parser_leaves_token_errors_to_source_owned_listeners() {
14667        let source_diagnostics = Rc::new(RefCell::new(Vec::new()));
14668        let source = ReportingSource {
14669            source: Source {
14670                tokens: vec![TestToken::eof("parser-test", 0, 1, 0)],
14671                index: 0,
14672            },
14673            diagnostics: Rc::clone(&source_diagnostics),
14674        };
14675        let mut parser = BaseParser::new(CommonTokenStream::new(source), mini_parser_data());
14676        parser.remove_error_listeners();
14677        let parser_diagnostics = Arc::new(Mutex::new(Vec::new()));
14678        parser.add_error_listener(RecordingErrorListener {
14679            diagnostics: Arc::clone(&parser_diagnostics),
14680        });
14681        let source_error = TokenSourceError::new(2, 4, "token recognition error at: '$'");
14682
14683        parser.dispatch_token_source_errors(std::slice::from_ref(&source_error));
14684
14685        assert_eq!(*source_diagnostics.borrow(), [source_error]);
14686        assert!(
14687            parser_diagnostics
14688                .lock()
14689                .expect("recorded diagnostics lock")
14690                .is_empty()
14691        );
14692    }
14693
14694    fn finish_atn(builder: ParserAtnBuilder) -> Atn {
14695        builder.finish().expect("valid packed parser ATN")
14696    }
14697
14698    fn nested_rule_chain_atn(depth: usize) -> Atn {
14699        nested_rule_graph_atn(depth, false, false)
14700    }
14701
14702    fn nested_rule_graph_atn(depth: usize, branching: bool, consuming_follows: bool) -> Atn {
14703        assert!(depth > 0);
14704        let mut atn = ParserAtnBuilder::new(2);
14705        let mut starts = Vec::with_capacity(depth);
14706        let mut stops = Vec::with_capacity(depth);
14707        let mut follows = Vec::with_capacity(depth.saturating_sub(1));
14708        for rule_index in 0..depth {
14709            starts.push(
14710                atn.add_state(AtnStateKind::RuleStart, Some(rule_index))
14711                    .expect("rule start")
14712                    .index(),
14713            );
14714        }
14715        for rule_index in 0..depth {
14716            stops.push(
14717                atn.add_state(AtnStateKind::RuleStop, Some(rule_index))
14718                    .expect("rule stop")
14719                    .index(),
14720            );
14721        }
14722        if consuming_follows {
14723            for rule_index in 0..depth - 1 {
14724                follows.push(
14725                    atn.add_state(AtnStateKind::Basic, Some(rule_index))
14726                        .expect("rule follow")
14727                        .index(),
14728                );
14729            }
14730        }
14731        atn.set_rule_to_start_state(starts.clone())
14732            .expect("rule start states");
14733        atn.set_rule_to_stop_state(stops.clone())
14734            .expect("rule stop states");
14735        for rule_index in 0..depth - 1 {
14736            let follow_state = if consuming_follows {
14737                follows[rule_index]
14738            } else {
14739                stops[rule_index]
14740            };
14741            atn.add_transition(
14742                starts[rule_index],
14743                ParserTransitionSpec::Rule {
14744                    target: starts[rule_index + 1],
14745                    rule_index: rule_index + 1,
14746                    follow_state,
14747                    precedence: 0,
14748                },
14749            )
14750            .expect("nested rule transition");
14751            if branching {
14752                atn.add_transition(
14753                    starts[rule_index],
14754                    ParserTransitionSpec::Atom {
14755                        target: stops[rule_index],
14756                        label: 2,
14757                    },
14758                )
14759                .expect("dead branch transition");
14760            }
14761            if consuming_follows {
14762                atn.add_transition(
14763                    follow_state,
14764                    ParserTransitionSpec::Atom {
14765                        target: stops[rule_index],
14766                        label: 1,
14767                    },
14768                )
14769                .expect("consuming follow transition");
14770            }
14771        }
14772        let token_set = atn.add_interval_set([(1, 1)]).expect("token set");
14773        atn.add_transition(
14774            starts[depth - 1],
14775            ParserTransitionSpec::Set {
14776                target: stops[depth - 1],
14777                set: token_set,
14778            },
14779        )
14780        .expect("terminal set transition");
14781        if branching {
14782            atn.add_transition(
14783                starts[depth - 1],
14784                ParserTransitionSpec::Atom {
14785                    target: stops[depth - 1],
14786                    label: 2,
14787                },
14788            )
14789            .expect("dead leaf branch transition");
14790        }
14791        finish_atn(atn)
14792    }
14793
14794    fn ordinary_star_loop_atn() -> Atn {
14795        let mut atn = ParserAtnBuilder::new(2);
14796        for (state_number, kind, rule_index) in [
14797            (0, AtnStateKind::RuleStart, 0),
14798            (1, AtnStateKind::StarLoopEntry, 0),
14799            (2, AtnStateKind::Basic, 0),
14800            (3, AtnStateKind::StarLoopBack, 0),
14801            (4, AtnStateKind::LoopEnd, 0),
14802            (5, AtnStateKind::Basic, 0),
14803            (6, AtnStateKind::RuleStop, 0),
14804            (7, AtnStateKind::RuleStart, 1),
14805            (8, AtnStateKind::Basic, 1),
14806            (9, AtnStateKind::RuleStop, 1),
14807        ] {
14808            assert_eq!(
14809                atn.add_state(kind, Some(rule_index))
14810                    .expect("state")
14811                    .index(),
14812                state_number
14813            );
14814        }
14815        atn.set_rule_to_start_state(vec![0, 7])
14816            .expect("rule start states");
14817        atn.set_rule_to_stop_state(vec![6, 9])
14818            .expect("rule stop states");
14819        atn.add_decision_state(1).expect("decision state");
14820        atn.set_loop_back_state(4, 3).expect("loop back state");
14821        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
14822            .expect("transition");
14823        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
14824            .expect("transition");
14825        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 4 })
14826            .expect("transition");
14827        atn.add_transition(
14828            2,
14829            ParserTransitionSpec::Rule {
14830                target: 7,
14831                rule_index: 1,
14832                follow_state: 3,
14833                precedence: 0,
14834            },
14835        )
14836        .expect("transition");
14837        atn.add_transition(3, ParserTransitionSpec::Epsilon { target: 1 })
14838            .expect("transition");
14839        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
14840            .expect("transition");
14841        atn.add_transition(
14842            5,
14843            ParserTransitionSpec::Atom {
14844                target: 6,
14845                label: TOKEN_EOF,
14846            },
14847        )
14848        .expect("transition");
14849        atn.add_transition(7, ParserTransitionSpec::Epsilon { target: 8 })
14850            .expect("transition");
14851        atn.add_transition(
14852            8,
14853            ParserTransitionSpec::Atom {
14854                target: 9,
14855                label: 1,
14856            },
14857        )
14858        .expect("transition");
14859        finish_atn(atn)
14860    }
14861
14862    /// ATN for `s : (X | X X)* EOF`.
14863    fn ambiguous_ordinary_star_loop_atn() -> Atn {
14864        let mut atn = ParserAtnBuilder::new(1);
14865        for (state_number, kind) in [
14866            (0, AtnStateKind::RuleStart),
14867            (1, AtnStateKind::StarLoopEntry),
14868            (2, AtnStateKind::StarBlockStart),
14869            (3, AtnStateKind::Basic),
14870            (4, AtnStateKind::BlockEnd),
14871            (5, AtnStateKind::StarLoopBack),
14872            (6, AtnStateKind::LoopEnd),
14873            (7, AtnStateKind::Basic),
14874            (8, AtnStateKind::RuleStop),
14875        ] {
14876            assert_eq!(
14877                atn.add_state(kind, Some(0)).expect("state").index(),
14878                state_number
14879            );
14880        }
14881        atn.set_rule_to_start_state(vec![0])
14882            .expect("rule start states");
14883        atn.set_rule_to_stop_state(vec![8])
14884            .expect("rule stop states");
14885        atn.set_end_state(2, 4).expect("block end state");
14886        atn.set_loop_back_state(6, 5).expect("loop back state");
14887        atn.add_decision_state(1).expect("decision state");
14888        atn.add_decision_state(2).expect("decision state");
14889        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
14890            .expect("transition");
14891        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
14892            .expect("transition");
14893        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 6 })
14894            .expect("transition");
14895        atn.add_transition(
14896            2,
14897            ParserTransitionSpec::Atom {
14898                target: 4,
14899                label: 1,
14900            },
14901        )
14902        .expect("transition");
14903        atn.add_transition(
14904            2,
14905            ParserTransitionSpec::Atom {
14906                target: 3,
14907                label: 1,
14908            },
14909        )
14910        .expect("transition");
14911        atn.add_transition(
14912            3,
14913            ParserTransitionSpec::Atom {
14914                target: 4,
14915                label: 1,
14916            },
14917        )
14918        .expect("transition");
14919        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
14920            .expect("transition");
14921        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 1 })
14922            .expect("transition");
14923        atn.add_transition(6, ParserTransitionSpec::Epsilon { target: 7 })
14924            .expect("transition");
14925        atn.add_transition(
14926            7,
14927            ParserTransitionSpec::Atom {
14928                target: 8,
14929                label: TOKEN_EOF,
14930            },
14931        )
14932        .expect("transition");
14933        finish_atn(atn)
14934    }
14935
14936    fn ordinary_plus_loop_atn() -> Atn {
14937        let mut atn = ParserAtnBuilder::new(2);
14938        for (state_number, kind, rule_index) in [
14939            (0, AtnStateKind::RuleStart, 0),
14940            (1, AtnStateKind::Basic, 0),
14941            (2, AtnStateKind::PlusLoopBack, 0),
14942            (3, AtnStateKind::LoopEnd, 0),
14943            (4, AtnStateKind::Basic, 0),
14944            (5, AtnStateKind::RuleStop, 0),
14945            (6, AtnStateKind::RuleStart, 1),
14946            (7, AtnStateKind::Basic, 1),
14947            (8, AtnStateKind::RuleStop, 1),
14948        ] {
14949            assert_eq!(
14950                atn.add_state(kind, Some(rule_index))
14951                    .expect("state")
14952                    .index(),
14953                state_number
14954            );
14955        }
14956        atn.set_rule_to_start_state(vec![0, 6])
14957            .expect("rule start states");
14958        atn.set_rule_to_stop_state(vec![5, 8])
14959            .expect("rule stop states");
14960        atn.add_decision_state(2).expect("decision state");
14961        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
14962            .expect("transition");
14963        atn.add_transition(
14964            1,
14965            ParserTransitionSpec::Rule {
14966                target: 6,
14967                rule_index: 1,
14968                follow_state: 2,
14969                precedence: 0,
14970            },
14971        )
14972        .expect("transition");
14973        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 1 })
14974            .expect("transition");
14975        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 3 })
14976            .expect("transition");
14977        atn.add_transition(3, ParserTransitionSpec::Epsilon { target: 4 })
14978            .expect("transition");
14979        atn.add_transition(
14980            4,
14981            ParserTransitionSpec::Atom {
14982                target: 5,
14983                label: TOKEN_EOF,
14984            },
14985        )
14986        .expect("transition");
14987        atn.add_transition(6, ParserTransitionSpec::Epsilon { target: 7 })
14988            .expect("transition");
14989        atn.add_transition(
14990            7,
14991            ParserTransitionSpec::Atom {
14992                target: 8,
14993                label: 1,
14994            },
14995        )
14996        .expect("transition");
14997        finish_atn(atn)
14998    }
14999
15000    fn repeated_x_tokens(count: usize) -> Vec<TestToken> {
15001        let mut tokens = (0..count)
15002            .map(|_| TestToken::new(1).with_text("x"))
15003            .collect::<Vec<_>>();
15004        tokens.push(TestToken::eof("parser-test", count, 1, count));
15005        tokens
15006    }
15007
15008    fn left_recursive_loop_with_caller_follow_atn(caller_symbol: i32) -> Atn {
15009        let mut atn = ParserAtnBuilder::new(2);
15010        assert_eq!(
15011            atn.add_state(AtnStateKind::RuleStart, Some(0))
15012                .expect("state")
15013                .index(),
15014            0
15015        );
15016        assert_eq!(
15017            atn.add_state(AtnStateKind::Basic, Some(0))
15018                .expect("state")
15019                .index(),
15020            1
15021        );
15022        assert_eq!(
15023            atn.add_state(AtnStateKind::Basic, Some(0))
15024                .expect("state")
15025                .index(),
15026            2
15027        );
15028        assert_eq!(
15029            atn.add_state(AtnStateKind::RuleStart, Some(1))
15030                .expect("state")
15031                .index(),
15032            3
15033        );
15034        atn.set_left_recursive_rule(3)
15035            .expect("left-recursive rule start");
15036        assert_eq!(
15037            atn.add_state(AtnStateKind::StarLoopEntry, Some(1))
15038                .expect("state")
15039                .index(),
15040            4
15041        );
15042        atn.set_precedence_rule_decision(4)
15043            .expect("precedence decision");
15044        assert_eq!(
15045            atn.add_state(AtnStateKind::Basic, Some(1))
15046                .expect("state")
15047                .index(),
15048            5
15049        );
15050        assert_eq!(
15051            atn.add_state(AtnStateKind::Basic, Some(1))
15052                .expect("state")
15053                .index(),
15054            6
15055        );
15056        assert_eq!(
15057            atn.add_state(AtnStateKind::LoopEnd, Some(1))
15058                .expect("state")
15059                .index(),
15060            7
15061        );
15062        assert_eq!(
15063            atn.add_state(AtnStateKind::RuleStop, Some(1))
15064                .expect("state")
15065                .index(),
15066            8
15067        );
15068        assert_eq!(
15069            atn.add_state(AtnStateKind::RuleStop, Some(0))
15070                .expect("state")
15071                .index(),
15072            9
15073        );
15074        atn.set_rule_to_start_state(vec![0, 3])
15075            .expect("rule start states");
15076        atn.set_rule_to_stop_state(vec![9, 8])
15077            .expect("rule stop states");
15078        atn.add_transition(
15079            1,
15080            ParserTransitionSpec::Rule {
15081                target: 3,
15082                rule_index: 1,
15083                follow_state: 2,
15084                precedence: 0,
15085            },
15086        )
15087        .expect("transition");
15088        atn.add_transition(
15089            2,
15090            ParserTransitionSpec::Atom {
15091                target: 9,
15092                label: caller_symbol,
15093            },
15094        )
15095        .expect("transition");
15096        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
15097            .expect("transition");
15098        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 7 })
15099            .expect("transition");
15100        atn.add_transition(
15101            5,
15102            ParserTransitionSpec::Precedence {
15103                target: 6,
15104                precedence: 1,
15105            },
15106        )
15107        .expect("transition");
15108        atn.add_transition(
15109            6,
15110            ParserTransitionSpec::Atom {
15111                target: 4,
15112                label: 1,
15113            },
15114        )
15115        .expect("transition");
15116        atn.add_transition(7, ParserTransitionSpec::Epsilon { target: 8 })
15117            .expect("transition");
15118        finish_atn(atn)
15119    }
15120
15121    fn labeled_left_recursive_operator_atn() -> Atn {
15122        let mut atn = ParserAtnBuilder::new(4);
15123        for (state, kind) in [
15124            (0, AtnStateKind::RuleStart),
15125            (1, AtnStateKind::BlockStart),
15126            (2, AtnStateKind::StarLoopEntry),
15127            (3, AtnStateKind::StarBlockStart),
15128            (4, AtnStateKind::Basic),
15129            (5, AtnStateKind::Basic),
15130            (6, AtnStateKind::Basic),
15131            (7, AtnStateKind::StarLoopBack),
15132            (8, AtnStateKind::LoopEnd),
15133            (9, AtnStateKind::RuleStop),
15134        ] {
15135            assert_eq!(atn.add_state(kind, Some(0)).expect("state").index(), state);
15136        }
15137        atn.set_left_recursive_rule(0)
15138            .expect("left-recursive rule start");
15139        atn.set_precedence_rule_decision(2)
15140            .expect("precedence decision");
15141        atn.set_loop_back_state(8, 7).expect("loop-back state");
15142        atn.set_rule_to_start_state(vec![0])
15143            .expect("rule start states");
15144        atn.set_rule_to_stop_state(vec![9])
15145            .expect("rule stop states");
15146        for state in [1, 2, 3] {
15147            atn.add_decision_state(state).expect("decision state");
15148        }
15149        for (source, target) in [(0, 1), (2, 3), (2, 8), (7, 2), (8, 9)] {
15150            atn.add_transition(source, ParserTransitionSpec::Epsilon { target })
15151                .expect("epsilon transition");
15152        }
15153        for (source, target, label) in [(1, 2, 1), (1, 2, 2), (4, 6, 4), (5, 6, 3), (6, 7, 1)] {
15154            atn.add_transition(source, ParserTransitionSpec::Atom { target, label })
15155                .expect("token transition");
15156        }
15157        for (target, precedence) in [(4, 2), (5, 1)] {
15158            atn.add_transition(3, ParserTransitionSpec::Precedence { target, precedence })
15159                .expect("operator precedence");
15160        }
15161        finish_atn(atn)
15162    }
15163
15164    fn parser_inside_left_recursive_callee(symbol: i32) -> BaseParser<Source> {
15165        let mut parser = mini_parser(vec![
15166            TestToken::new(symbol).with_text("lookahead"),
15167            TestToken::eof("parser-test", 1, 1, 1),
15168        ]);
15169        parser.rule_context_stack = vec![
15170            RuleContextFrame {
15171                rule_index: 0,
15172                invoking_state: -1,
15173            },
15174            RuleContextFrame {
15175                rule_index: 1,
15176                invoking_state: 1,
15177            },
15178        ];
15179        parser
15180    }
15181
15182    fn left_recursive_loop_with_shared_gt_prefix_atn() -> Atn {
15183        // StarLoopEntry with two operator alts that share leading token 1 (`>`):
15184        //   prec 2: token 1, token 1  (shift `>>`)
15185        //   prec 1: token 1           (relational `>`)
15186        let mut atn = ParserAtnBuilder::new(1);
15187        for (state, kind, rule) in [
15188            (0, AtnStateKind::RuleStart, 0),
15189            (1, AtnStateKind::StarLoopEntry, 0),
15190            (2, AtnStateKind::Basic, 0), // ops hub
15191            (3, AtnStateKind::Basic, 0), // shift prec
15192            (4, AtnStateKind::Basic, 0), // shift first >
15193            (5, AtnStateKind::Basic, 0), // shift second >
15194            (6, AtnStateKind::Basic, 0), // rel prec
15195            (7, AtnStateKind::Basic, 0), // rel >
15196            (8, AtnStateKind::LoopEnd, 0),
15197            (9, AtnStateKind::RuleStop, 0),
15198        ] {
15199            assert_eq!(
15200                atn.add_state(kind, Some(rule)).expect("state").index(),
15201                state
15202            );
15203            if state == 0 {
15204                atn.set_left_recursive_rule(state)
15205                    .expect("left-recursive rule start");
15206            } else if state == 1 {
15207                atn.set_precedence_rule_decision(state)
15208                    .expect("precedence decision");
15209            }
15210        }
15211        atn.set_rule_to_start_state(vec![0])
15212            .expect("rule start states");
15213        atn.set_rule_to_stop_state(vec![9])
15214            .expect("rule stop states");
15215        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
15216            .expect("ops");
15217        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 8 })
15218            .expect("exit");
15219        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 3 })
15220            .expect("to shift");
15221        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 6 })
15222            .expect("to rel");
15223        atn.add_transition(
15224            3,
15225            ParserTransitionSpec::Precedence {
15226                target: 4,
15227                precedence: 2,
15228            },
15229        )
15230        .expect("shift prec");
15231        atn.add_transition(
15232            4,
15233            ParserTransitionSpec::Atom {
15234                target: 5,
15235                label: 1,
15236            },
15237        )
15238        .expect("shift first >");
15239        atn.add_transition(
15240            5,
15241            ParserTransitionSpec::Atom {
15242                target: 1,
15243                label: 1,
15244            },
15245        )
15246        .expect("shift second >");
15247        atn.add_transition(
15248            6,
15249            ParserTransitionSpec::Precedence {
15250                target: 7,
15251                precedence: 1,
15252            },
15253        )
15254        .expect("rel prec");
15255        atn.add_transition(
15256            7,
15257            ParserTransitionSpec::Atom {
15258                target: 1,
15259                label: 1,
15260            },
15261        )
15262        .expect("rel >");
15263        atn.add_transition(8, ParserTransitionSpec::Epsilon { target: 9 })
15264            .expect("loop end");
15265        finish_atn(atn)
15266    }
15267
15268    fn left_recursive_loop_with_rule_wrapped_gt_prefix_atn() -> Atn {
15269        let mut atn = ParserAtnBuilder::new(2);
15270        for (state, kind, rule) in [
15271            (0, AtnStateKind::RuleStart, 0),
15272            (1, AtnStateKind::StarLoopEntry, 0),
15273            (2, AtnStateKind::Basic, 0),
15274            (3, AtnStateKind::Basic, 0),
15275            (4, AtnStateKind::Basic, 0),
15276            (5, AtnStateKind::Basic, 0),
15277            (6, AtnStateKind::Basic, 0),
15278            (7, AtnStateKind::Basic, 0),
15279            (8, AtnStateKind::LoopEnd, 0),
15280            (9, AtnStateKind::RuleStop, 0),
15281            (10, AtnStateKind::RuleStart, 1),
15282            (11, AtnStateKind::Basic, 1),
15283            (12, AtnStateKind::RuleStop, 1),
15284        ] {
15285            assert_eq!(
15286                atn.add_state(kind, Some(rule)).expect("state").index(),
15287                state
15288            );
15289            if state == 0 {
15290                atn.set_left_recursive_rule(state)
15291                    .expect("left-recursive rule start");
15292            } else if state == 1 {
15293                atn.set_precedence_rule_decision(state)
15294                    .expect("precedence decision");
15295            }
15296        }
15297        atn.set_rule_to_start_state(vec![0, 10])
15298            .expect("rule start states");
15299        atn.set_rule_to_stop_state(vec![9, 12])
15300            .expect("rule stop states");
15301        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
15302            .expect("ops");
15303        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 8 })
15304            .expect("exit");
15305        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 3 })
15306            .expect("to shift");
15307        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 6 })
15308            .expect("to relational");
15309        atn.add_transition(
15310            3,
15311            ParserTransitionSpec::Precedence {
15312                target: 4,
15313                precedence: 2,
15314            },
15315        )
15316        .expect("shift precedence");
15317        atn.add_transition(
15318            4,
15319            ParserTransitionSpec::Rule {
15320                target: 10,
15321                rule_index: 1,
15322                follow_state: 5,
15323                precedence: 0,
15324            },
15325        )
15326        .expect("first shift token helper");
15327        atn.add_transition(
15328            5,
15329            ParserTransitionSpec::Atom {
15330                target: 1,
15331                label: 1,
15332            },
15333        )
15334        .expect("second shift token");
15335        atn.add_transition(
15336            6,
15337            ParserTransitionSpec::Precedence {
15338                target: 7,
15339                precedence: 1,
15340            },
15341        )
15342        .expect("relational precedence");
15343        atn.add_transition(
15344            7,
15345            ParserTransitionSpec::Atom {
15346                target: 1,
15347                label: 1,
15348            },
15349        )
15350        .expect("relational token");
15351        atn.add_transition(8, ParserTransitionSpec::Epsilon { target: 9 })
15352            .expect("loop end");
15353        atn.add_transition(10, ParserTransitionSpec::Epsilon { target: 11 })
15354            .expect("helper entry");
15355        atn.add_transition(
15356            11,
15357            ParserTransitionSpec::Atom {
15358                target: 12,
15359                label: 1,
15360            },
15361        )
15362        .expect("first shift token");
15363        finish_atn(atn)
15364    }
15365
15366    fn left_recursive_loop_with_predicate_and_multi_token_prefix_atn() -> Atn {
15367        let mut atn = ParserAtnBuilder::new(1);
15368        for (state, kind) in [
15369            (0, AtnStateKind::RuleStart),
15370            (1, AtnStateKind::StarLoopEntry),
15371            (2, AtnStateKind::Basic),
15372            (3, AtnStateKind::Basic),
15373            (4, AtnStateKind::Basic),
15374            (5, AtnStateKind::Basic),
15375            (6, AtnStateKind::Basic),
15376            (7, AtnStateKind::Basic),
15377            (8, AtnStateKind::Basic),
15378            (9, AtnStateKind::LoopEnd),
15379            (10, AtnStateKind::RuleStop),
15380        ] {
15381            assert_eq!(atn.add_state(kind, Some(0)).expect("state").index(), state);
15382            if state == 0 {
15383                atn.set_left_recursive_rule(state)
15384                    .expect("left-recursive rule start");
15385            } else if state == 1 {
15386                atn.set_precedence_rule_decision(state)
15387                    .expect("precedence decision");
15388            }
15389        }
15390        atn.set_rule_to_start_state(vec![0])
15391            .expect("rule start states");
15392        atn.set_rule_to_stop_state(vec![10])
15393            .expect("rule stop states");
15394        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
15395            .expect("ops");
15396        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 9 })
15397            .expect("exit");
15398        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 3 })
15399            .expect("to multi-token operator");
15400        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 6 })
15401            .expect("to predicate operator");
15402        atn.add_transition(
15403            3,
15404            ParserTransitionSpec::Precedence {
15405                target: 4,
15406                precedence: 2,
15407            },
15408        )
15409        .expect("multi-token precedence");
15410        atn.add_transition(
15411            4,
15412            ParserTransitionSpec::Atom {
15413                target: 5,
15414                label: 1,
15415            },
15416        )
15417        .expect("multi-token first");
15418        atn.add_transition(
15419            5,
15420            ParserTransitionSpec::Atom {
15421                target: 1,
15422                label: 1,
15423            },
15424        )
15425        .expect("multi-token second");
15426        atn.add_transition(
15427            6,
15428            ParserTransitionSpec::Precedence {
15429                target: 7,
15430                precedence: 2,
15431            },
15432        )
15433        .expect("predicate precedence");
15434        atn.add_transition(
15435            7,
15436            ParserTransitionSpec::Predicate {
15437                target: 8,
15438                rule_index: 0,
15439                pred_index: 0,
15440                context_dependent: false,
15441            },
15442        )
15443        .expect("operator predicate");
15444        atn.add_transition(
15445            8,
15446            ParserTransitionSpec::Atom {
15447                target: 1,
15448                label: 1,
15449            },
15450        )
15451        .expect("predicate single token");
15452        atn.add_transition(9, ParserTransitionSpec::Epsilon { target: 10 })
15453            .expect("loop end");
15454        finish_atn(atn)
15455    }
15456
15457    fn left_recursive_loop_with_nullable_operator_prefix_atn() -> Atn {
15458        let mut atn = ParserAtnBuilder::new(2);
15459        for (state, kind, rule) in [
15460            (0, AtnStateKind::RuleStart, 0),
15461            (1, AtnStateKind::StarLoopEntry, 0),
15462            (2, AtnStateKind::Basic, 0),
15463            (3, AtnStateKind::Basic, 0),
15464            (4, AtnStateKind::Basic, 0),
15465            (5, AtnStateKind::LoopEnd, 0),
15466            (6, AtnStateKind::RuleStop, 0),
15467            (7, AtnStateKind::RuleStart, 1),
15468            (8, AtnStateKind::RuleStop, 1),
15469            (9, AtnStateKind::Basic, 1),
15470        ] {
15471            assert_eq!(
15472                atn.add_state(kind, Some(rule)).expect("state").index(),
15473                state
15474            );
15475            if state == 0 {
15476                atn.set_left_recursive_rule(state)
15477                    .expect("left-recursive rule start");
15478            } else if state == 1 {
15479                atn.set_precedence_rule_decision(state)
15480                    .expect("precedence decision");
15481            }
15482        }
15483        atn.set_rule_to_start_state(vec![0, 7])
15484            .expect("rule start states");
15485        atn.set_rule_to_stop_state(vec![6, 8])
15486            .expect("rule stop states");
15487        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
15488            .expect("transition");
15489        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 5 })
15490            .expect("transition");
15491        atn.add_transition(
15492            2,
15493            ParserTransitionSpec::Precedence {
15494                target: 3,
15495                precedence: 3,
15496            },
15497        )
15498        .expect("transition");
15499        atn.add_transition(
15500            3,
15501            ParserTransitionSpec::Rule {
15502                target: 7,
15503                rule_index: 1,
15504                follow_state: 4,
15505                precedence: 0,
15506            },
15507        )
15508        .expect("transition");
15509        atn.add_transition(
15510            4,
15511            ParserTransitionSpec::Atom {
15512                target: 1,
15513                label: 1,
15514            },
15515        )
15516        .expect("transition");
15517        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 6 })
15518            .expect("transition");
15519        atn.add_transition(
15520            7,
15521            ParserTransitionSpec::Precedence {
15522                target: 9,
15523                precedence: 1,
15524            },
15525        )
15526        .expect("transition");
15527        atn.add_transition(9, ParserTransitionSpec::Epsilon { target: 8 })
15528            .expect("transition");
15529        finish_atn(atn)
15530    }
15531
15532    fn left_recursive_loop_with_predicate_guarded_operator_atn() -> Atn {
15533        let mut atn = ParserAtnBuilder::new(2);
15534        for (state, kind) in [
15535            (0, AtnStateKind::RuleStart),
15536            (1, AtnStateKind::StarLoopEntry),
15537            (2, AtnStateKind::Basic),
15538            (3, AtnStateKind::Basic),
15539            (4, AtnStateKind::Basic),
15540            (5, AtnStateKind::LoopEnd),
15541            (6, AtnStateKind::RuleStop),
15542        ] {
15543            assert_eq!(atn.add_state(kind, Some(0)).expect("state").index(), state);
15544            if state == 0 {
15545                atn.set_left_recursive_rule(state)
15546                    .expect("left-recursive rule start");
15547            } else if state == 1 {
15548                atn.set_precedence_rule_decision(state)
15549                    .expect("precedence decision");
15550            }
15551        }
15552        atn.set_rule_to_start_state(vec![0])
15553            .expect("rule start states");
15554        atn.set_rule_to_stop_state(vec![6])
15555            .expect("rule stop states");
15556        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
15557            .expect("transition");
15558        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 5 })
15559            .expect("transition");
15560        atn.add_transition(
15561            2,
15562            ParserTransitionSpec::Precedence {
15563                target: 3,
15564                precedence: 1,
15565            },
15566        )
15567        .expect("transition");
15568        atn.add_transition(
15569            3,
15570            ParserTransitionSpec::Predicate {
15571                target: 4,
15572                rule_index: 0,
15573                pred_index: 0,
15574                context_dependent: false,
15575            },
15576        )
15577        .expect("transition");
15578        atn.add_transition(
15579            4,
15580            ParserTransitionSpec::Atom {
15581                target: 1,
15582                label: 1,
15583            },
15584        )
15585        .expect("transition");
15586        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 6 })
15587            .expect("transition");
15588        finish_atn(atn)
15589    }
15590
15591    fn left_recursive_loop_with_nullable_follow_call_atn(caller_symbol: i32) -> Atn {
15592        let mut atn = ParserAtnBuilder::new(2);
15593        for (state, kind, rule) in [
15594            (0, AtnStateKind::RuleStart, 0),
15595            (1, AtnStateKind::Basic, 0),
15596            (2, AtnStateKind::Basic, 0),
15597            (3, AtnStateKind::Basic, 0),
15598            (4, AtnStateKind::RuleStop, 0),
15599            (5, AtnStateKind::RuleStart, 1),
15600            (6, AtnStateKind::StarLoopEntry, 1),
15601            (7, AtnStateKind::Basic, 1),
15602            (8, AtnStateKind::Basic, 1),
15603            (9, AtnStateKind::LoopEnd, 1),
15604            (10, AtnStateKind::RuleStop, 1),
15605            (11, AtnStateKind::RuleStart, 2),
15606            (12, AtnStateKind::RuleStop, 2),
15607        ] {
15608            assert_eq!(
15609                atn.add_state(kind, Some(rule)).expect("state").index(),
15610                state
15611            );
15612            if state == 5 {
15613                atn.set_left_recursive_rule(state)
15614                    .expect("left-recursive rule start");
15615            } else if state == 6 {
15616                atn.set_precedence_rule_decision(state)
15617                    .expect("precedence decision");
15618            }
15619        }
15620        atn.set_rule_to_start_state(vec![0, 5, 11])
15621            .expect("rule start states");
15622        atn.set_rule_to_stop_state(vec![4, 10, 12])
15623            .expect("rule stop states");
15624        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
15625            .expect("transition");
15626        atn.add_transition(
15627            1,
15628            ParserTransitionSpec::Rule {
15629                target: 5,
15630                rule_index: 1,
15631                follow_state: 2,
15632                precedence: 0,
15633            },
15634        )
15635        .expect("transition");
15636        atn.add_transition(
15637            2,
15638            ParserTransitionSpec::Rule {
15639                target: 11,
15640                rule_index: 2,
15641                follow_state: 3,
15642                precedence: 0,
15643            },
15644        )
15645        .expect("transition");
15646        atn.add_transition(
15647            3,
15648            ParserTransitionSpec::Atom {
15649                target: 4,
15650                label: caller_symbol,
15651            },
15652        )
15653        .expect("transition");
15654        atn.add_transition(6, ParserTransitionSpec::Epsilon { target: 7 })
15655            .expect("transition");
15656        atn.add_transition(6, ParserTransitionSpec::Epsilon { target: 9 })
15657            .expect("transition");
15658        atn.add_transition(
15659            7,
15660            ParserTransitionSpec::Precedence {
15661                target: 8,
15662                precedence: 1,
15663            },
15664        )
15665        .expect("transition");
15666        atn.add_transition(
15667            8,
15668            ParserTransitionSpec::Atom {
15669                target: 6,
15670                label: 1,
15671            },
15672        )
15673        .expect("transition");
15674        atn.add_transition(9, ParserTransitionSpec::Epsilon { target: 10 })
15675            .expect("transition");
15676        atn.add_transition(11, ParserTransitionSpec::Epsilon { target: 12 })
15677            .expect("transition");
15678        finish_atn(atn)
15679    }
15680
15681    fn left_recursive_loop_with_nullable_parent_return_atn(caller_symbol: i32) -> Atn {
15682        let mut atn = ParserAtnBuilder::new(2);
15683        for (state, kind, rule) in [
15684            (0, AtnStateKind::RuleStart, 0),
15685            (1, AtnStateKind::Basic, 0),
15686            (2, AtnStateKind::Basic, 0),
15687            (3, AtnStateKind::RuleStop, 0),
15688            (4, AtnStateKind::RuleStart, 1),
15689            (5, AtnStateKind::Basic, 1),
15690            (6, AtnStateKind::Basic, 1),
15691            (7, AtnStateKind::RuleStop, 1),
15692            (8, AtnStateKind::RuleStart, 2),
15693            (9, AtnStateKind::StarLoopEntry, 2),
15694            (10, AtnStateKind::Basic, 2),
15695            (11, AtnStateKind::Basic, 2),
15696            (12, AtnStateKind::LoopEnd, 2),
15697            (13, AtnStateKind::RuleStop, 2),
15698        ] {
15699            assert_eq!(
15700                atn.add_state(kind, Some(rule)).expect("state").index(),
15701                state
15702            );
15703            if state == 8 {
15704                atn.set_left_recursive_rule(state)
15705                    .expect("left-recursive rule start");
15706            } else if state == 9 {
15707                atn.set_precedence_rule_decision(state)
15708                    .expect("precedence decision");
15709            }
15710        }
15711        atn.set_rule_to_start_state(vec![0, 4, 8])
15712            .expect("rule start states");
15713        atn.set_rule_to_stop_state(vec![3, 7, 13])
15714            .expect("rule stop states");
15715        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
15716            .expect("transition");
15717        atn.add_transition(
15718            1,
15719            ParserTransitionSpec::Rule {
15720                target: 4,
15721                rule_index: 1,
15722                follow_state: 2,
15723                precedence: 0,
15724            },
15725        )
15726        .expect("transition");
15727        atn.add_transition(
15728            2,
15729            ParserTransitionSpec::Atom {
15730                target: 3,
15731                label: caller_symbol,
15732            },
15733        )
15734        .expect("transition");
15735        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
15736            .expect("transition");
15737        atn.add_transition(
15738            5,
15739            ParserTransitionSpec::Rule {
15740                target: 8,
15741                rule_index: 2,
15742                follow_state: 6,
15743                precedence: 0,
15744            },
15745        )
15746        .expect("transition");
15747        atn.add_transition(6, ParserTransitionSpec::Epsilon { target: 7 })
15748            .expect("transition");
15749        atn.add_transition(9, ParserTransitionSpec::Epsilon { target: 10 })
15750            .expect("transition");
15751        atn.add_transition(9, ParserTransitionSpec::Epsilon { target: 12 })
15752            .expect("transition");
15753        atn.add_transition(
15754            10,
15755            ParserTransitionSpec::Precedence {
15756                target: 11,
15757                precedence: 1,
15758            },
15759        )
15760        .expect("transition");
15761        atn.add_transition(
15762            11,
15763            ParserTransitionSpec::Atom {
15764                target: 9,
15765                label: 1,
15766            },
15767        )
15768        .expect("transition");
15769        atn.add_transition(12, ParserTransitionSpec::Epsilon { target: 13 })
15770            .expect("transition");
15771        finish_atn(atn)
15772    }
15773
15774    fn left_recursive_loop_with_recursive_operand_return_atn(caller_symbol: i32) -> Atn {
15775        let mut atn = ParserAtnBuilder::new(2);
15776        for (state, kind, rule) in [
15777            (0, AtnStateKind::RuleStart, 0),
15778            (1, AtnStateKind::Basic, 0),
15779            (2, AtnStateKind::Basic, 0),
15780            (3, AtnStateKind::RuleStop, 0),
15781            (4, AtnStateKind::RuleStart, 1),
15782            (5, AtnStateKind::StarLoopEntry, 1),
15783            (6, AtnStateKind::Basic, 1),
15784            (7, AtnStateKind::Basic, 1),
15785            (8, AtnStateKind::Basic, 1),
15786            (9, AtnStateKind::Basic, 1),
15787            (10, AtnStateKind::LoopEnd, 1),
15788            (11, AtnStateKind::RuleStop, 1),
15789        ] {
15790            assert_eq!(
15791                atn.add_state(kind, Some(rule)).expect("state").index(),
15792                state
15793            );
15794            if state == 4 {
15795                atn.set_left_recursive_rule(state)
15796                    .expect("left-recursive rule start");
15797            } else if state == 5 {
15798                atn.set_precedence_rule_decision(state)
15799                    .expect("precedence decision");
15800            }
15801        }
15802        atn.set_rule_to_start_state(vec![0, 4])
15803            .expect("rule start states");
15804        atn.set_rule_to_stop_state(vec![3, 11])
15805            .expect("rule stop states");
15806        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
15807            .expect("transition");
15808        atn.add_transition(
15809            1,
15810            ParserTransitionSpec::Rule {
15811                target: 4,
15812                rule_index: 1,
15813                follow_state: 2,
15814                precedence: 0,
15815            },
15816        )
15817        .expect("transition");
15818        atn.add_transition(
15819            2,
15820            ParserTransitionSpec::Atom {
15821                target: 3,
15822                label: caller_symbol,
15823            },
15824        )
15825        .expect("transition");
15826        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 6 })
15827            .expect("transition");
15828        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 10 })
15829            .expect("transition");
15830        atn.add_transition(
15831            6,
15832            ParserTransitionSpec::Precedence {
15833                target: 7,
15834                precedence: 1,
15835            },
15836        )
15837        .expect("transition");
15838        atn.add_transition(
15839            7,
15840            ParserTransitionSpec::Atom {
15841                target: 8,
15842                label: 1,
15843            },
15844        )
15845        .expect("transition");
15846        atn.add_transition(
15847            8,
15848            ParserTransitionSpec::Rule {
15849                target: 4,
15850                rule_index: 1,
15851                follow_state: 9,
15852                precedence: 2,
15853            },
15854        )
15855        .expect("transition");
15856        atn.add_transition(9, ParserTransitionSpec::Epsilon { target: 5 })
15857            .expect("transition");
15858        atn.add_transition(10, ParserTransitionSpec::Epsilon { target: 11 })
15859            .expect("transition");
15860        finish_atn(atn)
15861    }
15862
15863    #[test]
15864    fn left_recursive_loop_defers_overlapping_caller_lookahead() {
15865        let overlapping_atn = left_recursive_loop_with_caller_follow_atn(1);
15866        let unambiguous_atn = left_recursive_loop_with_caller_follow_atn(2);
15867
15868        let mut overlapping = parser_inside_left_recursive_callee(1);
15869        assert_eq!(
15870            overlapping.left_recursive_loop_enter_prediction(&overlapping_atn, 4, 0),
15871            None
15872        );
15873
15874        let mut unambiguous_enter = parser_inside_left_recursive_callee(1);
15875        assert_eq!(
15876            unambiguous_enter.left_recursive_loop_enter_prediction(&unambiguous_atn, 4, 0),
15877            Some(true)
15878        );
15879
15880        let mut unambiguous_exit = parser_inside_left_recursive_callee(2);
15881        assert_eq!(
15882            unambiguous_exit.left_recursive_loop_enter_prediction(&unambiguous_atn, 4, 0),
15883            Some(false)
15884        );
15885
15886        assert_eq!(
15887            overlapping.left_recursive_loop_enter_prediction(&unambiguous_atn, 4, 0),
15888            Some(true),
15889            "overlap results must not leak across ATNs"
15890        );
15891    }
15892
15893    #[test]
15894    fn left_recursive_loop_enters_after_nullable_operator_prefix() {
15895        let atn = left_recursive_loop_with_nullable_operator_prefix_atn();
15896        let mut parser = mini_parser(vec![
15897            TestToken::new(1).with_text("operator"),
15898            TestToken::eof("parser-test", 1, 1, 1),
15899        ]);
15900        parser.rule_context_stack = vec![RuleContextFrame {
15901            rule_index: 0,
15902            invoking_state: -1,
15903        }];
15904
15905        assert_eq!(
15906            parser.left_recursive_loop_enter_prediction(&atn, 1, 0),
15907            Some(true)
15908        );
15909        assert_eq!(
15910            parser.left_recursive_loop_enter_prediction(&atn, 1, 0),
15911            Some(true),
15912            "cached operator lookahead must preserve the nullable prefix return path"
15913        );
15914        assert_eq!(
15915            parser.left_recursive_loop_enter_prediction(&atn, 1, 2),
15916            Some(true),
15917            "the nullable child must use its rule-call precedence, not the caller precedence"
15918        );
15919    }
15920
15921    #[test]
15922    fn left_recursive_loop_defers_multi_token_prefix_that_shadows_lower_single_token() {
15923        // Models Java `>` (relational, prec 1, one token) vs `>>` (shift, prec 2,
15924        // two tokens). At prec 2 only shift is viable; one-token lookahead on `>`
15925        // must defer so StarLoopEntry adaptive predict can exit when the second
15926        // `>` is absent (as in `a < b > c`).
15927        let atn = left_recursive_loop_with_shared_gt_prefix_atn();
15928        let mut parser = mini_parser(vec![
15929            TestToken::new(1).with_text(">"),
15930            TestToken::new(2).with_text("id"),
15931            TestToken::eof("parser-test", 1, 1, 1),
15932        ]);
15933        parser.rule_context_stack = vec![RuleContextFrame {
15934            rule_index: 0,
15935            invoking_state: -1,
15936        }];
15937
15938        assert_eq!(
15939            parser.left_recursive_loop_enter_prediction(&atn, 1, 0),
15940            Some(true),
15941            "at low precedence relational `>` is a single-token operator"
15942        );
15943        assert_eq!(
15944            parser.left_recursive_loop_enter_prediction(&atn, 1, 1),
15945            Some(true),
15946            "relational remains single-token at its own precedence"
15947        );
15948        assert_eq!(
15949            parser.left_recursive_loop_enter_prediction(&atn, 1, 2),
15950            None,
15951            "at shift precedence, bare `>` must not force enter"
15952        );
15953    }
15954
15955    #[test]
15956    fn left_recursive_loop_preserves_rule_wrapped_operator_continuation() {
15957        let atn = left_recursive_loop_with_rule_wrapped_gt_prefix_atn();
15958        let mut parser = mini_parser(vec![
15959            TestToken::new(1).with_text(">"),
15960            TestToken::new(2).with_text("id"),
15961            TestToken::eof("parser-test", 1, 1, 1),
15962        ]);
15963        parser.rule_context_stack = vec![RuleContextFrame {
15964            rule_index: 0,
15965            invoking_state: -1,
15966        }];
15967
15968        assert_eq!(
15969            parser.left_recursive_loop_enter_prediction(&atn, 1, 0),
15970            Some(true),
15971            "the direct relational alternative remains a one-token operator"
15972        );
15973        assert_eq!(
15974            parser.left_recursive_loop_enter_prediction(&atn, 1, 2),
15975            None,
15976            "a token matched in the helper rule must return to the second shift token"
15977        );
15978    }
15979
15980    #[test]
15981    fn left_recursive_loop_preserves_predicate_and_multi_token_reachability() {
15982        let atn = left_recursive_loop_with_predicate_and_multi_token_prefix_atn();
15983        let mut parser = mini_parser(vec![
15984            TestToken::new(1).with_text(">"),
15985            TestToken::new(2).with_text("id"),
15986            TestToken::eof("parser-test", 1, 1, 1),
15987        ]);
15988        parser.rule_context_stack = vec![RuleContextFrame {
15989            rule_index: 0,
15990            invoking_state: -1,
15991        }];
15992
15993        assert_eq!(
15994            parser.left_recursive_loop_enter_prediction(&atn, 1, 2),
15995            None,
15996            "a predicate-gated single-token path must not be hidden by a multi-token path"
15997        );
15998    }
15999
16000    #[test]
16001    fn left_recursive_loop_defers_predicate_guarded_operator() {
16002        let atn = left_recursive_loop_with_predicate_guarded_operator_atn();
16003        let mut parser = mini_parser_with_hooks(
16004            vec![
16005                TestToken::new(1).with_text("operator"),
16006                TestToken::eof("parser-test", 1, 1, 1),
16007            ],
16008            RejectingPredicateHooks::default(),
16009        );
16010        parser.rule_context_stack = vec![RuleContextFrame {
16011            rule_index: 0,
16012            invoking_state: -1,
16013        }];
16014
16015        assert_eq!(
16016            parser.left_recursive_loop_enter_prediction(&atn, 1, 0),
16017            None,
16018            "a false predicate must be evaluated before entering the operator alternative"
16019        );
16020        assert_eq!(
16021            parser.left_recursive_loop_enter_prediction(&atn, 1, 0),
16022            None,
16023            "cached predicate-dependent lookahead must keep deferring"
16024        );
16025    }
16026
16027    #[test]
16028    fn left_recursive_loop_defers_through_nullable_caller_rule_call() {
16029        let atn = left_recursive_loop_with_nullable_follow_call_atn(1);
16030        let mut parser = parser_inside_left_recursive_callee(1);
16031
16032        assert_eq!(
16033            parser.left_recursive_loop_enter_prediction(&atn, 6, 0),
16034            None
16035        );
16036        assert_eq!(
16037            parser.left_recursive_loop_enter_prediction(&atn, 6, 0),
16038            None,
16039            "the cached overlap must preserve the nullable child return path"
16040        );
16041    }
16042
16043    #[test]
16044    fn left_recursive_loop_defers_through_nullable_parent_return() {
16045        let atn = left_recursive_loop_with_nullable_parent_return_atn(1);
16046        let mut parser = mini_parser(vec![
16047            TestToken::new(1).with_text("lookahead"),
16048            TestToken::eof("parser-test", 1, 1, 1),
16049        ]);
16050        parser.rule_context_stack = vec![
16051            RuleContextFrame {
16052                rule_index: 0,
16053                invoking_state: -1,
16054            },
16055            RuleContextFrame {
16056                rule_index: 1,
16057                invoking_state: 1,
16058            },
16059            RuleContextFrame {
16060                rule_index: 2,
16061                invoking_state: 5,
16062            },
16063        ];
16064
16065        assert_eq!(
16066            parser.left_recursive_loop_enter_prediction(&atn, 9, 0),
16067            None,
16068            "a nullable caller must unwind to its parent's consuming follow path"
16069        );
16070        assert_eq!(
16071            parser.left_recursive_loop_enter_prediction(&atn, 9, 0),
16072            None,
16073            "the caller-overlap cache must not retain a false negative"
16074        );
16075    }
16076
16077    #[test]
16078    fn left_recursive_loop_defers_after_recursive_operand_returns_to_loop() {
16079        let atn = left_recursive_loop_with_recursive_operand_return_atn(1);
16080        let mut parser = mini_parser(vec![
16081            TestToken::new(1).with_text("lookahead"),
16082            TestToken::eof("parser-test", 1, 1, 1),
16083        ]);
16084        parser.rule_context_stack = vec![
16085            RuleContextFrame {
16086                rule_index: 0,
16087                invoking_state: -1,
16088            },
16089            RuleContextFrame {
16090                rule_index: 1,
16091                invoking_state: 1,
16092            },
16093            RuleContextFrame {
16094                rule_index: 1,
16095                invoking_state: 8,
16096            },
16097        ];
16098
16099        assert_eq!(
16100            parser.left_recursive_loop_enter_prediction(&atn, 5, 0),
16101            None,
16102            "a recursive operand return must preserve its parent caller context"
16103        );
16104        assert_eq!(
16105            parser.left_recursive_loop_enter_prediction(&atn, 5, 0),
16106            None,
16107            "the caller-overlap cache must preserve the loop-boundary return"
16108        );
16109    }
16110
16111    fn token_then_eof_atn() -> Atn {
16112        AtnDeserializer::new(&SerializedAtn::from_i32(&[
16113            4, 1, 2, // version, parser, max token type
16114            3, // states
16115            2, 0, // rule start
16116            1, 0, // basic
16117            7, 0, // rule stop
16118            0, // non-greedy states
16119            0, // precedence states
16120            1, // rules
16121            0, // rule 0 start
16122            0, // modes
16123            0, // sets
16124            2, // transitions
16125            0, 1, 5, 1, 0, 0, // match token 1
16126            1, 2, 5, -1, 0, 0, // match EOF
16127            0, // decisions
16128        ]))
16129        .deserialize_parser()
16130        .expect("artificial parser ATN should deserialize")
16131    }
16132
16133    fn epsilon_cycle_atn() -> Atn {
16134        let mut atn = ParserAtnBuilder::new(1);
16135        for (state_number, kind) in [
16136            (0, AtnStateKind::RuleStart),
16137            (1, AtnStateKind::Basic),
16138            (2, AtnStateKind::RuleStop),
16139        ] {
16140            assert_eq!(
16141                atn.add_state(kind, Some(0)).expect("state").index(),
16142                state_number
16143            );
16144        }
16145        atn.set_rule_to_start_state(vec![0])
16146            .expect("rule start states");
16147        atn.set_rule_to_stop_state(vec![2])
16148            .expect("rule stop states");
16149        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
16150            .expect("transition");
16151        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 1 })
16152            .expect("self-cycle transition");
16153        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
16154            .expect("exit transition");
16155        finish_atn(atn)
16156    }
16157
16158    fn committed_non_consuming_cycle_atn() -> Atn {
16159        let mut atn = ParserAtnBuilder::new(1);
16160        for (state_number, kind) in [
16161            (0, AtnStateKind::RuleStart),
16162            (1, AtnStateKind::Basic),
16163            (2, AtnStateKind::RuleStop),
16164        ] {
16165            assert_eq!(
16166                atn.add_state(kind, Some(0)).expect("state").index(),
16167                state_number
16168            );
16169        }
16170        atn.set_rule_to_start_state(vec![0])
16171            .expect("rule start states");
16172        atn.set_rule_to_stop_state(vec![2])
16173            .expect("rule stop states");
16174        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
16175            .expect("cycle entry");
16176        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 1 })
16177            .expect("self-cycle transition");
16178        finish_atn(atn)
16179    }
16180
16181    fn eof_then_action_atn() -> Atn {
16182        AtnDeserializer::new(&SerializedAtn::from_i32(&[
16183            4, 1, 1, // version, parser, max token type
16184            3, // states
16185            2, 0, // rule start
16186            1, 0, // basic
16187            7, 0, // rule stop
16188            0, // non-greedy states
16189            0, // precedence states
16190            1, // rules
16191            0, // rule 0 start
16192            0, // modes
16193            0, // sets
16194            2, // transitions
16195            0, 1, 5, -1, 0, 0, // match EOF
16196            1, 2, 6, 0, 0, 0, // parser action
16197            0, // decisions
16198        ]))
16199        .deserialize_parser()
16200        .expect("artificial parser ATN should deserialize")
16201    }
16202
16203    fn noop_action_then_token_then_eof_atn() -> Atn {
16204        AtnDeserializer::new(&SerializedAtn::from_i32(&[
16205            4, 1, 2, // version, parser, max token type
16206            4, // states
16207            2, 0, // rule start
16208            1, 0, // basic
16209            1, 0, // basic
16210            7, 0, // rule stop
16211            0, // non-greedy states
16212            0, // precedence states
16213            1, // rules
16214            0, // rule 0 start
16215            0, // modes
16216            0, // sets
16217            3, // transitions
16218            0, 1, 6, 0, -1, 0, // no-op parser action
16219            1, 2, 5, 1, 0, 0, // match token 1
16220            2, 3, 5, -1, 0, 0, // match EOF
16221            0, // decisions
16222        ]))
16223        .deserialize_parser()
16224        .expect("artificial no-op action ATN should deserialize")
16225    }
16226
16227    fn committed_action_then_predicate_atn() -> Atn {
16228        let mut atn = ParserAtnBuilder::new(1);
16229        for (state_number, kind) in [
16230            (0, AtnStateKind::RuleStart),
16231            (1, AtnStateKind::Basic),
16232            (2, AtnStateKind::Basic),
16233            (3, AtnStateKind::Basic),
16234            (4, AtnStateKind::RuleStop),
16235        ] {
16236            assert_eq!(
16237                atn.add_state(kind, Some(0)).expect("state").index(),
16238                state_number
16239            );
16240        }
16241        atn.set_rule_to_start_state(vec![0])
16242            .expect("rule start states");
16243        atn.set_rule_to_stop_state(vec![4])
16244            .expect("rule stop states");
16245        atn.add_transition(
16246            0,
16247            ParserTransitionSpec::Action {
16248                target: 1,
16249                rule_index: 0,
16250                action_index: None,
16251                context_dependent: false,
16252            },
16253        )
16254        .expect("action transition");
16255        atn.add_transition(
16256            1,
16257            ParserTransitionSpec::Predicate {
16258                target: 2,
16259                rule_index: 0,
16260                pred_index: 0,
16261                context_dependent: false,
16262            },
16263        )
16264        .expect("predicate transition");
16265        atn.add_transition(
16266            2,
16267            ParserTransitionSpec::Atom {
16268                target: 3,
16269                label: 1,
16270            },
16271        )
16272        .expect("token transition");
16273        atn.add_transition(
16274            3,
16275            ParserTransitionSpec::Atom {
16276                target: 4,
16277                label: TOKEN_EOF,
16278            },
16279        )
16280        .expect("EOF transition");
16281        finish_atn(atn)
16282    }
16283
16284    /// ATN for `parent : child[42] {Parent();}; child[int value] : {Child();} EOF;`.
16285    fn parameterized_child_action_eof_atn() -> Atn {
16286        let mut atn = ParserAtnBuilder::new(1);
16287        for (state_number, kind, rule_index) in [
16288            (0, AtnStateKind::RuleStart, 0),
16289            (1, AtnStateKind::Basic, 0),
16290            (2, AtnStateKind::Basic, 0),
16291            (3, AtnStateKind::RuleStop, 0),
16292            (4, AtnStateKind::RuleStart, 1),
16293            (5, AtnStateKind::Basic, 1),
16294            (6, AtnStateKind::RuleStop, 1),
16295        ] {
16296            assert_eq!(
16297                atn.add_state(kind, Some(rule_index))
16298                    .expect("state")
16299                    .index(),
16300                state_number
16301            );
16302        }
16303        atn.set_rule_to_start_state(vec![0, 4])
16304            .expect("rule start states");
16305        atn.set_rule_to_stop_state(vec![3, 6])
16306            .expect("rule stop states");
16307        atn.add_transition(
16308            0,
16309            ParserTransitionSpec::Rule {
16310                target: 4,
16311                rule_index: 1,
16312                follow_state: 1,
16313                precedence: 0,
16314            },
16315        )
16316        .expect("parameterized child call");
16317        atn.add_transition(
16318            1,
16319            ParserTransitionSpec::Action {
16320                target: 2,
16321                rule_index: 0,
16322                action_index: None,
16323                context_dependent: false,
16324            },
16325        )
16326        .expect("parent action");
16327        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 3 })
16328            .expect("parent stop");
16329        atn.add_transition(
16330            4,
16331            ParserTransitionSpec::Action {
16332                target: 5,
16333                rule_index: 1,
16334                action_index: None,
16335                context_dependent: false,
16336            },
16337        )
16338        .expect("child action");
16339        atn.add_transition(
16340            5,
16341            ParserTransitionSpec::Atom {
16342                target: 6,
16343                label: TOKEN_EOF,
16344            },
16345        )
16346        .expect("child EOF");
16347        finish_atn(atn)
16348    }
16349
16350    fn action_then_nested_rule_atn() -> Atn {
16351        let mut atn = ParserAtnBuilder::new(1);
16352        for (state_number, kind, rule_index) in [
16353            (0, AtnStateKind::RuleStart, 0),
16354            (1, AtnStateKind::Basic, 0),
16355            (2, AtnStateKind::Basic, 0),
16356            (3, AtnStateKind::RuleStop, 0),
16357            (4, AtnStateKind::RuleStart, 1),
16358            (5, AtnStateKind::RuleStop, 1),
16359        ] {
16360            assert_eq!(
16361                atn.add_state(kind, Some(rule_index))
16362                    .expect("state")
16363                    .index(),
16364                state_number
16365            );
16366        }
16367        atn.set_rule_to_start_state(vec![0, 4])
16368            .expect("rule start states");
16369        atn.set_rule_to_stop_state(vec![3, 5])
16370            .expect("rule stop states");
16371        atn.add_transition(
16372            0,
16373            ParserTransitionSpec::Action {
16374                target: 1,
16375                rule_index: 0,
16376                action_index: None,
16377                context_dependent: false,
16378            },
16379        )
16380        .expect("parent action");
16381        atn.add_transition(
16382            1,
16383            ParserTransitionSpec::Rule {
16384                target: 4,
16385                rule_index: 1,
16386                follow_state: 2,
16387                precedence: 0,
16388            },
16389        )
16390        .expect("nested rule call");
16391        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 3 })
16392            .expect("parent stop");
16393        atn.add_transition(
16394            4,
16395            ParserTransitionSpec::Atom {
16396                target: 5,
16397                label: TOKEN_EOF,
16398            },
16399        )
16400        .expect("child EOF");
16401        finish_atn(atn)
16402    }
16403
16404    fn losing_alternative_action_atn() -> Atn {
16405        let mut atn = ParserAtnBuilder::new(2);
16406        for (state_number, kind) in [
16407            (0, AtnStateKind::RuleStart),
16408            (1, AtnStateKind::BlockStart),
16409            (2, AtnStateKind::Basic),
16410            (3, AtnStateKind::Basic),
16411            (4, AtnStateKind::BlockEnd),
16412            (5, AtnStateKind::RuleStop),
16413        ] {
16414            assert_eq!(
16415                atn.add_state(kind, Some(0)).expect("state").index(),
16416                state_number
16417            );
16418        }
16419        atn.set_rule_to_start_state(vec![0])
16420            .expect("rule start states");
16421        atn.set_rule_to_stop_state(vec![5])
16422            .expect("rule stop states");
16423        atn.set_end_state(1, 4).expect("block end state");
16424        atn.add_decision_state(1).expect("decision state");
16425        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
16426            .expect("entry transition");
16427        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
16428            .expect("first alternative");
16429        atn.add_transition(
16430            1,
16431            ParserTransitionSpec::Atom {
16432                target: 4,
16433                label: 2,
16434            },
16435        )
16436        .expect("second alternative");
16437        atn.add_transition(
16438            2,
16439            ParserTransitionSpec::Action {
16440                target: 3,
16441                rule_index: 0,
16442                action_index: None,
16443                context_dependent: false,
16444            },
16445        )
16446        .expect("losing action");
16447        atn.add_transition(
16448            3,
16449            ParserTransitionSpec::Atom {
16450                target: 4,
16451                label: 1,
16452            },
16453        )
16454        .expect("first alternative token");
16455        atn.add_transition(
16456            4,
16457            ParserTransitionSpec::Atom {
16458                target: 5,
16459                label: TOKEN_EOF,
16460            },
16461        )
16462        .expect("EOF transition");
16463        finish_atn(atn)
16464    }
16465
16466    fn committed_action_star_loop_atn() -> Atn {
16467        let mut atn = ParserAtnBuilder::new(1);
16468        for (state_number, kind) in [
16469            (0, AtnStateKind::RuleStart),
16470            (1, AtnStateKind::StarLoopEntry),
16471            (2, AtnStateKind::Basic),
16472            (3, AtnStateKind::Basic),
16473            (4, AtnStateKind::StarLoopBack),
16474            (5, AtnStateKind::LoopEnd),
16475            (6, AtnStateKind::RuleStop),
16476        ] {
16477            assert_eq!(
16478                atn.add_state(kind, Some(0)).expect("state").index(),
16479                state_number
16480            );
16481        }
16482        atn.set_rule_to_start_state(vec![0])
16483            .expect("rule start states");
16484        atn.set_rule_to_stop_state(vec![6])
16485            .expect("rule stop states");
16486        atn.add_decision_state(1).expect("decision state");
16487        atn.set_loop_back_state(5, 4).expect("loop back state");
16488        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
16489            .expect("entry transition");
16490        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
16491            .expect("loop body");
16492        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 5 })
16493            .expect("loop exit");
16494        atn.add_transition(
16495            2,
16496            ParserTransitionSpec::Action {
16497                target: 3,
16498                rule_index: 0,
16499                action_index: None,
16500                context_dependent: false,
16501            },
16502        )
16503        .expect("loop action");
16504        atn.add_transition(
16505            3,
16506            ParserTransitionSpec::Atom {
16507                target: 4,
16508                label: 1,
16509            },
16510        )
16511        .expect("loop token");
16512        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 1 })
16513            .expect("loop back");
16514        atn.add_transition(
16515            5,
16516            ParserTransitionSpec::Atom {
16517                target: 6,
16518                label: TOKEN_EOF,
16519            },
16520        )
16521        .expect("EOF transition");
16522        finish_atn(atn)
16523    }
16524
16525    fn committed_action_left_recursive_atn() -> Atn {
16526        let mut atn = ParserAtnBuilder::new(4);
16527        for (state, kind) in [
16528            (0, AtnStateKind::RuleStart),
16529            (1, AtnStateKind::BlockStart),
16530            (2, AtnStateKind::StarLoopEntry),
16531            (3, AtnStateKind::StarBlockStart),
16532            (4, AtnStateKind::Basic),
16533            (5, AtnStateKind::Basic),
16534            (6, AtnStateKind::Basic),
16535            (7, AtnStateKind::StarLoopBack),
16536            (8, AtnStateKind::LoopEnd),
16537            (9, AtnStateKind::RuleStop),
16538            (10, AtnStateKind::Basic),
16539        ] {
16540            assert_eq!(atn.add_state(kind, Some(0)).expect("state").index(), state);
16541        }
16542        atn.set_left_recursive_rule(0)
16543            .expect("left-recursive rule start");
16544        atn.set_precedence_rule_decision(2)
16545            .expect("precedence decision");
16546        atn.set_loop_back_state(8, 7).expect("loop-back state");
16547        atn.set_rule_to_start_state(vec![0])
16548            .expect("rule start states");
16549        atn.set_rule_to_stop_state(vec![9])
16550            .expect("rule stop states");
16551        for state in [1, 2, 3] {
16552            atn.add_decision_state(state).expect("decision state");
16553        }
16554        for (source, target) in [(0, 1), (2, 3), (2, 8), (7, 2), (8, 9)] {
16555            atn.add_transition(source, ParserTransitionSpec::Epsilon { target })
16556                .expect("epsilon transition");
16557        }
16558        for (source, target, label) in [(1, 2, 1), (1, 2, 2), (4, 6, 4), (5, 6, 3)] {
16559            atn.add_transition(source, ParserTransitionSpec::Atom { target, label })
16560                .expect("token transition");
16561        }
16562        for (target, precedence) in [(4, 2), (5, 1)] {
16563            atn.add_transition(3, ParserTransitionSpec::Precedence { target, precedence })
16564                .expect("operator precedence");
16565        }
16566        atn.add_transition(
16567            6,
16568            ParserTransitionSpec::Action {
16569                target: 10,
16570                rule_index: 0,
16571                action_index: None,
16572                context_dependent: false,
16573            },
16574        )
16575        .expect("operator action");
16576        atn.add_transition(
16577            10,
16578            ParserTransitionSpec::Atom {
16579                target: 7,
16580                label: 1,
16581            },
16582        )
16583        .expect("right operand");
16584        finish_atn(atn)
16585    }
16586
16587    fn two_alt_decision_atn() -> Atn {
16588        let mut atn = ParserAtnBuilder::new(2);
16589        assert_eq!(
16590            atn.add_state(AtnStateKind::RuleStart, Some(0))
16591                .expect("state")
16592                .index(),
16593            0
16594        );
16595        assert_eq!(
16596            atn.add_state(AtnStateKind::BlockStart, Some(0))
16597                .expect("state")
16598                .index(),
16599            1
16600        );
16601        assert_eq!(
16602            atn.add_state(AtnStateKind::Basic, Some(0))
16603                .expect("state")
16604                .index(),
16605            2
16606        );
16607        assert_eq!(
16608            atn.add_state(AtnStateKind::Basic, Some(0))
16609                .expect("state")
16610                .index(),
16611            3
16612        );
16613        assert_eq!(
16614            atn.add_state(AtnStateKind::BlockEnd, Some(0))
16615                .expect("state")
16616                .index(),
16617            4
16618        );
16619        assert_eq!(
16620            atn.add_state(AtnStateKind::RuleStop, Some(0))
16621                .expect("state")
16622                .index(),
16623            5
16624        );
16625        atn.set_rule_to_start_state(vec![0])
16626            .expect("rule start states");
16627        atn.set_rule_to_stop_state(vec![5])
16628            .expect("rule stop states");
16629        atn.add_decision_state(1).expect("decision state");
16630        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
16631            .expect("transition");
16632        atn.add_transition(
16633            1,
16634            ParserTransitionSpec::Atom {
16635                target: 2,
16636                label: 1,
16637            },
16638        )
16639        .expect("transition");
16640        atn.add_transition(
16641            1,
16642            ParserTransitionSpec::Atom {
16643                target: 3,
16644                label: 2,
16645            },
16646        )
16647        .expect("transition");
16648        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 4 })
16649            .expect("transition");
16650        atn.add_transition(3, ParserTransitionSpec::Epsilon { target: 4 })
16651            .expect("transition");
16652        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
16653            .expect("transition");
16654        finish_atn(atn)
16655    }
16656
16657    /// ATN for `start : (A)? B EOF ;` (A=1, B=2, C=3, max token type 3).
16658    /// State 1 is the nullable optional-block decision; its sync set is {A, B}.
16659    fn optional_then_b_eof_atn() -> Atn {
16660        let mut atn = ParserAtnBuilder::new(3);
16661        assert_eq!(
16662            atn.add_state(AtnStateKind::RuleStart, Some(0))
16663                .expect("state")
16664                .index(),
16665            0
16666        );
16667        assert_eq!(
16668            atn.add_state(AtnStateKind::BlockStart, Some(0))
16669                .expect("state")
16670                .index(),
16671            1
16672        );
16673        assert_eq!(
16674            atn.add_state(AtnStateKind::Basic, Some(0))
16675                .expect("state")
16676                .index(),
16677            2
16678        );
16679        assert_eq!(
16680            atn.add_state(AtnStateKind::Basic, Some(0))
16681                .expect("state")
16682                .index(),
16683            3
16684        );
16685        assert_eq!(
16686            atn.add_state(AtnStateKind::Basic, Some(0))
16687                .expect("state")
16688                .index(),
16689            4
16690        );
16691        assert_eq!(
16692            atn.add_state(AtnStateKind::RuleStop, Some(0))
16693                .expect("state")
16694                .index(),
16695            5
16696        );
16697        atn.set_rule_to_start_state(vec![0])
16698            .expect("rule start states");
16699        atn.set_rule_to_stop_state(vec![5])
16700            .expect("rule stop states");
16701        atn.add_decision_state(1).expect("decision state");
16702        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
16703            .expect("transition");
16704        // Optional block: match A then fall through, or skip straight to state 3.
16705        atn.add_transition(
16706            1,
16707            ParserTransitionSpec::Atom {
16708                target: 3,
16709                label: 1,
16710            },
16711        )
16712        .expect("transition");
16713        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 3 })
16714            .expect("transition");
16715        // Match B, then EOF.
16716        atn.add_transition(
16717            3,
16718            ParserTransitionSpec::Atom {
16719                target: 4,
16720                label: 2,
16721            },
16722        )
16723        .expect("transition");
16724        atn.add_transition(
16725            4,
16726            ParserTransitionSpec::Atom {
16727                target: 5,
16728                label: TOKEN_EOF,
16729            },
16730        )
16731        .expect("transition");
16732        finish_atn(atn)
16733    }
16734
16735    #[test]
16736    fn sync_decision_deletes_only_a_single_token() {
16737        // ANTLR sync recovery deletes exactly one token, only when LA(2) is
16738        // expected. `(A)? B EOF` at the optional-block decision:
16739        //  - `C B`   -> single-token deletion: one error node for the extra `C`.
16740        //  - `C C B` -> LA(2) is `C` (not expected), so NO deletion; sync returns
16741        //               without consuming and records the expected set for the
16742        //               subsequent mismatch (the parser must not over-consume both
16743        //               `C`s and accept the input).
16744        let atn = optional_then_b_eof_atn();
16745
16746        let mut single = mini_parser(vec![
16747            TestToken::new(3).with_text("c"),
16748            TestToken::new(2).with_text("b"),
16749            TestToken::eof("parser-test", 1, 2, 2),
16750        ]);
16751        single.rule_context_stack = vec![RuleContextFrame {
16752            rule_index: 0,
16753            invoking_state: 0,
16754        }];
16755        let children = single
16756            .sync_decision(&atn, 1, true, false)
16757            .expect("single extraneous token recovers");
16758        assert_eq!(children.len(), 1);
16759        assert_eq!(single.node(children[0]).kind(), NodeKind::Error);
16760        assert_eq!(single.number_of_syntax_errors(), 1);
16761        // Exactly one token consumed (the cursor now sits on `b`).
16762        assert_eq!(single.la(1), 2);
16763
16764        let mut double = mini_parser(vec![
16765            TestToken::new(3).with_text("c"),
16766            TestToken::new(3).with_text("c"),
16767            TestToken::new(2).with_text("b"),
16768            TestToken::eof("parser-test", 1, 3, 3),
16769        ]);
16770        double.rule_context_stack = vec![RuleContextFrame {
16771            rule_index: 0,
16772            invoking_state: 0,
16773        }];
16774        let result = double.sync_decision(&atn, 1, true, false);
16775        // No single-token deletion fires (LA(2) is `c`, not expected): sync must NOT
16776        // consume either `c`. It reports the mismatch at the first `c` (so the parser
16777        // does not over-consume both and accept the input). Nothing is consumed, so
16778        // the cursor still sits on the first `c` for rule-level recovery.
16779        let error = result.expect_err("two extraneous tokens must not be deleted by sync");
16780        match error {
16781            AntlrError::ParserError { message, .. } => {
16782                assert!(message.starts_with("mismatched input"), "got: {message}");
16783            }
16784            other => panic!("expected a mismatched-input ParserError, got {other:?}"),
16785        }
16786        assert_eq!(double.la(1), 3);
16787    }
16788
16789    /// The real serialized ATN that `antlr4-rust-gen` emits for
16790    /// `grammar T; s : A* EOF; A:'a'; C:'c';` — a `*` loop whose follow set after
16791    /// the loop is `EOF`. The loop decision is state 5.
16792    fn star_loop_then_eof_atn() -> Atn {
16793        AtnDeserializer::new(&SerializedAtn::from_i32(&[
16794            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,
16795            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,
16796            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,
16797            0, 0, 1, 9, 1, 1, 0, 0, 0, 1, 5,
16798        ]))
16799        .deserialize_parser()
16800        .expect("star-loop-then-EOF ATN should deserialize")
16801    }
16802
16803    /// ATN for `entry : nested EOF; nested : A*;`.
16804    ///
16805    /// State 5 is nullable within `nested`; its caller follow is EOF.
16806    fn nested_star_rule_atn() -> Atn {
16807        let mut atn = ParserAtnBuilder::new(2);
16808        for (state_number, kind, rule_index) in [
16809            (0, AtnStateKind::RuleStart, 0),
16810            (1, AtnStateKind::Basic, 0),
16811            (2, AtnStateKind::Basic, 0),
16812            (3, AtnStateKind::RuleStop, 0),
16813            (4, AtnStateKind::RuleStart, 1),
16814            (5, AtnStateKind::StarLoopEntry, 1),
16815            (6, AtnStateKind::Basic, 1),
16816            (7, AtnStateKind::StarLoopBack, 1),
16817            (8, AtnStateKind::LoopEnd, 1),
16818            (9, AtnStateKind::RuleStop, 1),
16819        ] {
16820            assert_eq!(
16821                atn.add_state(kind, Some(rule_index))
16822                    .expect("state")
16823                    .index(),
16824                state_number
16825            );
16826        }
16827        atn.set_rule_to_start_state(vec![0, 4])
16828            .expect("rule start states");
16829        atn.set_rule_to_stop_state(vec![3, 9])
16830            .expect("rule stop states");
16831        atn.add_decision_state(5).expect("decision state");
16832        atn.set_loop_back_state(8, 7).expect("loop back state");
16833        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
16834            .expect("transition");
16835        atn.add_transition(
16836            1,
16837            ParserTransitionSpec::Rule {
16838                target: 4,
16839                rule_index: 1,
16840                follow_state: 2,
16841                precedence: 0,
16842            },
16843        )
16844        .expect("transition");
16845        atn.add_transition(
16846            2,
16847            ParserTransitionSpec::Atom {
16848                target: 3,
16849                label: TOKEN_EOF,
16850            },
16851        )
16852        .expect("transition");
16853        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
16854            .expect("transition");
16855        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 6 })
16856            .expect("transition");
16857        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 8 })
16858            .expect("transition");
16859        atn.add_transition(
16860            6,
16861            ParserTransitionSpec::Atom {
16862                target: 7,
16863                label: 1,
16864            },
16865        )
16866        .expect("transition");
16867        atn.add_transition(7, ParserTransitionSpec::Epsilon { target: 5 })
16868            .expect("transition");
16869        atn.add_transition(8, ParserTransitionSpec::Epsilon { target: 9 })
16870            .expect("transition");
16871        finish_atn(atn)
16872    }
16873
16874    /// ATN for `s : a+ Y ; a : X ;`.
16875    ///
16876    /// At EOF, recovery can synthesize an empty failed `a` child. The enclosing
16877    /// `+` loop must not treat that zero-width child as a successful iteration
16878    /// and then re-enter the loop at the same token index.
16879    fn plus_loop_with_recovering_body_atn() -> Atn {
16880        let mut atn = ParserAtnBuilder::new(2);
16881        assert_eq!(
16882            atn.add_state(AtnStateKind::RuleStart, Some(0))
16883                .expect("state")
16884                .index(),
16885            0
16886        );
16887        assert_eq!(
16888            atn.add_state(AtnStateKind::PlusBlockStart, Some(0))
16889                .expect("state")
16890                .index(),
16891            1
16892        );
16893        assert_eq!(
16894            atn.add_state(AtnStateKind::Basic, Some(0))
16895                .expect("state")
16896                .index(),
16897            2
16898        );
16899        assert_eq!(
16900            atn.add_state(AtnStateKind::BlockEnd, Some(0))
16901                .expect("state")
16902                .index(),
16903            3
16904        );
16905        assert_eq!(
16906            atn.add_state(AtnStateKind::PlusLoopBack, Some(0))
16907                .expect("state")
16908                .index(),
16909            4
16910        );
16911        assert_eq!(
16912            atn.add_state(AtnStateKind::LoopEnd, Some(0))
16913                .expect("state")
16914                .index(),
16915            5
16916        );
16917        assert_eq!(
16918            atn.add_state(AtnStateKind::RuleStop, Some(0))
16919                .expect("state")
16920                .index(),
16921            6
16922        );
16923        assert_eq!(
16924            atn.add_state(AtnStateKind::RuleStart, Some(1))
16925                .expect("state")
16926                .index(),
16927            7
16928        );
16929        assert_eq!(
16930            atn.add_state(AtnStateKind::Basic, Some(1))
16931                .expect("state")
16932                .index(),
16933            8
16934        );
16935        assert_eq!(
16936            atn.add_state(AtnStateKind::RuleStop, Some(1))
16937                .expect("state")
16938                .index(),
16939            9
16940        );
16941        atn.set_rule_to_start_state(vec![0, 7])
16942            .expect("rule start states");
16943        atn.set_rule_to_stop_state(vec![6, 9])
16944            .expect("rule stop states");
16945        atn.set_end_state(1, 3).expect("block end state");
16946        atn.set_loop_back_state(5, 4).expect("loop back state");
16947        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
16948            .expect("transition");
16949        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
16950            .expect("transition");
16951        atn.add_transition(
16952            2,
16953            ParserTransitionSpec::Rule {
16954                target: 7,
16955                rule_index: 1,
16956                follow_state: 3,
16957                precedence: 0,
16958            },
16959        )
16960        .expect("transition");
16961        atn.add_transition(3, ParserTransitionSpec::Epsilon { target: 4 })
16962            .expect("transition");
16963        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 1 })
16964            .expect("transition");
16965        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
16966            .expect("transition");
16967        atn.add_transition(
16968            5,
16969            ParserTransitionSpec::Atom {
16970                target: 6,
16971                label: 2,
16972            },
16973        )
16974        .expect("transition");
16975        atn.add_transition(
16976            7,
16977            ParserTransitionSpec::Atom {
16978                target: 8,
16979                label: 1,
16980            },
16981        )
16982        .expect("transition");
16983        atn.add_transition(8, ParserTransitionSpec::Epsilon { target: 9 })
16984            .expect("transition");
16985        finish_atn(atn)
16986    }
16987
16988    #[test]
16989    fn runtime_options_default_exits_recovering_empty_plus_iteration() {
16990        let atn = plus_loop_with_recovering_body_atn();
16991        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
16992
16993        let error = parser
16994            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
16995            .expect_err("EOF recovery should report a bounded mismatch");
16996
16997        let AntlrError::ParserError { message, .. } = error else {
16998            panic!("expected ParserError, got {error:?}");
16999        };
17000        insta::assert_snapshot!(message, @"mismatched input '<EOF>' expecting {'x', 2}");
17001        assert_eq!(parser.number_of_syntax_errors(), 1);
17002        assert_eq!(parser.input.index(), 0, "EOF remains unconsumed");
17003    }
17004
17005    #[test]
17006    fn sync_decision_deletes_token_before_eof_at_loop_back() {
17007        // `s : A* EOF` on `c`: the loop decision (state 5) can recover onto EOF.
17008        // At the loop ENTRY (loop_back = false) a single unexpected token before
17009        // EOF is deleted as an error node (then the generated EOF match consumes
17010        // the real EOF) — matching ANTLR's `(s c <EOF>)` + "extraneous input".
17011        // EOF must be a valid scan-stop for this to fire.
17012        let atn = star_loop_then_eof_atn();
17013        let mut parser = mini_parser(vec![
17014            TestToken::new(2).with_text("c"),
17015            TestToken::eof("parser-test", 1, 1, 1),
17016        ]);
17017        parser.rule_context_stack = vec![RuleContextFrame {
17018            rule_index: 0,
17019            invoking_state: 0,
17020        }];
17021        let children = parser
17022            .sync_decision(&atn, 5, true, false)
17023            .expect("single token before EOF recovers");
17024        assert_eq!(children.len(), 1);
17025        assert_eq!(parser.node(children[0]).kind(), NodeKind::Error);
17026        assert_eq!(parser.number_of_syntax_errors(), 1);
17027        assert_eq!(
17028            parser.la(1),
17029            TOKEN_EOF,
17030            "EOF is left for the rule's EOF match"
17031        );
17032    }
17033
17034    #[test]
17035    fn sync_decision_does_not_delete_two_tokens_before_eof_at_loop_entry() {
17036        // `s : A* EOF` on `c c`: at the loop ENTRY (loop_back = false) ANTLR does
17037        // single-token deletion, which fails because LA(2) = `c` is not expected —
17038        // so it reports `mismatched input` and consumes nothing (ANTLR: `(s c c)`
17039        // with no EOF). The scan must NOT multi-token-consume both `c`s here.
17040        let atn = star_loop_then_eof_atn();
17041        let mut parser = mini_parser(vec![
17042            TestToken::new(2).with_text("c"),
17043            TestToken::new(2).with_text("c"),
17044            TestToken::eof("parser-test", 1, 2, 2),
17045        ]);
17046        parser.rule_context_stack = vec![RuleContextFrame {
17047            rule_index: 0,
17048            invoking_state: 0,
17049        }];
17050        let error = parser
17051            .sync_decision(&atn, 5, true, false)
17052            .expect_err("two tokens at the loop entry must not be deleted");
17053        match error {
17054            AntlrError::ParserError { message, .. } => {
17055                assert!(message.starts_with("mismatched input"), "got: {message}");
17056            }
17057            other => panic!("expected mismatched-input ParserError, got {other:?}"),
17058        }
17059        assert_eq!(
17060            parser.la(1),
17061            2,
17062            "nothing consumed; cursor still on first `c`"
17063        );
17064    }
17065
17066    #[test]
17067    fn sync_decision_consumes_until_eof_at_loop_back() {
17068        // Same `s : A* EOF` decision, but at a loop-BACK (loop_back = true, i.e.
17069        // after ≥1 `A` matched). ANTLR uses multi-token `consumeUntil(recoverSet)`
17070        // there, so two unexpected tokens before EOF are BOTH deleted and the rule
17071        // recovers (matching `(s a c c <EOF>)` for input `a c c`). Here we feed the
17072        // post-`a` state directly: `c c <EOF>` with loop_back = true.
17073        let atn = star_loop_then_eof_atn();
17074        let mut parser = mini_parser(vec![
17075            TestToken::new(2).with_text("c"),
17076            TestToken::new(2).with_text("c"),
17077            TestToken::eof("parser-test", 1, 2, 2),
17078        ]);
17079        parser.rule_context_stack = vec![RuleContextFrame {
17080            rule_index: 0,
17081            invoking_state: 0,
17082        }];
17083        let children = parser
17084            .sync_decision(&atn, 5, false, true)
17085            .expect("loop-back multi-token deletion recovers onto EOF");
17086        assert_eq!(children.len(), 2, "both `c`s deleted as error nodes");
17087        assert!(
17088            children
17089                .iter()
17090                .all(|child| parser.node(*child).kind() == NodeKind::Error)
17091        );
17092        assert_eq!(parser.number_of_syntax_errors(), 1);
17093        assert_eq!(parser.la(1), TOKEN_EOF, "EOF left for the rule's EOF match");
17094    }
17095
17096    #[test]
17097    fn sync_decision_returns_before_recovery_for_nullable_exit() {
17098        let atn = nested_star_rule_atn();
17099        for (current_context_empty, loop_back) in [(true, false), (false, true)] {
17100            let mut parser = mini_parser(vec![
17101                TestToken::new(2).with_text("c"),
17102                TestToken::new(1).with_text("a"),
17103                TestToken::eof("parser-test", 1, 2, 2),
17104            ]);
17105            parser.rule_context_stack = vec![
17106                RuleContextFrame {
17107                    rule_index: 0,
17108                    invoking_state: 0,
17109                },
17110                RuleContextFrame {
17111                    rule_index: 1,
17112                    invoking_state: 1,
17113                },
17114            ];
17115
17116            let children = parser
17117                .sync_decision(&atn, 5, current_context_empty, loop_back)
17118                .expect("nullable synchronization is a no-op");
17119
17120            assert!(children.is_empty());
17121            assert_eq!(parser.la(1), 2, "the caller must receive the current token");
17122            assert_eq!(parser.number_of_syntax_errors(), 0);
17123            assert_eq!(
17124                parser
17125                    .generated_sync_expected
17126                    .as_ref()
17127                    .expect("nullable sync preserves expected symbols")
17128                    .to_btree_set(),
17129                BTreeSet::from([TOKEN_EOF, 1])
17130            );
17131        }
17132    }
17133
17134    fn predicate_after_token_atn() -> Atn {
17135        let mut atn = ParserAtnBuilder::new(2);
17136        assert_eq!(
17137            atn.add_state(AtnStateKind::RuleStart, Some(0))
17138                .expect("state")
17139                .index(),
17140            0
17141        );
17142        assert_eq!(
17143            atn.add_state(AtnStateKind::Basic, Some(0))
17144                .expect("state")
17145                .index(),
17146            1
17147        );
17148        assert_eq!(
17149            atn.add_state(AtnStateKind::Basic, Some(0))
17150                .expect("state")
17151                .index(),
17152            2
17153        );
17154        assert_eq!(
17155            atn.add_state(AtnStateKind::Basic, Some(0))
17156                .expect("state")
17157                .index(),
17158            3
17159        );
17160        assert_eq!(
17161            atn.add_state(AtnStateKind::RuleStop, Some(0))
17162                .expect("state")
17163                .index(),
17164            4
17165        );
17166        atn.set_rule_to_start_state(vec![0])
17167            .expect("rule start states");
17168        atn.set_rule_to_stop_state(vec![4])
17169            .expect("rule stop states");
17170        atn.add_transition(
17171            0,
17172            ParserTransitionSpec::Atom {
17173                target: 1,
17174                label: 1,
17175            },
17176        )
17177        .expect("transition");
17178        atn.add_transition(
17179            1,
17180            ParserTransitionSpec::Predicate {
17181                target: 2,
17182                rule_index: 0,
17183                pred_index: 0,
17184                context_dependent: false,
17185            },
17186        )
17187        .expect("transition");
17188        atn.add_transition(
17189            2,
17190            ParserTransitionSpec::Atom {
17191                target: 3,
17192                label: 2,
17193            },
17194        )
17195        .expect("transition");
17196        atn.add_transition(3, ParserTransitionSpec::Epsilon { target: 4 })
17197            .expect("transition");
17198        finish_atn(atn)
17199    }
17200
17201    fn predicate_gated_same_lookahead_atn(pred_indexes: [usize; 2]) -> Atn {
17202        let mut atn = ParserAtnBuilder::new(1);
17203        for (state_number, kind) in [
17204            (0, AtnStateKind::RuleStart),
17205            (1, AtnStateKind::BlockStart),
17206            (2, AtnStateKind::Basic),
17207            (3, AtnStateKind::Basic),
17208            (4, AtnStateKind::Basic),
17209            (5, AtnStateKind::Basic),
17210            (6, AtnStateKind::BlockEnd),
17211            (7, AtnStateKind::RuleStop),
17212        ] {
17213            assert_eq!(
17214                atn.add_state(kind, Some(0)).expect("state").index(),
17215                state_number
17216            );
17217        }
17218        atn.set_rule_to_start_state(vec![0])
17219            .expect("rule start states");
17220        atn.set_rule_to_stop_state(vec![7])
17221            .expect("rule stop states");
17222        atn.add_decision_state(1).expect("decision state");
17223        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
17224            .expect("transition");
17225        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
17226            .expect("transition");
17227        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 3 })
17228            .expect("transition");
17229        atn.add_transition(
17230            2,
17231            ParserTransitionSpec::Predicate {
17232                target: 4,
17233                rule_index: 0,
17234                pred_index: pred_indexes[0],
17235                context_dependent: false,
17236            },
17237        )
17238        .expect("transition");
17239        atn.add_transition(
17240            3,
17241            ParserTransitionSpec::Predicate {
17242                target: 5,
17243                rule_index: 0,
17244                pred_index: pred_indexes[1],
17245                context_dependent: false,
17246            },
17247        )
17248        .expect("transition");
17249        atn.add_transition(
17250            4,
17251            ParserTransitionSpec::Atom {
17252                target: 6,
17253                label: 1,
17254            },
17255        )
17256        .expect("transition");
17257        atn.add_transition(
17258            5,
17259            ParserTransitionSpec::Atom {
17260                target: 6,
17261                label: 1,
17262            },
17263        )
17264        .expect("transition");
17265        atn.add_transition(
17266            6,
17267            ParserTransitionSpec::Atom {
17268                target: 7,
17269                label: TOKEN_EOF,
17270            },
17271        )
17272        .expect("transition");
17273        finish_atn(atn)
17274    }
17275
17276    /// ATN for `s : A B | {false}? A C | {true}? A C;`.
17277    fn semantic_fallback_viability_atn() -> Atn {
17278        let mut atn = ParserAtnBuilder::new(3);
17279        for (state_number, kind) in [
17280            (0, AtnStateKind::RuleStart),
17281            (1, AtnStateKind::BlockStart),
17282            (2, AtnStateKind::Basic),
17283            (3, AtnStateKind::Basic),
17284            (4, AtnStateKind::Basic),
17285            (5, AtnStateKind::Basic),
17286            (6, AtnStateKind::Basic),
17287            (7, AtnStateKind::Basic),
17288            (8, AtnStateKind::Basic),
17289            (9, AtnStateKind::BlockEnd),
17290            (10, AtnStateKind::RuleStop),
17291        ] {
17292            assert_eq!(
17293                atn.add_state(kind, Some(0)).expect("state").index(),
17294                state_number
17295            );
17296        }
17297        atn.set_rule_to_start_state(vec![0])
17298            .expect("rule start states");
17299        atn.set_rule_to_stop_state(vec![10])
17300            .expect("rule stop states");
17301        atn.set_end_state(1, 9).expect("block end state");
17302        atn.add_decision_state(1).expect("decision state");
17303        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
17304            .expect("entry transition");
17305        atn.add_transition(
17306            1,
17307            ParserTransitionSpec::Atom {
17308                target: 2,
17309                label: 1,
17310            },
17311        )
17312        .expect("first alternative");
17313        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 3 })
17314            .expect("second alternative");
17315        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 6 })
17316            .expect("third alternative");
17317        atn.add_transition(
17318            2,
17319            ParserTransitionSpec::Atom {
17320                target: 9,
17321                label: 2,
17322            },
17323        )
17324        .expect("first alternative suffix");
17325        for (source, target, pred_index) in [(3, 4, 0), (6, 7, 1)] {
17326            atn.add_transition(
17327                source,
17328                ParserTransitionSpec::Predicate {
17329                    target,
17330                    rule_index: 0,
17331                    pred_index,
17332                    context_dependent: false,
17333                },
17334            )
17335            .expect("predicate transition");
17336        }
17337        for (source, target, label) in [(4, 5, 1), (5, 9, 3), (7, 8, 1), (8, 9, 3)] {
17338            atn.add_transition(source, ParserTransitionSpec::Atom { target, label })
17339                .expect("predicate alternative token");
17340        }
17341        atn.add_transition(
17342            9,
17343            ParserTransitionSpec::Atom {
17344                target: 10,
17345                label: TOKEN_EOF,
17346            },
17347        )
17348        .expect("EOF transition");
17349        finish_atn(atn)
17350    }
17351
17352    /// ATN for `s : gated | A; gated : {false}? A;`.
17353    fn rule_call_predicate_decision_atn() -> Atn {
17354        let mut atn = ParserAtnBuilder::new(1);
17355        for (state_number, kind, rule_index) in [
17356            (0, AtnStateKind::RuleStart, 0),
17357            (1, AtnStateKind::BlockStart, 0),
17358            (2, AtnStateKind::Basic, 0),
17359            (3, AtnStateKind::Basic, 0),
17360            (4, AtnStateKind::BlockEnd, 0),
17361            (5, AtnStateKind::RuleStop, 0),
17362            (6, AtnStateKind::RuleStart, 1),
17363            (7, AtnStateKind::Basic, 1),
17364            (8, AtnStateKind::RuleStop, 1),
17365        ] {
17366            assert_eq!(
17367                atn.add_state(kind, Some(rule_index))
17368                    .expect("state")
17369                    .index(),
17370                state_number
17371            );
17372        }
17373        atn.set_rule_to_start_state(vec![0, 6])
17374            .expect("rule start states");
17375        atn.set_rule_to_stop_state(vec![5, 8])
17376            .expect("rule stop states");
17377        atn.set_end_state(1, 4).expect("block end state");
17378        atn.add_decision_state(1).expect("decision state");
17379        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
17380            .expect("entry transition");
17381        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
17382            .expect("gated alternative entry");
17383        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 3 })
17384            .expect("direct alternative entry");
17385        atn.add_transition(
17386            2,
17387            ParserTransitionSpec::Rule {
17388                target: 6,
17389                rule_index: 1,
17390                follow_state: 4,
17391                precedence: 0,
17392            },
17393        )
17394        .expect("gated alternative");
17395        atn.add_transition(
17396            3,
17397            ParserTransitionSpec::Atom {
17398                target: 4,
17399                label: 1,
17400            },
17401        )
17402        .expect("direct alternative");
17403        atn.add_transition(
17404            4,
17405            ParserTransitionSpec::Atom {
17406                target: 5,
17407                label: TOKEN_EOF,
17408            },
17409        )
17410        .expect("EOF transition");
17411        atn.add_transition(
17412            6,
17413            ParserTransitionSpec::Predicate {
17414                target: 7,
17415                rule_index: 1,
17416                pred_index: 0,
17417                context_dependent: false,
17418            },
17419        )
17420        .expect("callee predicate");
17421        atn.add_transition(
17422            7,
17423            ParserTransitionSpec::Atom {
17424                target: 8,
17425                label: 1,
17426            },
17427        )
17428        .expect("callee token");
17429        finish_atn(atn)
17430    }
17431
17432    /// ATN for `s : ({true}? A)* EOF;`.
17433    fn predicate_gated_star_loop_atn() -> Atn {
17434        let mut atn = ParserAtnBuilder::new(2);
17435        for (state_number, kind) in [
17436            (0, AtnStateKind::RuleStart),
17437            (1, AtnStateKind::StarLoopEntry),
17438            (2, AtnStateKind::Basic),
17439            (3, AtnStateKind::Basic),
17440            (4, AtnStateKind::StarLoopBack),
17441            (5, AtnStateKind::LoopEnd),
17442            (6, AtnStateKind::RuleStop),
17443        ] {
17444            assert_eq!(
17445                atn.add_state(kind, Some(0)).expect("state").index(),
17446                state_number
17447            );
17448        }
17449        atn.set_rule_to_start_state(vec![0])
17450            .expect("rule start states");
17451        atn.set_rule_to_stop_state(vec![6])
17452            .expect("rule stop states");
17453        atn.add_decision_state(1).expect("decision state");
17454        atn.set_loop_back_state(5, 4).expect("loop back state");
17455        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
17456            .expect("entry transition");
17457        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
17458            .expect("loop enter");
17459        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 5 })
17460            .expect("loop exit");
17461        atn.add_transition(
17462            2,
17463            ParserTransitionSpec::Predicate {
17464                target: 3,
17465                rule_index: 0,
17466                pred_index: 0,
17467                context_dependent: false,
17468            },
17469        )
17470        .expect("loop predicate");
17471        atn.add_transition(
17472            3,
17473            ParserTransitionSpec::Atom {
17474                target: 4,
17475                label: 1,
17476            },
17477        )
17478        .expect("loop token");
17479        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 1 })
17480            .expect("loop back");
17481        atn.add_transition(
17482            5,
17483            ParserTransitionSpec::Atom {
17484                target: 6,
17485                label: TOKEN_EOF,
17486            },
17487        )
17488        .expect("EOF transition");
17489        finish_atn(atn)
17490    }
17491
17492    fn nested_nullable_context_atn() -> Atn {
17493        let mut atn = ParserAtnBuilder::new(1);
17494        for state_number in 0..=20 {
17495            let kind = match state_number {
17496                0 | 10 | 16 => AtnStateKind::RuleStart,
17497                9 | 15 | 20 => AtnStateKind::RuleStop,
17498                _ => AtnStateKind::Basic,
17499            };
17500            let rule_index = match state_number {
17501                0..=9 => 0,
17502                10..=15 => 1,
17503                _ => 2,
17504            };
17505            assert_eq!(
17506                atn.add_state(kind, Some(rule_index))
17507                    .expect("state")
17508                    .index(),
17509                state_number
17510            );
17511        }
17512        atn.set_rule_to_start_state(vec![0, 10, 16])
17513            .expect("rule start states");
17514        atn.set_rule_to_stop_state(vec![9, 15, 20])
17515            .expect("rule stop states");
17516        atn.add_transition(
17517            1,
17518            ParserTransitionSpec::Rule {
17519                target: 10,
17520                rule_index: 1,
17521                follow_state: 8,
17522                precedence: 0,
17523            },
17524        )
17525        .expect("transition");
17526        atn.add_transition(
17527            8,
17528            ParserTransitionSpec::Atom {
17529                target: 9,
17530                label: 1,
17531            },
17532        )
17533        .expect("transition");
17534        atn.add_transition(8, ParserTransitionSpec::Epsilon { target: 9 })
17535            .expect("transition");
17536        atn.add_transition(
17537            2,
17538            ParserTransitionSpec::Rule {
17539                target: 16,
17540                rule_index: 2,
17541                follow_state: 14,
17542                precedence: 0,
17543            },
17544        )
17545        .expect("transition");
17546        atn.add_transition(14, ParserTransitionSpec::Epsilon { target: 15 })
17547            .expect("transition");
17548        finish_atn(atn)
17549    }
17550
17551    fn generated_match_recovery_atn() -> Atn {
17552        let mut atn = ParserAtnBuilder::new(2);
17553        assert_eq!(
17554            atn.add_state(AtnStateKind::RuleStart, Some(0))
17555                .expect("state")
17556                .index(),
17557            0
17558        );
17559        assert_eq!(
17560            atn.add_state(AtnStateKind::Basic, Some(0))
17561                .expect("state")
17562                .index(),
17563            1
17564        );
17565        assert_eq!(
17566            atn.add_state(AtnStateKind::Basic, Some(0))
17567                .expect("state")
17568                .index(),
17569            2
17570        );
17571        assert_eq!(
17572            atn.add_state(AtnStateKind::RuleStop, Some(0))
17573                .expect("state")
17574                .index(),
17575            3
17576        );
17577        assert_eq!(
17578            atn.add_state(AtnStateKind::RuleStart, Some(1))
17579                .expect("state")
17580                .index(),
17581            4
17582        );
17583        assert_eq!(
17584            atn.add_state(AtnStateKind::RuleStop, Some(1))
17585                .expect("state")
17586                .index(),
17587            5
17588        );
17589        atn.set_rule_to_start_state(vec![0, 4])
17590            .expect("rule start states");
17591        atn.set_rule_to_stop_state(vec![3, 5])
17592            .expect("rule stop states");
17593        atn.add_transition(
17594            1,
17595            ParserTransitionSpec::Rule {
17596                target: 4,
17597                rule_index: 1,
17598                follow_state: 2,
17599                precedence: 0,
17600            },
17601        )
17602        .expect("transition");
17603        atn.add_transition(
17604            2,
17605            ParserTransitionSpec::Atom {
17606                target: 3,
17607                label: TOKEN_EOF,
17608            },
17609        )
17610        .expect("transition");
17611        finish_atn(atn)
17612    }
17613
17614    fn complement_set_atn() -> Atn {
17615        let mut atn = ParserAtnBuilder::new(1);
17616        assert_eq!(
17617            atn.add_state(AtnStateKind::RuleStart, Some(0))
17618                .expect("state")
17619                .index(),
17620            0
17621        );
17622        assert_eq!(
17623            atn.add_state(AtnStateKind::RuleStop, Some(0))
17624                .expect("state")
17625                .index(),
17626            1
17627        );
17628        atn.set_rule_to_start_state(vec![0])
17629            .expect("rule start states");
17630        atn.set_rule_to_stop_state(vec![1])
17631            .expect("rule stop states");
17632        let excluded = atn.add_interval_set([(1, 1)]).expect("excluded set");
17633        atn.add_transition(
17634            0,
17635            ParserTransitionSpec::NotSet {
17636                target: 1,
17637                set: excluded,
17638            },
17639        )
17640        .expect("transition");
17641        finish_atn(atn)
17642    }
17643
17644    /// ATN for `start : . EOF ;`: a wildcard whose follow state explicitly matches
17645    /// EOF. State 0 (`RuleStart`) -wildcard-> 2 -EOF-> 1 (`RuleStop`).
17646    fn wildcard_then_eof_atn() -> Atn {
17647        let mut atn = ParserAtnBuilder::new(1);
17648        assert_eq!(
17649            atn.add_state(AtnStateKind::RuleStart, Some(0))
17650                .expect("state")
17651                .index(),
17652            0
17653        );
17654        assert_eq!(
17655            atn.add_state(AtnStateKind::RuleStop, Some(0))
17656                .expect("state")
17657                .index(),
17658            1
17659        );
17660        assert_eq!(
17661            atn.add_state(AtnStateKind::Basic, Some(0))
17662                .expect("state")
17663                .index(),
17664            2
17665        );
17666        atn.set_rule_to_start_state(vec![0])
17667            .expect("rule start states");
17668        atn.set_rule_to_stop_state(vec![1])
17669            .expect("rule stop states");
17670        atn.add_transition(0, ParserTransitionSpec::Wildcard { target: 2 })
17671            .expect("transition");
17672        atn.add_transition(
17673            2,
17674            ParserTransitionSpec::Atom {
17675                target: 1,
17676                label: TOKEN_EOF,
17677            },
17678        )
17679        .expect("transition");
17680        finish_atn(atn)
17681    }
17682
17683    #[test]
17684    fn parser_matches_token_and_reports_mismatch() {
17685        let source = Source {
17686            tokens: vec![
17687                TestToken::new(1).with_text("x"),
17688                TestToken::eof("parser-test", 1, 1, 1),
17689            ],
17690            index: 0,
17691        };
17692        let data = RecognizerData::new(
17693            "Mini.g4",
17694            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
17695        );
17696        let mut parser = BaseParser::new(CommonTokenStream::new(source), data);
17697        let matched = parser.match_token(1).expect("token 1 should match");
17698        assert_eq!(parser.node(matched).text(), "x");
17699        assert!(parser.match_token(1).is_err());
17700    }
17701
17702    #[test]
17703    fn parser_matches_token_sets() {
17704        let mut parser = mini_parser(vec![
17705            TestToken::new(1).with_text("x"),
17706            TestToken::eof("parser-test", 1, 1, 1),
17707        ]);
17708
17709        let matched = parser
17710            .match_set(&[(1, 1), (3, 4)])
17711            .expect("token set should match");
17712        assert_eq!(parser.node(matched).text(), "x");
17713        assert!(parser.match_not_set(&[(1, 1)], 1, 4).is_err());
17714    }
17715
17716    #[test]
17717    fn generated_rule_api_tracks_state_and_precedence() {
17718        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
17719
17720        let context = parser.enter_rule(7, 2);
17721        assert_eq!(context.rule_index(), 2);
17722        assert_eq!(parser.state(), 7);
17723        assert_eq!(
17724            parser.rule_context_stack,
17725            vec![RuleContextFrame {
17726                rule_index: 2,
17727                invoking_state: 7
17728            }]
17729        );
17730
17731        let recursive = parser.enter_recursion_rule(11, 3, 4);
17732        assert_eq!(recursive.rule_index(), 3);
17733        assert!(parser.precpred(4));
17734        assert!(parser.precpred(5));
17735        assert!(!parser.precpred(3));
17736
17737        let next = parser.push_new_recursion_context(13, 3);
17738        assert_eq!(next.invoking_state(), 13);
17739        parser.unroll_recursion_context();
17740        assert_eq!(parser.precedence_stack, vec![0]);
17741        assert_eq!(
17742            parser.rule_context_stack,
17743            vec![RuleContextFrame {
17744                rule_index: 2,
17745                invoking_state: 7
17746            }]
17747        );
17748
17749        parser.exit_rule();
17750        assert!(parser.rule_context_stack.is_empty());
17751    }
17752
17753    #[test]
17754    fn reset_rewinds_input_and_clears_parser_owned_parse_state() {
17755        let mut parser = mini_parser(vec![
17756            TestToken::new(1).with_text("x"),
17757            TestToken::eof("parser-test", 1, 1, 1),
17758        ]);
17759        let matched = parser.match_token(1).expect("token should match");
17760        assert_eq!(parser.node(matched).text(), "x");
17761        parser.record_generated_syntax_error();
17762        parser.set_int_member(7, 11);
17763        parser.set_build_parse_trees(false);
17764        parser.set_report_diagnostic_errors(true);
17765        parser.set_prediction_mode(PredictionMode::Sll);
17766        parser.set_bail_on_error(true);
17767        let _context = parser.enter_recursion_rule(9, 0, 4);
17768        parser.pending_invoking_states.push(5);
17769        parser.unknown_predicate_hits.push((0, 1));
17770        parser.unhandled_action_hits.push((0, 2));
17771
17772        parser.reset();
17773
17774        assert_eq!(parser.input.index(), 0);
17775        assert_eq!(parser.la(1), 1);
17776        assert_eq!(parser.state(), -1);
17777        assert_eq!(parser.number_of_syntax_errors(), 0);
17778        assert_eq!(parser.parse_tree_storage().node_count(), 0);
17779        assert!(parser.rule_context_stack.is_empty());
17780        assert!(parser.pending_invoking_states.is_empty());
17781        assert_eq!(parser.precedence_stack, [0]);
17782        assert!(parser.unknown_predicate_hits.is_empty());
17783        assert!(parser.unhandled_action_hits.is_empty());
17784        assert_eq!(parser.int_member(7), Some(11));
17785        assert!(!parser.build_parse_trees());
17786        assert!(parser.report_diagnostic_errors());
17787        assert_eq!(parser.prediction_mode(), PredictionMode::Sll);
17788        assert!(parser.bail_on_error());
17789    }
17790
17791    #[test]
17792    fn set_token_stream_replaces_input_and_resets_parser() {
17793        let mut parser = mini_parser(vec![
17794            TestToken::new(1).with_text("old"),
17795            TestToken::eof("parser-test", 1, 1, 1),
17796        ]);
17797        parser.consume();
17798        parser.record_generated_syntax_error();
17799        let replacement = CommonTokenStream::new(Source {
17800            tokens: vec![
17801                TestToken::new(2).with_text("new"),
17802                TestToken::eof("parser-test", 1, 1, 1),
17803            ],
17804            index: 0,
17805        });
17806
17807        parser.set_token_stream(replacement);
17808
17809        assert_eq!(parser.input.index(), 0);
17810        assert_eq!(parser.la(1), 2);
17811        assert_eq!(parser.input.text_all(), "new");
17812        assert_eq!(parser.number_of_syntax_errors(), 0);
17813    }
17814
17815    #[test]
17816    fn active_invocation_states_exclude_the_root_frame() {
17817        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
17818
17819        let _root = parser.enter_rule(0, 0);
17820        assert!(parser.active_invocation_states().is_empty());
17821
17822        let marker = parser.push_invoking_state(6);
17823        let _child = parser.enter_rule(2, 1);
17824        parser.discard_invoking_state(marker);
17825        assert_eq!(parser.active_invocation_states(), [6]);
17826
17827        let marker = parser.push_invoking_state(13);
17828        let _grandchild = parser.enter_rule(4, 2);
17829        parser.discard_invoking_state(marker);
17830        assert_eq!(parser.active_invocation_states(), [13, 6]);
17831
17832        parser.exit_rule();
17833        parser.exit_rule();
17834        parser.exit_rule();
17835    }
17836
17837    #[test]
17838    fn parser_predicates_support_token_adjacency() {
17839        let mut parser = mini_parser(vec![
17840            TestToken::new(1).with_text("=").with_span(0, 0),
17841            TestToken::new(1).with_text(">").with_span(1, 1),
17842            TestToken::eof("parser-test", 2, 1, 2),
17843        ]);
17844        parser.consume();
17845        parser.consume();
17846
17847        let predicates = [(0, 0, ParserPredicate::TokenPairAdjacent)];
17848
17849        assert!(parser.parser_semantic_predicate_matches(&predicates, 0, 0));
17850
17851        let mut parser = mini_parser(vec![
17852            TestToken::new(1).with_text("=").with_span(0, 0),
17853            TestToken::new(1)
17854                .with_text(" ")
17855                .with_channel(HIDDEN_CHANNEL)
17856                .with_span(1, 1),
17857            TestToken::new(1).with_text(">").with_span(2, 2),
17858            TestToken::eof("parser-test", 3, 1, 3),
17859        ]);
17860        parser.consume();
17861        parser.consume();
17862
17863        assert!(!parser.parser_semantic_predicate_matches(&predicates, 0, 0));
17864    }
17865
17866    #[test]
17867    fn parser_predicates_support_context_child_text_checks() {
17868        let mut parser = mini_parser(vec![
17869            TestToken::new(1).with_text("var"),
17870            TestToken::eof("parser-test", 1, 1, 1),
17871        ]);
17872        let mut context = ParserRuleContext::new(1, 0);
17873        let mut child_context = ParserRuleContext::new(2, 0);
17874        let terminal = parser.terminal_tree(TokenId::try_from(0).expect("test token ID"));
17875        parser.tree.add_child(&mut child_context, terminal);
17876        let child = parser.rule_node(child_context);
17877        parser.tree.add_child(&mut context, child);
17878        let predicates = [(
17879            1,
17880            0,
17881            ParserPredicate::ContextChildRuleTextNotEquals {
17882                rule_index: 2,
17883                text: "var",
17884            },
17885        )];
17886
17887        assert!(
17888            !parser.parser_semantic_predicate_matches_with_context_and_local(
17889                &predicates,
17890                1,
17891                0,
17892                &context,
17893                0,
17894            )
17895        );
17896    }
17897
17898    #[test]
17899    fn context_expected_symbols_walks_nullable_parent_contexts() {
17900        let atn = nested_nullable_context_atn();
17901        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
17902        parser.rule_context_stack = vec![
17903            RuleContextFrame {
17904                rule_index: 0,
17905                invoking_state: 0,
17906            },
17907            RuleContextFrame {
17908                rule_index: 1,
17909                invoking_state: 1,
17910            },
17911            RuleContextFrame {
17912                rule_index: 2,
17913                invoking_state: 2,
17914            },
17915        ];
17916
17917        let expected = parser.context_expected_symbols(&atn);
17918
17919        assert!(expected.contains(&1));
17920        assert!(expected.contains(&TOKEN_EOF));
17921    }
17922
17923    #[test]
17924    fn prediction_context_return_states_track_rule_stack_changes() {
17925        let atn = nested_nullable_context_atn();
17926        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
17927        parser.rule_context_stack = vec![
17928            RuleContextFrame {
17929                rule_index: 0,
17930                invoking_state: 0,
17931            },
17932            RuleContextFrame {
17933                rule_index: 1,
17934                invoking_state: 1,
17935            },
17936            RuleContextFrame {
17937                rule_index: 2,
17938                invoking_state: 2,
17939            },
17940        ];
17941
17942        let initial_version = parser.rule_context_version();
17943        let first: Vec<_> = parser.prediction_context_return_states(&atn).collect();
17944        let second: Vec<_> = parser.prediction_context_return_states(&atn).collect();
17945        assert_eq!(first, second);
17946        assert_eq!(parser.rule_context_version(), initial_version);
17947
17948        parser.exit_rule();
17949        let after_pop: Vec<_> = parser.prediction_context_return_states(&atn).collect();
17950        assert_ne!(first, after_pop);
17951        assert_ne!(parser.rule_context_version(), initial_version);
17952    }
17953
17954    #[test]
17955    fn generated_match_token_recovers_missing_token_from_context_follow() {
17956        let atn = generated_match_recovery_atn();
17957        let data = RecognizerData::new(
17958            "Mini.g4",
17959            Vocabulary::new(
17960                [None, Some("'X'"), Some("'Y'")],
17961                [None, Some("X"), Some("Y")],
17962                [None::<&str>, None, None],
17963            ),
17964        );
17965        let mut parser = BaseParser::new(
17966            CommonTokenStream::new(Source {
17967                tokens: vec![TestToken::eof("parser-test", 3, 1, 3)],
17968                index: 0,
17969            }),
17970            data,
17971        );
17972        parser.rule_context_stack = vec![
17973            RuleContextFrame {
17974                rule_index: 0,
17975                invoking_state: 0,
17976            },
17977            RuleContextFrame {
17978                rule_index: 1,
17979                invoking_state: 1,
17980            },
17981        ];
17982        assert_eq!(parser.number_of_syntax_errors(), 0);
17983
17984        let node = parser
17985            .match_token_recovering(2, 5, &atn)
17986            .expect("generated match should insert missing token");
17987
17988        assert_eq!(node.children().len(), 1);
17989        assert_eq!(parser.node(node.children()[0]).text(), "<missing 'Y'>");
17990        assert_eq!(
17991            node.clone()
17992                .into_child_iter()
17993                .map(|child| parser.node(child).text())
17994                .collect::<Vec<_>>(),
17995            ["<missing 'Y'>"]
17996        );
17997        // Single-token insertion synthesizes a missing token and consumes nothing,
17998        // so no EOF terminal is consumed even though lookahead is EOF.
17999        assert!(!node.consumed_eof());
18000        assert_eq!(parser.la(1), TOKEN_EOF);
18001        assert_eq!(parser.number_of_syntax_errors(), 1);
18002        assert_eq!(
18003            parser.generated_parser_diagnostics,
18004            [ParserDiagnostic {
18005                line: 1,
18006                column: 3,
18007                message: "missing 'Y' at '<EOF>'".to_owned(),
18008                offending: parser.input.lt_id(1),
18009            }]
18010        );
18011    }
18012
18013    #[test]
18014    fn generated_match_token_counts_single_token_deletion_recovery() {
18015        let atn = generated_match_recovery_atn();
18016        let data = RecognizerData::new(
18017            "Mini.g4",
18018            Vocabulary::new(
18019                [None, Some("'X'"), Some("'Y'"), Some("'Z'")],
18020                [None, Some("X"), Some("Y"), Some("Z")],
18021                [None::<&str>, None, None, None],
18022            ),
18023        );
18024        let mut parser = BaseParser::new(
18025            CommonTokenStream::new(Source {
18026                tokens: vec![
18027                    TestToken::new(3).with_text("z"),
18028                    TestToken::new(2).with_text("y"),
18029                    TestToken::eof("parser-test", 3, 1, 3),
18030                ],
18031                index: 0,
18032            }),
18033            data,
18034        );
18035
18036        let node = parser
18037            .match_token_recovering(2, 5, &atn)
18038            .expect("generated match should delete the extraneous token");
18039
18040        assert_eq!(node.children().len(), 2);
18041        assert_eq!(parser.node(node.children()[0]).kind(), NodeKind::Error);
18042        assert_eq!(parser.node(node.children()[0]).text(), "z");
18043        assert_eq!(parser.node(node.children()[1]).text(), "y");
18044        assert_eq!(
18045            node.into_child_iter()
18046                .map(|child| parser.node(child).text())
18047                .collect::<Vec<_>>(),
18048            ["z", "y"]
18049        );
18050        assert_eq!(parser.number_of_syntax_errors(), 1);
18051    }
18052
18053    #[test]
18054    fn generated_match_token_iterates_single_success_without_a_children_vec() {
18055        let atn = generated_match_recovery_atn();
18056        let data = RecognizerData::new(
18057            "Mini.g4",
18058            Vocabulary::new(
18059                [None, Some("'X'"), Some("'Y'")],
18060                [None, Some("X"), Some("Y")],
18061                [None::<&str>, None, None],
18062            ),
18063        );
18064        let mut parser = BaseParser::new(
18065            CommonTokenStream::new(Source {
18066                tokens: vec![
18067                    TestToken::new(2).with_text("y"),
18068                    TestToken::eof("parser-test", 1, 1, 1),
18069                ],
18070                index: 0,
18071            }),
18072            data,
18073        );
18074
18075        let node = parser
18076            .match_token_recovering(2, 5, &atn)
18077            .expect("generated match should consume the expected token");
18078
18079        assert_eq!(
18080            node.into_child_iter()
18081                .map(|child| parser.node(child).text())
18082                .collect::<Vec<_>>(),
18083            ["y"]
18084        );
18085        assert_eq!(parser.number_of_syntax_errors(), 0);
18086    }
18087
18088    #[test]
18089    fn generated_diagnostic_restore_rolls_back_syntax_error_count() {
18090        let atn = generated_match_recovery_atn();
18091        let data = RecognizerData::new(
18092            "Mini.g4",
18093            Vocabulary::new(
18094                [None, Some("'X'"), Some("'Y'")],
18095                [None, Some("X"), Some("Y")],
18096                [None::<&str>, None, None],
18097            ),
18098        );
18099        let mut parser = BaseParser::new(
18100            CommonTokenStream::new(Source {
18101                tokens: vec![TestToken::eof("parser-test", 3, 1, 3)],
18102                index: 0,
18103            }),
18104            data,
18105        );
18106        parser.rule_context_stack = vec![
18107            RuleContextFrame {
18108                rule_index: 0,
18109                invoking_state: 0,
18110            },
18111            RuleContextFrame {
18112                rule_index: 1,
18113                invoking_state: 1,
18114            },
18115        ];
18116        let marker = parser.generated_diagnostics_checkpoint();
18117
18118        let _ = parser
18119            .match_token_recovering(2, 5, &atn)
18120            .expect("generated match should insert missing token");
18121        assert_eq!(parser.number_of_syntax_errors(), 1);
18122
18123        parser.restore_generated_diagnostics(marker);
18124
18125        assert_eq!(parser.number_of_syntax_errors(), 0);
18126        assert!(parser.generated_parser_diagnostics.is_empty());
18127    }
18128
18129    #[test]
18130    fn generated_prediction_diagnostics_use_adaptive_context() {
18131        let atn = two_alt_decision_atn();
18132        let data = RecognizerData::new(
18133            "Mini.g4",
18134            Vocabulary::new(
18135                [None, Some("'x'"), Some("'y'")],
18136                [None, Some("X"), Some("Y")],
18137                [None::<&str>, None, None],
18138            ),
18139        )
18140        .with_rule_names(["s"]);
18141        let mut parser = BaseParser::new(
18142            CommonTokenStream::new(Source {
18143                tokens: vec![
18144                    TestToken::new(1)
18145                        .with_text("x")
18146                        .with_position(1, 0)
18147                        .with_span(0, 0),
18148                    TestToken::new(2)
18149                        .with_text("y")
18150                        .with_position(1, 2)
18151                        .with_span(1, 1),
18152                    TestToken::eof("parser-test", 2, 1, 3),
18153                ],
18154                index: 0,
18155            }),
18156            data,
18157        );
18158        parser.set_report_diagnostic_errors(true);
18159
18160        parser.record_generated_prediction_diagnostic(
18161            &atn,
18162            1,
18163            &ParserAtnPrediction {
18164                alt: 1,
18165                requires_full_context: true,
18166                has_semantic_context: false,
18167                diagnostic: Some(ParserAtnPredictionDiagnostic {
18168                    kind: ParserAtnPredictionDiagnosticKind::ContextSensitivity,
18169                    start_index: 0,
18170                    sll_stop_index: 1,
18171                    ll_stop_index: 0,
18172                    conflicting_alts: vec![1, 2],
18173                    exact: false,
18174                }),
18175            },
18176        );
18177        // Ambiguities from the default LL prediction mode are non-exact, so —
18178        // matching Java's exactOnly DiagnosticErrorListener — only the
18179        // attempting-full-context line is reported. Exact-ambiguity mode
18180        // reports the ambiguity itself.
18181        parser.record_generated_prediction_diagnostic(
18182            &atn,
18183            1,
18184            &ParserAtnPrediction {
18185                alt: 1,
18186                requires_full_context: true,
18187                has_semantic_context: false,
18188                diagnostic: Some(ParserAtnPredictionDiagnostic {
18189                    kind: ParserAtnPredictionDiagnosticKind::Ambiguity,
18190                    start_index: 0,
18191                    sll_stop_index: 1,
18192                    ll_stop_index: 1,
18193                    conflicting_alts: vec![1, 2],
18194                    exact: false,
18195                }),
18196            },
18197        );
18198
18199        // The full-context/context-sensitivity diagnostic trace (order + decision + input windows)
18200        // is one snapshot rather than three ParserDiagnostic literals.
18201        insta::assert_debug_snapshot!(
18202            "generated_prediction_diagnostics_use_adaptive_context",
18203            parser.generated_parser_diagnostics
18204        );
18205    }
18206
18207    #[test]
18208    fn generated_match_not_set_recovers_empty_complement_at_eof() {
18209        let atn = complement_set_atn();
18210        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
18211        parser.rule_context_stack = vec![RuleContextFrame {
18212            rule_index: 0,
18213            invoking_state: 0,
18214        }];
18215
18216        let node = parser
18217            .match_not_token_set_recovering(
18218                atn.token_set(0).expect("excluded token set"),
18219                1,
18220                1,
18221                1,
18222                &atn,
18223            )
18224            .expect("empty complement should recover at EOF");
18225
18226        assert_eq!(node.children().len(), 1);
18227        // Recovery synthesizes a missing token without consuming EOF, so the
18228        // enclosing rule must not record EOF as its stop token.
18229        assert!(!node.consumed_eof());
18230        assert_eq!(parser.la(1), TOKEN_EOF);
18231        assert_eq!(
18232            parser.generated_parser_diagnostics,
18233            [ParserDiagnostic {
18234                line: 1,
18235                column: 1,
18236                message: "missing {} at '<EOF>'".to_owned(),
18237                offending: parser.input.lt_id(1),
18238            }]
18239        );
18240    }
18241
18242    #[test]
18243    fn wildcard_recovers_via_insertion_when_follow_expects_eof_at_eof() {
18244        // `start : . EOF ;` on empty input. The wildcard is modeled as an
18245        // empty-complement not-set; at EOF the follow state (the explicit EOF
18246        // match) expects EOF, so even in the start rule recovery must perform
18247        // single-token insertion (`<missing ...>`) rather than aborting — matching
18248        // ANTLR's `(start <missing ...> <EOF>)` / "missing ... at '<EOF>'".
18249        let atn = wildcard_then_eof_atn();
18250        let data = RecognizerData::new(
18251            "Mini.g4",
18252            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
18253        );
18254        let mut parser = BaseParser::new(
18255            CommonTokenStream::new(Source {
18256                tokens: vec![TestToken::eof("parser-test", 1, 1, 1)],
18257                index: 0,
18258            }),
18259            data,
18260        );
18261        parser.rule_context_stack = vec![RuleContextFrame {
18262            rule_index: 0,
18263            invoking_state: 0,
18264        }];
18265
18266        let node = parser
18267            .match_not_set_recovering(&[], 1, atn.max_token_type(), 2, &atn)
18268            .expect("wildcard at EOF should recover by insertion when follow expects EOF");
18269
18270        // A single `<missing ...>` error node is inserted; EOF is not consumed.
18271        assert_eq!(node.children().len(), 1);
18272        assert!(!node.consumed_eof());
18273        assert!(
18274            parser
18275                .node(node.children()[0])
18276                .text()
18277                .starts_with("<missing")
18278        );
18279        assert_eq!(parser.la(1), TOKEN_EOF);
18280        assert_eq!(
18281            parser.generated_parser_diagnostics,
18282            [ParserDiagnostic {
18283                line: 1,
18284                column: 1,
18285                message: "missing 'x' at '<EOF>'".to_owned(),
18286                offending: parser.input.lt_id(1),
18287            }]
18288        );
18289    }
18290
18291    #[test]
18292    fn generated_rule_recovery_consumes_to_parent_follow() {
18293        let atn = generated_match_recovery_atn();
18294        let data = RecognizerData::new(
18295            "Mini.g4",
18296            Vocabulary::new(
18297                [None, Some("'X'"), Some("'Y'"), Some("'Z'")],
18298                [None, Some("X"), Some("Y"), Some("Z")],
18299                [None::<&str>, None, None, None],
18300            ),
18301        );
18302        let mut parser = BaseParser::new(
18303            CommonTokenStream::new(Source {
18304                tokens: vec![
18305                    TestToken::new(3).with_text("z"),
18306                    TestToken::eof("parser-test", 1, 1, 1),
18307                ],
18308                index: 0,
18309            }),
18310            data,
18311        );
18312        let _parent = parser.enter_rule(0, 0);
18313        let marker = parser.push_invoking_state(1);
18314        let mut child = parser.enter_rule(4, 1);
18315        parser.discard_invoking_state(marker);
18316
18317        // The anchor recorded where the error was built must survive into the
18318        // dispatched diagnostic even though recovery consumes past it below.
18319        let offending = parser.input.lt_id(1);
18320        assert!(offending.is_some(), "the 'z' token should be buffered");
18321        parser.recover_generated_rule(
18322            &mut child,
18323            &atn,
18324            AntlrError::ParserError {
18325                line: 1,
18326                column: 0,
18327                message: "mismatched input 'z' expecting {'X', 'Y'}".to_owned(),
18328                offending,
18329            },
18330        );
18331        let tree = parser.finish_rule(child, false);
18332
18333        assert_eq!(parser.la(1), TOKEN_EOF);
18334        assert_eq!(
18335            parser.node(tree).to_string_tree_with_names(&["s", "a"]),
18336            "(a z)"
18337        );
18338        assert_eq!(parser.number_of_syntax_errors(), 1);
18339        assert_eq!(
18340            parser.generated_parser_diagnostics,
18341            [ParserDiagnostic {
18342                line: 1,
18343                column: 0,
18344                message: "mismatched input 'z' expecting {'X', 'Y'}".to_owned(),
18345                offending,
18346            }]
18347        );
18348        parser.exit_rule();
18349    }
18350
18351    #[test]
18352    fn generated_rule_recovery_forces_progress_after_repeated_error_state() {
18353        let atn = nested_nullable_context_atn();
18354        let mut parser = mini_parser(vec![
18355            TestToken::new(1).with_text("x"),
18356            TestToken::eof("parser-test", 1, 1, 1),
18357        ]);
18358        parser.rule_context_stack = vec![
18359            RuleContextFrame {
18360                rule_index: 0,
18361                invoking_state: 0,
18362            },
18363            RuleContextFrame {
18364                rule_index: 1,
18365                invoking_state: 1,
18366            },
18367            RuleContextFrame {
18368                rule_index: 2,
18369                invoking_state: 2,
18370            },
18371        ];
18372        parser.set_state(20);
18373        let mut context = ParserRuleContext::new(2, 2);
18374
18375        parser.recover_generated_rule(
18376            &mut context,
18377            &atn,
18378            AntlrError::NoViableAlternative {
18379                input: "'x'".to_owned(),
18380            },
18381        );
18382        assert_eq!(parser.input.index(), 0);
18383
18384        parser.set_state(21);
18385        parser.recover_generated_rule(
18386            &mut context,
18387            &atn,
18388            AntlrError::NoViableAlternative {
18389                input: "'x'".to_owned(),
18390            },
18391        );
18392        assert_eq!(parser.input.index(), 0);
18393        assert_eq!(
18394            parser.generated_recovery_error_states,
18395            BTreeSet::from([20, 21])
18396        );
18397
18398        parser.set_state(20);
18399        parser.recover_generated_rule(
18400            &mut context,
18401            &atn,
18402            AntlrError::NoViableAlternative {
18403                input: "'x'".to_owned(),
18404            },
18405        );
18406
18407        assert_eq!(parser.input.index(), 1);
18408        assert_eq!(parser.la(1), TOKEN_EOF);
18409        assert!(context.has_matched_child());
18410        assert_eq!(parser.generated_recovery_error_states, BTreeSet::from([20]));
18411
18412        parser.match_eof().expect("EOF should match");
18413        assert_eq!(parser.generated_recovery_error_index, None);
18414        assert!(parser.generated_recovery_error_states.is_empty());
18415    }
18416
18417    #[test]
18418    fn greedy_ll1_alt_handles_nullable_loop_exit() {
18419        let mut body_symbols = TokenBitSet::default();
18420        body_symbols.insert(1);
18421        let entry = DecisionLookahead {
18422            transitions: vec![
18423                TransitionLookSet {
18424                    symbols: body_symbols,
18425                    nullable: false,
18426                },
18427                TransitionLookSet {
18428                    symbols: TokenBitSet::default(),
18429                    nullable: true,
18430                },
18431            ],
18432        };
18433
18434        assert_eq!(ll1_unique_alt(&entry, 2), None);
18435        assert_eq!(ll1_greedy_alt(&entry, 2, false), Some(1));
18436        assert_eq!(ll1_greedy_alt(&entry, 1, false), None);
18437        assert_eq!(ll1_greedy_alt(&entry, 1, true), None);
18438    }
18439
18440    #[test]
18441    fn ordinary_repetition_builds_tree_in_input_order() {
18442        for atn in [ordinary_star_loop_atn(), ordinary_plus_loop_atn()] {
18443            let mut parser = mini_parser(repeated_x_tokens(3));
18444            let tree = parser
18445                .parse_atn_rule(&atn, 0)
18446                .expect("ordinary repetition should parse");
18447
18448            let root = parser
18449                .node(tree)
18450                .as_rule()
18451                .expect("entry result should be a rule");
18452            let body_rules = root.child_rules(1).collect::<Vec<_>>();
18453            assert_eq!(root.text(), "xxx<EOF>");
18454            assert_eq!(body_rules.len(), 3);
18455            assert_eq!(
18456                body_rules
18457                    .iter()
18458                    .map(|rule| rule.start_id().expect("body start").index())
18459                    .collect::<Vec<_>>(),
18460                [0, 1, 2]
18461            );
18462            assert_eq!(
18463                body_rules
18464                    .iter()
18465                    .map(|rule| rule.stop_id().expect("body stop").index())
18466                    .collect::<Vec<_>>(),
18467                [0, 1, 2]
18468            );
18469            assert_eq!(parser.number_of_syntax_errors(), 0);
18470        }
18471    }
18472
18473    #[test]
18474    fn deeply_nested_deferred_rules_materialize_on_small_stack() {
18475        const DEPTH: usize = 20_000;
18476
18477        std::thread::Builder::new()
18478            .name("deferred-rule-materialization".to_owned())
18479            .stack_size(256 * 1024)
18480            .spawn(|| {
18481                let mut parser = mini_parser(vec![TestToken::eof("parser-test", 0, 1, 0)]);
18482                let mut root = FastDeferredNodeId::EMPTY;
18483                for depth in 0..DEPTH {
18484                    root = parser
18485                        .recognition_arena
18486                        .deferred_rule_node(FastDeferredRule {
18487                            rule_index: u32::try_from(depth).expect("depth fits in u32"),
18488                            invoking_state: i32::try_from(depth).expect("depth fits in i32"),
18489                            start_index: 0,
18490                            stop_index: None,
18491                            deferred_children: root,
18492                            children: NodeSeqId::EMPTY,
18493                        });
18494                }
18495
18496                let (mut children, alt_number) =
18497                    parser.materialize_fast_deferred_nodes(root, NodeSeqId::EMPTY);
18498                assert_eq!(alt_number, 0);
18499                for expected_rule in (0..DEPTH).rev() {
18500                    let mut nodes = parser.recognition_arena.iter(children);
18501                    let node = nodes.next().expect("nested rule node");
18502                    assert!(nodes.next().is_none(), "each rule has one child");
18503                    let ArenaRecognizedNode::Rule {
18504                        rule_index,
18505                        children: nested,
18506                        ..
18507                    } = parser.recognition_arena.node(node)
18508                    else {
18509                        panic!("expected nested rule");
18510                    };
18511                    assert_eq!(rule_index as usize, expected_rule);
18512                    children = nested;
18513                }
18514                assert!(children.is_empty());
18515            })
18516            .expect("small-stack thread should start")
18517            .join()
18518            .expect("deferred rules should materialize without recursion");
18519    }
18520
18521    #[test]
18522    fn deferred_alternatives_preserve_left_recursive_contexts() {
18523        let mut parser = mini_parser(vec![
18524            TestToken::new(1).with_text("1"),
18525            TestToken::new(2).with_text("+"),
18526            TestToken::new(1).with_text("2"),
18527            TestToken::eof("parser-test", 3, 1, 3),
18528        ]);
18529        let base = parser.arena_token_node(0, false);
18530        let operator = parser.arena_token_node(1, false);
18531        let right = parser.arena_token_node(2, false);
18532
18533        let base = parser.recognition_arena.prepend(NodeSeqId::EMPTY, base);
18534        let base = parser.recognition_arena.deferred_fragment(base);
18535        let operator = parser.recognition_arena.prepend(NodeSeqId::EMPTY, operator);
18536        let operator = parser.recognition_arena.deferred_fragment(operator);
18537        let right = parser.recognition_arena.prepend(NodeSeqId::EMPTY, right);
18538        let right = parser.recognition_arena.deferred_fragment(right);
18539        let base_alt = parser.recognition_arena.deferred_alternative(1);
18540        let boundary = parser.recognition_arena.deferred_left_recursive_boundary(0);
18541        let operator_alt = parser.recognition_arena.deferred_alternative(6);
18542
18543        let mut deferred = FastDeferredNodeId::EMPTY;
18544        for fragment in [base_alt, base, boundary, operator_alt, operator, right] {
18545            deferred = parser
18546                .recognition_arena
18547                .concat_deferred_nodes(deferred, fragment);
18548        }
18549        let (nodes, root_alt_number) =
18550            parser.materialize_fast_deferred_nodes(deferred, NodeSeqId::EMPTY);
18551        let nodes = parser
18552            .recognition_arena
18553            .fold_left_recursive_boundaries(nodes);
18554
18555        let mut root = ParserRuleContext::new(0, -1);
18556        root.set_context_alt_number(root_alt_number);
18557        let mut cursor = nodes;
18558        while let Some(link) = parser.recognition_arena.link(cursor) {
18559            let child = parser
18560                .arena_recognized_node_tree(link.head, false, true)
18561                .expect("materialized child should become a public tree");
18562            parser.tree.add_child(&mut root, child);
18563            cursor = link.tail;
18564        }
18565        let tree = parser.rule_node(root);
18566        let contexts = parser
18567            .node(tree)
18568            .descendants()
18569            .filter_map(Node::as_rule)
18570            .map(|rule| {
18571                (
18572                    rule.rule_index(),
18573                    rule.alt_number(),
18574                    rule.context_alt_number(),
18575                    rule.text(),
18576                )
18577            })
18578            .collect::<Vec<_>>();
18579
18580        insta::assert_debug_snapshot!(
18581            "deferred_alternatives_preserve_left_recursive_contexts",
18582            contexts
18583        );
18584    }
18585
18586    #[test]
18587    fn fast_recognizer_preserves_labeled_left_recursive_operator_context() {
18588        let atn = labeled_left_recursive_operator_atn();
18589        let mut parser = mini_parser(vec![
18590            TestToken::new(1).with_text("a"),
18591            TestToken::new(3).with_text("+"),
18592            TestToken::new(1).with_text("b"),
18593            TestToken::eof("parser-test", 3, 1, 3),
18594        ]);
18595
18596        let (tree, _) = parser
18597            .parse_atn_rule_with_runtime_options(
18598                &atn,
18599                0,
18600                ParserRuntimeOptions {
18601                    track_context_alt_numbers: true,
18602                    ..ParserRuntimeOptions::default()
18603                },
18604            )
18605            .expect("labeled left-recursive addition should parse");
18606        let contexts = parser
18607            .node(tree)
18608            .descendants()
18609            .filter_map(Node::as_rule)
18610            .map(|rule| {
18611                let operator = rule
18612                    .children()
18613                    .next()
18614                    .and_then(Node::as_rule)
18615                    .is_some_and(|child| child.rule_index() == rule.rule_index());
18616                (operator, rule.context_alt_number(), rule.text())
18617            })
18618            .collect::<Vec<_>>();
18619
18620        insta::assert_debug_snapshot!(
18621            "fast_recognizer_preserves_labeled_left_recursive_operator_context",
18622            contexts
18623        );
18624        assert!(!parser.recognition_arena.deferred_nodes.is_empty());
18625        assert_eq!(parser.number_of_syntax_errors(), 0);
18626    }
18627
18628    #[test]
18629    fn deeply_nested_rule_calls_grow_the_stack() {
18630        const DEPTH: usize = 4_096;
18631        const STACK_SIZE: usize = 256 * 1024;
18632        let atn = nested_rule_chain_atn(DEPTH);
18633        std::thread::Builder::new()
18634            .name("nested-adaptive-set-rules".to_owned())
18635            .stack_size(STACK_SIZE)
18636            .spawn(move || {
18637                let mut parser = mini_parser(vec![TestToken::new(1).with_text("x")]);
18638                parser.set_build_parse_trees(false);
18639                // This test isolates recognizer depth from the separately
18640                // cached FIRST-set metadata walk.
18641                parser.fast_first_set_prefilter = false;
18642                parser
18643                    .parse_atn_rule(&atn, 0)
18644                    .expect("nested rule chain should grow the native stack");
18645                assert_eq!(parser.input.index(), 1);
18646            })
18647            .expect("small-stack thread should start")
18648            .join()
18649            .expect("nested rule chain should not overflow its stack");
18650    }
18651
18652    #[test]
18653    fn deeply_nested_branching_rules_grow_the_stack() {
18654        const DEPTH: usize = 4_096;
18655        const STACK_SIZE: usize = 256 * 1024;
18656        let atn = nested_rule_graph_atn(DEPTH, true, false);
18657        std::thread::Builder::new()
18658            .name("nested-branching-rules".to_owned())
18659            .stack_size(STACK_SIZE)
18660            .spawn(move || {
18661                let mut parser = mini_parser(vec![TestToken::new(1).with_text("x")]);
18662                parser.set_build_parse_trees(false);
18663                parser
18664                    .parse_atn_rule(&atn, 0)
18665                    .expect("branching rule chain should grow the native stack");
18666                assert_eq!(parser.input.index(), 1);
18667            })
18668            .expect("small-stack thread should start")
18669            .join()
18670            .expect("branching rule chain should not overflow its stack");
18671    }
18672
18673    #[test]
18674    fn deeply_nested_rule_follows_grow_the_stack() {
18675        const DEPTH: usize = 4_096;
18676        const STACK_SIZE: usize = 256 * 1024;
18677        let atn = nested_rule_graph_atn(DEPTH, false, true);
18678        std::thread::Builder::new()
18679            .name("nested-rule-follows".to_owned())
18680            .stack_size(STACK_SIZE)
18681            .spawn(move || {
18682                let mut parser = mini_parser(repeated_x_tokens(DEPTH));
18683                parser.set_build_parse_trees(false);
18684                parser.fast_first_set_prefilter = false;
18685                parser
18686                    .parse_atn_rule(&atn, 0)
18687                    .expect("rule follow chain should grow the native stack");
18688                assert_eq!(parser.input.index(), DEPTH);
18689            })
18690            .expect("small-stack thread should start")
18691            .join()
18692            .expect("nested rule follow chain should not overflow its stack");
18693    }
18694
18695    #[test]
18696    fn deeply_nested_recovery_grows_the_stack() {
18697        const DEPTH: usize = 4_096;
18698        const STACK_SIZE: usize = 256 * 1024;
18699        let atn = nested_rule_chain_atn(DEPTH);
18700        std::thread::Builder::new()
18701            .name("nested-rule-recovery".to_owned())
18702            .stack_size(STACK_SIZE)
18703            .spawn(move || {
18704                let mut parser = mini_parser(vec![
18705                    TestToken::new(2).with_text("z"),
18706                    TestToken::new(1).with_text("x"),
18707                    TestToken::eof("parser-test", 2, 1, 2),
18708                ]);
18709                parser.set_build_parse_trees(false);
18710                parser.fast_first_set_prefilter = false;
18711                parser
18712                    .parse_atn_rule(&atn, 0)
18713                    .expect("nested recovery should grow the native stack");
18714                assert_eq!(parser.input.index(), 2);
18715                assert_eq!(parser.number_of_syntax_errors(), 1);
18716            })
18717            .expect("small-stack thread should start")
18718            .join()
18719            .expect("nested rule recovery should not overflow its stack");
18720    }
18721
18722    #[test]
18723    fn ambiguous_ordinary_repetition_merges_equivalent_coordinates() {
18724        const REPETITIONS: usize = 64;
18725
18726        let atn = ambiguous_ordinary_star_loop_atn();
18727        let mut parser = mini_parser(repeated_x_tokens(REPETITIONS));
18728        let tree = parser
18729            .parse_atn_rule(&atn, 0)
18730            .expect("ambiguous ordinary repetition should parse");
18731
18732        let root = parser
18733            .node(tree)
18734            .as_rule()
18735            .expect("entry result should be a rule");
18736        assert_eq!(root.text(), format!("{}<EOF>", "x".repeat(REPETITIONS)));
18737        assert_eq!(parser.input.index(), REPETITIONS);
18738        assert!(
18739            parser.recognition_arena.deferred_nodes.len() <= REPETITIONS * 8,
18740            "equivalent segmentations should keep deferred storage linear"
18741        );
18742        assert_eq!(parser.number_of_syntax_errors(), 0);
18743    }
18744
18745    #[test]
18746    fn long_ordinary_repetition_does_not_consume_native_stack() {
18747        const REPETITIONS: usize = 20_000;
18748
18749        for atn in [ordinary_star_loop_atn(), ordinary_plus_loop_atn()] {
18750            let mut parser = mini_parser(repeated_x_tokens(REPETITIONS));
18751            parser.set_build_parse_trees(false);
18752            parser
18753                .parse_atn_rule(&atn, 0)
18754                .expect("long ordinary repetition should parse");
18755
18756            assert_eq!(parser.input.index(), REPETITIONS);
18757            assert_eq!(parser.number_of_syntax_errors(), 0);
18758        }
18759    }
18760
18761    #[test]
18762    fn long_rule_repetition_materializes_tree_with_linear_arena_growth() {
18763        const REPETITIONS: usize = 2_000;
18764        let expected_text = format!("{}<EOF>", "x".repeat(REPETITIONS));
18765
18766        for atn in [ordinary_star_loop_atn(), ordinary_plus_loop_atn()] {
18767            let mut parser = mini_parser(repeated_x_tokens(REPETITIONS));
18768            let tree = parser
18769                .parse_atn_rule(&atn, 0)
18770                .expect("long rule repetition should parse");
18771
18772            let root = parser
18773                .node(tree)
18774                .as_rule()
18775                .expect("entry result should be a rule");
18776            assert_eq!(root.text(), expected_text);
18777            assert_eq!(root.child_rules(1).count(), REPETITIONS);
18778            let first_body = root.child_rules(1).next().expect("first body rule");
18779            let last_body = root.child_rules(1).next_back().expect("last body rule");
18780            assert_eq!(first_body.start_id().expect("first body start").index(), 0);
18781            assert_eq!(
18782                last_body.stop_id().expect("last body stop").index(),
18783                REPETITIONS - 1
18784            );
18785
18786            let stats = parser.recognition_arena_stats();
18787            assert_eq!(
18788                (stats.total_nodes, stats.live_nodes, stats.dead_nodes),
18789                (REPETITIONS, REPETITIONS, 0)
18790            );
18791            assert_eq!(
18792                (stats.total_links, stats.live_links, stats.dead_links),
18793                (REPETITIONS, REPETITIONS, 0)
18794            );
18795            assert_eq!(parser.recognition_arena.deferred_rules.len(), REPETITIONS);
18796            assert_eq!(
18797                parser.recognition_arena.deferred_nodes.len(),
18798                REPETITIONS * 2 - 1
18799            );
18800            assert_eq!(parser.number_of_syntax_errors(), 0);
18801        }
18802    }
18803
18804    #[test]
18805    fn clean_memo_probe_selects_sparse_promote_and_reprobe_modes() {
18806        let key = |state_number| FastRecognizeKey {
18807            state_number,
18808            stop_state: 10,
18809            index: state_number,
18810            rule_start_index: 0,
18811            decision_start_index: None,
18812            precedence: 0,
18813            recovery_symbols_id: 0,
18814            recovery_state: None,
18815        };
18816
18817        let mut sparse = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
18818        for state_number in 0..(CLEAN_MEMO_PROBE_LIMIT - 1) {
18819            assert!(sparse.clean_memo_enabled_for_key(&key(state_number)));
18820        }
18821        assert!(!sparse.clean_memo_enabled_for_key(&key(CLEAN_MEMO_PROBE_LIMIT)));
18822        assert_eq!(sparse.clean_memo_mode, CleanMemoMode::Sparse);
18823
18824        let mut promote = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
18825        let repeated = key(1);
18826        for _ in 0..=CLEAN_MEMO_REPEAT_LIMIT {
18827            assert!(promote.clean_memo_enabled_for_key(&repeated));
18828        }
18829        assert_eq!(promote.clean_memo_mode, CleanMemoMode::Promote);
18830
18831        for _ in 1..CLEAN_MEMO_REPROBE_INTERVAL {
18832            assert!(!sparse.clean_memo_enabled_for_key(&repeated));
18833        }
18834        assert!(sparse.clean_memo_enabled_for_key(&repeated));
18835        assert_eq!(sparse.clean_memo_mode, CleanMemoMode::Probe);
18836        for _ in 0..CLEAN_MEMO_REPEAT_LIMIT {
18837            assert!(sparse.clean_memo_enabled_for_key(&repeated));
18838        }
18839        assert_eq!(sparse.clean_memo_mode, CleanMemoMode::Promote);
18840    }
18841
18842    #[test]
18843    fn fast_recognize_memo_capacity_scales_from_small_floor_to_bounded_maximum() {
18844        assert_eq!(
18845            fast_recognize_memo_capacity(0),
18846            FAST_RECOGNIZE_MIN_MEMO_CAPACITY
18847        );
18848        assert_eq!(
18849            fast_recognize_memo_capacity(FAST_RECOGNIZE_MIN_MEMO_CAPACITY / 8),
18850            FAST_RECOGNIZE_MIN_MEMO_CAPACITY
18851        );
18852        assert_eq!(fast_recognize_memo_capacity(1_000), 8_000);
18853        assert_eq!(
18854            fast_recognize_memo_capacity(usize::MAX),
18855            FAST_RECOGNIZE_MAX_MEMO_CAPACITY
18856        );
18857    }
18858
18859    #[test]
18860    fn fast_recognize_scratch_reuses_small_tables_and_releases_oversized_memo() {
18861        let mut scratch = FastRecognizeTopScratch::default();
18862        scratch.prepare(FAST_RECOGNIZE_MIN_MEMO_CAPACITY);
18863        let retained_capacity = scratch.memo.capacity();
18864        assert!(retained_capacity >= FAST_RECOGNIZE_MIN_MEMO_CAPACITY);
18865        assert!(retained_capacity <= FAST_RECOGNIZE_MAX_RETAINED_MEMO_CAPACITY);
18866
18867        let larger_capacity = retained_capacity + 1;
18868        scratch.prepare(larger_capacity);
18869        let grown_capacity = scratch.memo.capacity();
18870        assert!(grown_capacity >= larger_capacity);
18871        assert!(grown_capacity <= FAST_RECOGNIZE_MAX_RETAINED_MEMO_CAPACITY);
18872
18873        scratch.memo.insert(
18874            FastRecognizeKey {
18875                state_number: 0,
18876                stop_state: 0,
18877                index: 0,
18878                rule_start_index: 0,
18879                decision_start_index: None,
18880                precedence: 0,
18881                recovery_symbols_id: 0,
18882                recovery_state: None,
18883            },
18884            Rc::from([FastRecognizeOutcome {
18885                index: 0,
18886                consumed_eof: false,
18887                diagnostics: DiagnosticSeqId::EMPTY,
18888                deferred_nodes: FastDeferredNodeId::EMPTY,
18889                nodes: NodeSeqId::EMPTY,
18890            }]),
18891        );
18892        scratch.release_oversized_memo();
18893        assert!(scratch.memo.is_empty());
18894        assert_eq!(scratch.memo.capacity(), grown_capacity);
18895
18896        scratch
18897            .memo
18898            .reserve(FAST_RECOGNIZE_MAX_RETAINED_MEMO_CAPACITY * 2);
18899        assert!(scratch.memo.capacity() > FAST_RECOGNIZE_MAX_RETAINED_MEMO_CAPACITY);
18900
18901        scratch.release_oversized_memo();
18902        assert!(scratch.memo.is_empty());
18903        assert_eq!(scratch.memo.capacity(), 0);
18904    }
18905
18906    #[test]
18907    fn clean_empty_multi_alt_outcomes_are_memoized() {
18908        let mut atn = ParserAtnBuilder::new(2);
18909        assert_eq!(
18910            atn.add_state(AtnStateKind::RuleStart, Some(0))
18911                .expect("state")
18912                .index(),
18913            0
18914        );
18915        assert_eq!(
18916            atn.add_state(AtnStateKind::BlockStart, Some(0))
18917                .expect("state")
18918                .index(),
18919            1
18920        );
18921        assert_eq!(
18922            atn.add_state(AtnStateKind::RuleStop, Some(0))
18923                .expect("state")
18924                .index(),
18925            2
18926        );
18927        atn.set_rule_to_start_state(vec![0])
18928            .expect("rule start states");
18929        atn.set_rule_to_stop_state(vec![2])
18930            .expect("rule stop states");
18931        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
18932            .expect("transition");
18933        atn.add_transition(
18934            1,
18935            ParserTransitionSpec::Atom {
18936                target: 2,
18937                label: 1,
18938            },
18939        )
18940        .expect("transition");
18941        atn.add_transition(
18942            1,
18943            ParserTransitionSpec::Atom {
18944                target: 2,
18945                label: 2,
18946            },
18947        )
18948        .expect("transition");
18949        let atn = finish_atn(atn);
18950
18951        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 0, 1, 0)]);
18952        parser.fast_recovery_enabled = false;
18953        let mut visiting = FxHashSet::default();
18954        let mut memo = FxHashMap::default();
18955        let mut expected = ExpectedTokens::default();
18956        let outcomes = parser.recognize_state_fast(
18957            &atn,
18958            FastRecognizeRequest {
18959                state_number: 1,
18960                stop_state: 2,
18961                index: 0,
18962                rule_start_index: 0,
18963                decision_start_index: None,
18964                precedence: 0,
18965                depth: 0,
18966                recovery_symbols: parser.empty_recovery_symbols(),
18967                recovery_state: None,
18968            },
18969            FastRecognizeScratch {
18970                predicate_context: None,
18971                visiting: &mut visiting,
18972                memo: &mut memo,
18973                expected: &mut expected,
18974                native_depth: 0,
18975            },
18976        );
18977
18978        assert!(outcomes.is_empty());
18979        assert_eq!(memo.len(), 1);
18980        assert!(memo.values().next().expect("memo entry").is_empty());
18981
18982        parser.clean_memo_mode = CleanMemoMode::Sparse;
18983        visiting.clear();
18984        memo.clear();
18985        expected = ExpectedTokens::default();
18986        let sparse_outcomes = parser.recognize_state_fast(
18987            &atn,
18988            FastRecognizeRequest {
18989                state_number: 1,
18990                stop_state: 2,
18991                index: 0,
18992                rule_start_index: 0,
18993                decision_start_index: None,
18994                precedence: 0,
18995                depth: 0,
18996                recovery_symbols: parser.empty_recovery_symbols(),
18997                recovery_state: None,
18998            },
18999            FastRecognizeScratch {
19000                predicate_context: None,
19001                visiting: &mut visiting,
19002                memo: &mut memo,
19003                expected: &mut expected,
19004                native_depth: 0,
19005            },
19006        );
19007
19008        assert!(sparse_outcomes.is_empty());
19009        assert!(memo.is_empty());
19010    }
19011
19012    #[test]
19013    fn wildcard_matches_non_eof_only() {
19014        let mut parser = mini_parser(vec![
19015            TestToken::new(1).with_text("x"),
19016            TestToken::eof("parser-test", 1, 1, 1),
19017        ]);
19018        let matched = parser.match_wildcard().expect("wildcard");
19019        assert_eq!(parser.node(matched).text(), "x");
19020        assert!(parser.match_wildcard().is_err());
19021    }
19022
19023    #[test]
19024    fn add_parse_child_records_match_even_without_tree_building() {
19025        // `sync_decision`'s "is the current context empty" flag must reflect real
19026        // matches, not parse-tree children: when `build_parse_trees(false)`,
19027        // `children` stays empty but `has_matched_child` must still flip so nested
19028        // recovery does not wrongly suppress single-token deletion.
19029        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
19030        let token = TestToken::new(1).with_text("x");
19031
19032        parser.set_build_parse_trees(false);
19033        let mut ctx = ParserRuleContext::new(0, 0);
19034        assert!(!ctx.has_matched_child());
19035        let child = parser.terminal_tree(token.id);
19036        parser.add_parse_child(&mut ctx, child);
19037        // Tree building is off, so no child is stored...
19038        assert_eq!(ctx.child_count(), 0);
19039        assert_eq!(parser.parse_tree_storage().node_count(), 0);
19040        // ...but the match is recorded, so the context is no longer "empty".
19041        assert!(ctx.has_matched_child());
19042
19043        // With tree building on, the child is stored and the match is recorded.
19044        parser.set_build_parse_trees(true);
19045        let mut ctx = ParserRuleContext::new(0, 0);
19046        let child = parser.terminal_tree(token.id);
19047        parser.add_parse_child(&mut ctx, child);
19048        assert_eq!(ctx.child_count(), 1);
19049        assert!(ctx.has_matched_child());
19050    }
19051
19052    #[test]
19053    fn disabled_tree_building_does_not_grow_flat_storage() {
19054        let mut parser = mini_parser(vec![
19055            TestToken::new(1).with_text("x"),
19056            TestToken::new(1).with_text("y"),
19057            TestToken::eof("parser-test", 2, 1, 2),
19058        ]);
19059        parser.set_build_parse_trees(false);
19060        let mut context = ParserRuleContext::new(0, -1);
19061
19062        for _ in 0..2 {
19063            let child = parser.match_token(1).expect("token should match");
19064            parser.add_parse_child(&mut context, child);
19065        }
19066        let current = parser.input.lt_id(1).expect("EOF token");
19067        let error = parser.error_tree(current);
19068        parser.add_parse_child(&mut context, error);
19069        let root = parser.rule_node(context);
19070
19071        assert_eq!(
19072            parser.parse_tree_storage().stats(),
19073            ParseTreeStats::default()
19074        );
19075        assert!(
19076            parser
19077                .parse_tree_storage()
19078                .node(parser.token_store(), root)
19079                .is_none(),
19080            "the no-tree sentinel must not resolve to stored data"
19081        );
19082    }
19083
19084    #[test]
19085    fn disabled_tree_building_skips_recognition_rule_node_storage() {
19086        let atn = ordinary_star_loop_atn();
19087        let mut parser = mini_parser(repeated_x_tokens(3));
19088        parser.set_build_parse_trees(false);
19089
19090        parser
19091            .parse_atn_rule(&atn, 0)
19092            .expect("ordinary repetition should parse without a tree");
19093
19094        assert_eq!(parser.input.index(), 3);
19095        assert!(parser.recognition_arena.nodes.is_empty());
19096        assert!(parser.recognition_arena.seq_links.is_empty());
19097        assert!(parser.recognition_arena.deferred_nodes.is_empty());
19098        assert!(parser.recognition_arena.deferred_rules.is_empty());
19099        assert!(!parser.fast_token_nodes_enabled);
19100        assert!(parser.fast_recognize_scratch.memo.is_empty());
19101    }
19102
19103    #[test]
19104    fn parser_interprets_simple_atn_rule() {
19105        let atn = token_then_eof_atn();
19106        let mut parser = mini_parser(vec![
19107            TestToken::new(1).with_text("x"),
19108            TestToken::eof("parser-test", 1, 1, 1),
19109        ]);
19110
19111        let tree = parser
19112            .parse_atn_rule(&atn, 0)
19113            .expect("artificial parser rule should parse");
19114        assert_eq!(parser.node(tree).text(), "x<EOF>");
19115        assert_eq!(parser.number_of_syntax_errors(), 0);
19116        assert_eq!(
19117            parser
19118                .node(tree)
19119                .first_rule_stop(0)
19120                .expect("rule should stop at EOF")
19121                .token_type(),
19122            TOKEN_EOF
19123        );
19124
19125        let mut parser = mini_parser(vec![
19126            TestToken::new(1).with_text("x"),
19127            TestToken::eof("parser-test", 1, 1, 1),
19128        ]);
19129        let (tree, actions) = parser
19130            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
19131            .expect("runtime-option parser rule should parse");
19132        assert!(actions.is_empty());
19133        assert_eq!(
19134            parser
19135                .node(tree)
19136                .first_rule_stop(0)
19137                .expect("rule should stop at EOF")
19138                .token_type(),
19139            TOKEN_EOF
19140        );
19141    }
19142
19143    #[test]
19144    fn runtime_options_default_ignores_noop_action_transitions() {
19145        let atn = noop_action_then_token_then_eof_atn();
19146        let mut parser = mini_parser(vec![
19147            TestToken::new(1).with_text("x"),
19148            TestToken::eof("parser-test", 1, 1, 1),
19149        ]);
19150
19151        let (tree, actions) = parser
19152            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
19153            .expect("no-op parser action should not force action replay");
19154
19155        assert_eq!(parser.node(tree).text(), "x<EOF>");
19156        assert!(
19157            actions.is_empty(),
19158            "action_index=None transitions are ANTLR metadata, not replay actions"
19159        );
19160        assert_eq!(parser.number_of_syntax_errors(), 0);
19161    }
19162
19163    #[test]
19164    fn parser_exposes_buffered_token_stream_after_parse() {
19165        let atn = token_then_eof_atn();
19166        let mut parser = mini_parser(vec![
19167            TestToken::new(1).with_text("x"),
19168            TestToken::eof("parser-test", 1, 1, 1),
19169        ]);
19170
19171        let tree = parser
19172            .parse_atn_rule(&atn, 0)
19173            .expect("artificial parser rule should parse");
19174        assert_eq!(parser.node(tree).text(), "x<EOF>");
19175
19176        let stream = parser.token_stream();
19177        let source_index_after_parse = stream.token_source().index;
19178        let buffered = stream.tokens().collect::<Vec<_>>();
19179        assert_eq!(buffered.len(), 2);
19180        assert_eq!(buffered[0].text(), Some("x"));
19181        assert_eq!(buffered[0].token_id().index(), 0);
19182        assert_eq!(buffered[1].token_type(), TOKEN_EOF);
19183        assert_eq!(stream.token_source().index, source_index_after_parse);
19184        drop(buffered);
19185
19186        let stream = parser.into_token_stream();
19187        assert_eq!(stream.token_source().index, source_index_after_parse);
19188        assert_eq!(
19189            stream.tokens().next().expect("first token").text(),
19190            Some("x")
19191        );
19192        assert_eq!(
19193            stream.tokens().nth(1).expect("EOF token").token_type(),
19194            TOKEN_EOF
19195        );
19196    }
19197
19198    #[test]
19199    fn parsed_file_exposes_all_buffered_tokens() {
19200        let atn = token_then_eof_atn();
19201        let mut parser = mini_parser(vec![
19202            TestToken::new(99)
19203                .with_text(" comment")
19204                .with_channel(HIDDEN_CHANNEL),
19205            TestToken::new(1).with_text("x"),
19206            TestToken::eof("parser-test", 9, 1, 9),
19207        ]);
19208
19209        let tree = parser
19210            .parse_atn_rule(&atn, 0)
19211            .expect("artificial parser rule should parse");
19212        let parsed = parser.into_parsed_file(tree);
19213
19214        // Snapshot the full buffered stream — hidden-channel comment, default-channel token, EOF —
19215        // as (type, channel, text) triples; contents make the count self-evident.
19216        insta::assert_debug_snapshot!(
19217            "parsed_file_exposes_all_buffered_tokens",
19218            parsed
19219                .tokens()
19220                .iter()
19221                .map(|token| (token.token_type(), token.channel(), token.text()))
19222                .collect::<Vec<_>>()
19223        );
19224        assert_eq!(parsed.tokens().into_iter().count(), 3);
19225    }
19226
19227    #[test]
19228    fn parser_syntax_error_count_tracks_interpreted_recovery() {
19229        let atn = token_then_eof_atn();
19230        let mut parser = mini_parser(vec![
19231            TestToken::new(1).with_text("x"),
19232            TestToken::new(2).with_text("y"),
19233            TestToken::eof("parser-test", 2, 1, 2),
19234        ]);
19235
19236        let tree = parser
19237            .parse_atn_rule(&atn, 0)
19238            .expect("invalid token should recover into an error node");
19239
19240        assert_eq!(parser.number_of_syntax_errors(), 1);
19241        assert_eq!(
19242            parser
19243                .node(tree)
19244                .first_error_token()
19245                .expect("recovery should embed an error token")
19246                .text(),
19247            Some("y")
19248        );
19249    }
19250
19251    #[test]
19252    fn failed_interpreted_parse_notifies_error_listener() {
19253        let atn = token_then_eof_atn();
19254        let mut parser = mini_parser(vec![
19255            TestToken::new(2)
19256                .with_text("y")
19257                .with_span(0, 0)
19258                .with_byte_span(0, 1)
19259                .with_position(3, 5),
19260            TestToken::eof("parser-test", 1, 1, 1),
19261        ]);
19262        parser.remove_error_listeners();
19263        let diagnostics = Arc::new(Mutex::new(Vec::new()));
19264        parser.add_error_listener(RecordingErrorListener {
19265            diagnostics: Arc::clone(&diagnostics),
19266        });
19267
19268        let error = parser
19269            .parse_atn_rule(&atn, 0)
19270            .expect_err("start-rule mismatch should remain a parser error");
19271
19272        assert_eq!(parser.number_of_syntax_errors(), 1);
19273        assert!(matches!(&error, AntlrError::ParserError { .. }));
19274        insta::assert_debug_snapshot!(
19275            "failed_interpreted_parse_notifies_error_listener",
19276            *diagnostics.lock().expect("recorded diagnostics lock")
19277        );
19278    }
19279
19280    #[test]
19281    fn adaptive_direct_rule_uses_simulator_decision() {
19282        let atn = two_alt_decision_atn();
19283        let mut simulator = ParserAtnSimulator::new(&atn);
19284        let mut parser = mini_parser(vec![
19285            TestToken::new(2).with_text("y"),
19286            TestToken::eof("parser-test", 1, 1, 1),
19287        ]);
19288
19289        let tree = parser
19290            .parse_atn_rule_adaptive_or_fallback(&atn, &mut simulator, 0)
19291            .expect("direct adaptive rule should parse");
19292
19293        assert_eq!(parser.node(tree).text(), "y");
19294        assert_eq!(parser.input.index(), 1);
19295    }
19296
19297    #[test]
19298    fn adaptive_direct_rule_restores_input_on_fallback() {
19299        let atn = predicate_after_token_atn();
19300        let mut simulator = ParserAtnSimulator::new(&atn);
19301        let mut parser = mini_parser(vec![
19302            TestToken::new(1).with_text("x"),
19303            TestToken::new(2).with_text("y"),
19304            TestToken::eof("parser-test", 2, 1, 2),
19305        ]);
19306
19307        let tree = parser
19308            .parse_atn_rule_adaptive_or_fallback(&atn, &mut simulator, 0)
19309            .expect("fallback recognizer should parse");
19310
19311        assert_eq!(parser.node(tree).text(), "xy");
19312        assert_eq!(parser.input.index(), 2);
19313        let stats = parser.parse_tree_storage().stats();
19314        assert_eq!(stats.nodes, parser.node(tree).descendants().count());
19315        assert_eq!(stats.edges, stats.nodes.saturating_sub(1));
19316        assert_eq!(stats.scratch_links, 0);
19317    }
19318
19319    #[test]
19320    fn unknown_predicate_policy_defaults_to_assume_true() {
19321        let atn = predicate_after_token_atn();
19322        let mut parser = mini_parser(vec![
19323            TestToken::new(1).with_text("x"),
19324            TestToken::new(2).with_text("y"),
19325            TestToken::eof("parser-test", 2, 1, 2),
19326        ]);
19327
19328        let (tree, _) = parser
19329            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
19330            .expect("unknown predicate should pass under the default policy");
19331
19332        assert_eq!(parser.node(tree).text(), "xy");
19333        assert_eq!(parser.number_of_syntax_errors(), 0);
19334    }
19335
19336    #[test]
19337    fn private_context_alt_tracking_keeps_fast_predicate_recognition() {
19338        let atn = predicate_gated_same_lookahead_atn([0, 1]);
19339        let mut parser = mini_parser(vec![
19340            TestToken::new(1).with_text("x"),
19341            TestToken::eof("parser-test", 1, 1, 1),
19342        ]);
19343
19344        let (tree, _) = parser
19345            .parse_atn_rule_with_runtime_options(
19346                &atn,
19347                0,
19348                ParserRuntimeOptions {
19349                    predicates: &[
19350                        (0, 0, ParserPredicate::False),
19351                        (0, 1, ParserPredicate::True),
19352                    ],
19353                    track_context_alt_numbers: true,
19354                    ..ParserRuntimeOptions::default()
19355                },
19356            )
19357            .expect("the second predicate-gated alternative should match");
19358
19359        let root = parser.node(tree).as_rule().expect("entry result is a rule");
19360        insta::assert_debug_snapshot!(
19361            "private_context_alt_tracking_keeps_fast_predicate_recognition",
19362            (root.alt_number(), root.context_alt_number(), root.text())
19363        );
19364        assert_eq!(parser.number_of_syntax_errors(), 0);
19365        assert_eq!(parser.fast_predicate_cache.get(&(0, 0, 0)), Some(&false));
19366        assert_eq!(parser.fast_predicate_cache.get(&(0, 0, 1)), Some(&true));
19367    }
19368
19369    #[test]
19370    fn nested_interpreted_parse_preserves_prior_unknown_predicate_hits() {
19371        // A generated parent may record an unknown-predicate coordinate, then
19372        // descend into an interpreted child. The child's interpreter entry must
19373        // not wipe the parent's recorded hit before the top-level surfaces it.
19374        let atn = token_then_eof_atn();
19375        let mut parser = mini_parser(vec![
19376            TestToken::new(1).with_text("x"),
19377            TestToken::eof("parser-test", 1, 1, 1),
19378        ]);
19379
19380        // Simulate the parent having recorded a fail-loud coordinate.
19381        parser.unknown_predicate_hits.push((7, 3));
19382
19383        // Run an interpreted child parse that records no coordinate of its own.
19384        parser
19385            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
19386            .expect("child rule parses");
19387
19388        // The parent's coordinate must still be present for the top-level entry.
19389        let error = parser
19390            .take_unknown_semantic_error()
19391            .expect("parent's recorded coordinate must survive the nested interpreted parse");
19392        let AntlrError::Unsupported(message) = error else {
19393            panic!("expected AntlrError::Unsupported, got {error:?}");
19394        };
19395        assert!(message.contains("pred_index=3"), "message: {message}");
19396    }
19397
19398    #[test]
19399    fn nested_committed_parse_preserves_prior_unhandled_action_hits() {
19400        let atn = token_then_eof_atn();
19401        let mut parser = mini_parser(vec![
19402            TestToken::new(1).with_text("x"),
19403            TestToken::eof("parser-test", 1, 1, 1),
19404        ]);
19405        parser.unhandled_action_hits.push((7, 42));
19406
19407        parser
19408            .parse_atn_rule_with_runtime_options(
19409                &atn,
19410                0,
19411                ParserRuntimeOptions {
19412                    action_indices: &[(usize::MAX, 0)],
19413                    ..ParserRuntimeOptions::default()
19414                },
19415            )
19416            .expect("a child with no action miss must not observe its parent's miss");
19417
19418        let error = parser
19419            .take_unknown_semantic_error()
19420            .expect("the parent's action miss must survive the nested committed parse");
19421        let AntlrError::Unsupported(message) = error else {
19422            panic!("expected AntlrError::Unsupported, got {error:?}");
19423        };
19424        assert!(
19425            message.contains("rule_index=7") && message.contains("state=42"),
19426            "message: {message}"
19427        );
19428    }
19429
19430    #[test]
19431    fn unknown_predicate_policy_assume_false_kills_the_guarded_path() {
19432        let atn = predicate_after_token_atn();
19433        let mut parser = mini_parser(vec![
19434            TestToken::new(1).with_text("x"),
19435            TestToken::new(2).with_text("y"),
19436            TestToken::eof("parser-test", 2, 1, 2),
19437        ]);
19438
19439        let result = parser.parse_atn_rule_with_runtime_options(
19440            &atn,
19441            0,
19442            ParserRuntimeOptions {
19443                unknown_predicate_policy: UnknownSemanticPolicy::AssumeFalse,
19444                ..ParserRuntimeOptions::default()
19445            },
19446        );
19447
19448        assert!(
19449            result.is_err(),
19450            "the only path is predicate-guarded, so assume-false must fail the parse"
19451        );
19452    }
19453
19454    #[test]
19455    fn predicate_failure_message_keeps_semantic_recovery_path() {
19456        let atn = predicate_after_token_atn();
19457        let mut parser = mini_parser(vec![
19458            TestToken::new(1).with_text("x"),
19459            TestToken::new(2).with_text("y"),
19460            TestToken::eof("parser-test", 2, 1, 2),
19461        ]);
19462
19463        let (tree, _) = parser
19464            .parse_atn_rule_with_runtime_options(
19465                &atn,
19466                0,
19467                ParserRuntimeOptions {
19468                    predicates: &[(
19469                        0,
19470                        0,
19471                        ParserPredicate::FalseWithMessage {
19472                            message: "predicate rejected input",
19473                        },
19474                    )],
19475                    ..ParserRuntimeOptions::default()
19476                },
19477            )
19478            .expect("failure-message predicates recover through the semantic interpreter");
19479
19480        assert_eq!(parser.node(tree).text(), "xy");
19481        assert_eq!(parser.number_of_syntax_errors(), 1);
19482        assert!(
19483            parser.fast_predicate_cache.is_empty(),
19484            "failure-message predicates need the semantic interpreter's recovery outcome"
19485        );
19486    }
19487
19488    #[test]
19489    fn unknown_predicate_policy_error_names_the_coordinate() {
19490        let atn = predicate_after_token_atn();
19491        let mut parser = mini_parser(vec![
19492            TestToken::new(1).with_text("x"),
19493            TestToken::new(2).with_text("y"),
19494            TestToken::eof("parser-test", 2, 1, 2),
19495        ]);
19496
19497        let error = parser
19498            .parse_atn_rule_with_runtime_options(
19499                &atn,
19500                0,
19501                ParserRuntimeOptions {
19502                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
19503                    ..ParserRuntimeOptions::default()
19504                },
19505            )
19506            .expect_err("evaluating an unknown predicate under Error policy must fail");
19507
19508        let AntlrError::Unsupported(message) = error else {
19509            panic!("expected AntlrError::Unsupported, got {error:?}");
19510        };
19511        assert!(
19512            message.contains("unsupported semantic predicate"),
19513            "message should name the failure class: {message}"
19514        );
19515        assert!(
19516            message.contains("pred_index=0"),
19517            "message should carry the coordinate: {message}"
19518        );
19519    }
19520
19521    #[test]
19522    fn fail_loud_hits_do_not_leak_into_a_reused_interpreter_parse() {
19523        // A parser reused after a fail-loud parse must not carry the old
19524        // coordinates into a later parse. The fail-loud return keeps the hits
19525        // (so a generated parent can surface a recovered child's coordinate),
19526        // and the next parse's entry stashes/replaces them, so a subsequent
19527        // clean parse surfaces no stale error.
19528        let atn = predicate_after_token_atn();
19529        let mut parser = mini_parser(vec![
19530            TestToken::new(1).with_text("x"),
19531            TestToken::new(2).with_text("y"),
19532            TestToken::eof("parser-test", 2, 1, 2),
19533        ]);
19534
19535        parser
19536            .parse_atn_rule_with_runtime_options(
19537                &atn,
19538                0,
19539                ParserRuntimeOptions {
19540                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
19541                    ..ParserRuntimeOptions::default()
19542                },
19543            )
19544            .expect_err("first parse fails loud under the Error policy");
19545
19546        // The failed parse kept its coordinate on the parser (so a generated
19547        // parent could surface a recovered child). A top-level reuse resets the
19548        // hits — generated parsers call `reset_unknown_semantic_hits` at their
19549        // public entry; direct interpreter-API callers do the same.
19550        parser.reset_unknown_semantic_hits();
19551        assert!(
19552            parser.take_unknown_semantic_error().is_none(),
19553            "reset must drop stale unknown-predicate coordinates before a reused parse"
19554        );
19555    }
19556
19557    #[derive(Debug, Default)]
19558    struct RecordingHooks {
19559        predicates: Vec<(usize, usize, usize, Option<String>)>,
19560        actions: Vec<(usize, String, Option<String>)>,
19561        action_trees: Vec<Option<String>>,
19562    }
19563
19564    impl SemanticHooks for RecordingHooks {
19565        fn sempred<S>(
19566            &mut self,
19567            ctx: &mut ParserSemCtx<'_, S>,
19568            rule_index: usize,
19569            pred_index: usize,
19570        ) -> Option<bool>
19571        where
19572            S: TokenSource,
19573        {
19574            self.predicates.push((
19575                ctx.input_index(),
19576                rule_index,
19577                pred_index,
19578                ctx.token_text(1)
19579                    .and_then(|token| token.text().map(str::to_owned)),
19580            ));
19581            Some(true)
19582        }
19583
19584        fn action<S>(&mut self, ctx: &mut ParserSemCtx<'_, S>, action: ParserAction) -> bool
19585        where
19586            S: TokenSource,
19587        {
19588            self.actions.push((
19589                action.source_state(),
19590                ctx.action_text(),
19591                ctx.rule_name().map(str::to_owned),
19592            ));
19593            self.action_trees.push(ctx.tree().map(Node::text));
19594            true
19595        }
19596    }
19597
19598    #[derive(Debug, Default)]
19599    struct StatefulActionHooks {
19600        entered: bool,
19601        events: Vec<String>,
19602    }
19603
19604    impl SemanticHooks for StatefulActionHooks {
19605        fn sempred<S>(
19606            &mut self,
19607            _ctx: &mut ParserSemCtx<'_, S>,
19608            _rule_index: usize,
19609            _pred_index: usize,
19610        ) -> Option<bool>
19611        where
19612            S: TokenSource,
19613        {
19614            self.events.push(format!("predicate:{}", self.entered));
19615            Some(self.entered)
19616        }
19617
19618        fn action<S>(&mut self, _ctx: &mut ParserSemCtx<'_, S>, action: ParserAction) -> bool
19619        where
19620            S: TokenSource,
19621        {
19622            self.events.push(format!(
19623                "action:{}",
19624                action
19625                    .action_index()
19626                    .map_or_else(|| "legacy".to_owned(), |index| index.to_string())
19627            ));
19628            self.entered = true;
19629            true
19630        }
19631    }
19632
19633    #[derive(Debug, Default)]
19634    struct InitOrderingHooks {
19635        initialized: bool,
19636        events: Vec<String>,
19637    }
19638
19639    impl SemanticHooks for InitOrderingHooks {
19640        fn sempred<S>(
19641            &mut self,
19642            _ctx: &mut ParserSemCtx<'_, S>,
19643            _rule_index: usize,
19644            _pred_index: usize,
19645        ) -> Option<bool>
19646        where
19647            S: TokenSource,
19648        {
19649            self.events.push(format!("predicate:{}", self.initialized));
19650            Some(self.initialized)
19651        }
19652
19653        fn action<S>(&mut self, _ctx: &mut ParserSemCtx<'_, S>, action: ParserAction) -> bool
19654        where
19655            S: TokenSource,
19656        {
19657            if action.is_rule_init() {
19658                self.initialized = true;
19659                self.events.push("init".to_owned());
19660            } else {
19661                self.events.push(format!(
19662                    "action:{}:initialized={}",
19663                    action
19664                        .action_index()
19665                        .map_or_else(|| "legacy".to_owned(), |index| index.to_string()),
19666                    self.initialized
19667                ));
19668            }
19669            true
19670        }
19671    }
19672
19673    #[derive(Debug, Default)]
19674    struct ActionContextHooks {
19675        actions: Vec<(usize, Option<i64>, Option<usize>)>,
19676    }
19677
19678    impl SemanticHooks for ActionContextHooks {
19679        fn action<S>(&mut self, ctx: &mut ParserSemCtx<'_, S>, action: ParserAction) -> bool
19680        where
19681            S: TokenSource,
19682        {
19683            self.actions.push((
19684                action.action_index().unwrap_or(usize::MAX),
19685                ctx.local_int_arg(),
19686                action.stop_index(),
19687            ));
19688            true
19689        }
19690    }
19691
19692    #[derive(Debug, Default)]
19693    struct DecliningActionHooks {
19694        actions: Vec<usize>,
19695    }
19696
19697    impl SemanticHooks for DecliningActionHooks {
19698        fn action<S>(&mut self, _ctx: &mut ParserSemCtx<'_, S>, action: ParserAction) -> bool
19699        where
19700            S: TokenSource,
19701        {
19702            self.actions.push(action.source_state());
19703            false
19704        }
19705    }
19706
19707    #[derive(Debug, Default)]
19708    struct ForcedSecondAlternativeHooks {
19709        decisions: Vec<(usize, usize, usize)>,
19710    }
19711
19712    impl SemanticHooks for ForcedSecondAlternativeHooks {
19713        fn observes_parser_decisions(&self) -> bool {
19714            true
19715        }
19716
19717        fn parser_decision_override(
19718            &mut self,
19719            decision: usize,
19720            input_index: usize,
19721            alternative_count: usize,
19722        ) -> Option<usize> {
19723            self.decisions
19724                .push((decision, input_index, alternative_count));
19725            Some(2)
19726        }
19727    }
19728
19729    struct RecordingParseListener {
19730        events: Arc<Mutex<Vec<String>>>,
19731    }
19732
19733    impl ParseListener for RecordingParseListener {
19734        fn enter_every_rule(&mut self, event: &EnterRuleEvent<'_>) -> Result<(), AntlrError> {
19735            self.events
19736                .lock()
19737                .expect("parse-listener event lock")
19738                .push(format!("enter:{}", event.rule_index));
19739            Ok(())
19740        }
19741
19742        fn exit_every_rule(&mut self, rule_index: usize) {
19743            self.events
19744                .lock()
19745                .expect("parse-listener event lock")
19746                .push(format!("exit:{rule_index}"));
19747        }
19748    }
19749
19750    #[derive(Debug, Default)]
19751    struct RejectingPredicateHooks {
19752        predicates: Vec<(usize, usize, usize, Option<String>)>,
19753    }
19754
19755    impl SemanticHooks for RejectingPredicateHooks {
19756        fn sempred<S>(
19757            &mut self,
19758            ctx: &mut ParserSemCtx<'_, S>,
19759            rule_index: usize,
19760            pred_index: usize,
19761        ) -> Option<bool>
19762        where
19763            S: TokenSource,
19764        {
19765            self.predicates.push((
19766                ctx.input_index(),
19767                rule_index,
19768                pred_index,
19769                ctx.token_text(1)
19770                    .and_then(|token| token.text().map(str::to_owned)),
19771            ));
19772            Some(false)
19773        }
19774    }
19775
19776    #[test]
19777    fn fast_predicate_cache_replays_hook_once_per_coordinate_and_input() {
19778        let atn = predicate_gated_same_lookahead_atn([0, 0]);
19779        let mut parser = mini_parser_with_hooks(
19780            vec![
19781                TestToken::new(1).with_text("x"),
19782                TestToken::eof("parser-test", 1, 1, 1),
19783            ],
19784            RecordingHooks::default(),
19785        );
19786
19787        let (tree, _) = parser
19788            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
19789            .expect("both alternatives share one replay-safe predicate result");
19790
19791        assert_eq!(parser.node(tree).text(), "x<EOF>");
19792        assert_eq!(
19793            parser.semantic_hooks.predicates,
19794            vec![(0, 0, 0, Some("x".to_owned()))]
19795        );
19796        assert_eq!(parser.fast_predicate_cache.get(&(0, 0, 0)), Some(&true));
19797    }
19798
19799    #[test]
19800    fn semantic_hook_handles_unknown_predicate_before_error_policy() {
19801        let atn = predicate_after_token_atn();
19802        let mut parser = mini_parser_with_hooks(
19803            vec![
19804                TestToken::new(1).with_text("x"),
19805                TestToken::new(2).with_text("y"),
19806                TestToken::eof("parser-test", 2, 1, 2),
19807            ],
19808            RecordingHooks::default(),
19809        );
19810
19811        let (tree, _) = parser
19812            .parse_atn_rule_with_runtime_options(
19813                &atn,
19814                0,
19815                ParserRuntimeOptions {
19816                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
19817                    ..ParserRuntimeOptions::default()
19818                },
19819            )
19820            .expect("hook supplies the missing predicate result");
19821
19822        assert_eq!(parser.node(tree).text(), "xy");
19823        assert_eq!(
19824            parser.semantic_hooks.predicates,
19825            vec![(1, 0, 0, Some("y".to_owned()))]
19826        );
19827        assert_eq!(parser.fast_predicate_cache.get(&(1, 0, 0)), Some(&true));
19828    }
19829
19830    #[test]
19831    fn runtime_options_default_preserves_semantic_hook_predicates() {
19832        let atn = predicate_after_token_atn();
19833        let mut parser = mini_parser_with_hooks(
19834            vec![
19835                TestToken::new(1).with_text("x"),
19836                TestToken::new(2).with_text("y"),
19837                TestToken::eof("parser-test", 2, 1, 2),
19838            ],
19839            RejectingPredicateHooks::default(),
19840        );
19841
19842        let result =
19843            parser.parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default());
19844
19845        assert!(
19846            result.is_err(),
19847            "default runtime options must not bypass semantic hooks for predicate ATNs"
19848        );
19849        assert_eq!(
19850            parser.semantic_hooks.predicates,
19851            vec![(1, 0, 0, Some("y".to_owned()))]
19852        );
19853        assert_eq!(parser.fast_predicate_cache.get(&(1, 0, 0)), Some(&false));
19854    }
19855
19856    #[test]
19857    fn committed_action_runs_before_later_predicate() {
19858        let atn = committed_action_then_predicate_atn();
19859        let mut parser = mini_parser_with_hooks(
19860            vec![
19861                TestToken::new(1).with_text("x"),
19862                TestToken::eof("parser-test", 1, 1, 1),
19863            ],
19864            StatefulActionHooks::default(),
19865        );
19866
19867        let (tree, deferred_actions) = parser
19868            .parse_atn_rule_with_runtime_options(
19869                &atn,
19870                0,
19871                ParserRuntimeOptions {
19872                    action_indices: &[(0, 7)],
19873                    ..ParserRuntimeOptions::default()
19874                },
19875            )
19876            .expect("the predicate should observe the preceding committed action");
19877
19878        assert_eq!(parser.node(tree).text(), "x<EOF>");
19879        assert!(deferred_actions.is_empty());
19880        assert_eq!(parser.semantic_hooks.events, ["action:7", "predicate:true"]);
19881    }
19882
19883    #[test]
19884    fn committed_action_hook_observes_parameterized_rule_argument() {
19885        let atn = parameterized_child_action_eof_atn();
19886        let rule_args = [ParserRuleArg {
19887            source_state: 0,
19888            rule_index: 1,
19889            value: 42,
19890            inherit_local: false,
19891        }];
19892        let mut parser = mini_parser_with_hooks(
19893            vec![TestToken::eof("parser-test", 0, 1, 0)],
19894            ActionContextHooks::default(),
19895        );
19896
19897        parser
19898            .parse_atn_rule_with_runtime_options(
19899                &atn,
19900                0,
19901                ParserRuntimeOptions {
19902                    action_indices: &[(1, 20), (4, 10)],
19903                    rule_args: &rule_args,
19904                    ..ParserRuntimeOptions::default()
19905                },
19906            )
19907            .expect("the parameterized child should parse");
19908
19909        assert_eq!(
19910            parser.semantic_hooks.actions[0],
19911            (10, Some(42), None),
19912            "the child action should observe its invocation argument"
19913        );
19914    }
19915
19916    #[test]
19917    fn committed_parent_propagates_child_eof_consumption() {
19918        let atn = parameterized_child_action_eof_atn();
19919        let mut parser = mini_parser_with_hooks(
19920            vec![TestToken::eof("parser-test", 0, 1, 0)],
19921            ActionContextHooks::default(),
19922        );
19923
19924        let (tree, _) = parser
19925            .parse_atn_rule_with_runtime_options(
19926                &atn,
19927                0,
19928                ParserRuntimeOptions {
19929                    action_indices: &[(1, 20), (4, 10)],
19930                    ..ParserRuntimeOptions::default()
19931                },
19932            )
19933            .expect("the parent should retain its child's EOF boundary");
19934
19935        assert_eq!(
19936            parser.semantic_hooks.actions[1],
19937            (20, None, Some(0)),
19938            "the parent action should stop at EOF"
19939        );
19940        let root = parser.node(tree).as_rule().expect("entry result is a rule");
19941        assert_eq!(root.stop().map(|token| token.token_type()), Some(TOKEN_EOF));
19942        let child = root
19943            .child_rules(1)
19944            .next()
19945            .expect("the parent should contain the child rule");
19946        assert_eq!(
19947            child.stop().map(|token| token.token_type()),
19948            Some(TOKEN_EOF)
19949        );
19950    }
19951
19952    #[test]
19953    fn committed_walker_does_not_run_action_in_losing_alternative() {
19954        let atn = losing_alternative_action_atn();
19955        let mut parser = mini_parser_with_hooks(
19956            vec![
19957                TestToken::new(2).with_text("y"),
19958                TestToken::eof("parser-test", 1, 1, 1),
19959            ],
19960            StatefulActionHooks::default(),
19961        );
19962
19963        let (tree, deferred_actions) = parser
19964            .parse_atn_rule_with_runtime_options(
19965                &atn,
19966                0,
19967                ParserRuntimeOptions {
19968                    action_indices: &[(2, 0)],
19969                    ..ParserRuntimeOptions::default()
19970                },
19971            )
19972            .expect("the token-led second alternative should be selected");
19973
19974        assert_eq!(parser.node(tree).text(), "y");
19975        assert!(deferred_actions.is_empty());
19976        assert!(parser.semantic_hooks.events.is_empty());
19977    }
19978
19979    #[test]
19980    fn committed_walker_honors_decision_overrides() {
19981        let atn = predicate_gated_same_lookahead_atn([0, 1]);
19982        let predicates = [(0, 0, ParserPredicate::True), (0, 1, ParserPredicate::True)];
19983        let mut parser = mini_parser_with_hooks(
19984            vec![
19985                TestToken::new(1).with_text("x"),
19986                TestToken::eof("parser-test", 1, 1, 1),
19987            ],
19988            ForcedSecondAlternativeHooks::default(),
19989        );
19990
19991        let (tree, deferred_actions) = parser
19992            .parse_atn_rule_with_runtime_options(
19993                &atn,
19994                0,
19995                ParserRuntimeOptions {
19996                    action_indices: &[(usize::MAX, 0)],
19997                    track_alt_numbers: true,
19998                    predicates: &predicates,
19999                    ..ParserRuntimeOptions::default()
20000                },
20001            )
20002            .expect("the forced second alternative should parse");
20003
20004        let root = parser.node(tree).as_rule().expect("entry result is a rule");
20005        assert_eq!(root.alt_number(), 2);
20006        assert_eq!(root.text(), "x<EOF>");
20007        assert!(deferred_actions.is_empty());
20008        assert_eq!(parser.semantic_hooks.decisions, [(0, 0, 2)]);
20009        assert_eq!(parser.number_of_syntax_errors(), 0);
20010    }
20011
20012    #[test]
20013    fn committed_walker_sll_mode_does_not_report_full_context_diagnostics() {
20014        let atn = predicate_gated_same_lookahead_atn([0, 1]);
20015        let predicates = [(0, 0, ParserPredicate::True), (0, 1, ParserPredicate::True)];
20016        let diagnostics = Arc::new(Mutex::new(Vec::new()));
20017        let mut parser = mini_parser(vec![
20018            TestToken::new(1).with_text("x"),
20019            TestToken::eof("parser-test", 1, 1, 1),
20020        ]);
20021        parser.set_prediction_mode(PredictionMode::Sll);
20022        parser.set_report_diagnostic_errors(true);
20023        parser.remove_error_listeners();
20024        parser.add_error_listener(RecordingErrorListener {
20025            diagnostics: Arc::clone(&diagnostics),
20026        });
20027
20028        let (tree, deferred_actions) = parser
20029            .parse_atn_rule_with_runtime_options(
20030                &atn,
20031                0,
20032                ParserRuntimeOptions {
20033                    action_indices: &[(usize::MAX, 0)],
20034                    predicates: &predicates,
20035                    ..ParserRuntimeOptions::default()
20036                },
20037            )
20038            .expect("SLL prediction should select the first viable alternative");
20039
20040        assert_eq!(parser.node(tree).text(), "x<EOF>");
20041        assert!(deferred_actions.is_empty());
20042        assert_eq!(parser.number_of_syntax_errors(), 0);
20043        assert!(
20044            diagnostics
20045                .lock()
20046                .expect("recorded diagnostics lock")
20047                .is_empty(),
20048            "SLL mode must not retry with full context or report LL diagnostics"
20049        );
20050    }
20051
20052    #[test]
20053    fn committed_walker_filters_diagnostics_after_semantic_selection() {
20054        let atn = predicate_gated_same_lookahead_atn([0, 1]);
20055        let predicates = [
20056            (0, 0, ParserPredicate::False),
20057            (0, 1, ParserPredicate::True),
20058        ];
20059        let diagnostics = Arc::new(Mutex::new(Vec::new()));
20060        let mut parser = mini_parser(vec![
20061            TestToken::new(1).with_text("x"),
20062            TestToken::eof("parser-test", 1, 1, 1),
20063        ]);
20064        parser.set_prediction_mode(PredictionMode::LlExactAmbigDetection);
20065        parser.set_report_diagnostic_errors(true);
20066        parser.remove_error_listeners();
20067        parser.add_error_listener(RecordingErrorListener {
20068            diagnostics: Arc::clone(&diagnostics),
20069        });
20070
20071        let (tree, _) = parser
20072            .parse_atn_rule_with_runtime_options(
20073                &atn,
20074                0,
20075                ParserRuntimeOptions {
20076                    action_indices: &[(usize::MAX, 0)],
20077                    track_alt_numbers: true,
20078                    predicates: &predicates,
20079                    ..ParserRuntimeOptions::default()
20080                },
20081            )
20082            .expect("the true predicate should make the second alternative unique");
20083
20084        let root = parser.node(tree).as_rule().expect("entry result is a rule");
20085        assert_eq!(root.alt_number(), 2);
20086        assert!(
20087            diagnostics
20088                .lock()
20089                .expect("recorded diagnostics lock")
20090                .is_empty(),
20091            "predicate filtering made the decision unambiguous"
20092        );
20093    }
20094
20095    #[test]
20096    fn committed_walker_skips_diagnostic_only_predicates_when_reporting_is_disabled() {
20097        let atn = predicate_gated_same_lookahead_atn([0, 1]);
20098        let mut parser = mini_parser_with_hooks(
20099            vec![
20100                TestToken::new(1).with_text("x"),
20101                TestToken::eof("parser-test", 1, 1, 1),
20102            ],
20103            RecordingHooks::default(),
20104        );
20105        parser.set_prediction_mode(PredictionMode::LlExactAmbigDetection);
20106
20107        let (tree, _) = parser
20108            .parse_atn_rule_with_runtime_options(
20109                &atn,
20110                0,
20111                ParserRuntimeOptions {
20112                    action_indices: &[(usize::MAX, 0)],
20113                    track_alt_numbers: true,
20114                    ..ParserRuntimeOptions::default()
20115                },
20116            )
20117            .expect("the first predicate-bearing alternative should parse");
20118
20119        let root = parser.node(tree).as_rule().expect("entry result is a rule");
20120        assert_eq!(root.alt_number(), 1);
20121        assert_eq!(
20122            parser.semantic_hooks.predicates,
20123            [
20124                (0, 0, 0, Some("x".to_owned())),
20125                (0, 0, 0, Some("x".to_owned())),
20126            ],
20127            "diagnostic-only alternatives must not invoke semantic hooks"
20128        );
20129    }
20130
20131    #[test]
20132    fn committed_walker_falls_back_only_to_simulator_viable_alternatives() {
20133        let atn = semantic_fallback_viability_atn();
20134        let predicates = [
20135            (0, 0, ParserPredicate::False),
20136            (0, 1, ParserPredicate::True),
20137        ];
20138        let mut parser = mini_parser(vec![
20139            TestToken::new(1).with_text("a"),
20140            TestToken::new(3).with_text("c"),
20141            TestToken::eof("parser-test", 2, 1, 2),
20142        ]);
20143
20144        let (tree, deferred_actions) = parser
20145            .parse_atn_rule_with_runtime_options(
20146                &atn,
20147                0,
20148                ParserRuntimeOptions {
20149                    action_indices: &[(usize::MAX, 0)],
20150                    track_alt_numbers: true,
20151                    predicates: &predicates,
20152                    ..ParserRuntimeOptions::default()
20153                },
20154            )
20155            .expect("the true A C alternative should survive semantic fallback");
20156
20157        let root = parser.node(tree).as_rule().expect("entry result is a rule");
20158        assert_eq!(root.alt_number(), 3);
20159        assert_eq!(root.text(), "ac<EOF>");
20160        assert!(deferred_actions.is_empty());
20161        assert_eq!(parser.number_of_syntax_errors(), 0);
20162    }
20163
20164    #[test]
20165    fn committed_walker_evaluates_predicates_reached_through_rule_calls() {
20166        let atn = rule_call_predicate_decision_atn();
20167        let predicates = [(1, 0, ParserPredicate::False)];
20168        let mut parser = mini_parser(vec![
20169            TestToken::new(1).with_text("a"),
20170            TestToken::eof("parser-test", 1, 1, 1),
20171        ]);
20172
20173        let (tree, deferred_actions) = parser
20174            .parse_atn_rule_with_runtime_options(
20175                &atn,
20176                0,
20177                ParserRuntimeOptions {
20178                    action_indices: &[(usize::MAX, 0)],
20179                    track_alt_numbers: true,
20180                    predicates: &predicates,
20181                    ..ParserRuntimeOptions::default()
20182                },
20183            )
20184            .expect("the direct caller alternative should survive the false callee predicate");
20185
20186        let root = parser.node(tree).as_rule().expect("entry result is a rule");
20187        assert_eq!(root.alt_number(), 2);
20188        assert_eq!(root.text(), "a<EOF>");
20189        assert_eq!(root.child_rules(1).count(), 0);
20190        assert!(deferred_actions.is_empty());
20191        assert_eq!(parser.number_of_syntax_errors(), 0);
20192    }
20193
20194    #[test]
20195    fn committed_walker_uses_callee_argument_for_prediction_predicates() {
20196        let atn = rule_call_predicate_decision_atn();
20197        let predicates = [(1, 0, ParserPredicate::LocalIntEquals { value: 1 })];
20198        let rule_args = [ParserRuleArg {
20199            source_state: 2,
20200            rule_index: 1,
20201            value: 2,
20202            inherit_local: false,
20203        }];
20204        let mut parser = mini_parser(vec![
20205            TestToken::new(1).with_text("a"),
20206            TestToken::eof("parser-test", 1, 1, 1),
20207        ]);
20208
20209        let (tree, _) = parser
20210            .parse_atn_rule_with_runtime_options(
20211                &atn,
20212                0,
20213                ParserRuntimeOptions {
20214                    action_indices: &[(usize::MAX, 0)],
20215                    track_alt_numbers: true,
20216                    predicates: &predicates,
20217                    rule_args: &rule_args,
20218                    ..ParserRuntimeOptions::default()
20219                },
20220            )
20221            .expect("the direct alternative should survive the false callee predicate");
20222
20223        let root = parser.node(tree).as_rule().expect("entry result is a rule");
20224        assert_eq!(root.alt_number(), 2);
20225        assert_eq!(root.child_rules(1).count(), 0);
20226        assert_eq!(parser.number_of_syntax_errors(), 0);
20227    }
20228
20229    #[test]
20230    fn committed_predicate_star_loop_uses_single_token_deletion() {
20231        let atn = predicate_gated_star_loop_atn();
20232        let predicates = [(0, 0, ParserPredicate::True)];
20233        let diagnostics = Arc::new(Mutex::new(Vec::new()));
20234        let mut parser = mini_parser(vec![
20235            TestToken::new(2).with_text("x"),
20236            TestToken::new(1).with_text("a"),
20237            TestToken::eof("parser-test", 2, 1, 2),
20238        ]);
20239        parser.remove_error_listeners();
20240        parser.add_error_listener(RecordingErrorListener {
20241            diagnostics: Arc::clone(&diagnostics),
20242        });
20243
20244        let (tree, deferred_actions) = parser
20245            .parse_atn_rule_with_runtime_options(
20246                &atn,
20247                0,
20248                ParserRuntimeOptions {
20249                    action_indices: &[(usize::MAX, 0)],
20250                    predicates: &predicates,
20251                    ..ParserRuntimeOptions::default()
20252                },
20253            )
20254            .expect("the loop decision should delete the extraneous token and continue");
20255
20256        assert_eq!(parser.node(tree).text(), "xa<EOF>");
20257        assert!(deferred_actions.is_empty());
20258        assert_eq!(parser.number_of_syntax_errors(), 1);
20259        insta::assert_debug_snapshot!(
20260            "committed_predicate_star_loop_uses_single_token_deletion",
20261            *diagnostics.lock().expect("recorded diagnostics lock")
20262        );
20263    }
20264
20265    #[test]
20266    fn committed_walker_applies_legacy_and_semir_actions_before_indexed_hooks() {
20267        let atn = committed_action_then_predicate_atn();
20268        let member_actions = [ParserMemberAction {
20269            source_state: 0,
20270            member: 0,
20271            delta: 2,
20272        }];
20273        let return_actions = [ParserReturnAction {
20274            source_state: 0,
20275            rule_index: 0,
20276            name: "legacy",
20277            value: 3,
20278        }];
20279        let predicates = [(
20280            0,
20281            0,
20282            ParserPredicate::MemberEquals {
20283                member: 0,
20284                value: 7,
20285                equals: true,
20286            },
20287        )];
20288        let mut ir = SemIr::new();
20289        let semantic_member = ParserMemberAction {
20290            source_state: 0,
20291            member: 0,
20292            delta: 5,
20293        }
20294        .lower_into_semir(&mut ir);
20295        let semantic_return = ParserReturnAction {
20296            source_state: 0,
20297            rule_index: 0,
20298            name: "semantic",
20299            value: 11,
20300        }
20301        .lower_into_semir(&mut ir);
20302        let semantics = ParserSemantics {
20303            ir,
20304            predicates: Vec::new(),
20305            actions: vec![semantic_member, semantic_return],
20306        };
20307        let mut parser = mini_parser_with_hooks(
20308            vec![
20309                TestToken::new(1).with_text("x"),
20310                TestToken::eof("parser-test", 1, 1, 1),
20311            ],
20312            StatefulActionHooks::default(),
20313        );
20314
20315        let (tree, deferred_actions) = parser
20316            .parse_atn_rule_with_runtime_options(
20317                &atn,
20318                0,
20319                ParserRuntimeOptions {
20320                    action_indices: &[(0, 7)],
20321                    predicates: &predicates,
20322                    semantics: Some(&semantics),
20323                    member_actions: &member_actions,
20324                    return_actions: &return_actions,
20325                    ..ParserRuntimeOptions::default()
20326                },
20327            )
20328            .expect("the predicate should observe both committed member actions");
20329
20330        let root = parser.node(tree).as_rule().expect("entry result is a rule");
20331        assert_eq!(root.text(), "x<EOF>");
20332        assert_eq!(root.int_return("legacy"), Some(3));
20333        assert_eq!(root.int_return("semantic"), Some(11));
20334        assert_eq!(parser.int_member(0), Some(7));
20335        assert!(deferred_actions.is_empty());
20336        assert_eq!(parser.semantic_hooks.events, ["action:7"]);
20337        assert_eq!(parser.number_of_syntax_errors(), 0);
20338    }
20339
20340    #[test]
20341    fn committed_walker_runs_action_once_per_star_loop_iteration() {
20342        let atn = committed_action_star_loop_atn();
20343        let mut parser = mini_parser_with_hooks(
20344            vec![
20345                TestToken::new(1).with_text("a"),
20346                TestToken::new(1).with_text("b"),
20347                TestToken::eof("parser-test", 2, 1, 2),
20348            ],
20349            StatefulActionHooks::default(),
20350        );
20351
20352        let (tree, deferred_actions) = parser
20353            .parse_atn_rule_with_runtime_options(
20354                &atn,
20355                0,
20356                ParserRuntimeOptions {
20357                    action_indices: &[(2, 3)],
20358                    ..ParserRuntimeOptions::default()
20359                },
20360            )
20361            .expect("the committed star loop should parse");
20362
20363        assert_eq!(parser.node(tree).text(), "ab<EOF>");
20364        assert!(deferred_actions.is_empty());
20365        assert_eq!(parser.semantic_hooks.events, ["action:3", "action:3"]);
20366    }
20367
20368    #[test]
20369    fn committed_walker_has_no_total_step_cap() {
20370        const TOKEN_COUNT: usize = RECOGNITION_DEPTH_LIMIT + 1;
20371        let atn = committed_action_star_loop_atn();
20372        let mut parser = mini_parser(repeated_x_tokens(TOKEN_COUNT));
20373        parser.set_build_parse_trees(false);
20374
20375        parser
20376            .parse_atn_rule_with_runtime_options(
20377                &atn,
20378                0,
20379                ParserRuntimeOptions {
20380                    action_indices: &[(usize::MAX, 0)],
20381                    ..ParserRuntimeOptions::default()
20382                },
20383            )
20384            .expect("valid committed loops must not have a total-work cap");
20385
20386        assert_eq!(parser.input.index(), TOKEN_COUNT);
20387        assert_eq!(parser.number_of_syntax_errors(), 0);
20388    }
20389
20390    #[test]
20391    fn committed_walker_rejects_non_consuming_cycles() {
20392        let atn = committed_non_consuming_cycle_atn();
20393        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 0, 1, 0)]);
20394        parser.set_bail_on_error(true);
20395
20396        let error = parser
20397            .parse_atn_rule_with_runtime_options(
20398                &atn,
20399                0,
20400                ParserRuntimeOptions {
20401                    action_indices: &[(usize::MAX, 0)],
20402                    ..ParserRuntimeOptions::default()
20403                },
20404            )
20405            .expect_err("a non-consuming cycle must not spin forever");
20406
20407        assert!(
20408            error.to_string().contains("non-consuming ATN cycle"),
20409            "unexpected error: {error}"
20410        );
20411    }
20412
20413    #[test]
20414    fn deeply_nested_committed_rule_calls_grow_the_stack() {
20415        const DEPTH: usize = 4_096;
20416        const STACK_SIZE: usize = 256 * 1024;
20417        let atn = nested_rule_chain_atn(DEPTH);
20418        std::thread::Builder::new()
20419            .name("nested-committed-rules".to_owned())
20420            .stack_size(STACK_SIZE)
20421            .spawn(move || {
20422                let mut parser = mini_parser(vec![TestToken::new(1).with_text("x")]);
20423                parser.set_build_parse_trees(false);
20424                parser
20425                    .parse_atn_rule_with_runtime_options(
20426                        &atn,
20427                        0,
20428                        ParserRuntimeOptions {
20429                            action_indices: &[(usize::MAX, 0)],
20430                            ..ParserRuntimeOptions::default()
20431                        },
20432                    )
20433                    .expect("nested committed rules should grow the native stack");
20434                assert_eq!(parser.input.index(), 1);
20435            })
20436            .expect("small-stack thread should start")
20437            .join()
20438            .expect("nested committed rules should not overflow their stack");
20439    }
20440
20441    #[test]
20442    fn committed_walker_runs_action_once_per_left_recursive_operator() {
20443        let atn = committed_action_left_recursive_atn();
20444        let mut parser = mini_parser_with_hooks(
20445            vec![
20446                TestToken::new(1).with_text("a"),
20447                TestToken::new(3).with_text("+"),
20448                TestToken::new(1).with_text("b"),
20449                TestToken::new(3).with_text("+"),
20450                TestToken::new(1).with_text("c"),
20451                TestToken::eof("parser-test", 5, 1, 5),
20452            ],
20453            StatefulActionHooks::default(),
20454        );
20455
20456        let (tree, deferred_actions) = parser
20457            .parse_atn_rule_with_runtime_options(
20458                &atn,
20459                0,
20460                ParserRuntimeOptions {
20461                    action_indices: &[(6, 11)],
20462                    ..ParserRuntimeOptions::default()
20463                },
20464            )
20465            .expect("the committed left-recursive rule should parse");
20466
20467        assert_eq!(parser.node(tree).text(), "a+b+c");
20468        assert!(deferred_actions.is_empty());
20469        assert_eq!(parser.semantic_hooks.events, ["action:11", "action:11"]);
20470    }
20471
20472    #[test]
20473    fn committed_left_recursive_depth_cap_keeps_listener_events_balanced() {
20474        let atn = committed_action_left_recursive_atn();
20475        let events = Arc::new(Mutex::new(Vec::new()));
20476        let mut parser = mini_parser(vec![
20477            TestToken::new(1).with_text("a"),
20478            TestToken::new(3).with_text("+"),
20479            TestToken::new(1).with_text("b"),
20480            TestToken::eof("parser-test", 3, 1, 3),
20481        ]);
20482        parser.set_max_rule_depth(Some(1));
20483        parser.add_parse_listener(RecordingParseListener {
20484            events: Arc::clone(&events),
20485        });
20486
20487        let error = parser
20488            .parse_atn_rule_with_runtime_options(
20489                &atn,
20490                0,
20491                ParserRuntimeOptions {
20492                    action_indices: &[(6, 11)],
20493                    ..ParserRuntimeOptions::default()
20494                },
20495            )
20496            .expect_err("the left-recursive expansion should exceed the depth cap");
20497
20498        insta::assert_debug_snapshot!(
20499            "committed_left_recursive_depth_cap_keeps_listener_events_balanced",
20500            (
20501                error.to_string(),
20502                events.lock().expect("parse-listener event lock").as_slice(),
20503            )
20504        );
20505    }
20506
20507    #[test]
20508    fn committed_walker_preserves_nested_rule_listener_events() {
20509        let atn = ordinary_star_loop_atn();
20510        let events = Arc::new(Mutex::new(Vec::new()));
20511        let mut parser = mini_parser(vec![
20512            TestToken::new(1).with_text("a"),
20513            TestToken::new(1).with_text("b"),
20514            TestToken::eof("parser-test", 2, 1, 2),
20515        ]);
20516        parser.add_parse_listener(RecordingParseListener {
20517            events: Arc::clone(&events),
20518        });
20519
20520        let (tree, _) = parser
20521            .parse_atn_rule_with_runtime_options(
20522                &atn,
20523                0,
20524                ParserRuntimeOptions {
20525                    action_indices: &[(usize::MAX, 0)],
20526                    ..ParserRuntimeOptions::default()
20527                },
20528            )
20529            .expect("the committed nested-rule path should parse");
20530
20531        assert_eq!(parser.node(tree).text(), "ab<EOF>");
20532        assert_eq!(
20533            *events.lock().expect("parse-listener event lock"),
20534            [
20535                "enter:0", "enter:1", "exit:1", "enter:1", "exit:1", "exit:0",
20536            ]
20537        );
20538    }
20539
20540    #[test]
20541    fn committed_walker_enforces_rule_depth_cap() {
20542        let atn = ordinary_star_loop_atn();
20543        let mut parser = mini_parser(vec![
20544            TestToken::new(1).with_text("a"),
20545            TestToken::eof("parser-test", 1, 1, 1),
20546        ]);
20547        parser.set_max_rule_depth(Some(1));
20548
20549        let error = parser
20550            .parse_atn_rule_with_runtime_options(
20551                &atn,
20552                0,
20553                ParserRuntimeOptions {
20554                    action_indices: &[(usize::MAX, 0)],
20555                    ..ParserRuntimeOptions::default()
20556                },
20557            )
20558            .expect_err("the nested rule should exceed the committed-path cap");
20559
20560        assert!(
20561            error
20562                .to_string()
20563                .contains("rule nesting depth limit of 1 exceeded"),
20564            "unexpected error: {error}"
20565        );
20566    }
20567
20568    #[test]
20569    fn committed_abort_precedes_and_clears_unhandled_action_error() {
20570        let atn = action_then_nested_rule_atn();
20571        let mut parser = mini_parser_with_hooks(
20572            vec![TestToken::eof("parser-test", 0, 1, 0)],
20573            DecliningActionHooks::default(),
20574        );
20575        parser.set_max_rule_depth(Some(1));
20576
20577        let error = parser
20578            .parse_atn_rule_with_runtime_options(
20579                &atn,
20580                0,
20581                ParserRuntimeOptions {
20582                    action_indices: &[(0, 7)],
20583                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
20584                    ..ParserRuntimeOptions::default()
20585                },
20586            )
20587            .expect_err("the recovered child abort must outrank the earlier action miss");
20588
20589        assert_eq!(parser.semantic_hooks.actions, [0]);
20590        assert!(
20591            error
20592                .to_string()
20593                .contains("rule nesting depth limit of 1 exceeded"),
20594            "unexpected error: {error}"
20595        );
20596        assert!(
20597            parser.take_parse_abort().is_none(),
20598            "the returned abort must not remain sticky"
20599        );
20600        assert!(
20601            parser.take_unknown_semantic_error().is_none(),
20602            "the masked action miss must not poison parser reuse"
20603        );
20604    }
20605
20606    #[test]
20607    fn top_level_committed_semantic_error_does_not_poison_reuse() {
20608        let atn = committed_action_then_predicate_atn();
20609        let predicates = [(0, 0, ParserPredicate::True)];
20610        let mut parser = mini_parser_with_hooks(
20611            vec![
20612                TestToken::new(1).with_text("x"),
20613                TestToken::eof("parser-test", 1, 1, 1),
20614            ],
20615            DecliningActionHooks::default(),
20616        );
20617
20618        let error = parser
20619            .parse_atn_rule_with_runtime_options(
20620                &atn,
20621                0,
20622                ParserRuntimeOptions {
20623                    action_indices: &[(0, 7)],
20624                    predicates: &predicates,
20625                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
20626                    ..ParserRuntimeOptions::default()
20627                },
20628            )
20629            .expect_err("the declined committed action must fail loud");
20630        assert!(
20631            error.to_string().contains("unhandled semantic action"),
20632            "unexpected error: {error}"
20633        );
20634
20635        parser.input.seek(0);
20636        let (tree, _) = parser
20637            .parse_atn_rule_with_runtime_options(
20638                &atn,
20639                0,
20640                ParserRuntimeOptions {
20641                    predicates: &predicates,
20642                    ..ParserRuntimeOptions::default()
20643                },
20644            )
20645            .expect("a clean interpreted reuse must not observe the prior action miss");
20646
20647        assert_eq!(parser.node(tree).text(), "x<EOF>");
20648        assert!(
20649            parser.take_unknown_semantic_error().is_none(),
20650            "the returned top-level semantic error must drain its recorded hit"
20651        );
20652    }
20653
20654    #[test]
20655    fn committed_walker_runs_handled_rule_init_before_indexed_action() {
20656        let atn = committed_action_then_predicate_atn();
20657        let mut parser = mini_parser_with_hooks(
20658            vec![
20659                TestToken::new(1).with_text("x"),
20660                TestToken::eof("parser-test", 1, 1, 1),
20661            ],
20662            InitOrderingHooks::default(),
20663        );
20664
20665        let (_, deferred_actions) = parser
20666            .parse_atn_rule_with_runtime_options(
20667                &atn,
20668                0,
20669                ParserRuntimeOptions {
20670                    init_action_rules: &[0],
20671                    action_indices: &[(0, 7)],
20672                    ..ParserRuntimeOptions::default()
20673                },
20674            )
20675            .expect("the named action should observe rule-init state");
20676
20677        assert!(deferred_actions.is_empty());
20678        assert_eq!(
20679            parser.semantic_hooks.events,
20680            ["init", "action:7:initialized=true", "predicate:true",]
20681        );
20682    }
20683
20684    #[test]
20685    fn committed_walker_defers_unhandled_rule_init_for_legacy_replay() {
20686        let atn = token_then_eof_atn();
20687        let mut parser = mini_parser(vec![
20688            TestToken::new(1).with_text("x"),
20689            TestToken::eof("parser-test", 1, 1, 1),
20690        ]);
20691
20692        let (_, deferred_actions) = parser
20693            .parse_atn_rule_with_runtime_options(
20694                &atn,
20695                0,
20696                ParserRuntimeOptions {
20697                    init_action_rules: &[0],
20698                    action_indices: &[(usize::MAX, 0)],
20699                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
20700                    ..ParserRuntimeOptions::default()
20701                },
20702            )
20703            .expect("a declined init should remain available for legacy replay");
20704
20705        assert_eq!(
20706            deferred_actions,
20707            [ParserAction::new_rule_init(0, 0, Some(0))]
20708        );
20709    }
20710
20711    #[test]
20712    fn committed_walker_dispatches_recovery_diagnostics() {
20713        let atn = noop_action_then_token_then_eof_atn();
20714        let diagnostics = Arc::new(Mutex::new(Vec::new()));
20715        let mut parser = mini_parser_with_hooks(
20716            vec![
20717                TestToken::new(1).with_text("x"),
20718                TestToken::new(2).with_text("y"),
20719                TestToken::eof("parser-test", 2, 1, 2),
20720            ],
20721            StatefulActionHooks::default(),
20722        );
20723        parser.remove_error_listeners();
20724        parser.add_error_listener(RecordingErrorListener {
20725            diagnostics: Arc::clone(&diagnostics),
20726        });
20727
20728        let (tree, _) = parser
20729            .parse_atn_rule_with_runtime_options(
20730                &atn,
20731                0,
20732                ParserRuntimeOptions {
20733                    action_indices: &[(0, 5)],
20734                    ..ParserRuntimeOptions::default()
20735                },
20736            )
20737            .expect("the committed rule should recover");
20738
20739        assert_eq!(parser.node(tree).text(), "xy<EOF>");
20740        assert_eq!(parser.number_of_syntax_errors(), 1);
20741        insta::assert_debug_snapshot!(
20742            "committed_walker_dispatches_recovery_diagnostics",
20743            *diagnostics.lock().expect("recorded diagnostics lock")
20744        );
20745    }
20746
20747    #[test]
20748    fn committed_bail_error_notifies_error_listener() {
20749        let atn = noop_action_then_token_then_eof_atn();
20750        let diagnostics = Arc::new(Mutex::new(Vec::new()));
20751        let mut parser = mini_parser(vec![
20752            TestToken::new(2)
20753                .with_text("y")
20754                .with_span(0, 0)
20755                .with_byte_span(0, 1)
20756                .with_position(3, 5),
20757            TestToken::eof("parser-test", 1, 1, 1),
20758        ]);
20759        parser.set_bail_on_error(true);
20760        parser.remove_error_listeners();
20761        parser.add_error_listener(RecordingErrorListener {
20762            diagnostics: Arc::clone(&diagnostics),
20763        });
20764
20765        let error = parser
20766            .parse_atn_rule_with_runtime_options(
20767                &atn,
20768                0,
20769                ParserRuntimeOptions {
20770                    action_indices: &[(0, 5)],
20771                    ..ParserRuntimeOptions::default()
20772                },
20773            )
20774            .expect_err("bail mode must return the committed token mismatch");
20775        let diagnostics = diagnostics
20776            .lock()
20777            .expect("recorded diagnostics lock")
20778            .clone();
20779
20780        insta::assert_debug_snapshot!(
20781            "committed_bail_error_notifies_error_listener",
20782            (error, diagnostics)
20783        );
20784    }
20785
20786    #[test]
20787    fn semantic_hook_handles_committed_parser_action() {
20788        let atn = token_then_eof_atn();
20789        let mut parser = mini_parser_with_hooks(
20790            vec![
20791                TestToken::new(1).with_text("x"),
20792                TestToken::eof("parser-test", 1, 1, 1),
20793            ],
20794            RecordingHooks::default(),
20795        );
20796        let (tree, _) = parser
20797            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
20798            .expect("rule parses before action hook is tested");
20799
20800        assert!(parser.parser_action_hook(ParserAction::new(42, 0, 0, Some(0)), tree));
20801        assert_eq!(
20802            parser.semantic_hooks.actions,
20803            vec![(42, "x".to_owned(), Some("s".to_owned()))]
20804        );
20805        assert_eq!(
20806            parser.semantic_hooks.action_trees,
20807            [Some("x<EOF>".to_owned())]
20808        );
20809    }
20810
20811    #[test]
20812    fn unhandled_committed_action_fails_loud_under_error_policy() {
20813        // An action offered to the hook that no hook handles (returns false)
20814        // must be recorded and surfaced as `AntlrError::Unsupported` under the
20815        // Error policy, so a `hook`-disposed action is not silently dropped.
20816        let mut parser = mini_parser_with_hooks(vec![TestToken::eof("t", 0, 1, 0)], DecliningHooks);
20817        parser.set_unknown_predicate_policy(UnknownSemanticPolicy::Error);
20818        let tree = parser.rule_node(ParserRuleContext::new(0, -1));
20819
20820        // DecliningHooks::action returns false (unhandled).
20821        assert!(!parser.parser_action_hook(ParserAction::new(42, 0, 0, Some(0)), tree));
20822
20823        let error = parser
20824            .take_unknown_semantic_error()
20825            .expect("an unhandled committed action under Error policy must fail loud");
20826        let AntlrError::Unsupported(message) = error else {
20827            panic!("expected AntlrError::Unsupported, got {error:?}");
20828        };
20829        assert!(
20830            message.contains("unhandled semantic action") && message.contains("state=42"),
20831            "message should name the dropped action coordinate: {message}"
20832        );
20833
20834        // Under the default (assume-true) policy the same miss is not recorded.
20835        let mut lenient =
20836            mini_parser_with_hooks(vec![TestToken::eof("t", 0, 1, 0)], DecliningHooks);
20837        let tree = lenient.rule_node(ParserRuleContext::new(0, -1));
20838        assert!(!lenient.parser_action_hook(ParserAction::new(42, 0, 0, Some(0)), tree));
20839        assert!(lenient.take_unknown_semantic_error().is_none());
20840    }
20841
20842    #[test]
20843    fn translated_predicate_is_unaffected_by_error_policy() {
20844        let atn = predicate_after_token_atn();
20845        let mut parser = mini_parser(vec![
20846            TestToken::new(1).with_text("x"),
20847            TestToken::new(2).with_text("y"),
20848            TestToken::eof("parser-test", 2, 1, 2),
20849        ]);
20850
20851        let (tree, _) = parser
20852            .parse_atn_rule_with_runtime_options(
20853                &atn,
20854                0,
20855                ParserRuntimeOptions {
20856                    predicates: &[(0, 0, ParserPredicate::True)],
20857                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
20858                    ..ParserRuntimeOptions::default()
20859                },
20860            )
20861            .expect("a predicate covered by the table is not an unknown coordinate");
20862
20863        assert_eq!(parser.node(tree).text(), "xy");
20864    }
20865
20866    /// Stack-valued member statements must execute on the parser's speculative
20867    /// replay path, not just the lexer's committed one (issue #206). This drives
20868    /// `apply_member_actions` -> `ParserTableSemCtx` -> `MemberEnv` directly,
20869    /// which is the path a generated parser's `@members` stack state takes.
20870    #[test]
20871    fn parser_speculative_replay_threads_stack_member_state() {
20872        let mut ir = SemIr::new();
20873        let one = ir.expr(PExpr::Int(1));
20874        let push = ir.stmt(AStmt::PushMember(0, one));
20875        let pop = ir.stmt(AStmt::PopMember(0));
20876        let semantics = ParserSemantics {
20877            ir,
20878            predicates: Vec::new(),
20879            actions: vec![
20880                ParserSemanticAction {
20881                    source_state: 1,
20882                    rule_index: usize::MAX,
20883                    stmt: push,
20884                    speculative: true,
20885                },
20886                ParserSemanticAction {
20887                    source_state: 2,
20888                    rule_index: usize::MAX,
20889                    stmt: pop,
20890                    speculative: true,
20891                },
20892            ],
20893        };
20894
20895        // Replaying the push state must be visible to a later read...
20896        let pushed = member_values_after_action(1, &[], Some(&semantics), &MemberEnv::new());
20897        assert_eq!(pushed.stack_top(0), Some(1));
20898        assert_eq!(pushed.stack_len(0), 1);
20899
20900        // ...and must not mutate the caller's env: speculative paths are
20901        // path-local, so an abandoned branch cannot leak state to its sibling.
20902        assert_eq!(MemberEnv::new().stack_len(0), 0);
20903
20904        // Replaying the pop state restores the empty, canonical env, so the
20905        // resulting memo key matches an equivalent untouched path.
20906        let popped = member_values_after_action(2, &[], Some(&semantics), &pushed);
20907        assert_eq!(popped.stack_top(0), None);
20908        assert_eq!(popped, MemberEnv::new(), "emptied stack must canonicalize");
20909
20910        // An unbalanced pop is a defined no-op rather than a panic.
20911        let underflowed = member_values_after_action(2, &[], Some(&semantics), &MemberEnv::new());
20912        assert_eq!(underflowed, MemberEnv::new());
20913    }
20914
20915    /// Hooks that decline (`None`) must fall through to the configured policy
20916    /// even when the coordinate carries a [`semir`] `Hook` node, matching the
20917    /// legacy table path. Regression for the `unwrap_or(false)` that silently
20918    /// rejected declined hook nodes and bypassed [`UnknownSemanticPolicy`].
20919    fn hook_predicate_semantics() -> ParserSemantics {
20920        let mut ir = SemIr::new();
20921        let expr = ir.expr(PExpr::Hook(HookId::new(0)));
20922        ParserSemantics {
20923            ir,
20924            predicates: vec![ParserSemanticPredicate {
20925                rule_index: 0,
20926                pred_index: 0,
20927                expr,
20928                failure_message: None,
20929            }],
20930            actions: Vec::new(),
20931        }
20932    }
20933
20934    #[derive(Debug, Default)]
20935    struct DecliningHooks;
20936
20937    impl SemanticHooks for DecliningHooks {}
20938
20939    #[test]
20940    fn semir_hook_none_falls_through_to_assume_true() {
20941        let atn = predicate_after_token_atn();
20942        let semantics = hook_predicate_semantics();
20943        let mut parser = mini_parser_with_hooks(
20944            vec![
20945                TestToken::new(1).with_text("x"),
20946                TestToken::new(2).with_text("y"),
20947                TestToken::eof("parser-test", 2, 1, 2),
20948            ],
20949            DecliningHooks,
20950        );
20951
20952        let (tree, _) = parser
20953            .parse_atn_rule_with_runtime_options(
20954                &atn,
20955                0,
20956                ParserRuntimeOptions {
20957                    semantics: Some(&semantics),
20958                    unknown_predicate_policy: UnknownSemanticPolicy::AssumeTrue,
20959                    ..ParserRuntimeOptions::default()
20960                },
20961            )
20962            .expect("a declined SemIR hook must pass under assume-true");
20963
20964        assert_eq!(parser.node(tree).text(), "xy");
20965    }
20966
20967    #[test]
20968    fn semir_hook_none_falls_through_to_assume_false() {
20969        let atn = predicate_after_token_atn();
20970        let semantics = hook_predicate_semantics();
20971        let mut parser = mini_parser_with_hooks(
20972            vec![
20973                TestToken::new(1).with_text("x"),
20974                TestToken::new(2).with_text("y"),
20975                TestToken::eof("parser-test", 2, 1, 2),
20976            ],
20977            DecliningHooks,
20978        );
20979
20980        let result = parser.parse_atn_rule_with_runtime_options(
20981            &atn,
20982            0,
20983            ParserRuntimeOptions {
20984                semantics: Some(&semantics),
20985                unknown_predicate_policy: UnknownSemanticPolicy::AssumeFalse,
20986                ..ParserRuntimeOptions::default()
20987            },
20988        );
20989
20990        assert!(
20991            result.is_err(),
20992            "a declined SemIR hook must fail the only guarded path under assume-false"
20993        );
20994    }
20995
20996    #[test]
20997    fn semir_hook_none_records_coordinate_under_error_policy() {
20998        let atn = predicate_after_token_atn();
20999        let semantics = hook_predicate_semantics();
21000        let mut parser = mini_parser_with_hooks(
21001            vec![
21002                TestToken::new(1).with_text("x"),
21003                TestToken::new(2).with_text("y"),
21004                TestToken::eof("parser-test", 2, 1, 2),
21005            ],
21006            DecliningHooks,
21007        );
21008
21009        let error = parser
21010            .parse_atn_rule_with_runtime_options(
21011                &atn,
21012                0,
21013                ParserRuntimeOptions {
21014                    semantics: Some(&semantics),
21015                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
21016                    ..ParserRuntimeOptions::default()
21017                },
21018            )
21019            .expect_err("a declined SemIR hook under Error policy must fail the parse");
21020
21021        let AntlrError::Unsupported(message) = error else {
21022            panic!("expected AntlrError::Unsupported, got {error:?}");
21023        };
21024        assert!(
21025            message.contains("unsupported semantic predicate") && message.contains("pred_index=0"),
21026            "message should name the unresolved coordinate: {message}"
21027        );
21028    }
21029
21030    #[test]
21031    fn generated_direct_predicate_honors_installed_policy() {
21032        // The generated recursive-descent path calls
21033        // `parser_semantic_ir_predicate_matches_with_context_and_local` without
21034        // going through `ParserRuntimeOptions`, so the policy must be installed
21035        // via `set_unknown_predicate_policy` (as the generated constructor now
21036        // does). A declining hook must then honor it rather than the default.
21037        let semantics = hook_predicate_semantics();
21038        let context = ParserRuleContext::new(0, -1);
21039
21040        let mut assume_true =
21041            mini_parser_with_hooks(vec![TestToken::eof("t", 0, 1, 0)], DecliningHooks);
21042        assert!(
21043            assume_true.parser_semantic_ir_predicate_matches_with_context_and_local(
21044                &semantics, 0, 0, &context, 0
21045            ),
21046            "default AssumeTrue accepts a declined hook"
21047        );
21048        assert!(assume_true.take_unknown_semantic_error().is_none());
21049
21050        let mut error_policy =
21051            mini_parser_with_hooks(vec![TestToken::eof("t", 0, 1, 0)], DecliningHooks);
21052        error_policy.set_unknown_predicate_policy(UnknownSemanticPolicy::Error);
21053        assert!(
21054            !error_policy.parser_semantic_ir_predicate_matches_with_context_and_local(
21055                &semantics, 0, 0, &context, 0
21056            ),
21057            "Error policy rejects a declined hook on the generated-direct path"
21058        );
21059        let error = error_policy
21060            .take_unknown_semantic_error()
21061            .expect("Error policy records the unresolved coordinate for the generated path");
21062        let AntlrError::Unsupported(message) = error else {
21063            panic!("expected AntlrError::Unsupported, got {error:?}");
21064        };
21065        assert!(message.contains("pred_index=0"), "message: {message}");
21066    }
21067
21068    #[test]
21069    fn parser_rule_start_skips_leading_hidden_tokens() {
21070        let atn = token_then_eof_atn();
21071        let mut parser = mini_parser(vec![
21072            TestToken::new(99)
21073                .with_text(" ")
21074                .with_channel(HIDDEN_CHANNEL),
21075            TestToken::new(1).with_text("x"),
21076            TestToken::eof("parser-test", 2, 1, 2),
21077        ]);
21078
21079        let tree = parser
21080            .parse_atn_rule(&atn, 0)
21081            .expect("artificial parser rule should parse");
21082        let Some(rule) = parser.node(tree).first_rule(0).and_then(Node::as_rule) else {
21083            panic!("rule node should be present");
21084        };
21085        assert_eq!(
21086            rule.start()
21087                .expect("rule should have a start token")
21088                .token_type(),
21089            1
21090        );
21091    }
21092
21093    #[test]
21094    fn parser_action_after_eof_stops_at_eof_token() {
21095        let atn = eof_then_action_atn();
21096        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 0, 1, 0)]);
21097
21098        let (_, actions) = parser
21099            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
21100            .expect("EOF action rule should parse");
21101
21102        assert_eq!(actions.len(), 1);
21103        assert_eq!(actions[0].stop_index(), Some(0));
21104        assert_eq!(
21105            parser.text_interval(actions[0].start_index(), actions[0].stop_index()),
21106            ""
21107        );
21108    }
21109
21110    #[test]
21111    fn after_action_stop_uses_rule_context_stop_not_cursor() {
21112        // A rule that ends right before EOF without matching it (e.g. `a: ID;`
21113        // called from `start: a EOF;`): after matching ID the cursor parks on EOF,
21114        // but the rule did not consume it. The @after stop must follow the rule
21115        // context's recorded stop (ID at index 0), not the cursor's EOF (index 1).
21116        let mut id = TestToken::new(1).with_text("x");
21117        id.set_token_index(0);
21118        let mut eof = TestToken::eof("parser-test", 1, 1, 1);
21119        eof.set_token_index(1);
21120        let mut parser = mini_parser(vec![id.clone(), eof]);
21121        // Advance the cursor onto EOF, as it would be after `a` matched ID.
21122        parser.consume();
21123        assert_eq!(parser.la(1), TOKEN_EOF);
21124
21125        // Rule `a` matched only ID, so its context stop is the ID token (index 0),
21126        // exactly what finish_rule(consumed_eof = false) records.
21127        let mut ctx = ParserRuleContext::new(0, 0);
21128        parser.set_context_stop(
21129            &mut ctx,
21130            parser.token_id_at(0).expect("ID token should be buffered"),
21131        );
21132        let tree = parser.rule_node(ctx);
21133
21134        let current_index = parser.input.index();
21135        // Cursor-only inference would wrongly pick EOF (the parked cursor)...
21136        assert_eq!(parser.after_action_stop_index(current_index), Some(1));
21137        // ...but the tree-aware helper follows the rule context stop (ID).
21138        assert_eq!(
21139            parser.after_action_stop_index_for_tree(tree, current_index),
21140            Some(0)
21141        );
21142    }
21143
21144    #[test]
21145    fn after_action_start_uses_rule_context_start_not_cursor() {
21146        // A rule that begins after leading hidden-channel tokens: the rule context
21147        // start (set by `enter_rule`) is the first visible token, not the raw cursor
21148        // that may still point at the hidden prefix. The @after start must follow
21149        // the context start so `$start`/`$text` excludes the hidden prefix.
21150        let mut parser = mini_parser(vec![
21151            TestToken::new(9)
21152                .with_text(" ")
21153                .with_channel(HIDDEN_CHANNEL),
21154            TestToken::new(9)
21155                .with_text(" ")
21156                .with_channel(HIDDEN_CHANNEL),
21157            TestToken::new(1).with_text("x"),
21158            TestToken::eof("parser-test", 3, 1, 3),
21159        ]);
21160
21161        let mut ctx = ParserRuleContext::new(0, 0);
21162        parser.set_context_start(
21163            &mut ctx,
21164            parser.token_id_at(2).expect("ID token should be buffered"),
21165        );
21166        let tree = parser.rule_node(ctx);
21167
21168        // The raw fallback (pre-rule cursor) would be 0 (the hidden prefix)...
21169        // ...but the tree-aware helper follows the rule context start (index 2).
21170        assert_eq!(parser.after_action_start_index_for_tree(tree, 0), 2);
21171
21172        // With no rule start recorded, it falls back to the provided index.
21173        let empty = parser.rule_node(ParserRuleContext::new(0, 0));
21174        assert_eq!(parser.after_action_start_index_for_tree(empty, 7), 7);
21175    }
21176
21177    fn clean_fast_outcome(index: usize, consumed_eof: bool, marker: u32) -> FastRecognizeOutcome {
21178        FastRecognizeOutcome {
21179            index,
21180            consumed_eof,
21181            diagnostics: DiagnosticSeqId::EMPTY,
21182            deferred_nodes: FastDeferredNodeId::EMPTY,
21183            nodes: NodeSeqId(marker),
21184        }
21185    }
21186
21187    #[test]
21188    fn clean_fast_outcome_dedupe_scans_small_lists_inline() {
21189        let mut outcomes = vec![
21190            clean_fast_outcome(4, false, 0),
21191            clean_fast_outcome(2, false, 1),
21192            clean_fast_outcome(4, false, 2),
21193            clean_fast_outcome(4, true, 3),
21194            clean_fast_outcome(2, false, 4),
21195        ];
21196        let mut scratch = FastOutcomeDedupScratch::default();
21197
21198        let strategy = dedupe_clean_fast_outcomes(&mut outcomes, &mut scratch);
21199
21200        assert_eq!(strategy, FastOutcomeDedupStrategy::Inline);
21201        assert_eq!(
21202            outcomes
21203                .iter()
21204                .map(|outcome| (outcome.index, outcome.consumed_eof, outcome.nodes.0))
21205                .collect::<Vec<_>>(),
21206            vec![(4, false, 0), (2, false, 1), (4, true, 3)]
21207        );
21208        assert!(scratch.dense_words.is_empty());
21209        assert!(scratch.sparse_keys.is_empty());
21210    }
21211
21212    #[test]
21213    fn clean_fast_outcome_dedupe_uses_and_reuses_dense_bitmap() {
21214        let mut scratch = FastOutcomeDedupScratch::default();
21215        let mut outcomes = (100..109)
21216            .flat_map(|index| {
21217                [
21218                    clean_fast_outcome(
21219                        index,
21220                        false,
21221                        u32::try_from(index).expect("test index fits in u32"),
21222                    ),
21223                    clean_fast_outcome(index, false, u32::MAX),
21224                ]
21225            })
21226            .collect();
21227
21228        let strategy = dedupe_clean_fast_outcomes(&mut outcomes, &mut scratch);
21229
21230        assert_eq!(strategy, FastOutcomeDedupStrategy::Dense);
21231        assert_eq!(outcomes.len(), 9);
21232        assert_eq!(outcomes[0].nodes, NodeSeqId(100));
21233        let dense_capacity = scratch.dense_words.capacity();
21234
21235        let mut reused = (1_000..1_009)
21236            .map(|index| {
21237                clean_fast_outcome(
21238                    index,
21239                    false,
21240                    u32::try_from(index).expect("test index fits in u32"),
21241                )
21242            })
21243            .collect();
21244        let strategy = dedupe_clean_fast_outcomes(&mut reused, &mut scratch);
21245
21246        assert_eq!(strategy, FastOutcomeDedupStrategy::Dense);
21247        assert_eq!(reused.len(), 9);
21248        assert_eq!(scratch.dense_words.capacity(), dense_capacity);
21249    }
21250
21251    #[test]
21252    fn clean_fast_outcome_dedupe_uses_and_reuses_sparse_hash() {
21253        let mut scratch = FastOutcomeDedupScratch::default();
21254        let sparse_indexes = [
21255            0, 100_000, 200_000, 300_000, 400_000, 500_000, 600_000, 700_000, 800_000,
21256        ];
21257        let mut outcomes = sparse_indexes
21258            .into_iter()
21259            .chain([400_000])
21260            .enumerate()
21261            .map(|(marker, index)| {
21262                clean_fast_outcome(
21263                    index,
21264                    false,
21265                    u32::try_from(marker).expect("test marker fits in u32"),
21266                )
21267            })
21268            .collect();
21269
21270        let strategy = dedupe_clean_fast_outcomes(&mut outcomes, &mut scratch);
21271
21272        assert_eq!(strategy, FastOutcomeDedupStrategy::Sparse);
21273        assert_eq!(outcomes.len(), sparse_indexes.len());
21274        assert_eq!(outcomes[4].nodes, NodeSeqId(4));
21275        let sparse_capacity = scratch.sparse_keys.capacity();
21276
21277        let mut reused = sparse_indexes
21278            .into_iter()
21279            .map(|index| {
21280                clean_fast_outcome(
21281                    index,
21282                    false,
21283                    u32::try_from(index).expect("test index fits in u32"),
21284                )
21285            })
21286            .collect();
21287        let strategy = dedupe_clean_fast_outcomes(&mut reused, &mut scratch);
21288
21289        assert_eq!(strategy, FastOutcomeDedupStrategy::Sparse);
21290        assert_eq!(reused.len(), sparse_indexes.len());
21291        assert_eq!(scratch.sparse_keys.capacity(), sparse_capacity);
21292    }
21293
21294    #[test]
21295    fn clean_fast_outcome_dedupe_releases_oversized_sparse_hash() {
21296        let mut scratch = FastOutcomeDedupScratch::default();
21297        scratch
21298            .sparse_keys
21299            .reserve(MAX_RETAINED_FAST_OUTCOME_SPARSE_KEYS * 2);
21300        assert!(scratch.sparse_keys.capacity() > MAX_RETAINED_FAST_OUTCOME_SPARSE_KEYS);
21301        let mut outcomes = (0..9)
21302            .map(|index| clean_fast_outcome(index * 100_000, false, index as u32))
21303            .collect();
21304
21305        let strategy = dedupe_clean_fast_outcomes(&mut outcomes, &mut scratch);
21306
21307        assert_eq!(strategy, FastOutcomeDedupStrategy::Sparse);
21308        assert!(scratch.sparse_keys.is_empty());
21309        assert!(scratch.sparse_keys.capacity() <= MAX_RETAINED_FAST_OUTCOME_SPARSE_KEYS);
21310    }
21311
21312    #[test]
21313    fn fast_outcome_selection_respects_sll_tie_order() {
21314        let mut arena = RecognitionArena::default();
21315        let first = FastRecognizeOutcome {
21316            index: 1,
21317            consumed_eof: false,
21318            diagnostics: arena.diagnostic_sequence([ParserDiagnostic {
21319                line: 1,
21320                column: 0,
21321                message: "mismatched input 'x'".to_owned(),
21322                offending: None,
21323            }]),
21324            deferred_nodes: FastDeferredNodeId::EMPTY,
21325            nodes: NodeSeqId::EMPTY,
21326        };
21327        let second = FastRecognizeOutcome {
21328            index: first.index,
21329            consumed_eof: first.consumed_eof,
21330            diagnostics: DiagnosticSeqId::EMPTY,
21331            deferred_nodes: FastDeferredNodeId::EMPTY,
21332            nodes: NodeSeqId::EMPTY,
21333        };
21334
21335        let selected = select_best_fast_outcome(
21336            [first, second].into_iter(),
21337            PredictionMode::Sll,
21338            None,
21339            |_| panic!("caller-follow token probe should not run"),
21340            &arena,
21341        )
21342        .expect("one outcome should be selected");
21343        assert_eq!(arena.diagnostics_len(selected.diagnostics), 1);
21344        let eof_second = FastRecognizeOutcome {
21345            index: second.index,
21346            consumed_eof: true,
21347            diagnostics: DiagnosticSeqId::EMPTY,
21348            deferred_nodes: FastDeferredNodeId::EMPTY,
21349            nodes: NodeSeqId::EMPTY,
21350        };
21351        let selected = select_best_fast_outcome(
21352            [first, eof_second].into_iter(),
21353            PredictionMode::Sll,
21354            None,
21355            |_| panic!("caller-follow token probe should not run"),
21356            &arena,
21357        )
21358        .expect("one outcome should be selected");
21359        assert!(!selected.consumed_eof);
21360        let selected = select_best_fast_outcome(
21361            [first, second].into_iter(),
21362            PredictionMode::Ll,
21363            None,
21364            |_| panic!("caller-follow token probe should not run"),
21365            &arena,
21366        )
21367        .expect("one outcome should be selected");
21368        assert!(selected.diagnostics.is_empty());
21369    }
21370
21371    #[test]
21372    fn recovery_fast_outcome_dedupe_uses_selection_rank() {
21373        let mut arena = RecognitionArena::default();
21374        let first = FastRecognizeOutcome {
21375            index: 3,
21376            consumed_eof: false,
21377            diagnostics: arena.diagnostic_sequence([ParserDiagnostic {
21378                line: 1,
21379                column: 0,
21380                message: "mismatched input 'x' expecting 'a'".to_owned(),
21381                offending: None,
21382            }]),
21383            deferred_nodes: FastDeferredNodeId::EMPTY,
21384            nodes: NodeSeqId::EMPTY,
21385        };
21386        let same_rank = FastRecognizeOutcome {
21387            index: first.index,
21388            consumed_eof: first.consumed_eof,
21389            diagnostics: arena.diagnostic_sequence([ParserDiagnostic {
21390                line: 1,
21391                column: 0,
21392                message: "mismatched input 'x' expecting 'b'".to_owned(),
21393                offending: None,
21394            }]),
21395            deferred_nodes: FastDeferredNodeId::EMPTY,
21396            nodes: NodeSeqId::EMPTY,
21397        };
21398        let better_rank = FastRecognizeOutcome {
21399            index: first.index,
21400            consumed_eof: first.consumed_eof,
21401            diagnostics: arena.diagnostic_sequence([ParserDiagnostic {
21402                line: 1,
21403                column: 0,
21404                message: "missing 'a' at 'x'".to_owned(),
21405                offending: None,
21406            }]),
21407            deferred_nodes: FastDeferredNodeId::EMPTY,
21408            nodes: NodeSeqId::EMPTY,
21409        };
21410        let mut outcomes = vec![first, same_rank, better_rank];
21411
21412        dedupe_fast_outcomes(&mut outcomes, &arena);
21413
21414        assert_eq!(outcomes.len(), 2);
21415        assert_eq!(
21416            arena
21417                .diagnostics(outcomes[0].diagnostics)
21418                .next()
21419                .expect("first diagnostic")
21420                .message,
21421            "mismatched input 'x' expecting 'a'"
21422        );
21423        assert_eq!(
21424            arena
21425                .diagnostics(outcomes[1].diagnostics)
21426                .next()
21427                .expect("second diagnostic")
21428                .message,
21429            "missing 'a' at 'x'"
21430        );
21431    }
21432
21433    #[test]
21434    fn fast_outcome_selection_prefers_generated_caller_follow() {
21435        let arena = RecognitionArena::default();
21436        let earlier = FastRecognizeOutcome {
21437            index: 7,
21438            consumed_eof: false,
21439            diagnostics: DiagnosticSeqId::EMPTY,
21440            deferred_nodes: FastDeferredNodeId::EMPTY,
21441            nodes: NodeSeqId::EMPTY,
21442        };
21443        let later = FastRecognizeOutcome {
21444            index: 8,
21445            consumed_eof: false,
21446            diagnostics: DiagnosticSeqId::EMPTY,
21447            deferred_nodes: FastDeferredNodeId::EMPTY,
21448            nodes: NodeSeqId::EMPTY,
21449        };
21450        let mut follow = TokenBitSet::default();
21451        follow.insert(5);
21452
21453        let selected = select_best_fast_outcome(
21454            [later, earlier].into_iter(),
21455            PredictionMode::Ll,
21456            Some(&follow),
21457            |index| (if index == 7 { 5 } else { TOKEN_EOF }, index == 7, true),
21458            &arena,
21459        )
21460        .expect("one outcome should be selected");
21461        assert_eq!(selected.index, 7);
21462
21463        let selected = select_best_fast_outcome(
21464            [later, earlier].into_iter(),
21465            PredictionMode::Ll,
21466            Some(&follow),
21467            |index| (if index == 7 { 5 } else { TOKEN_EOF }, false, true),
21468            &arena,
21469        )
21470        .expect("one outcome should be selected");
21471        assert_eq!(selected.index, 8);
21472
21473        let indented_next_statement = FastRecognizeOutcome {
21474            index: 9,
21475            consumed_eof: false,
21476            diagnostics: DiagnosticSeqId::EMPTY,
21477            deferred_nodes: FastDeferredNodeId::EMPTY,
21478            nodes: NodeSeqId::EMPTY,
21479        };
21480        let selected = select_best_fast_outcome(
21481            [indented_next_statement, earlier].into_iter(),
21482            PredictionMode::Ll,
21483            Some(&follow),
21484            |index| {
21485                let is_boundary = index == 7;
21486                let is_boundary_gap = matches!(index, 7 | 8);
21487                (
21488                    if index == 7 { 5 } else { TOKEN_EOF },
21489                    is_boundary,
21490                    is_boundary_gap,
21491                )
21492            },
21493            &arena,
21494        )
21495        .expect("one outcome should be selected");
21496        assert_eq!(selected.index, 7);
21497
21498        let continuation = FastRecognizeOutcome {
21499            index: 10,
21500            consumed_eof: false,
21501            diagnostics: DiagnosticSeqId::EMPTY,
21502            deferred_nodes: FastDeferredNodeId::EMPTY,
21503            nodes: NodeSeqId::EMPTY,
21504        };
21505        let selected = select_best_fast_outcome(
21506            [continuation, earlier].into_iter(),
21507            PredictionMode::Ll,
21508            Some(&follow),
21509            |index| {
21510                let is_boundary = matches!(index, 7 | 9);
21511                (
21512                    if index == 7 { 5 } else { TOKEN_EOF },
21513                    is_boundary,
21514                    is_boundary,
21515                )
21516            },
21517            &arena,
21518        )
21519        .expect("one outcome should be selected");
21520        assert_eq!(selected.index, 10);
21521
21522        let selected = select_best_fast_outcome(
21523            [earlier, later].into_iter(),
21524            PredictionMode::Sll,
21525            Some(&follow),
21526            |_| panic!("caller-follow token probe should not run in SLL mode"),
21527            &arena,
21528        )
21529        .expect("one outcome should be selected");
21530        assert_eq!(selected.index, 8);
21531    }
21532
21533    #[test]
21534    fn caller_follow_boundary_text_requires_separator_shape() {
21535        assert!(is_caller_follow_boundary_text(";"));
21536        assert!(is_caller_follow_boundary_text("\n"));
21537        assert!(is_caller_follow_boundary_text("\r\n  "));
21538        assert!(is_caller_follow_boundary_text(";\n"));
21539        assert!(!is_caller_follow_boundary_text("\"\"\"line1\nline2\"\"\""));
21540        assert!(!is_caller_follow_boundary_text("/* line1\nline2 */"));
21541        assert!(!is_caller_follow_boundary_text("identifier"));
21542        assert!(is_caller_follow_boundary_gap_text(" \t "));
21543        assert!(is_caller_follow_boundary_gap_text("\n  "));
21544        assert!(is_caller_follow_boundary_gap_text(";\t"));
21545        assert!(!is_caller_follow_boundary_gap_text(
21546            "\"\"\"line1\nline2\"\"\""
21547        ));
21548        assert!(!is_caller_follow_boundary_gap_text("/* line1\nline2 */"));
21549    }
21550
21551    #[test]
21552    fn caller_follow_token_info_treats_hidden_tokens_as_boundary_gaps() {
21553        let mut parser = mini_parser(vec![
21554            TestToken::new(5).with_text("\n"),
21555            TestToken::new(6)
21556                .with_text("// comment\n")
21557                .with_channel(HIDDEN_CHANNEL),
21558            TestToken::new(1).with_text("x"),
21559            TestToken::eof("parser-test", 1, 2, 0),
21560        ]);
21561
21562        assert_eq!(parser.caller_follow_token_info(0), (5, true, true));
21563        assert_eq!(parser.caller_follow_token_info(1), (6, false, true));
21564        assert_eq!(parser.caller_follow_token_info(2), (1, false, false));
21565    }
21566
21567    #[test]
21568    fn caller_follow_token_info_uses_stream_visible_channel() {
21569        let source = Source {
21570            tokens: vec![
21571                TestToken::new(5).with_text("\n").with_channel(2),
21572                TestToken::new(1).with_text("x").with_channel(2),
21573                TestToken::new(6)
21574                    .with_text("// comment\n")
21575                    .with_channel(HIDDEN_CHANNEL),
21576                TestToken::eof("parser-test", 1, 2, 0),
21577            ],
21578            index: 0,
21579        };
21580        let data = RecognizerData::new(
21581            "Mini.g4",
21582            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
21583        );
21584        let mut parser = BaseParser::new(CommonTokenStream::with_channel(source, 2), data);
21585
21586        assert_eq!(parser.caller_follow_token_info(0), (5, true, true));
21587        assert_eq!(parser.caller_follow_token_info(1), (1, false, false));
21588        assert_eq!(parser.caller_follow_token_info(2), (6, false, true));
21589    }
21590
21591    #[test]
21592    fn reset_per_parse_caches_clears_state_expected_token_cache() {
21593        let atn = token_then_eof_atn();
21594        let mut parser = mini_parser(Vec::new());
21595
21596        let _ = parser.cached_state_expected_token_set(&atn, 0);
21597        assert!(!parser.state_expected_token_cache.is_empty());
21598
21599        parser.reset_per_parse_caches();
21600        assert!(parser.state_expected_token_cache.is_empty());
21601    }
21602
21603    #[test]
21604    fn empty_cycle_cache_survives_reset_and_invalidates_for_a_different_atn() {
21605        let cyclic = epsilon_cycle_atn();
21606        let acyclic = token_then_eof_atn();
21607        let mut parser = mini_parser(Vec::new());
21608
21609        assert!(parser.state_can_reenter_without_consuming(&cyclic, 1));
21610        assert_eq!(
21611            parser.empty_cycle_cache_atn,
21612            Some(SharedAtnCacheKey::for_atn(&cyclic))
21613        );
21614        assert_eq!(parser.empty_cycle_cache[1], Some(true));
21615
21616        parser.reset_per_parse_caches();
21617        assert_eq!(parser.empty_cycle_cache[1], Some(true));
21618        assert!(parser.state_can_reenter_without_consuming(&cyclic, 1));
21619
21620        assert!(!parser.state_can_reenter_without_consuming(&acyclic, 1));
21621        assert_eq!(
21622            parser.empty_cycle_cache_atn,
21623            Some(SharedAtnCacheKey::for_atn(&acyclic))
21624        );
21625        assert_eq!(parser.empty_cycle_cache[1], Some(false));
21626    }
21627
21628    #[test]
21629    fn parser_error_with_empty_expected_set_omits_empty_set_display() {
21630        let source = Source {
21631            tokens: vec![
21632                TestToken::new(1).with_text("x"),
21633                TestToken::eof("parser-test", 1, 1, 1),
21634            ],
21635            index: 0,
21636        };
21637        let data = RecognizerData::new(
21638            "Mini.g4",
21639            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
21640        );
21641        let mut parser = BaseParser::new(CommonTokenStream::new(source), data);
21642        let expected = ExpectedTokens {
21643            index: Some(0),
21644            symbols: BTreeSet::new(),
21645            no_viable: None,
21646        };
21647
21648        let (_, message) = parser.expected_error_message(0, 0, &expected);
21649
21650        assert_eq!(message, "mismatched input 'x'");
21651    }
21652
21653    #[test]
21654    fn eof_rule_stop_index_points_at_eof_token() {
21655        let source = Source {
21656            tokens: vec![
21657                TestToken::new(1).with_text("x"),
21658                TestToken::eof("parser-test", 1, 1, 1),
21659            ],
21660            index: 0,
21661        };
21662        let data = RecognizerData::new(
21663            "Mini.g4",
21664            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
21665        );
21666        let mut parser = BaseParser::new(CommonTokenStream::new(source), data);
21667
21668        assert_eq!(parser.rule_stop_token_index(1, true), Some(1));
21669        assert_eq!(parser.rule_stop_token_index(1, false), Some(0));
21670    }
21671
21672    #[test]
21673    fn generated_parser_action_uses_current_rule_stop_boundary() {
21674        let mut parser = mini_parser(vec![
21675            TestToken::new(1).with_text("x"),
21676            TestToken::eof("parser-test", 1, 1, 1),
21677        ]);
21678
21679        parser.match_token(1).expect("token should match");
21680        let action = parser.parser_action_at_current(7, 0, 0, false);
21681        assert_eq!(action.source_state(), 7);
21682        assert_eq!(action.rule_index(), 0);
21683        assert_eq!(action.start_index(), 0);
21684        assert_eq!(action.stop_index(), Some(0));
21685
21686        parser.match_eof().expect("EOF should match");
21687        let action = parser.parser_action_at_current(8, 0, 0, true);
21688        assert_eq!(action.stop_index(), Some(1));
21689    }
21690
21691    #[test]
21692    fn folds_left_recursive_boundary_into_rule_node() {
21693        let mut arena = RecognitionArena::default();
21694        let first = arena.push_node(ArenaRecognizedNode::Token {
21695            token: TokenId::try_from(0).expect("test token ID"),
21696        });
21697        let boundary = arena.push_node(ArenaRecognizedNode::LeftRecursiveBoundary {
21698            rule_index: 1,
21699            alt_number: 3,
21700        });
21701        let second = arena.push_node(ArenaRecognizedNode::Token {
21702            token: TokenId::try_from(1).expect("test token ID"),
21703        });
21704        let mut nodes = NodeSeqId::EMPTY;
21705        for node in [first, boundary, second].into_iter().rev() {
21706            nodes = arena.prepend(nodes, node);
21707        }
21708
21709        let folded = arena.fold_left_recursive_boundaries(nodes);
21710        let folded_nodes = arena.iter(folded).collect::<Vec<_>>();
21711
21712        assert_eq!(folded_nodes.len(), 2);
21713        let ArenaRecognizedNode::Rule {
21714            rule_index,
21715            invoking_state,
21716            alt_number,
21717            start_index,
21718            stop_index,
21719            children,
21720            ..
21721        } = arena.node(folded_nodes[0])
21722        else {
21723            panic!("first folded node should be a rule");
21724        };
21725        // The folded rule node's scalar shape (rule/invoking-state/alt/start/stop) is one snapshot;
21726        // child resolution and the sibling identity below stay explicit — a node Debug prints the
21727        // children handle, not the resolved sequence they assert on.
21728        insta::assert_debug_snapshot!(
21729            "folds_left_recursive_boundary_into_rule_node",
21730            (
21731                rule_index,
21732                invoking_state,
21733                alt_number,
21734                start_index,
21735                stop_index
21736            )
21737        );
21738        assert_eq!(arena.iter(children).collect::<Vec<_>>(), [first]);
21739        assert_eq!(arena.node(folded_nodes[1]), arena.node(second));
21740
21741        let stats = arena.stats(folded, DiagnosticSeqId::EMPTY);
21742        assert_eq!(
21743            (stats.total_nodes, stats.live_nodes, stats.dead_nodes),
21744            (4, 3, 1)
21745        );
21746        assert_eq!(
21747            (stats.total_links, stats.live_links, stats.dead_links),
21748            (9, 3, 6)
21749        );
21750    }
21751
21752    #[test]
21753    fn recognition_arena_reports_live_dead_and_retained_capacity() {
21754        let mut arena = RecognitionArena::default();
21755        let token = arena.push_node(ArenaRecognizedNode::Token {
21756            token: TokenId::try_from(0).expect("test token ID"),
21757        });
21758        let extra = arena.push_extra(RecognitionExtra::MissingToken {
21759            token_type: 2,
21760            at_index: 1,
21761            text: "<missing X>".to_owned(),
21762        });
21763        let missing = arena.push_node(ArenaRecognizedNode::MissingToken { extra });
21764        let discarded = arena.push_node(ArenaRecognizedNode::ErrorToken {
21765            token: TokenId::try_from(1).expect("test token ID"),
21766        });
21767        let mut live = NodeSeqId::EMPTY;
21768        live = arena.prepend(live, missing);
21769        live = arena.prepend(live, token);
21770        let _discarded_sequence = arena.prepend(NodeSeqId::EMPTY, discarded);
21771        let live_diagnostics = arena.diagnostic_sequence([ParserDiagnostic {
21772            line: 1,
21773            column: 0,
21774            message: "missing X".to_owned(),
21775            offending: None,
21776        }]);
21777        let _discarded_diagnostics = arena.diagnostic_sequence([ParserDiagnostic {
21778            line: 1,
21779            column: 1,
21780            message: "discarded".to_owned(),
21781            offending: None,
21782        }]);
21783        let deferred_children = arena.deferred_fragment(live);
21784        let _deferred_rule = arena.deferred_rule_node(FastDeferredRule {
21785            rule_index: 0,
21786            invoking_state: -1,
21787            start_index: 0,
21788            stop_index: Some(1),
21789            deferred_children,
21790            children: NodeSeqId::EMPTY,
21791        });
21792
21793        let stats = arena.stats(live, live_diagnostics);
21794
21795        assert_eq!(
21796            (stats.total_nodes, stats.live_nodes, stats.dead_nodes),
21797            (3, 2, 1)
21798        );
21799        assert_eq!(
21800            (stats.total_links, stats.live_links, stats.dead_links),
21801            (5, 3, 2)
21802        );
21803        assert_eq!(
21804            (stats.total_extras, stats.live_extras, stats.dead_extras),
21805            (3, 2, 1)
21806        );
21807        assert!(size_of::<SeqLink>() <= 8);
21808        assert!(size_of::<DiagnosticLink>() <= 8);
21809        assert!(size_of::<FastDeferredNode>() <= 12);
21810        assert!(size_of::<FastDeferredRule>() <= 28);
21811        assert!(size_of::<FastRecognizeOutcome>() <= 24);
21812        let capacities = (
21813            stats.node_capacity,
21814            stats.link_capacity,
21815            stats.extra_capacity,
21816        );
21817        let deferred_capacities = (
21818            arena.deferred_nodes.capacity(),
21819            arena.deferred_rules.capacity(),
21820        );
21821
21822        arena.reset();
21823        let reset = arena.stats(NodeSeqId::EMPTY, DiagnosticSeqId::EMPTY);
21824        assert_eq!(
21825            (reset.total_nodes, reset.total_links, reset.total_extras),
21826            (0, 0, 0)
21827        );
21828        assert_eq!(
21829            (
21830                reset.node_capacity,
21831                reset.link_capacity,
21832                reset.extra_capacity,
21833            ),
21834            capacities
21835        );
21836        assert!(arena.deferred_nodes.is_empty());
21837        assert!(arena.deferred_rules.is_empty());
21838        assert_eq!(
21839            (
21840                arena.deferred_nodes.capacity(),
21841                arena.deferred_rules.capacity(),
21842            ),
21843            deferred_capacities
21844        );
21845    }
21846
21847    #[test]
21848    fn parser_computes_recognition_arena_stats_on_demand() {
21849        let mut parser = mini_parser(Vec::new());
21850        let live = parser
21851            .recognition_arena
21852            .push_node(ArenaRecognizedNode::Token {
21853                token: TokenId::try_from(0).expect("test token ID"),
21854            });
21855        let discarded = parser
21856            .recognition_arena
21857            .push_node(ArenaRecognizedNode::ErrorToken {
21858                token: TokenId::try_from(1).expect("test token ID"),
21859            });
21860        let live_root = parser.recognition_arena.prepend(NodeSeqId::EMPTY, live);
21861        let _discarded_root = parser
21862            .recognition_arena
21863            .prepend(NodeSeqId::EMPTY, discarded);
21864        parser.finish_recognition_arena(live_root, DiagnosticSeqId::EMPTY);
21865
21866        let stats = parser.recognition_arena_stats();
21867
21868        assert_eq!(
21869            (stats.total_nodes, stats.live_nodes, stats.dead_nodes),
21870            (2, 1, 1)
21871        );
21872        assert_eq!(
21873            (stats.total_links, stats.live_links, stats.dead_links),
21874            (2, 1, 1)
21875        );
21876    }
21877
21878    #[test]
21879    fn recognition_arena_drops_capacity_above_retention_limit() {
21880        let mut storage = Vec::<u8>::with_capacity(4);
21881        storage.extend([1, 2, 3]);
21882
21883        reset_arena_vec(&mut storage, 3);
21884
21885        assert!(storage.is_empty());
21886        assert_eq!(storage.capacity(), 0);
21887    }
21888
21889    #[test]
21890    fn recognition_arena_concatenates_diagnostics_in_source_order() {
21891        let mut arena = RecognitionArena::default();
21892        let prefix = arena.diagnostic_sequence([
21893            ParserDiagnostic {
21894                line: 1,
21895                column: 0,
21896                message: "first".to_owned(),
21897                offending: None,
21898            },
21899            ParserDiagnostic {
21900                line: 1,
21901                column: 1,
21902                message: "second".to_owned(),
21903                offending: None,
21904            },
21905        ]);
21906        let suffix = arena.diagnostic_sequence([ParserDiagnostic {
21907            line: 1,
21908            column: 2,
21909            message: "third".to_owned(),
21910            offending: None,
21911        }]);
21912        let extras_before = arena.extras.len();
21913
21914        let combined = arena.concat_diagnostics(prefix, suffix);
21915        let messages = arena
21916            .diagnostics(combined)
21917            .map(|diagnostic| diagnostic.message.as_str())
21918            .collect::<Vec<_>>();
21919
21920        assert_eq!(messages, ["first", "second", "third"]);
21921        assert_eq!(arena.extras.len(), extras_before);
21922    }
21923
21924    #[test]
21925    fn outcome_ties_keep_later_non_recursive_alternative() {
21926        let arena = RecognitionArena::default();
21927        let first = RecognizeOutcome {
21928            index: 1,
21929            consumed_eof: false,
21930            alt_number: 0,
21931            member_values: MemberEnv::new(),
21932            return_values: BTreeMap::new(),
21933            diagnostics: DiagnosticSeqId::EMPTY,
21934            decisions: Vec::new(),
21935            actions: vec![ParserAction::new(1, 0, 0, None)],
21936            nodes: NodeSeqId::EMPTY,
21937        };
21938        let second = RecognizeOutcome {
21939            actions: vec![ParserAction::new(2, 0, 0, None)],
21940            ..first.clone()
21941        };
21942
21943        let selected = select_best_outcome([first, second].into_iter(), PredictionMode::Ll, &arena)
21944            .expect("one outcome should be selected");
21945        assert_eq!(selected.actions[0].source_state(), 2);
21946    }
21947
21948    #[test]
21949    fn outcome_ties_prefer_more_actions_for_non_recursive_paths() {
21950        let arena = RecognitionArena::default();
21951        let first = RecognizeOutcome {
21952            index: 1,
21953            consumed_eof: false,
21954            alt_number: 0,
21955            member_values: MemberEnv::new(),
21956            return_values: BTreeMap::new(),
21957            diagnostics: DiagnosticSeqId::EMPTY,
21958            decisions: Vec::new(),
21959            actions: vec![ParserAction::new(1, 0, 0, None)],
21960            nodes: NodeSeqId::EMPTY,
21961        };
21962        let second = RecognizeOutcome {
21963            actions: vec![
21964                ParserAction::new(2, 0, 0, None),
21965                ParserAction::new(3, 0, 0, None),
21966            ],
21967            ..first.clone()
21968        };
21969
21970        let selected = select_best_outcome([second, first].into_iter(), PredictionMode::Ll, &arena)
21971            .expect("one outcome should be selected");
21972        assert_eq!(selected.actions.len(), 2);
21973    }
21974
21975    #[test]
21976    fn outcome_ties_prefer_later_action_stop_for_greedy_optional_paths() {
21977        let arena = RecognitionArena::default();
21978        let first = RecognizeOutcome {
21979            index: 7,
21980            consumed_eof: false,
21981            alt_number: 0,
21982            member_values: MemberEnv::new(),
21983            return_values: BTreeMap::new(),
21984            diagnostics: DiagnosticSeqId::EMPTY,
21985            decisions: vec![1, 0],
21986            actions: vec![
21987                ParserAction::new(23, 2, 2, Some(4)),
21988                ParserAction::new(23, 2, 0, Some(6)),
21989            ],
21990            nodes: NodeSeqId::EMPTY,
21991        };
21992        let second = RecognizeOutcome {
21993            decisions: vec![0, 1],
21994            actions: vec![
21995                ParserAction::new(23, 2, 2, Some(6)),
21996                ParserAction::new(23, 2, 0, Some(6)),
21997            ],
21998            ..first.clone()
21999        };
22000
22001        let selected = select_best_outcome([first, second].into_iter(), PredictionMode::Ll, &arena)
22002            .expect("one outcome should be selected");
22003        assert_eq!(selected.actions[0].stop_index(), Some(6));
22004    }
22005
22006    #[test]
22007    fn outcome_ties_keep_first_recursive_tree_shape() {
22008        let mut arena = RecognitionArena::default();
22009        let token = arena.push_node(ArenaRecognizedNode::Token {
22010            token: TokenId::try_from(0).expect("test token ID"),
22011        });
22012        let token_children = arena.prepend(NodeSeqId::EMPTY, token);
22013        let inner = arena.push_node(ArenaRecognizedNode::Rule {
22014            rule_index: 1,
22015            invoking_state: -1,
22016            alt_number: 0,
22017            start_index: 0,
22018            stop_index: Some(0),
22019            return_values: None,
22020            children: token_children,
22021        });
22022        let inner_children = arena.prepend(NodeSeqId::EMPTY, inner);
22023        let outer = arena.push_node(ArenaRecognizedNode::Rule {
22024            rule_index: 1,
22025            invoking_state: -1,
22026            alt_number: 0,
22027            start_index: 0,
22028            stop_index: Some(0),
22029            return_values: None,
22030            children: inner_children,
22031        });
22032        let recursive_nodes = arena.prepend(NodeSeqId::EMPTY, outer);
22033        let first = RecognizeOutcome {
22034            index: 1,
22035            consumed_eof: false,
22036            alt_number: 0,
22037            member_values: MemberEnv::new(),
22038            return_values: BTreeMap::new(),
22039            diagnostics: DiagnosticSeqId::EMPTY,
22040            decisions: Vec::new(),
22041            actions: vec![ParserAction::new(1, 0, 0, None)],
22042            nodes: recursive_nodes,
22043        };
22044        let second = RecognizeOutcome {
22045            index: 1,
22046            consumed_eof: false,
22047            alt_number: 0,
22048            member_values: MemberEnv::new(),
22049            return_values: BTreeMap::new(),
22050            diagnostics: DiagnosticSeqId::EMPTY,
22051            decisions: Vec::new(),
22052            actions: vec![ParserAction::new(2, 0, 0, None)],
22053            nodes: recursive_nodes,
22054        };
22055
22056        let selected = select_best_outcome([first, second].into_iter(), PredictionMode::Ll, &arena)
22057            .expect("one outcome should be selected");
22058        assert_eq!(selected.actions[0].source_state(), 1);
22059    }
22060
22061    #[test]
22062    fn sll_outcome_selection_keeps_earlier_recovered_alt() {
22063        let mut arena = RecognitionArena::default();
22064        let recovered_diagnostics = arena.diagnostic_sequence([ParserDiagnostic {
22065            line: 1,
22066            column: 3,
22067            message: "missing 'Y' at '<EOF>'".to_owned(),
22068            offending: None,
22069        }]);
22070        let first_alt = RecognizeOutcome {
22071            index: 2,
22072            consumed_eof: true,
22073            alt_number: 0,
22074            member_values: MemberEnv::new(),
22075            return_values: BTreeMap::new(),
22076            diagnostics: recovered_diagnostics,
22077            decisions: vec![0],
22078            actions: vec![ParserAction::new(1, 0, 0, None)],
22079            nodes: NodeSeqId::EMPTY,
22080        };
22081        let second_alt = RecognizeOutcome {
22082            diagnostics: DiagnosticSeqId::EMPTY,
22083            decisions: vec![1],
22084            actions: vec![ParserAction::new(2, 0, 0, None)],
22085            ..first_alt.clone()
22086        };
22087
22088        let selected = select_best_outcome(
22089            [second_alt, first_alt].into_iter(),
22090            PredictionMode::Sll,
22091            &arena,
22092        )
22093        .expect("one outcome should be selected");
22094        assert_eq!(arena.diagnostics_len(selected.diagnostics), 1);
22095        assert_eq!(selected.decisions, [0]);
22096    }
22097}